diff --git a/cloud/apps/relay-edge/src/host-relay-base.ts b/cloud/apps/relay-edge/src/host-relay-base.ts index f3f34839b10..d550b6ca840 100644 --- a/cloud/apps/relay-edge/src/host-relay-base.ts +++ b/cloud/apps/relay-edge/src/host-relay-base.ts @@ -45,6 +45,9 @@ export type ControlAttachment = { clientKeepalive?: boolean // A keepalive control found silent: one relay ping sent at this time (see probeSilentControls). probeAt?: number + // Upgrade and activation times, for metrics (absent on attachments from before these fields). + openedAt?: number + activeAt?: number } export type Attachment = ControlAttachment export type Conn = { diff --git a/cloud/apps/relay-edge/src/host-relay-control.ts b/cloud/apps/relay-edge/src/host-relay-control.ts index 16697097b1c..2cc2756c22c 100644 --- a/cloud/apps/relay-edge/src/host-relay-control.ts +++ b/cloud/apps/relay-edge/src/host-relay-control.ts @@ -28,8 +28,16 @@ export abstract class HostRelayControl extends HostRelayHandshake { // Where the host is going away anyway (export, erase, drain, a new control of the same host): a // silent control is closed now. Its orphan time is the latest the ping alarm would have found it, // so rebind and the orphan grace are never shorter than before. + // A control closed for silence: value = seconds silent, label = where it was found, reason = + // keepalive | legacy; double2 = seconds since it became active (-1 if unknown). + protected deadControlMetric(a: ControlAttachment, now: number, seen: number, found: 'alarm' | 'on_demand' | 'expired'): void { + const ageS = a.activeAt === undefined ? -1 : Math.round((now - a.activeAt) / 1000) + metric(this.env, 'silence_close', Math.round((now - seen) / 1000), found, [ageS], this.keepalive(a) ? 'keepalive' : 'legacy', a.place) + } + protected async closeSilentControls(now = Date.now()): Promise { - for (const { ws, seen } of this.silentControls(now)) { + for (const { ws, a, seen } of this.silentControls(now)) { + this.deadControlMetric(a, now, seen, 'on_demand') this.close(ws, RELAY_CLOSE_CODE.PEER_DROPPED, 'control silence timeout') await this.onSocketGone(ws, RELAY_CLOSE_CODE.PEER_DROPPED, '', Math.min(now, seen + this.config.silenceTimeoutMs + this.config.pingIntervalMs)) } diff --git a/cloud/apps/relay-edge/src/host-relay-handshake.ts b/cloud/apps/relay-edge/src/host-relay-handshake.ts index bc153be8a0c..1d9995d44bf 100644 --- a/cloud/apps/relay-edge/src/host-relay-handshake.ts +++ b/cloud/apps/relay-edge/src/host-relay-handshake.ts @@ -157,6 +157,7 @@ export abstract class HostRelayHandshake extends HostRelayBase { }) const leaseExpiresAt = now + LEASE_BASE_MS + Math.round((Math.random() * 2 - 1) * LEASE_JITTER_MS) a.phase = 'active' + a.activeAt = now a.generation = generation a.lastPongAt = now a.lastPingAt = now @@ -191,7 +192,7 @@ export abstract class HostRelayHandshake extends HostRelayBase { }) // After the ack, which strict shipped parsers must see unchanged; only hosts that asked get it. if (a.clientKeepalive) { this.send(ws, { type: 'keepalive-offer', v: 1, intervalMs: this.config.pingIntervalMs }) } - metric(this.env, 'control_active', 1, rebind ? 'rebind' : 'new', [], '', a.place) + metric(this.env, 'control_active', 1, rebind ? 'rebind' : 'new', [a.openedAt === undefined ? -1 : now - a.openedAt], a.clientKeepalive ? 'keepalive' : 'legacy', a.place) await this.reschedule() } } diff --git a/cloud/apps/relay-edge/src/host-relay.ts b/cloud/apps/relay-edge/src/host-relay.ts index 958232f8ff4..bc6095bc33a 100644 --- a/cloud/apps/relay-edge/src/host-relay.ts +++ b/cloud/apps/relay-edge/src/host-relay.ts @@ -145,7 +145,8 @@ export class HostRelay extends HostRelayPhones { claims, origin, caps: [...parseRelayHostCapabilities(request.headers.get('x-orca-host-capabilities') ?? '')], - deadline: Date.now() + RELAY_PROTOCOL_LIMITS.firstFrameDeadlineMs + deadline: Date.now() + RELAY_PROTOCOL_LIMITS.firstFrameDeadlineMs, + openedAt: Date.now() }) await this.reschedule() return new Response(null, { status: 101, webSocket: client }) @@ -180,14 +181,25 @@ export class HostRelay extends HostRelayPhones { continue } if (now - seen > this.config.silenceTimeoutMs && (!this.keepalive(a) || now - a.probeAt! >= KEEPALIVE_PROBE_MS - 50)) { + this.deadControlMetric(a, now, seen, 'alarm') this.close(ws, RELAY_CLOSE_CODE.PEER_DROPPED, 'control silence timeout') await this.onSocketGone(ws, RELAY_CLOSE_CODE.PEER_DROPPED, '') continue } // Same order as the cells' heartbeat: expired auth past its grace, then the 6 h lease. if (now > a.claims.exp + CONTROL_CONTINUITY_LIMITS.expiredAuthExistingSpliceGraceMs) { + // A host already silent past the limit is gone (asleep, offline): it closes as one, so + // drop counts stay comparable with the cells, whose pings would have closed it earlier. + // Its probe is cut short: the expired authorization ends the socket either way. + if (now - seen > this.config.silenceTimeoutMs) { + this.deadControlMetric(a, now, seen, 'expired') + this.close(ws, RELAY_CLOSE_CODE.PEER_DROPPED, 'control silence timeout') + await this.onSocketGone(ws, RELAY_CLOSE_CODE.PEER_DROPPED, '', Math.min(now, seen + this.config.silenceTimeoutMs + this.config.pingIntervalMs)) + continue + } const sinceRefreshS = a.lastRefreshAt === undefined ? -1 : Math.round((now - a.lastRefreshAt) / 1000) - metric(this.env, 'auth_expired_close', sinceRefreshS, a.lastRefreshAt === undefined ? 'never' : 'refreshed', [], '', a.place) + const seenAgoS = Math.round((now - seen) / 1000) + metric(this.env, 'auth_expired_close', sinceRefreshS, a.lastRefreshAt === undefined ? 'never' : 'refreshed', [seenAgoS, a.activeAt === undefined ? -1 : Math.round((now - a.activeAt) / 1000)], this.keepalive(a) ? 'keepalive' : 'legacy', a.place) this.close(ws, RELAY_CLOSE_CODE.BAD_OUTER_CREDENTIAL, 'relay authorization expired') await this.onSocketGone(ws, RELAY_CLOSE_CODE.BAD_OUTER_CREDENTIAL, '') continue diff --git a/cloud/apps/relay-edge/src/metrics.ts b/cloud/apps/relay-edge/src/metrics.ts index 7d87b759e4d..ea76d7f7f2c 100644 --- a/cloud/apps/relay-edge/src/metrics.ts +++ b/cloud/apps/relay-edge/src/metrics.ts @@ -2,6 +2,8 @@ import type { Env } from './env' export type MetricEvent = + // label 'new' | 'rebind'; reason 'keepalive' | 'legacy' (took the keepalive offer or not); + // double2 = ms from the upgrade to activation (the desktop gives up a connect after 15 s). | 'control_active' | 'control_close' | 'phone_open' @@ -26,7 +28,11 @@ export type MetricEvent = | 'control_upgrade' // Control closed 4401 for expired authorization: value = seconds since its last extending // refresh, label 'refreshed'; -1 and label 'never' when this socket never extended its token. + // double2 = seconds since the host's last inbound frame or keepalive, double3 = seconds since the + // control became active (-1 if unknown); reason 'keepalive' | 'legacy'. | 'auth_expired_close' + // Control closed for silence (deadControlMetric, host-relay-control.ts). + | 'silence_close' // Pre-auth socket refused by the per-source limiter: label 'phone' | 'data' | 'health'. Unpushed-host phones: 'not_on_edge'. | 'preauth_limited' | 'not_on_edge' diff --git a/cloud/apps/relay-edge/test/harness-mvp-object.ts b/cloud/apps/relay-edge/test/harness-mvp-object.ts index 89ec43b1e7c..69530b07307 100644 --- a/cloud/apps/relay-edge/test/harness-mvp-object.ts +++ b/cloud/apps/relay-edge/test/harness-mvp-object.ts @@ -47,14 +47,14 @@ export function newHost(): Host { } } -export async function mint(key: KeyLike, relayHostId: string, issuer = ISSUER): Promise { +export async function mint(key: KeyLike, relayHostId: string, issuer = ISSUER, expiresIn = '5m'): Promise { return new SignJWT({ purpose: 'host-control', prof: `prof-${USER}`, relayHostId }) .setProtectedHeader({ alg: 'ES256', kid: REMOTE ? 'spike' : 'mvp' }) .setSubject(USER) .setIssuer(issuer) .setAudience('orca-relay') .setIssuedAt() - .setExpirationTime('5m') + .setExpirationTime(expiresIn) .sign(key) } diff --git a/cloud/apps/relay-edge/test/mvp-object-hardening.ts b/cloud/apps/relay-edge/test/mvp-object-hardening.ts index 5bd6553acab..1e86d0058ee 100644 --- a/cloud/apps/relay-edge/test/mvp-object-hardening.ts +++ b/cloud/apps/relay-edge/test/mvp-object-hardening.ts @@ -128,6 +128,32 @@ export async function keepaliveProbeCheck(key: KeyLike): Promise { } } +// K4: a keepalive host gone silent when its authorization expires closes as a dropped host (4408), +// not 4401, so edge drop counts stay comparable with the cells (their pings would have closed it). +export async function keepaliveExpiredSilentCheck(key: KeyLike): Promise { + const host = newHost() + await assign(host.relayHostId, 'edge', EPOCH, []) + const started = Date.now() + // Alive for 50 s, then silent: the silence probe (sent ~9 s later) is still pending when the + // 3 s token passes its 60 s grace at ~63 s, so the expiry check is what closes it. + const c = control(host, await mint(key, host.relayHostId, undefined, '3s'), EPOCH, { + caps: `${SHIPPED_CAPS},client-keepalive-v1`, + drop: () => Date.now() - started > 50_000 + }) + await c.client.connect() + try { + const closed = await waitFor(() => c.events.closes.length > 0, 3_000 + 60_000 + 15_000) + const after = Date.now() - started + record( + 'K4 silent keepalive host at token expiry: closed 4408 (not 4401)', + closed && c.events.closes.includes(4408) && !c.events.closes.includes(4401) && after >= 59_000, + `closedAfter=${after}ms pings=${c.events.pings} closes=${c.events.closes}` + ) + } finally { + c.client.closeNow() + } +} + // F5: POST /__admin/drain sends the host's controls back to the director (drain frame, 4503). export async function drainCheck(key: KeyLike): Promise { const host = newHost() diff --git a/cloud/apps/relay-edge/test/mvp-object.ts b/cloud/apps/relay-edge/test/mvp-object.ts index 5558bb2d179..f9a436c1d37 100644 --- a/cloud/apps/relay-edge/test/mvp-object.ts +++ b/cloud/apps/relay-edge/test/mvp-object.ts @@ -41,7 +41,7 @@ import { waitFor, type Host } from './harness-mvp-object' -import { drainCheck, heartbeatCheck, keepaliveCheck, keepaliveProbeCheck, objectHealthCheck } from './mvp-object-hardening' +import { drainCheck, heartbeatCheck, keepaliveCheck, keepaliveExpiredSilentCheck, keepaliveProbeCheck, objectHealthCheck } from './mvp-object-hardening' import { replayCheck, rotationCheck } from './mvp-object-replay' async function mainRemote(): Promise { @@ -107,7 +107,7 @@ async function main(): Promise { await sleep(500) } await run(host, privateKey, () => jwksHits) - await Promise.all([heartbeatCheck(privateKey), keepaliveCheck(privateKey), keepaliveProbeCheck(privateKey), drainCheck(privateKey), replayCheck(), rotationCheck()]) + await Promise.all([heartbeatCheck(privateKey), keepaliveCheck(privateKey), keepaliveProbeCheck(privateKey), keepaliveExpiredSilentCheck(privateKey), drainCheck(privateKey), replayCheck(), rotationCheck()]) await sweepCheck() await preAuthCheck(stateDir) await objectHealthCheck(stateDir) diff --git a/cloud/apps/relay/src/edge-relay-cohort.ts b/cloud/apps/relay/src/edge-relay-cohort.ts index 5227e8f9ff4..d6a8818c55d 100644 --- a/cloud/apps/relay/src/edge-relay-cohort.ts +++ b/cloud/apps/relay/src/edge-relay-cohort.ts @@ -50,18 +50,18 @@ export function edgeCohortBucketPermille(relayHostId: string): number { } // Mode off or down empties the cohort. Otherwise deny wins, then host allow, then region scope; -// within the region, account allow or the rollout share. +// within the region, account allow or the rollout share. Region 'any' skips the region scope. export function inEdgeCohort( config: EdgeRelayConfig, relayHostId: string, - region: RelayRegion | undefined, + region: RelayRegion | undefined | 'any', userId?: string ): boolean { const flags = config.control?.() ?? EDGE_CONTROL_DEFAULTS if (flags.mode !== 'on') { return false } if (config.denyHosts.has(relayHostId)) { return false } if (config.allowHosts.has(relayHostId)) { return true } - if (!config.regions.has(region ?? RELAY_DEFAULT_REGION)) { return false } + if (region !== 'any' && !config.regions.has(region ?? RELAY_DEFAULT_REGION)) { return false } if (userId !== undefined && config.allowUsers?.has(userId)) { return true } return edgeCohortBucketPermille(relayHostId) < edgeRolloutPermille(config.rolloutPercent, flags) } diff --git a/cloud/apps/relay/src/edge-relay-evacuation.test.ts b/cloud/apps/relay/src/edge-relay-evacuation.test.ts index 9b671710f28..855eb2ea55f 100644 --- a/cloud/apps/relay/src/edge-relay-evacuation.test.ts +++ b/cloud/apps/relay/src/edge-relay-evacuation.test.ts @@ -108,6 +108,22 @@ describe('edge evacuation under runtime control', () => { h.evacuation.stop() }) + it('leaves region scope to the assign path: a stored preference outside it drains nobody', async () => { + vi.spyOn(console, 'warn').mockImplementation(() => {}) + const flags: EdgeControlFlags = { mode: 'on', rolloutPermille: 1000 } + const h = await harness({ control: () => flags }) + // On the edge by its ask (no region, or us-central1); its stored preference says otherwise. + await h.insert(hostId(1)) + await h.prefer(hostId(1), 'asia-east2') + await h.insert(hostId(2)) + expect(await h.evacuation.sweep()).toBe(0) + expect(h.admin.drained).toEqual([]) + // Leaving the cohort still drains, whatever the stored region. + flags.rolloutPermille = 0 + expect(await h.evacuation.sweep()).toBe(2) + expect(h.admin.drained.sort()).toEqual([hostId(1), hostId(2)]) + }) + it(`sends at most ${EDGE_EVACUATION_CONCURRENCY} drains at once`, async () => { vi.spyOn(console, 'warn').mockImplementation(() => {}) const h = await harness() diff --git a/cloud/apps/relay/src/edge-relay-evacuation.ts b/cloud/apps/relay/src/edge-relay-evacuation.ts index ae1c31f5056..db103f67c55 100644 --- a/cloud/apps/relay/src/edge-relay-evacuation.ts +++ b/cloud/apps/relay/src/edge-relay-evacuation.ts @@ -3,7 +3,6 @@ // rows whose host is no longer in the cohort and asks the edge to drain them; the desktop then // re-asks /v1/assign, and that ask exports its data and places it on a cell (app.ts). Each pass also // retries fences that did not land after a host left (edge-relay-fence.ts). -import { RELAY_DEFAULT_REGION, RelayRegionSchema } from '@orca-cloud/relay-contract/relay-regions' import type { RelayDatabase } from './database/database.js' import { EdgeAdminUnavailableError, type EdgeAdmin } from './edge-admin-client.js' import { inEdgeCohort, text, type EdgeRelayConfig, type Identity } from './edge-relay-cohort.js' @@ -116,9 +115,11 @@ export class EdgeEvacuation { for (const row of rows) { const identity = { userId: text(row, 'user_id'), relayHostId: text(row, 'relay_host_id') } pass.cursor = identity - const stored = RelayRegionSchema.safeParse(row.preferred_region) - const region = stored.success ? stored.data : RELAY_DEFAULT_REGION - if (inEdgeCohort(this.config, identity.relayHostId, region, identity.userId)) { continue } + // Region scope is the assign path's call alone: it decides with the region the desktop + // asks for, which the stored preference can miss or lag. Judging it here too drained + // hosts that the next ask put straight back (a drain every few minutes). A host that asks + // for a region outside the scope leaves on that ask. + if (inEdgeCohort(this.config, identity.relayHostId, 'any', identity.userId)) { continue } if (this.drainedAt.has(drainKey(identity))) { continue } leaving.push(identity) // Resume after the last host taken, so the rest of the page is read next tick. @@ -143,10 +144,8 @@ export class EdgeEvacuation { private async readPage(pass: Pass) { const { cursor, origin, wrapped } = pass return await this.database.query( - `SELECT a.user_id, a.relay_host_id, p.preferred_region + `SELECT a.user_id, a.relay_host_id FROM relay_assignments a - LEFT JOIN relay_assignment_region_preferences p - ON p.user_id = a.user_id AND p.relay_host_id = a.relay_host_id WHERE a.cell_id = ? AND (a.user_id > ? OR (a.user_id = ? AND a.relay_host_id > ?)) ${wrapped ? 'AND (a.user_id < ? OR (a.user_id = ? AND a.relay_host_id <= ?))' : ''} ORDER BY a.user_id, a.relay_host_id diff --git a/cloud/apps/relay/src/edge-relay-fence.test.ts b/cloud/apps/relay/src/edge-relay-fence.test.ts index abdef6a01ba..bfee89d38c3 100644 --- a/cloud/apps/relay/src/edge-relay-fence.test.ts +++ b/cloud/apps/relay/src/edge-relay-fence.test.ts @@ -116,6 +116,43 @@ describe('relay edge fence after a host leaves', () => { }) }) +describe('relay edge fence over a same-epoch conflict', () => { + it('fences once more one epoch above a conflict at its epoch, and never bumps over a stale answer', async () => { + vi.spyOn(console, 'error').mockImplementation(() => {}) + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}) + const h = await harness() + h.edge.answers = ['conflict', 'applied'] + expect(await h.assignments.fenceAway({ userId: USER, relayHostId: HOST }, 'us-c1', 9)).toBe(true) + expect(h.edge.calls.map((call) => call.body.assignmentEpoch)).toEqual([9, 10]) + expect(h.edge.calls.every((call) => call.body.cellId === 'us-c1')).toBe(true) + expect(logged(warn, 'orca_relay_edge_fence_above_conflict')).toEqual([ + { event: 'orca_relay_edge_fence_above_conflict', outcome: 'applied', assignmentEpoch: 10 } + ]) + expect(await h.pending()).toEqual([]) + // Stale: the edge holds a newer epoch (the host may be back there); no bump, recorded for retry. + h.edge.calls = [] + h.edge.answers = ['stale'] + expect(await h.assignments.fenceAway({ userId: USER, relayHostId: HOST }, 'us-c1', 11)).toBe(false) + expect(h.edge.calls.map((call) => call.body.assignmentEpoch)).toEqual([11]) + }) + + it('a pending fence retried into a same-epoch conflict lands one epoch above the row', async () => { + vi.spyOn(console, 'error').mockImplementation(() => {}) + vi.spyOn(console, 'warn').mockImplementation(() => {}) + const h = await harness() + await h.placeRow('us-c1', 7) + h.edge.answers = ['down', 'down', 'down', 'down', 'down', 'down', 'down', 'down', 'down', 'down'] + expect(await h.assignments.fenceAway({ userId: USER, relayHostId: HOST }, 'us-c1', 7)).toBe(false) + expect(await h.pending()).toHaveLength(1) + h.edge.calls = [] + h.edge.answers = ['conflict', 'applied'] + h.clock.now += 60_000 + await h.retry() + expect(h.edge.calls.map((call) => call.body.assignmentEpoch)).toEqual([7, 8]) + expect(await h.pending()).toEqual([]) + }) +}) + describe('relay edge pending fence retries', () => { it('re-fences to the current row, not the recorded one, and clears the record once it lands', async () => { const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}) diff --git a/cloud/apps/relay/src/edge-relay-fence.ts b/cloud/apps/relay/src/edge-relay-fence.ts index 3d01795ddaa..e18056b5eeb 100644 --- a/cloud/apps/relay/src/edge-relay-fence.ts +++ b/cloud/apps/relay/src/edge-relay-fence.ts @@ -41,6 +41,27 @@ export async function recordPendingFence( ) } +// One fence call. `conflict` means the edge holds this very epoch for another placement (a move onto +// the edge whose push landed though the director counted it as failed, then a placement elsewhere +// minted the same epoch). No later move can produce that (a later move has a higher epoch, which +// answers `stale`), so the fence goes once more one epoch above: it lands, and a later move onto +// the edge re-mints above it as for any edge epoch (moveToEdge). +async function assignFence( + admin: EdgeAdmin, + fence: Identity & { cellId: string; assignmentEpoch: number } +): Promise<{ outcome: string; assignmentEpoch: number }> { + const first = await admin.assign(fence) + if (first.outcome !== 'conflict' || first.assignmentEpoch !== fence.assignmentEpoch) { + return { outcome: first.outcome, assignmentEpoch: fence.assignmentEpoch } + } + const above = fence.assignmentEpoch + 1 + const second = await admin.assign({ ...fence, assignmentEpoch: above }) + console.warn( + JSON.stringify({ event: 'orca_relay_edge_fence_above_conflict', outcome: second.outcome, assignmentEpoch: above }) + ) + return { outcome: second.outcome, assignmentEpoch: above } +} + // The fence right after a host left (EdgeAssignments.fenceAway). Anything but applied/unchanged // fails: unavailable, `conflict`, or `stale` (the edge holds a newer epoch, so it still claims the // host); the failure is logged and recorded for retry. Returns whether the fence landed. @@ -55,7 +76,7 @@ export async function fenceEdge( let outcome = 'unavailable' for (let attempt = 0; attempt < attempts; attempt += 1) { try { - outcome = (await admin.assign(fence)).outcome + outcome = (await assignFence(admin, fence)).outcome } catch (error) { if (!(error instanceof EdgeAdminUnavailableError)) { throw error } outcome = error.message @@ -138,7 +159,7 @@ async function retryOne( const assignmentEpoch = integer(row, 'assignment_epoch') let outcome: string try { - outcome = (await admin.assign({ ...identity, cellId, assignmentEpoch })).outcome + outcome = (await assignFence(admin, { ...identity, cellId, assignmentEpoch })).outcome } catch (error) { if (!(error instanceof EdgeAdminUnavailableError)) { throw error } outcome = error.message diff --git a/config/ast-grep/rule-tests/profile-full-save-callers-test.yml b/config/ast-grep/rule-tests/profile-full-save-callers-test.yml new file mode 100644 index 00000000000..8fcafde2d70 --- /dev/null +++ b/config/ast-grep/rule-tests/profile-full-save-callers-test.yml @@ -0,0 +1,5 @@ +id: profile-full-save-callers +valid: + - "scheduleSave(scheduling, ['repos'])" +invalid: + - 'scheduleFullProfileSave(scheduling)' diff --git a/config/ast-grep/rules/profile-full-save-callers.yml b/config/ast-grep/rules/profile-full-save-callers.yml new file mode 100644 index 00000000000..c8650a8b1f3 --- /dev/null +++ b/config/ast-grep/rules/profile-full-save-callers.yml @@ -0,0 +1,14 @@ +# Mutations save the domains they change; only startup load and maintenance resume rewrite the whole profile. +id: profile-full-save-callers +language: typescript +severity: error +message: Name the profile domains this mutation changed with scheduleSave(owner, [...domains]). scheduleFullProfileSave is for startup load and maintenance resume only. +files: + - src/** +ignores: + - '**/*.test.*' + - src/main/persistence/loading-store/write-scheduling.ts + - src/main/persistence/loading-store/store.ts + - src/main/persistence/loading-store/profile-state-maintenance.ts +rule: + pattern: scheduleFullProfileSave($$$) diff --git a/config/flaky-test-pattern-baseline.txt b/config/flaky-test-pattern-baseline.txt index 60f4477543d..508cf4fc6a1 100644 --- a/config/flaky-test-pattern-baseline.txt +++ b/config/flaky-test-pattern-baseline.txt @@ -29,7 +29,6 @@ 1 test-no-in-test-import-actual:src/renderer/src/components/terminal-pane/pty-connection/notifications/pty-connection-hook-idle-arbitration.test.ts 3 test-no-in-test-import-actual:src/renderer/src/components/terminal-pane/snapshots/remote-snapshot-alt-screen-host-chain.test.ts 1 test-no-in-test-import-actual:src/renderer/src/hooks/useIpcEvents-agent-status-pane-teardown.test.ts -1 test-no-in-test-import-actual:src/renderer/src/hooks/useIpcEvents-agent-status-snapshot-hydration.test.ts 1 test-no-polling-loop:src/main/browser/cookies/browser-cookie-import-concurrency.test.ts 1 test-no-polling-loop:src/main/claude/claude-stop-ack-race.test.ts 1 test-no-polling-loop:src/main/claude/claude-stream-json-connection.test.ts @@ -264,8 +263,7 @@ 1 test-no-real-time-wait:src/renderer/src/components/terminal-pane/layout/split/resolve-split-cwd.test.ts 2 test-no-real-time-wait:src/renderer/src/components/terminal-pane/pty-connection/emulation/fish-color-scheme-child-stdin.node-pty.test.ts 1 test-no-real-time-wait:src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-connect-failure-recovery.test.ts -2 test-no-real-time-wait:src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-exit-record.test.ts -3 test-no-real-time-wait:src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-subscribe-ack-input.test.ts +1 test-no-real-time-wait:src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-subscribe-ack-input.test.ts 1 test-no-real-time-wait:src/renderer/src/components/terminal-pane/viewport/terminal-fit-restore.test.ts 1 test-no-real-time-wait:src/renderer/src/hooks/runtime-project-refresh-scheduler.test.ts 1 test-no-real-time-wait:src/renderer/src/lib/agent-session/resume/cli-fork/native-chat-cli-fork-preparation.test.ts @@ -626,12 +624,7 @@ 2 test-no-wall-clock:src/renderer/src/components/artifacts/ArtifactCollection.test.tsx 1 test-no-wall-clock:src/renderer/src/components/browser-pane/assemble-chrome/browser-workspace-pane.adoption-chrome.test.tsx 2 test-no-wall-clock:src/renderer/src/components/dashboard/useLiveDashboardSnapshot.test.ts -1 test-no-wall-clock:src/renderer/src/components/native-chat/conversation/slots/NativeChatMessageList.opening-send.test.tsx -1 test-no-wall-clock:src/renderer/src/components/native-chat/conversation/slots/NativeChatMessageList.queued-turn-order.test.tsx -2 test-no-wall-clock:src/renderer/src/components/native-chat/conversation/turns/NativeChatMessageList.turn-indicator.test.tsx 3 test-no-wall-clock:src/renderer/src/components/native-chat/conversation/turns/NativeChatResolvedView.turn-status.test.tsx -1 test-no-wall-clock:src/renderer/src/components/native-chat/session/structured/delivery/NativeChatMessageList.unsent-message.test.tsx -3 test-no-wall-clock:src/renderer/src/components/native-chat/surfaces/integration/NativeChatMessageList.test.tsx 2 test-no-wall-clock:src/renderer/src/components/native-chat/tools/tasks/NativeChatStructuredSessionStatus.test.tsx 1 test-no-wall-clock:src/renderer/src/components/sidebar/workspace-card/review/use-workspace-reference-details.test.tsx 1 test-no-wall-clock:src/renderer/src/components/sidebar/worktree-list/listing/WorktreeList.lineage-agent-expansion-coupling.test.tsx @@ -641,18 +634,12 @@ 1 test-no-wall-clock:src/renderer/src/components/terminal/initial-terminal-structured-launch.test.tsx 2 test-no-wall-clock:src/renderer/src/components/workspace-cleanup/use-workspace-cleanup-removal.agent-stop.test.tsx 1 test-no-wall-clock:src/renderer/src/components/worktree-jump/WorktreeJumpPalette.recent-tabs.behavior.test.tsx -4 test-no-wall-clock:src/renderer/src/components/worktree-jump/WorktreeJumpPalette.recent-tabs.test.tsx 2 test-no-wall-clock:src/renderer/src/hooks/ipc-events/agent-status-terminal-title-tab-write.test.ts -1 test-no-wall-clock:src/renderer/src/lib/paired-runtime-closed-tab-resume.test.ts -2 test-no-wall-clock:src/renderer/src/lib/use-tab-agent-observed-signal-dispatch.test.tsx -2 test-no-wall-clock:src/renderer/src/lib/wake-sleeping-agents-live-unmounted-pane.test.ts +2 test-no-wall-clock:src/renderer/src/lib/agent-session/tab-identity/use-tab-agent-observed-signal-dispatch.test.tsx 1 test-no-wall-clock:src/renderer/src/lib/workspace/ownership/workspace-terminal-host-authority.test.ts 1 test-no-wall-clock:src/renderer/src/lib/workspace/activation/worktree-activation-emptied-workspace-reseed.test.ts 2 test-no-wall-clock:src/renderer/src/store/github/pull-requests/github-pr-branch-linked-pr-divergence.test.ts -6 test-no-wall-clock:src/renderer/src/store/slices/jira/jira.test.ts 5 test-no-wall-clock:src/renderer/src/store/slices/worktrees/metadata/worktree-meta-hosted-review.test.ts -1 test-no-wall-clock:src/renderer/src/store/slices/worktrees/session/worktrees-terminal-reference-origins.test.ts -1 test-no-wall-clock:src/renderer/src/store/terminals/store-sleep-exact-runtime-stop.test.ts 1 test-no-wall-clock:src/shared/__tests__/process-host/windows-cmd-shim-resolution.test.ts 7 test-no-wall-clock:src/shared/__tests__/process-host/windows-tree-kill-late-taskkill.win32.test.ts 1 test-no-wall-clock:src/shared/agent-hook-listener/transport/agent-hook-spool-drain.test.ts diff --git a/config/focus-setting-read-baseline.txt b/config/focus-setting-read-baseline.txt index f907d5d4bef..7fc0cfa7341 100644 --- a/config/focus-setting-read-baseline.txt +++ b/config/focus-setting-read-baseline.txt @@ -220,20 +220,20 @@ 1 src/renderer/src/lib/browser/navigation/http-link-localhost-route.ts # extracted from http-link-routing.ts 1 src/renderer/src/lib/browser/navigation/http-link-routing.ts 2 src/renderer/src/lib/browser/workspace/workspace-browser-tab-open.ts -1 src/renderer/src/lib/client-creation-action-error.ts -2 src/renderer/src/lib/client-creation-action-policy.ts +1 src/renderer/src/lib/workspace/creation/surface-policy/client-creation-action-error.ts +2 src/renderer/src/lib/workspace/creation/surface-policy/client-creation-action-policy.ts 1 src/renderer/src/runtime/hosts/selection/default-creation-host.ts # the sanctioned reader of the default host -1 src/renderer/src/lib/launch-ai-vault-session.ts -1 src/renderer/src/lib/local-preflight-context.ts +1 src/renderer/src/lib/agent-session/resume/history/launch-ai-vault-session.ts +1 src/renderer/src/runtime/hosts/preflight/local-preflight-context.ts 2 src/renderer/src/runtime/hosts/observations/provider-runtime-context.ts 2 src/renderer/src/lib/workspace/ownership/repo-runtime-owner.ts 1 src/renderer/src/lib/workspace/ownership/runtime-session-mirror-owners.ts -1 src/renderer/src/lib/runtime-session-mirror-targets.ts +1 src/renderer/src/runtime/web-session-tabs-sync/subscriptions/runtime-session-mirror-targets.ts 1 src/renderer/src/lib/workspace/ownership/single-runtime-legacy-owner.ts 1 src/renderer/src/lib/skills/runtime/skill-runtime-command.ts 1 src/renderer/src/lib/workspace/ownership/terminal-close-route.ts 4 src/renderer/src/lib/workspace/ownership/terminal-worktree-route.ts # resolveTerminalPtyOwner: teardown, close and PTY identity read spawn's attribution (round 3 F8), which retired the deprecated resolver's readers -3 src/renderer/src/lib/unread-badge-count-selector.ts +3 src/renderer/src/attention/unread/unread-badge-count-selector.ts 1 src/renderer/src/runtime/hosted-terminals/restoration/web-runtime-worktree-terminal-after-wake.ts 1 src/renderer/src/lib/work-items/linear/linear-issue-url-lookup.ts 1 src/renderer/src/lib/work-items/linear/linear-issue-write.ts diff --git a/config/main-layout-writer-baseline.txt b/config/main-layout-writer-baseline.txt index 38d52fa4386..54fb801ea75 100644 --- a/config/main-layout-writer-baseline.txt +++ b/config/main-layout-writer-baseline.txt @@ -27,7 +27,7 @@ 10 src/main/persistence/loading-store/repo-lifecycle-operations.ts 10 src/main/persistence/loading-store/session-host-partitions.ts 9 src/main/persistence/loading-store/session-snapshot-operations.ts -3 src/main/persistence/loading-store/state-serialization-secret-handling.ts +2 src/main/persistence/loading-store/state-serialization-secret-handling.ts 4 src/main/persistence/loading-store/workspace-session-snapshot-publication.ts 4 src/main/persistence/loading-store/workspace-session-terminal-binding-replay.ts 2 src/main/persistence/migrating-orcad-catalog/orcad-destination-client-state.ts diff --git a/config/main-sync-fs-baseline.txt b/config/main-sync-fs-baseline.txt index 1026db7975b..9269e3fea5e 100644 --- a/config/main-sync-fs-baseline.txt +++ b/config/main-sync-fs-baseline.txt @@ -482,7 +482,7 @@ 2 src/main/runtime/mobile-cloud-relay/relay-revoke-outbox.ts 1 src/main/runtime/orchestration/db/runtime-orchestration-database-access.ts 2 src/main/runtime/push/push-unregister-outbox.ts -2 src/main/runtime/rpc/methods/mobile-delivery/bundled-mobile-web-bundle.ts +1 src/main/runtime/rpc/methods/mobile-delivery/bundled-mobile-web-bundle.ts 1 src/main/runtime/rpc/server/network-source-policy-store.ts 2 src/main/runtime/rpc/server/pairing/device-registry-corruption.ts 2 src/main/runtime/rpc/server/pairing/device-registry-disk-merge.ts diff --git a/config/mobile-localization-coverage-allowlist.json b/config/mobile-localization-coverage-allowlist.json index 113c65c34da..594bc0a7919 100644 --- a/config/mobile-localization-coverage-allowlist.json +++ b/config/mobile-localization-coverage-allowlist.json @@ -42,70 +42,70 @@ "count": 1 }, { - "filePath": "mobile/src/components/accounts-snapshot.ts", + "filePath": "mobile/src/accounts/accounts-snapshot.ts", "kind": "object-property:message", "text": "Claude limits use the wrong provider identity", "dynamic": false, "count": 1 }, { - "filePath": "mobile/src/components/accounts-snapshot.ts", + "filePath": "mobile/src/accounts/accounts-snapshot.ts", "kind": "object-property:message", "text": "Codex limits use the wrong provider identity", "dynamic": false, "count": 1 }, { - "filePath": "mobile/src/components/accounts-snapshot.ts", + "filePath": "mobile/src/accounts/accounts-snapshot.ts", "kind": "object-property:message", "text": "Host Codex accounts cannot name a WSL distro", "dynamic": false, "count": 1 }, { - "filePath": "mobile/src/components/accounts-snapshot.ts", + "filePath": "mobile/src/accounts/accounts-snapshot.ts", "kind": "object-property:message", "text": "Host rate-limit targets cannot name a WSL distro", "dynamic": false, "count": 1 }, { - "filePath": "mobile/src/components/accounts-snapshot.ts", + "filePath": "mobile/src/accounts/accounts-snapshot.ts", "kind": "object-property:message", "text": "Inactive Claude limits use the wrong provider identity", "dynamic": false, "count": 1 }, { - "filePath": "mobile/src/components/accounts-snapshot.ts", + "filePath": "mobile/src/accounts/accounts-snapshot.ts", "kind": "object-property:message", "text": "Inactive Codex limits use the wrong provider identity", "dynamic": false, "count": 1 }, { - "filePath": "mobile/src/components/accounts-snapshot.ts", + "filePath": "mobile/src/accounts/accounts-snapshot.ts", "kind": "object-property:message", "text": "WSL Codex accounts require an exact distro", "dynamic": false, "count": 1 }, { - "filePath": "mobile/src/components/accounts-snapshot.ts", + "filePath": "mobile/src/accounts/accounts-snapshot.ts", "kind": "object-property:message", "text": "WSL rate-limit targets require an exact distro", "dynamic": false, "count": 1 }, { - "filePath": "mobile/src/components/codex-reset-credit-reply-schema.ts", + "filePath": "mobile/src/accounts/usage/codex-reset-credit-reply-schema.ts", "kind": "object-property:message", "text": "Host reset scopes cannot name a WSL distro", "dynamic": false, "count": 1 }, { - "filePath": "mobile/src/components/codex-reset-credit-reply-schema.ts", + "filePath": "mobile/src/accounts/usage/codex-reset-credit-reply-schema.ts", "kind": "object-property:message", "text": "WSL reset scopes require an exact distro", "dynamic": false, diff --git a/config/reliability-gates.jsonc b/config/reliability-gates.jsonc index 90b27e1136b..5eddf652fd5 100644 --- a/config/reliability-gates.jsonc +++ b/config/reliability-gates.jsonc @@ -1223,12 +1223,12 @@ ], "platforms": ["macos", "linux", "windows"], "providers": ["remote-runtime"], - "coveredPlatforms": ["macos", "linux"], + "coveredPlatforms": ["macos"], "coveredProviders": [], - "coverageNotes": "Audit1348 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Real authenticated sockets plus isolated desktop and headless hosts with desktop and browser viewers; deterministic lifecycle tests cover stale results and reader deadlines. The test-value audit removes the standalone runtime-status-snapshot.test.ts example that immediately applied the same supplied snapshots to two isolated slice stores. Its direct sequence-2 then older unavailable sequence-1 acceptance/rejection alarm is intentionally lost; it did not exercise a pending read, subscription delivery or a shared viewer connection. The suite retains failed-verification/recovery, disconnect/pairing retirement and catalog-refresh replay examples, which are not equivalent replacements. Historical executed commands, counts and results remain unchanged; no new live host, process restart or platform evidence is claimed. Audit1348: src/main/ipc/runtime-environments/runtime-environment-status-recovery.test.ts removed. Startup retry/broadcast counts and passive-before-active bootstrap request count. No equivalent replacement coverage is claimed. Audit1352: focused Linux unit selections validated on source head b638e07d395b76af3ba6b03761a1a0fe7e5e026e. Historical statements above retain their original scope. Intentional test losses are recorded in knownGaps; these runs claim no physical-provider, p95, rendered E2E or cross-platform validation. The current assertion index names unchanged owner lifecycle tests from the successful focused run. They do not replace the deleted startup retry/broadcast count alarms. Audit1360: focused Linux unit selections validated on source head 415c9cffc2d10024131ec4b6721767a22195de6d. Historical statements above retain their original scope. Intentional test losses are recorded in knownGaps; these runs claim no physical-provider, p95, rendered E2E or cross-platform validation. Audit1748 removes7 of13 authored host-status-owner definitions: request/polling counts, reconnect/no-request variants, deadline copy and blocked-reason projections. Lost alarms are intentional; no equivalent replacement coverage is claimed. Existing dated evidenceRuns are historical and unchanged, and do not validate this reduced source or current aggregate selectors. Focused candidate execution, if successful, validates only the retained local fake-request/clock tests, not authenticated sockets, rendered clients or platform parity.", + "coverageNotes": "Audit 3301 removes the failed-verification/recovery/restart generation and host-contact-epoch, hosting and no-toast example from runtime-status-snapshot.test.ts. Earlier prose describing that example as retained is historical. Disconnect/pairing retirement and delayed catalog replay remain unchanged without equivalent replacement. Archive both complete historical 22-case unit receipts because their selector includes the reduced source; preserve the unrelated rendered receipt, current selectors and other-owner assertion references. No fresh aggregate or live host validation is claimed. Linux coverage from those two unit runs is historical; current covered-platform scope is limited to the preserved macOS rendered receipt. Audit1348 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Real authenticated sockets plus isolated desktop and headless hosts with desktop and browser viewers; deterministic lifecycle tests cover stale results and reader deadlines. The test-value audit removes the standalone runtime-status-snapshot.test.ts example that immediately applied the same supplied snapshots to two isolated slice stores. Its direct sequence-2 then older unavailable sequence-1 acceptance/rejection alarm is intentionally lost; it did not exercise a pending read, subscription delivery or a shared viewer connection. The suite retains failed-verification/recovery, disconnect/pairing retirement and catalog-refresh replay examples, which are not equivalent replacements. Historical executed commands, counts and results remain unchanged; no new live host, process restart or platform evidence is claimed. Audit1348: src/main/ipc/runtime-environments/runtime-environment-status-recovery.test.ts removed. Startup retry/broadcast counts and passive-before-active bootstrap request count. No equivalent replacement coverage is claimed. Audit1352: focused Linux unit selections validated on source head b638e07d395b76af3ba6b03761a1a0fe7e5e026e. Historical statements above retain their original scope. Intentional test losses are recorded in knownGaps; these runs claim no physical-provider, p95, rendered E2E or cross-platform validation. The current assertion index names unchanged owner lifecycle tests from the successful focused run. They do not replace the deleted startup retry/broadcast count alarms. Audit1360: focused Linux unit selections validated on source head 415c9cffc2d10024131ec4b6721767a22195de6d. Historical statements above retain their original scope. Intentional test losses are recorded in knownGaps; these runs claim no physical-provider, p95, rendered E2E or cross-platform validation. Audit1748 removes7 of13 authored host-status-owner definitions: request/polling counts, reconnect/no-request variants, deadline copy and blocked-reason projections. Lost alarms are intentional; no equivalent replacement coverage is claimed. Existing dated evidenceRuns are historical and unchanged, and do not validate this reduced source or current aggregate selectors. Focused candidate execution, if successful, validates only the retained local fake-request/clock tests, not authenticated sockets, rendered clients or platform parity.", "motivatingLinks": ["https://github.com/stablyai/orca/pull/19163"], "invariant": "Failed bootstrap and authenticated reconnect converge without UI triggers; one connection owner publishes verified status, with no independent healthy status polling.", - "oracle": "Retained local cases check independent waiter deadlines/cancellation, failed-operation recovery, stale deferred results, disposal and explicit reconnect after authentication refusal. Historical aggregate receipts predate audit1748 and are not fresh validation of reduced sources.", + "oracle": "Audit 3301 removes the failed-verification/recovery/restart generation and host-contact-epoch, hosting and no-toast example from runtime-status-snapshot.test.ts. Earlier prose describing that example as retained is historical. Disconnect/pairing retirement and delayed catalog replay remain unchanged without equivalent replacement. Archive both complete historical 22-case unit receipts because their selector includes the reduced source; preserve the unrelated rendered receipt, current selectors and other-owner assertion references. No fresh aggregate or live host validation is claimed. Linux coverage from those two unit runs is historical; current covered-platform scope is limited to the preserved macOS rendered receipt. Retained local cases check independent waiter deadlines/cancellation, failed-operation recovery, stale deferred results, disposal and explicit reconnect after authentication refusal. Historical aggregate receipts predate audit1748 and are not fresh validation of reduced sources.", "commands": [ "ORCA_BACKGROUND_LAUNCH=1 pnpm test src/shared/remote-runtime/host-status/runtime-host-status-owner.test.ts src/main/ipc/runtime-environments/runtime-environment-status-connection.test.ts src/renderer/src/store/slices/runtime-status/runtime-status-snapshot.test.ts src/renderer/src/web/web-runtime-status-owner.test.ts", "ORCA_BACKGROUND_LAUNCH=1 ORCA_E2E_WEB_CLIENT=1 pnpm exec playwright test tests/e2e/runtime-host-status-recovery.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1" @@ -1258,26 +1258,6 @@ "result": "passed", "summary": "Desktop-host and headless-host journeys passed with desktop and browser viewers.", "durationSeconds": 31.3 - }, - { - "date": "2026-11-04", - "runner": "local", - "platform": "linux", - "result": "passed", - "command": "ORCA_BACKGROUND_LAUNCH=1 pnpm --config.verifyDepsBeforeRun=false test src/main/ipc/runtime-environments/runtime-environment-status-connection.test.ts src/renderer/src/store/slices/runtime-status-snapshot.test.ts src/renderer/src/web/web-runtime-status-owner.test.ts src/shared/remote-runtime/host-status/runtime-host-status-owner.test.ts --maxWorkers=2", - "currentCommand": "ORCA_BACKGROUND_LAUNCH=1 pnpm test src/shared/remote-runtime/host-status/runtime-host-status-owner.test.ts src/main/ipc/runtime-environments/runtime-environment-status-connection.test.ts src/renderer/src/store/slices/runtime-status/runtime-status-snapshot.test.ts src/renderer/src/web/web-runtime-status-owner.test.ts", - "durationSeconds": 4.37, - "summary": "Test Files 4 passed (4); Tests 22 passed (22). Focused Linux unit execution; no physical-provider, p95 or cross-platform claim. Source head b638e07d395b76af3ba6b03761a1a0fe7e5e026e." - }, - { - "date": "2026-11-04", - "runner": "local", - "platform": "linux", - "result": "passed", - "command": "ORCA_BACKGROUND_LAUNCH=1 pnpm --config.verifyDepsBeforeRun=false test src/main/ipc/runtime-environments/runtime-environment-status-connection.test.ts src/renderer/src/store/slices/runtime-status-snapshot.test.ts src/renderer/src/web/web-runtime-status-owner.test.ts src/shared/remote-runtime/host-status/runtime-host-status-owner.test.ts --maxWorkers=2", - "currentCommand": "ORCA_BACKGROUND_LAUNCH=1 pnpm test src/shared/remote-runtime/host-status/runtime-host-status-owner.test.ts src/main/ipc/runtime-environments/runtime-environment-status-connection.test.ts src/renderer/src/store/slices/runtime-status/runtime-status-snapshot.test.ts src/renderer/src/web/web-runtime-status-owner.test.ts", - "durationSeconds": 4.52, - "summary": "Test Files 4 passed (4); Tests 22 passed (22). Focused Linux unit execution; no physical-provider, p95 or cross-platform claim. Source head 415c9cffc2d10024131ec4b6721767a22195de6d." } ], "runtimeBudget": { @@ -1305,7 +1285,10 @@ "The test-value audit removes the standalone runtime-status-snapshot.test.ts example that immediately applied the same supplied snapshots to two isolated slice stores. Its direct sequence-2 then older unavailable sequence-1 acceptance/rejection alarm is intentionally lost; it did not exercise a pending read, subscription delivery or a shared viewer connection. The suite retains failed-verification/recovery, disconnect/pairing retirement and catalog-refresh replay examples, which are not equivalent replacements. Historical executed commands, counts and results remain unchanged; no new live host, process restart or platform evidence is claimed.", "Audit1348: src/main/ipc/runtime-environments/runtime-environment-status-recovery.test.ts removed. Startup retry/broadcast counts and passive-before-active bootstrap request count. No equivalent replacement coverage is claimed.", "Audit1348 historical platform/provider scope before source changes: {\"coveredPlatforms\":[\"macos\"],\"coveredProviders\":[\"remote-runtime\"]}. Remaining provider scope applies only to unchanged-source receipts.", - "Audit1348 historical assertion inventory for deleted/reduced sources; not current validated assertions:\n[\n {\n \"file\": \"src/main/ipc/runtime-environments/runtime-environment-status-recovery.test.ts\",\n \"assertions\": [\n \"recovers a saved host after its first status check fails, without another UI request\"\n ]\n }\n]" + "Audit1348 historical assertion inventory for deleted/reduced sources; not current validated assertions:\n[\n {\n \"file\": \"src/main/ipc/runtime-environments/runtime-environment-status-recovery.test.ts\",\n \"assertions\": [\n \"recovers a saved host after its first status check fails, without another UI request\"\n ]\n }\n]", + "Audit 3301 removes the failed-verification/recovery/restart generation and host-contact-epoch, hosting and no-toast example from runtime-status-snapshot.test.ts. Earlier prose describing that example as retained is historical. Disconnect/pairing retirement and delayed catalog replay remain unchanged without equivalent replacement. Archive both complete historical 22-case unit receipts because their selector includes the reduced source; preserve the unrelated rendered receipt, current selectors and other-owner assertion references. No fresh aggregate or live host validation is claimed. Linux coverage from those two unit runs is historical; current covered-platform scope is limited to the preserved macOS rendered receipt.", + "Audit 3301 retires this complete dated unit receipt because runtime-status-snapshot.test.ts was reduced. Its original command, result and counts remain historical and do not validate the reduced selector. Original receipt verbatim:\n{\n \"date\": \"2026-11-04\",\n \"runner\": \"local\",\n \"platform\": \"linux\",\n \"result\": \"passed\",\n \"command\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm --config.verifyDepsBeforeRun=false test src/main/ipc/runtime-environments/runtime-environment-status-connection.test.ts src/renderer/src/store/slices/runtime-status-snapshot.test.ts src/renderer/src/web/web-runtime-status-owner.test.ts src/shared/remote-runtime/host-status/runtime-host-status-owner.test.ts --maxWorkers=2\",\n \"currentCommand\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/shared/remote-runtime/host-status/runtime-host-status-owner.test.ts src/main/ipc/runtime-environments/runtime-environment-status-connection.test.ts src/renderer/src/store/slices/runtime-status/runtime-status-snapshot.test.ts src/renderer/src/web/web-runtime-status-owner.test.ts\",\n \"durationSeconds\": 4.37,\n \"summary\": \"Test Files 4 passed (4); Tests 22 passed (22). Focused Linux unit execution; no physical-provider, p95 or cross-platform claim. Source head b638e07d395b76af3ba6b03761a1a0fe7e5e026e.\"\n }", + "Audit 3301 retires this complete dated unit receipt because runtime-status-snapshot.test.ts was reduced. Its original command, result and counts remain historical and do not validate the reduced selector. Original receipt verbatim:\n{\n \"date\": \"2026-11-04\",\n \"runner\": \"local\",\n \"platform\": \"linux\",\n \"result\": \"passed\",\n \"command\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm --config.verifyDepsBeforeRun=false test src/main/ipc/runtime-environments/runtime-environment-status-connection.test.ts src/renderer/src/store/slices/runtime-status-snapshot.test.ts src/renderer/src/web/web-runtime-status-owner.test.ts src/shared/remote-runtime/host-status/runtime-host-status-owner.test.ts --maxWorkers=2\",\n \"currentCommand\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/shared/remote-runtime/host-status/runtime-host-status-owner.test.ts src/main/ipc/runtime-environments/runtime-environment-status-connection.test.ts src/renderer/src/store/slices/runtime-status/runtime-status-snapshot.test.ts src/renderer/src/web/web-runtime-status-owner.test.ts\",\n \"durationSeconds\": 4.52,\n \"summary\": \"Test Files 4 passed (4); Tests 22 passed (22). Focused Linux unit execution; no physical-provider, p95 or cross-platform claim. Source head 415c9cffc2d10024131ec4b6721767a22195de6d.\"\n }" ], "demotionRule": "Keep experimental until repeated runs establish reliability; preserve request-count and lifecycle assertions." }, @@ -1605,71 +1588,35 @@ "id": "agent-session.hibernation-runtime-inventory-budget", "title": "Hibernation preserves fresh host evidence and shutdown safety", "maturity": "experimental", - "protection": "partial", + "protection": "none", "owner": "agent-session-runtime", "layer": "shared-and-renderer-unit", "surfaces": ["automatic agent hibernation", "remote terminal liveness"], "platforms": ["macos", "linux", "windows"], "providers": ["local", "remote-runtime"], - "coveredPlatforms": ["linux"], - "coveredProviders": ["local", "remote-runtime"], - "coverageNotes": "Audit2058 intentionally retires the standalone visibility subscription/callback-count alarm without replacement. Audit2310 additionally retires two pane-age getter-map expiry/pruning samples without equivalent replacement. The reduced five-source hibernation selector was freshly run on Linux:52 tests pass. The earlier 54-test receipt is archived verbatim in knownGaps and does not validate the reduced source. Its prior macOS execution receipt/current-command association is archived verbatim in knownGaps and is not current execution evidence for the reduced selector. Current covered platform is Linux; remote replies remain scripted, with no live SSH/WSL/native provider or p95 claim. Historical prior account (preserved verbatim): Local hibernation, remote inventory authority and folder-workspace identity are covered by coordinator/model contracts on macOS. Daemon, SSH, WSL, relay and native platform execution boundaries and existing RPC payloads are unchanged. Current assertions cover shutdown safety and owning-host selection; historical inventory-count and performance evidence below is retained for provenance and is not current count coverage.", + "coveredPlatforms": [], + "coveredProviders": [], + "coverageNotes": "Audit3368 retires the whole hibernation coordinator suite and intentionally loses supplied inventory/liveness/attention/confirmation/changed-workspace/sequential teardown alarms without equivalent replacement. The sole compound dated receipt is retired verbatim; no shortened command inherits its results. With no active evidence, protection/platform/provider evidence clears and ALL current commands/testFiles/assertionRefs are retired as complete original arrays in historical gaps. Other source files remain in the broad suite. Prior red/green/flake accounts are historical only; no fresh runtime/provider/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit2058 intentionally retires the standalone visibility subscription/callback-count alarm without replacement. Audit2310 additionally retires two pane-age getter-map expiry/pruning samples without equivalent replacement. The reduced five-source hibernation selector was freshly run on Linux:52 tests pass. The earlier 54-test receipt is archived verbatim in knownGaps and does not validate the reduced source. Its prior macOS execution receipt/current-command association is archived verbatim in knownGaps and is not current execution evidence for the reduced selector. Current covered platform is Linux; remote replies remain scripted, with no live SSH/WSL/native provider or p95 claim. Historical prior account (preserved verbatim): Local hibernation, remote inventory authority and folder-workspace identity are covered by coordinator/model contracts on macOS. Daemon, SSH, WSL, relay and native platform execution boundaries and existing RPC payloads are unchanged. Current assertions cover shutdown safety and owning-host selection; historical inventory-count and performance evidence below is retained for provenance and is not current count coverage.", "motivatingLinks": [ "https://github.com/stablyai/orca/blob/main/src/renderer/src/lib/agent-hibernation-coordinator.test.ts" ], "invariant": "Automatic hibernation must retain two stable confirmations and fresh execution-host evidence before shutdown. Skipping a workspace with no completed agent must not authorize a newly completed pane using stale client PTYs.", - "oracle": "Audit2058 intentionally retires the standalone visibility subscription/callback-count alarm without replacement. Audit2310 additionally retires two pane-age getter-map expiry/pruning samples without equivalent replacement. The reduced five-source hibernation selector was freshly run on Linux:52 tests pass. The earlier 54-test receipt is archived verbatim in knownGaps and does not validate the reduced source. Its prior macOS execution receipt/current-command association is archived verbatim in knownGaps and is not current execution evidence for the reduced selector. Current covered platform is Linux; remote replies remain scripted, with no live SSH/WSL/native provider or p95 claim. Historical prior account (preserved verbatim): Working and waiting agents across remote workspaces must not be shut down. A skipped workspace completing while another inventory awaits remains ineligible until two later host-confirmed passes, and so does a workspace that only becomes runtime-owned while an inventory is outstanding — a pass carrying no host evidence for a workspace never counts as one of its two confirmations. Folder and git workspaces hibernate the exact host PTY; rejected/truncated inventories and intervening input/output or state changes block shutdown.", - "commands": [ - "ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-planner.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-pane-age.test.ts src/renderer/src/components/terminal-pane/parking/retention/foreground-terminal-tabs.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts --maxWorkers=2" - ], - "testFiles": [ - "src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts", - "src/renderer/src/lib/agent-session/hibernation/agent-hibernation-planner.test.ts", - "src/renderer/src/lib/agent-session/hibernation/agent-hibernation-pane-age.test.ts", - "src/renderer/src/components/terminal-pane/parking/retention/foreground-terminal-tabs.test.ts", - "src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts" - ], - "assertionRefs": [ - { - "file": "src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts", - "assertions": [ - "does not hibernate working or waiting agents across remote workspaces", - "requires host evidence after a skipped workspace completes during another inventory request", - "hibernates a runtime-backed candidate in %s with fresh liveness and exact PTYs", - "fails closed on truncated runtime liveness samples", - "fails closed when fresh runtime liveness rejects after an earlier good sample" - ] - }, - { - "file": "src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts", - "assertions": [ - "requires host evidence when a workspace becomes runtime-owned during an inventory request" - ] - } - ], - "evidenceRuns": [ - { - "date": "2026-11-08", - "runner": "local", - "platform": "linux", - "command": "ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-planner.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-pane-age.test.ts src/renderer/src/lib/foreground-terminal-tabs.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts --maxWorkers=2", - "currentCommand": "ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-planner.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-pane-age.test.ts src/renderer/src/components/terminal-pane/parking/retention/foreground-terminal-tabs.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts --maxWorkers=2", - "result": "passed", - "durationSeconds": 5.426, - "summary": "52 tests across the five coordinator/planner/age/foreground/liveness-race files passed on public parent60aee85d9182f602af45cf5f6facae7257670061 plus the audit2310 test-removal candidate (source tree da2595af5391e9fa07a924ac69afede47ad31906). Includes the reduced two-case pane-age suite. Scripted runtime contracts; no live SSH/native WSL, soak or measured p95 claim." - } - ], + "oracle": "Audit3368 retires the whole hibernation coordinator suite and intentionally loses supplied inventory/liveness/attention/confirmation/changed-workspace/sequential teardown alarms without equivalent replacement. The sole compound dated receipt is retired verbatim; no shortened command inherits its results. With no active evidence, protection/platform/provider evidence clears and ALL current commands/testFiles/assertionRefs are retired as complete original arrays in historical gaps. Other source files remain in the broad suite. Prior red/green/flake accounts are historical only; no fresh runtime/provider/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit2058 intentionally retires the standalone visibility subscription/callback-count alarm without replacement. Audit2310 additionally retires two pane-age getter-map expiry/pruning samples without equivalent replacement. The reduced five-source hibernation selector was freshly run on Linux:52 tests pass. The earlier 54-test receipt is archived verbatim in knownGaps and does not validate the reduced source. Its prior macOS execution receipt/current-command association is archived verbatim in knownGaps and is not current execution evidence for the reduced selector. Current covered platform is Linux; remote replies remain scripted, with no live SSH/WSL/native provider or p95 claim. Historical prior account (preserved verbatim): Working and waiting agents across remote workspaces must not be shut down. A skipped workspace completing while another inventory awaits remains ineligible until two later host-confirmed passes, and so does a workspace that only becomes runtime-owned while an inventory is outstanding — a pass carrying no host evidence for a workspace never counts as one of its two confirmations. Folder and git workspaces hibernate the exact host PTY; rejected/truncated inventories and intervening input/output or state changes block shutdown.", + "commands": [], + "testFiles": [], + "assertionRefs": [], + "evidenceRuns": [], "runtimeBudget": { "p95Seconds": 60, "scope": "Focused unit/provider-contract suite; local runtime budget, not an established p95." }, "flakeHistory": { - "status": "not-started", - "evidence": "Initial local validation; no CI soak history." + "status": "unknown", + "evidence": "Audit3368 retires sole active dated receipt. No fresh execution/soak validates current coverage; complete original account preserved verbatim as history." }, "redGreenEvidence": { - "status": "complete", - "evidence": "Baseline made 101 runtime calls in the new no-completed-agent fixture; candidate makes zero. Existing confirmation, final recheck and failure-path assertions continue to pass, including completion during an outstanding request. Separately, baseline hibernated a workspace that became runtime-owned mid-inventory one tick early, taking its first confirmation from a pass planned entirely from client PTYs; candidate withholds that pass and requires two host-confirmed ones." + "status": "missing", + "evidence": "Audit3368 changes/deletes referenced sources. No fresh red/green proof validates reduced coverage; original complete account preserved verbatim in knownGaps as history." }, "performanceBudget": { "required": true, @@ -1680,7 +1627,17 @@ "This improves the experimental automatic hibernation path only; it does not remove inventories for workspaces that contain completed agents.", "Historical audit2058 coverage note before audit2310, preserved verbatim; not current execution evidence: Audit2058 intentionally retires the standalone visibility subscription/callback-count alarm without replacement. The remaining five-source hibernation selector was freshly run on Linux:54 tests pass. Its prior macOS execution receipt/current-command association is archived verbatim in knownGaps and is not current execution evidence for the reduced selector. Current covered platform is Linux; remote replies remain scripted, with no live SSH/WSL/native provider or p95 claim.", "Audit2058 archives this exact historical receipt after deleting a selector in its currentCommand; historical provenance only, not current execution evidence:\n{\n \"date\": \"2026-09-07\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/lib/agent-hibernation-coordinator.test.ts src/renderer/src/lib/agent-hibernation-planner.test.ts src/renderer/src/lib/agent-hibernation-confirmation.test.ts src/renderer/src/lib/agent-hibernation-pane-age.test.ts src/renderer/src/lib/agent-hibernation-output-activity.test.ts src/renderer/src/lib/agent-hibernation-visibility.test.ts src/renderer/src/lib/foreground-terminal-tabs.test.ts src/renderer/src/lib/agent-hibernation-runtime-liveness-race.test.ts\",\n \"currentCommand\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-planner.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-pane-age.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-visibility.test.ts src/renderer/src/lib/foreground-terminal-tabs.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 48.18,\n \"summary\": \"93 tests passed across eight coordinator, liveness-race, planner, confirmation, age, activity and visibility files.\"\n }", - "Historical receipt retired by audit2310 because two pane-age getter-map registrations were removed; original record preserved verbatim, not current execution evidence:\n{\n \"date\": \"2026-11-08\",\n \"runner\": \"local\",\n \"platform\": \"linux\",\n \"command\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-planner.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-pane-age.test.ts src/renderer/src/lib/foreground-terminal-tabs.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts --maxWorkers=2\",\n \"result\": \"passed\",\n \"durationSeconds\": 7.377,\n \"summary\": \"54 tests across five unchanged coordinator/planner/age/foreground/liveness-race files passed on the actual39644 squash plus test-removal candidate. Reduced selector only; scripted runtime contracts, no live SSH/native WSL, soak or measured p95 claim.\"\n }" + "Historical receipt retired by audit2310 because two pane-age getter-map registrations were removed; original record preserved verbatim, not current execution evidence:\n{\n \"date\": \"2026-11-08\",\n \"runner\": \"local\",\n \"platform\": \"linux\",\n \"command\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-planner.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-pane-age.test.ts src/renderer/src/lib/foreground-terminal-tabs.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts --maxWorkers=2\",\n \"result\": \"passed\",\n \"durationSeconds\": 7.377,\n \"summary\": \"54 tests across five unchanged coordinator/planner/age/foreground/liveness-race files passed on the actual39644 squash plus test-removal candidate. Reduced selector only; scripted runtime contracts, no live SSH/native WSL, soak or measured p95 claim.\"\n }", + "Audit3368 retires the whole hibernation coordinator suite and intentionally loses supplied inventory/liveness/attention/confirmation/changed-workspace/sequential teardown alarms without equivalent replacement. The sole compound dated receipt is retired verbatim; no shortened command inherits its results. With no active evidence, protection/platform/provider evidence clears and ALL current commands/testFiles/assertionRefs are retired as complete original arrays in historical gaps. Other source files remain in the broad suite. Prior red/green/flake accounts are historical only; no fresh runtime/provider/UI/mobile/mixed-version/cross-platform evidence is claimed.", + "Audit3368 historical original commands object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\n \"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-planner.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-pane-age.test.ts src/renderer/src/components/terminal-pane/parking/retention/foreground-terminal-tabs.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts --maxWorkers=2\"\n ]", + "Audit3368 historical original testFiles object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\n \"src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts\",\n \"src/renderer/src/lib/agent-session/hibernation/agent-hibernation-planner.test.ts\",\n \"src/renderer/src/lib/agent-session/hibernation/agent-hibernation-pane-age.test.ts\",\n \"src/renderer/src/components/terminal-pane/parking/retention/foreground-terminal-tabs.test.ts\",\n \"src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts\"\n ]", + "Audit3368 historical original assertionRefs object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\n {\n \"file\": \"src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts\",\n \"assertions\": [\n \"does not hibernate working or waiting agents across remote workspaces\",\n \"requires host evidence after a skipped workspace completes during another inventory request\",\n \"hibernates a runtime-backed candidate in %s with fresh liveness and exact PTYs\",\n \"fails closed on truncated runtime liveness samples\",\n \"fails closed when fresh runtime liveness rejects after an earlier good sample\"\n ]\n },\n {\n \"file\": \"src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts\",\n \"assertions\": [\n \"requires host evidence when a workspace becomes runtime-owned during an inventory request\"\n ]\n }\n ]", + "Audit3368 historical original evidenceRuns object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\n {\n \"date\": \"2026-11-08\",\n \"runner\": \"local\",\n \"platform\": \"linux\",\n \"command\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-planner.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-pane-age.test.ts src/renderer/src/lib/foreground-terminal-tabs.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts --maxWorkers=2\",\n \"currentCommand\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-planner.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-pane-age.test.ts src/renderer/src/components/terminal-pane/parking/retention/foreground-terminal-tabs.test.ts src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts --maxWorkers=2\",\n \"result\": \"passed\",\n \"durationSeconds\": 5.426,\n \"summary\": \"52 tests across the five coordinator/planner/age/foreground/liveness-race files passed on public parent60aee85d9182f602af45cf5f6facae7257670061 plus the audit2310 test-removal candidate (source tree da2595af5391e9fa07a924ac69afede47ad31906). Includes the reduced two-case pane-age suite. Scripted runtime contracts; no live SSH/native WSL, soak or measured p95 claim.\"\n }\n ]", + "Audit3368 historical original protection object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"partial\"", + "Audit3368 historical original coveredPlatforms object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\"linux\"]", + "Audit3368 historical original coveredProviders object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\"local\", \"remote-runtime\"]", + "Audit3368 historical original redGreenEvidence object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"status\": \"complete\",\n \"evidence\": \"Baseline made 101 runtime calls in the new no-completed-agent fixture; candidate makes zero. Existing confirmation, final recheck and failure-path assertions continue to pass, including completion during an outstanding request. Separately, baseline hibernated a workspace that became runtime-owned mid-inventory one tick early, taking its first confirmation from a pass planned entirely from client PTYs; candidate withholds that pass and requires two host-confirmed ones.\"\n }", + "Audit3368 historical original flakeHistory object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"status\": \"not-started\",\n \"evidence\": \"Initial local validation; no CI soak history.\"\n }" ], "promotionCriteria": [ "Complete CI soak with zero unexplained flakes and preserve the observable oracle." @@ -2207,6 +2164,9 @@ "Exercise live SSH and paired-runtime snapshot adoption before claiming full provider coverage." ], "knownGaps": [ + "NEXT65 current scope qualification: The NEXT65 knownGaps entries below govern the changed selectors and qualify any broader coverage implication in this gate’s unchanged oracle/coverageNotes narratives. Those narratives and preserved dated evidenceRuns retain their historical text and original exact execution scopes only; no fresh execution, transferred pass or equivalent replacement coverage is claimed. Upstream case removals remain upstream; original NEXT65 proposal descriptions grant no duplicate retirement credit.", + "NEXT65 active selector scope reduction (including directory-selected whole-file retirements): src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts. Remove complete registrations or registrar files within the selected scope for src/renderer/src/components/terminal-pane/pty-connection/emulation/pty-connection-mode-2031-subscriptions.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/geometry/pty-connection-visibility-resume-size.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/geometry/remote-reconnect-unimaged-pane-redraw.test.ts, src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-restore-fit-overflow.test.ts, src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-restore-flood-abandon.test.ts, src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-restore-unhide-repaint-fallback.test.ts, src/renderer/src/components/terminal-pane/pty-connection/output-restore/remote-hidden-output-restore-outcomes.test.ts, src/renderer/src/components/terminal-pane/pty-connection/reattach/pty-connection-daemon-snapshot-replay.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/reattach/pty-connection-stale-daemon-snapshot-replay.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/spawn/pty-connection-split-spawn.spec.ts. Intentionally lose these named regression alarms without replacement: catches a subscribed pane up once per mode change across repeated reconnects — Mode2031 theme reporting catch-up/deduplication across repeated reconnects loses this direct protocol example.; defers to the viewer holding the grid, then catches up once on release — Held-grid viewer deferral and one catch-up/current-mode resending on release lose this direct protocol example.; repairs grid drift with a trailing probe when output stops inside the settled interval — A trailing drift probe after the last output frame loses this direct alarm.; skips foreground grid drift repair while mobile owns the PTY without a fit override — Mobile driver ownership suppressing foreground drift repair without override loses this direct alarm.; reports desktop geometry without resizing while a mobile-fit override is active — Desktop geometry reporting without resizing a mobile-owned grid loses this direct alarm.; defers a remote-desktop viewport claim until structural replay completes — Remote-desktop viewport claim waiting for structural replay completion loses this direct alarm.; skips observed desktop reassertion while mobile owns the PTY without a fit override — Observed desktop reassertion suppression under mobile ownership loses this direct alarm.; queues re-asserted resizes while pane resize holds are active — Resize hold release flushing the latest reasserted grid loses this direct alarm.; reasserts a remote grid only when visible (%s) — Visible-only remote grid reassertion loses its visible and hidden examples.; claims a focused visible remote mirror once when its passive fit hold arrives — Focused visible passive mirror claiming once, with unfocused and late repeat suppression, loses this direct sequence alarm.; does NOT re-assert while a mobile-fit override parks the PTY at phone dims — Phone fit hold suppressing visibility-resume PTY reassertion loses this direct alarm.; does NOT forward when the pane is hidden again before getSize resolves (stale hop) — Late size lookup after re-hide refusing a hidden-tab SIGWINCH loses this direct adverse-ordering alarm.; holds the repaint for a hidden pane until it is revealed — Unimaged hidden pane deferring one-row repaint until reveal loses this direct alarm.; puts the row back once the host confirms the short grid, not when the client sent it — Short-grid host confirmation gating row restoration loses this direct alarm.; does not take the size back from a viewer that claimed it mid-repaint — A viewer claiming geometry mid-repaint preventing old-size restoration loses this direct alarm.; leaves a swapped-out PTY alone when its nudge is still pending — Swapped-out PTY avoiding a pending repaint nudge loses this direct alarm.; puts the row back when the pane unmounts mid-repaint — Unmount during repaint restoring the nudged row loses this direct alarm.; recovers $name live output when the deadline interrupts an answered snapshot — Answered-snapshot deadline interruption under overflow/small/partial/split-escape/styled/styled-gap/unmapped/unhide-gap/fresh-gap live output loses nine direct recovery examples.; [invariant] reconciles the retained bytes through the deferred post-flood repaint — Queue-overflow quiet abandonment later reconciling retained bytes or disclosing loss loses this direct invariant alarm.; [invariant] keeps recovery armed while the user reads scrollback — Recovery remaining armed during scrollback reading/background stint then following output loses this direct invariant alarm.; [invariant] reconciles the retained bytes after the iteration backstop fires — Iteration-cap quiet abandonment owing later reconciliation/disclosure loses this direct invariant alarm.; does not leave a parked repaint after a repeated episode is repaired — Repeated repaired episode not leaving a parked repaint loses this direct alarm.; keeps the deferred repaint when pending live bytes overflow before the snapshot drains — Pending-live overflow before snapshot drain preserving deferred repaint loses this direct alarm.; keeps the existing repaint behavior for a pending-cap marker — Pending-cap marker preserving deferred repaint behavior loses this direct alarm.; fetches a fresh snapshot when hidden bytes arrived during the first fetch — Bytes arriving hidden during fetch forcing a fresh snapshot loses this direct alarm.; keeps recovery pending after the first snapshot is %s — Rejected/unavailable first capture preserving pending recovery until retry and acknowledgement loses two direct examples.; [modern] repaints a recovered visible pane from the retained host buffer — Visible modern recovery repaint from the retained host snapshot loses this direct example.; [modern] accepts an empty snapshot as successful recovery without a loss banner — Empty modern snapshots counting as successful recovery without loss disclosure loses this direct example.; [modern] waits for a reported outcome instead of applying the old elapsed-time deadline — Modern pending recovery respecting reported outcomes beyond the old elapsed deadline loses this direct example.; [modern] banners on the seventh retry-worthy host answer and never sends an eighth request — Seventh retry-worthy answer causing disclosure and suppression of an eighth request loses this direct example.; [modern] does not spend the host answer budget on locally-gated retries — Locally-gated answers leaving the host-answer budget available loses this direct example.; [modern] still bounds locally-gated retries at their own cap — Repeated local gating eventually ending recovery and disclosing loss loses this direct example.; [modern] banners immediately on permanent unavailability without retrying — Permanent host unavailability immediately disclosing loss without retry loses this direct example.; [modern] cancels a live flood repaint when it declares the output unrecoverable — Unrecoverable declaration cancelling a later flood repaint loses this direct example.; [legacy] switches an explicit unknown-host answer to the existing four-request heuristic — Explicit unknown-host result switching to legacy recovery heuristic loses this direct example.; [modern] parks retry repaint while scrolled back and resumes when following output — Scrolled-back recovery parking until follow-output resumes loses this direct example.; clears the captured pen for a normal-buffer fallback reattach — Fallback normal-buffer reattach clearing captured pen and dirty background loses this direct example.; waits for a recovered destination fit before forwarding its grid or live output — Recovered destination fitting before forwarding grid or live output loses this direct example.; suppresses the deferred reattach grid push when mobile claims the PTY while hidden — Mobile takeover while hidden suppressing deferred reattach grid forwarding loses this direct example.; drops stale callbacks but delivers fresh replacement output after an old replay clear — Fresh replacement output winning over stale callbacks after old replay clear loses this direct example.; clears the mobile-fit pane binding when the pane connection is disposed — Pane dispose clearing the mobile-fit binding and PTY dataset loses this direct example.; continues post-spawn size reconcile after a transient mobile presence lock — Size reconciliation continuing after a transient phone-presence lock loses this direct example.; spawns the delayed primary pane of an issue-command split when its sibling owns the tab PTY fallback — Delayed primary split spawning independently after a sibling acquires tab fallback loses this direct example.; does not reuse a sibling split pane pending spawn after remount — Remounted primary adopting its own pending PTY rather than the sibling spawn loses this direct example.; replays a stable-pane adoption without submitting the resume command — Stable-pane adoption replay preserving replay-before-live ordering and suppressing resume command loses this direct example.; forwards focus and hover reports without claiming a parked mirror (#26469) — Passive focus/hover forwarding without stealing mirror ownership, then intended Ctrl+C/click claiming, loses this direct example.. Surviving parent statements and sibling registrations are preserved, but these reduced parent selectors have no fresh execution or transferred historical pass. Unrelated complete dated receipts retain only their original exact scopes; no equivalent replacement, rendered UI, provider, mobile, or cross-platform coverage is claimed.", + "NEXT65 historical original active parent-selector fields (verbatim native JSON values; not current coverage):\ncommands: [\n \"pnpm test src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"pnpm test src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts\",\n \"pnpm test src/renderer/src/components/terminal-pane/pty-connection src/renderer/src/components/terminal-pane/pty-transport/ipc/pty-transport\",\n \"pnpm test src/shared/terminal/protocol/escape/terminal-synchronized-output-socket-splits.test.ts\"\n ]\ntestFiles: [\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"assertions\": [\n \"startup output covered by the snapshot is painted once\",\n \"new output remains visible\",\n \"legacy unsequenced and blank snapshots retain bytes\"\n ]\n }\n ]", "Audit3077 retires the IPC zero/nonzero snapshot-sequence and zero-keyboard-proof examples and their direct selectors. The retained join projects only sequence 7 and flags 3. No equivalent replacement or fresh gate execution is claimed.", "Audit3069 retires nominal spawn/resume/banner wiring, first-fit and lookup-budget variants, private pending-map checks, the split-CWD disposal suite and startup command/draft baseline variants. Distinct regression alarms are intentionally lost without equivalent replacement; retained ownership, cancellation and recovery cases remain. Existing selectors and dated evidence retain their original scope.", "Audit3061 retires the park-model supplied snapshot suite and nominal mode, cursor, focus, geometry and remote resume metadata variants. Their distinct alarms are intentionally lost; six retained mode/remote cases preserve selected tail-order, authority and parse-readiness boundaries without equivalent replacement. Existing selectors and dated evidence retain their original scope.", @@ -2349,35 +2309,33 @@ "providers": ["local", "ssh", "remote-runtime"], "coveredPlatforms": ["macos"], "coveredProviders": [], - "coverageNotes": "Audit2729 reduces browser-page-palette-activation.test.ts: separate SSH/paired-runtime alias forwarding, distinct multigroup views accepted, and remote-folder activation forwarding alarms are removed. Collision refusal, preactivation address-bar focus capture, owning-group activation state and missing-tab refusal remain byte-identical. No equivalent replacement, fresh gate execution or actual host/browser delivery evidence is claimed. Prior coverage account: Audit2697 browser source review (metadata followup2702): Reduce src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts by four authored/expanded cases without replacement. The remaining three cases preserve only their existing same-ID execution-host separation, absent stamped-owner refusal and ambiguous legacy-bucket refusal scope. Intentionally lose duplicate backing-tab-ID suppression, multiple unified-browser claims of one workspace, foreign-worktree unified-tab rejection, and the 1000-workspace output/internal getter-read budget alarm. These are real removed alarms; the retained host cases are not equivalent replacements. Current test-value policy rejects internal getter/read budgets; no replacement performance or measured-cost claim is made. Keep existing nonempty selectors and the retained same-ID browser assertionRef. No fresh gate execution or reduced-source validation is supplied; dated receipts, results, commands and historical coverage accounts remain within their original source scope. No live browser activation, physical provider, mixed-version execution, mobile, native UI, platform hardware, soak or timing result is added. Prior coverage account (preserved verbatim): Audit2266 reduces cmd-j-host-qualified-candidate-ownership.test.ts to the scoped open-tab hidden same-ID legacy ambiguity refusal. Separate browser/simulator paired-runtime alias and current-row projections, generic workspace host projection and hostless explicit-owner refusal examples are removed without equivalent replacement. No fresh gate execution, browser activation, physical host, simulator or remote delivery evidence is claimed. Historical dated receipts and budgets remain raw-byte exact. Prior coverage account: Audit1899 replays sealed Audit1895: workspace-session-schema.test.ts keeps only cross-workspace truncated-tab salvage and legacy browser-history cap normalization. Four current commands and testFiles retain that reduced source; no current assertionRef or active receipt selects it. SSH file-owner, isolated browser partition, launch/title/quick-command fields, recency, structured-chat/view-mode and remote browser identity hydration alarms are intentionally lost. Existing retired receipt strings and unrelated active receipts remain verbatim. No equivalent replacement, new Cmd-J gate execution, native simulator or remote/browser restore proof is claimed. Historical coverage account before Audit1899: Audit1494 removes use-open-tab-search.test.ts. Supplied host/worktree/title/ranking projections, simple subscription updates and result-array identity alarms are retired. No actual activation or navigation occurred in that suite. No equivalent replacement coverage or fresh Cmd-J gate validation is claimed. Historical receipts remain scoped to their original selectors. Audit1433 narrows worktree-checks-review-index.test.ts to same-ID local/SSH object-key review isolation. Local provider/cache lookup, GitLab preference, suppression/legacy fallback, explicit-PR authority, physical-versus-runtime review isolation, and branchless-workspace alarms are intentionally removed. No equivalent replacement coverage is claimed. Historical receipts and commands remain unchanged and do not certify the reduced source. Historical coverage account: Audit1396 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Audit1308 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Deterministic candidate-builder contracts inject local and paired-runtime worktrees with the same bare id into the real aggregated tab buckets, including folder workspaces and a paired runtime transporting an SSH-owned worktree. A mirror contract preserves distinct same-id runtime tabs. A paired Electron journey verifies both visible browser rows and both visible simulator rows, then requires each selection to render its owning active tab and update backing host-qualified state. The test-value audit narrowed simulator-palette-search.test.ts to the recency tie, same-id host isolation, ambiguous legacy host rejection and oversized-input getter tripwire. Supplied timestamp, empty-query context ordering, host projection, alias/range, metadata matching, active-tab score, over-token/whitespace and malformed display-name fallback examples were removed. Their separate alarms are lost; retained candidate and activation contracts do not establish equivalent coverage. Historical run commands and results remain historical. The audit also removed the standalone workspace-tab-palette-search suite: supplied row, title, metadata, alias, range, ranking and ownership examples no longer provide their separate alarms. Other retained contracts are not replacement coverage. The mirror-identity fixture now retains same-id sibling-runtime isolation and the repeated-frame subscriber tripwire only. Supplied field, owner, alias and mapping examples are removed; their separate alarms are lost. The retained sibling-runtime case is not equivalent coverage for them. The test-value audit removed tabs-open-close-lifecycle host-stamping examples and ordinary tab/group operations from tabs-pane-layout-operations. Local-null, explicit-runtime and SSH-without-active-host stamp assertions are lost; retained mobile/MRU and subscriber/atomic split cases do not replace them. Candidate and live Cmd-J evidence retains its own scope. Historical commands, outcomes and narratives remain historical. Audit1308: src/renderer/src/lib/browser-palette-search.test.ts removed. Browser-palette token and pasted-query size-guard work alarms disappear. No equivalent replacement coverage is claimed. Audit1386: src/renderer/src/lib/open-mobile-emulator-tab.test.ts reduced. Duplicate attach count and null-tab creation retry/guard reset standalone alarms removed; no simulator device used. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1396: src/renderer/src/lib/simulator-palette-search.test.ts reduced. Lose simulator-specific lastFocusedAt tie-order alarm; identity/routing and pre-scan size fence remain. No native simulator or real remote launch claim. No equivalent replacement coverage is claimed. Audit1402: src/renderer/src/runtime/web-session-tabs-sync-mirror-identity.test.ts reduced. Loses repeated no-op frame store-notification budget; independent cross-runtime resource preservation remains. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result.", + "coverageNotes": "Audit3359 retires the whole ensure-simulator-tab-behavior suite: host-collision reuse, host stamping, inactive creation and unknown-owner routing alarms are intentionally lost without equivalent replacement. Its standalone command is removed and four compound commands narrowed. Three complete dated receipts selecting that source through currentCommand are retired verbatim, including their compound historical selectors; no retained test inherits their validation. Seven unrelated macOS receipts retain their original scope. No fresh runtime/UI, simulator, provider, historical-import, mobile, mixed-version or cross-platform validation is claimed. Audit 3301 removes the orphaned mobile file-close fallback and ordinary cross-content MRU examples from tabs-open-close-lifecycle.test.ts. Earlier descriptions of retained MRU coverage are historical. The integrated mobile markdown close/frame-settlement case remains unchanged and is narrower. Preserve the existing administrative failed receipt and all complete retired receipts verbatim, along with selectors and unrelated assertions; no equivalent replacement or fresh Cmd-J, native or remote result is claimed. Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims. Audit2729 reduces browser-page-palette-activation.test.ts: separate SSH/paired-runtime alias forwarding, distinct multigroup views accepted, and remote-folder activation forwarding alarms are removed. Collision refusal, preactivation address-bar focus capture, owning-group activation state and missing-tab refusal remain byte-identical. No equivalent replacement, fresh gate execution or actual host/browser delivery evidence is claimed. Prior coverage account: Audit2697 browser source review (metadata followup2702): Reduce src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts by four authored/expanded cases without replacement. The remaining three cases preserve only their existing same-ID execution-host separation, absent stamped-owner refusal and ambiguous legacy-bucket refusal scope. Intentionally lose duplicate backing-tab-ID suppression, multiple unified-browser claims of one workspace, foreign-worktree unified-tab rejection, and the 1000-workspace output/internal getter-read budget alarm. These are real removed alarms; the retained host cases are not equivalent replacements. Current test-value policy rejects internal getter/read budgets; no replacement performance or measured-cost claim is made. Keep existing nonempty selectors and the retained same-ID browser assertionRef. No fresh gate execution or reduced-source validation is supplied; dated receipts, results, commands and historical coverage accounts remain within their original source scope. No live browser activation, physical provider, mixed-version execution, mobile, native UI, platform hardware, soak or timing result is added. Prior coverage account (preserved verbatim): Audit2266 reduces cmd-j-host-qualified-candidate-ownership.test.ts to the scoped open-tab hidden same-ID legacy ambiguity refusal. Separate browser/simulator paired-runtime alias and current-row projections, generic workspace host projection and hostless explicit-owner refusal examples are removed without equivalent replacement. No fresh gate execution, browser activation, physical host, simulator or remote delivery evidence is claimed. Historical dated receipts and budgets remain raw-byte exact. Prior coverage account: Audit1899 replays sealed Audit1895: workspace-session-schema.test.ts keeps only cross-workspace truncated-tab salvage and legacy browser-history cap normalization. Four current commands and testFiles retain that reduced source; no current assertionRef or active receipt selects it. SSH file-owner, isolated browser partition, launch/title/quick-command fields, recency, structured-chat/view-mode and remote browser identity hydration alarms are intentionally lost. Existing retired receipt strings and unrelated active receipts remain verbatim. No equivalent replacement, new Cmd-J gate execution, native simulator or remote/browser restore proof is claimed. Historical coverage account before Audit1899: Audit1494 removes use-open-tab-search.test.ts. Supplied host/worktree/title/ranking projections, simple subscription updates and result-array identity alarms are retired. No actual activation or navigation occurred in that suite. No equivalent replacement coverage or fresh Cmd-J gate validation is claimed. Historical receipts remain scoped to their original selectors. Audit1433 narrows worktree-checks-review-index.test.ts to same-ID local/SSH object-key review isolation. Local provider/cache lookup, GitLab preference, suppression/legacy fallback, explicit-PR authority, physical-versus-runtime review isolation, and branchless-workspace alarms are intentionally removed. No equivalent replacement coverage is claimed. Historical receipts and commands remain unchanged and do not certify the reduced source. Historical coverage account: Audit1396 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Audit1308 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Deterministic candidate-builder contracts inject local and paired-runtime worktrees with the same bare id into the real aggregated tab buckets, including folder workspaces and a paired runtime transporting an SSH-owned worktree. A mirror contract preserves distinct same-id runtime tabs. A paired Electron journey verifies both visible browser rows and both visible simulator rows, then requires each selection to render its owning active tab and update backing host-qualified state. The test-value audit narrowed simulator-palette-search.test.ts to the recency tie, same-id host isolation, ambiguous legacy host rejection and oversized-input getter tripwire. Supplied timestamp, empty-query context ordering, host projection, alias/range, metadata matching, active-tab score, over-token/whitespace and malformed display-name fallback examples were removed. Their separate alarms are lost; retained candidate and activation contracts do not establish equivalent coverage. Historical run commands and results remain historical. The audit also removed the standalone workspace-tab-palette-search suite: supplied row, title, metadata, alias, range, ranking and ownership examples no longer provide their separate alarms. Other retained contracts are not replacement coverage. The mirror-identity fixture now retains same-id sibling-runtime isolation and the repeated-frame subscriber tripwire only. Supplied field, owner, alias and mapping examples are removed; their separate alarms are lost. The retained sibling-runtime case is not equivalent coverage for them. The test-value audit removed tabs-open-close-lifecycle host-stamping examples and ordinary tab/group operations from tabs-pane-layout-operations. Local-null, explicit-runtime and SSH-without-active-host stamp assertions are lost; retained mobile/MRU and subscriber/atomic split cases do not replace them. Candidate and live Cmd-J evidence retains its own scope. Historical commands, outcomes and narratives remain historical. Audit1308: src/renderer/src/lib/browser-palette-search.test.ts removed. Browser-palette token and pasted-query size-guard work alarms disappear. No equivalent replacement coverage is claimed. Audit1386: src/renderer/src/lib/open-mobile-emulator-tab.test.ts reduced. Duplicate attach count and null-tab creation retry/guard reset standalone alarms removed; no simulator device used. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1396: src/renderer/src/lib/simulator-palette-search.test.ts reduced. Lose simulator-specific lastFocusedAt tie-order alarm; identity/routing and pre-scan size fence remain. No native simulator or real remote launch claim. No equivalent replacement coverage is claimed. Audit1402: src/renderer/src/runtime/web-session-tabs-sync-mirror-identity.test.ts reduced. Loses repeated no-op frame store-notification budget; independent cross-runtime resource preservation remains. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result.", "motivatingLinks": [ "https://linear.app/stably/issue/STA-4965", "https://github.com/stablyai/orca/pull/15371" ], "invariant": "Candidate identity is the tuple of execution-host identity and worktree identity: same-id sibling hosts retain separate correct browser, simulator, and workspace tabs, each tab appears exactly once, and selection activates its owning host.", - "oracle": "Audit2697 browser source review (metadata followup2702): Reduce src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts by four authored/expanded cases without replacement. The remaining three cases preserve only their existing same-ID execution-host separation, absent stamped-owner refusal and ambiguous legacy-bucket refusal scope. Intentionally lose duplicate backing-tab-ID suppression, multiple unified-browser claims of one workspace, foreign-worktree unified-tab rejection, and the 1000-workspace output/internal getter-read budget alarm. These are real removed alarms; the retained host cases are not equivalent replacements. Current test-value policy rejects internal getter/read budgets; no replacement performance or measured-cost claim is made. Keep existing nonempty selectors and the retained same-ID browser assertionRef. No fresh gate execution or reduced-source validation is supplied; dated receipts, results, commands and historical coverage accounts remain within their original source scope. No live browser activation, physical provider, mixed-version execution, mobile, native UI, platform hardware, soak or timing result is added. Prior coverage account (preserved verbatim): Audit2266 current retained source checks only that scoped open-tab search rejects hostless legacy browser, simulator and workspace tabs when a hidden same-ID sibling host remains in the ownership catalog. Reduced selectors require fresh validation; existing historical receipts do not validate the changed source. Prior oracle account: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Aggregate two hosts' tabs under one intentionally colliding worktree id, stamp each unified tab with its execution host, and require exactly one candidate per owner. Repeat with an SSH physical owner transported by a paired-runtime alias. Independently require each browser and simulator Cmd-J selection to update activeWorkspaceExecutionHostId plus its owning workspace/group and render the selected tab active. Ambiguous legacy tabs without ownership fail closed.", + "oracle": "Audit3359 retires the whole ensure-simulator-tab-behavior suite: host-collision reuse, host stamping, inactive creation and unknown-owner routing alarms are intentionally lost without equivalent replacement. Its standalone command is removed and four compound commands narrowed. Three complete dated receipts selecting that source through currentCommand are retired verbatim, including their compound historical selectors; no retained test inherits their validation. Seven unrelated macOS receipts retain their original scope. No fresh runtime/UI, simulator, provider, historical-import, mobile, mixed-version or cross-platform validation is claimed. Audit 3301 removes the orphaned mobile file-close fallback and ordinary cross-content MRU examples from tabs-open-close-lifecycle.test.ts. Earlier descriptions of retained MRU coverage are historical. The integrated mobile markdown close/frame-settlement case remains unchanged and is narrower. Preserve the existing administrative failed receipt and all complete retired receipts verbatim, along with selectors and unrelated assertions; no equivalent replacement or fresh Cmd-J, native or remote result is claimed. Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims. Audit2697 browser source review (metadata followup2702): Reduce src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts by four authored/expanded cases without replacement. The remaining three cases preserve only their existing same-ID execution-host separation, absent stamped-owner refusal and ambiguous legacy-bucket refusal scope. Intentionally lose duplicate backing-tab-ID suppression, multiple unified-browser claims of one workspace, foreign-worktree unified-tab rejection, and the 1000-workspace output/internal getter-read budget alarm. These are real removed alarms; the retained host cases are not equivalent replacements. Current test-value policy rejects internal getter/read budgets; no replacement performance or measured-cost claim is made. Keep existing nonempty selectors and the retained same-ID browser assertionRef. No fresh gate execution or reduced-source validation is supplied; dated receipts, results, commands and historical coverage accounts remain within their original source scope. No live browser activation, physical provider, mixed-version execution, mobile, native UI, platform hardware, soak or timing result is added. Prior coverage account (preserved verbatim): Audit2266 current retained source checks only that scoped open-tab search rejects hostless legacy browser, simulator and workspace tabs when a hidden same-ID sibling host remains in the ownership catalog. Reduced selectors require fresh validation; existing historical receipts do not validate the changed source. Prior oracle account: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Aggregate two hosts' tabs under one intentionally colliding worktree id, stamp each unified tab with its execution host, and require exactly one candidate per owner. Repeat with an SSH physical owner transported by a paired-runtime alias. Independently require each browser and simulator Cmd-J selection to update activeWorkspaceExecutionHostId plus its owning workspace/group and render the selected tab active. Ambiguous legacy tabs without ownership fail closed.", "commands": [ "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/cmd-j/worktree-checks-review-index.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/cmd-j-host-qualified-candidate-ownership.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts src/shared/workspace-session/workspace-session-schema.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/cmd-j-host-qualified-candidate-ownership.test.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts src/renderer/src/lib/browser/palette/browser-page-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/simulator-tab-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-tabs-sync-mirror-identity.test.ts src/shared/workspace-session/workspace-session-schema.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/cmd-j/worktree-checks-review-index.test.ts src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx src/renderer/src/lib/cmd-j-host-qualified-candidate-ownership.test.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts src/renderer/src/lib/browser/palette/browser-page-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/simulator-tab-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-tabs-sync-mirror-identity.test.ts src/shared/workspace-session/workspace-session-schema.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/cmd-j/worktree-checks-review-index.test.ts src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx src/renderer/src/lib/cmd-j-host-qualified-candidate-ownership.test.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts src/renderer/src/lib/browser/palette/browser-page-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/simulator-tab-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts src/renderer/src/lib/simulator/launch/open-mobile-emulator-tab.test.ts src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-tabs-sync-mirror-identity.test.ts src/shared/workspace-session/workspace-session-schema.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/workspace/search/palette/cmd-j-host-qualified-candidate-ownership.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts src/shared/workspace-session/workspace-session-schema.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/workspace/search/palette/cmd-j-host-qualified-candidate-ownership.test.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts src/renderer/src/lib/browser/palette/browser-page-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/simulator-tab-palette-activation.test.ts src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-tabs-sync-mirror-identity.test.ts src/shared/workspace-session/workspace-session-schema.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/cmd-j/worktree-checks-review-index.test.ts src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx src/renderer/src/lib/workspace/search/palette/cmd-j-host-qualified-candidate-ownership.test.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts src/renderer/src/lib/browser/palette/browser-page-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/simulator-tab-palette-activation.test.ts src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-tabs-sync-mirror-identity.test.ts src/shared/workspace-session/workspace-session-schema.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/cmd-j/worktree-checks-review-index.test.ts src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx src/renderer/src/lib/workspace/search/palette/cmd-j-host-qualified-candidate-ownership.test.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts src/renderer/src/lib/browser/palette/browser-page-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/simulator-tab-palette-activation.test.ts src/renderer/src/lib/simulator/launch/open-mobile-emulator-tab.test.ts src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-tabs-sync-mirror-identity.test.ts src/shared/workspace-session/workspace-session-schema.test.ts", "pnpm exec playwright test tests/e2e/paired-cmd-j-host-qualified-tabs.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1", "SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-cmd-j-host-qualified-tabs.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1" ], "testFiles": [ "src/renderer/src/components/cmd-j/worktree-checks-review-index.test.ts", "src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx", - "src/renderer/src/lib/cmd-j-host-qualified-candidate-ownership.test.ts", + "src/renderer/src/lib/workspace/search/palette/cmd-j-host-qualified-candidate-ownership.test.ts", "src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts", "src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts", "src/renderer/src/lib/browser/palette/browser-page-palette-activation.test.ts", "src/renderer/src/lib/simulator/tabs/simulator-tab-palette-activation.test.ts", - "src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts", "src/renderer/src/lib/simulator/launch/open-mobile-emulator-tab.test.ts", "src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-tabs-sync-mirror-identity.test.ts", "tests/e2e/paired-cmd-j-host-qualified-tabs.spec.ts", @@ -2388,21 +2346,12 @@ "file": "src/renderer/src/components/cmd-j/worktree-checks-review-index.test.ts", "assertions": ["same-id local and SSH worktrees keep separate review-index results"] }, - { - "file": "src/renderer/src/lib/cmd-j-host-qualified-candidate-ownership.test.ts", + "file": "src/renderer/src/lib/workspace/search/palette/cmd-j-host-qualified-candidate-ownership.test.ts", "assertions": [ "scoped open-tab search keeps a hidden same-id sibling in the legacy ownership ambiguity set" ] }, - { - "file": "src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts", - "assertions": [ - "same-id folder simulator reuse selects the active owning host", - "inactive local simulator creation remains host-stamped amid a collision", - "an explicitly owned simulator is reused before its matching worktree row hydrates" - ] - }, { "file": "src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts", "assertions": [ @@ -2426,7 +2375,7 @@ "result": "failed", "durationSeconds": 1.8, "summary": "The first review-round oracle failed 4/40: browser and simulator dropped the SSH worktree's paired-runtime-owned tab, generic workspace rows attributed the remote tab to local, and active local tab creation left ownership unstamped. Historical command and result are preserved after the test-value audit removed the tab-store assertions this run included. currentCommand is only an administrative link to the remaining gate command; the historical run has not validated that command or equivalent coverage.", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/cmd-j-host-qualified-candidate-ownership.test.ts" + "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/workspace/search/palette/cmd-j-host-qualified-candidate-ownership.test.ts" }, { "date": "2026-08-20", @@ -2448,37 +2397,6 @@ "summary": "A fresh electron-vite --mode e2e build passed the paired journey: the visible Cmd-J list retained one owning browser/simulator row and each selection changed the execution host plus its owning workspace or group.", "currentCommand": "pnpm exec playwright test tests/e2e/paired-cmd-j-host-qualified-tabs.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1" }, - { - "date": "2026-08-20", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/ensure-simulator-tab-behavior.test.ts src/renderer/src/lib/palette-repo-resolution.test.ts", - "result": "failed", - "durationSeconds": 0.8, - "summary": "The final-review oracle failed 4/16 before the follow-up: same-id folder simulator reuse selected no owning tab, inactive local simulator creation was unstamped, the paired SSH/runtime alias resolved local metadata, and an explicit unknown owner fell back locally. Historical command preserved after the test-value audit removed the palette repo resolver suite. currentCommand is an administrative link to a remaining gate command; this historical run has not validated that command or equivalent coverage.", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts" - }, - { - "date": "2026-08-20", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/palette-repo-resolution.test.ts", - "result": "failed", - "durationSeconds": 0.1, - "summary": "The final reviewer repo-label oracle failed 1/6 before the follow-up: a paired SSH worktree resolved the local bare-id repository instead of its runtime-owned repository. Historical command preserved after the test-value audit removed the palette repo resolver suite. currentCommand is an administrative link to a remaining gate command; this historical run has not validated that command or equivalent coverage.", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts" - }, - { - "date": "2026-08-20", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/palette-repo-resolution.test.ts", - "result": "failed", - "durationSeconds": 0.1, - "summary": "The final clean-round fail-closed oracle failed 1/7 before the follow-up: an unavailable explicit runtime owner borrowed physical SSH repository metadata. Historical command preserved after the test-value audit removed the palette repo resolver suite. currentCommand is an administrative link to a remaining gate command; this historical run has not validated that command or equivalent coverage.", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts" - }, - { "date": "2026-08-20", "runner": "local", @@ -2566,7 +2484,20 @@ "Audit1402: src/renderer/src/runtime/web-session-tabs-sync-mirror-identity.test.ts reduced. Loses repeated no-op frame store-notification budget; independent cross-runtime resource preservation remains. No equivalent replacement coverage is claimed. Historical removed assertion inventory: [{\"file\":\"src/renderer/src/runtime/web-session-tabs-sync-mirror-identity.test.ts\",\"assertions\":[\"preserves a sibling runtime mirror under the same bare worktree id\"]}]", "Audit1494 removes use-open-tab-search.test.ts. Supplied host/worktree/title/ranking projections, simple subscription updates and result-array identity alarms are retired. No actual activation or navigation occurred in that suite. No equivalent replacement coverage or fresh Cmd-J gate validation is claimed. Historical receipts remain scoped to their original selectors.", "Audit1899 replays sealed Audit1895: workspace-session-schema.test.ts keeps only cross-workspace truncated-tab salvage and legacy browser-history cap normalization. Four current commands and testFiles retain that reduced source; no current assertionRef or active receipt selects it. SSH file-owner, isolated browser partition, launch/title/quick-command fields, recency, structured-chat/view-mode and remote browser identity hydration alarms are intentionally lost. Existing retired receipt strings and unrelated active receipts remain verbatim. No equivalent replacement, new Cmd-J gate execution, native simulator or remote/browser restore proof is claimed.", - "Audit2192 retires the removed physical-SSH repository badge assertion from WorktreeJumpPalette.test.tsx and its exact historical failed oracle receipt. Current reduced test selectors and unrelated unit/E2E receipts remain; none was rerun by this source audit and equivalent coverage is not claimed. Original obsolete assertion object verbatim:\n{\n \"file\": \"src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx\",\n \"assertions\": [\n \"a runtime-owned worktree row never renders repository metadata borrowed from its physical SSH host\"\n ]\n }\nOriginal dated failed receipt object verbatim:\n{\n \"date\": \"2026-08-20\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/WorktreeJumpPalette.test.tsx\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx\",\n \"result\": \"failed\",\n \"durationSeconds\": 5.1,\n \"summary\": \"With the component's physical-host prelookup restored, the rendered palette oracle failed 1/12: the runtime-owned row displayed the physical SSH repository badge.\"\n }" + "Audit2192 retires the removed physical-SSH repository badge assertion from WorktreeJumpPalette.test.tsx and its exact historical failed oracle receipt. Current reduced test selectors and unrelated unit/E2E receipts remain; none was rerun by this source audit and equivalent coverage is not claimed. Original obsolete assertion object verbatim:\n{\n \"file\": \"src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx\",\n \"assertions\": [\n \"a runtime-owned worktree row never renders repository metadata borrowed from its physical SSH host\"\n ]\n }\nOriginal dated failed receipt object verbatim:\n{\n \"date\": \"2026-08-20\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/WorktreeJumpPalette.test.tsx\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx\",\n \"result\": \"failed\",\n \"durationSeconds\": 5.1,\n \"summary\": \"With the component's physical-host prelookup restored, the rendered palette oracle failed 1/12: the runtime-owned row displayed the physical SSH repository badge.\"\n }", + "Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims.", + "Audit 3301 removes the orphaned mobile file-close fallback and ordinary cross-content MRU examples from tabs-open-close-lifecycle.test.ts. Earlier descriptions of retained MRU coverage are historical. The integrated mobile markdown close/frame-settlement case remains unchanged and is narrower. Preserve the existing administrative failed receipt and all complete retired receipts verbatim, along with selectors and unrelated assertions; no equivalent replacement or fresh Cmd-J, native or remote result is claimed.", + "Audit3359 retires the whole ensure-simulator-tab-behavior suite: host-collision reuse, host stamping, inactive creation and unknown-owner routing alarms are intentionally lost without equivalent replacement. Its standalone command is removed and four compound commands narrowed. Three complete dated receipts selecting that source through currentCommand are retired verbatim, including their compound historical selectors; no retained test inherits their validation. Seven unrelated macOS receipts retain their original scope. No fresh runtime/UI, simulator, provider, historical-import, mobile, mixed-version or cross-platform validation is claimed.", + "Audit3359 historical original commands object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts\"", + "Audit3359 historical original commands object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts src/shared/workspace-session/workspace-session-schema.test.ts\"", + "Audit3359 historical original commands object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/workspace/search/palette/cmd-j-host-qualified-candidate-ownership.test.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts src/renderer/src/lib/browser/palette/browser-page-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/simulator-tab-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-tabs-sync-mirror-identity.test.ts src/shared/workspace-session/workspace-session-schema.test.ts\"", + "Audit3359 historical original commands object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/cmd-j/worktree-checks-review-index.test.ts src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx src/renderer/src/lib/workspace/search/palette/cmd-j-host-qualified-candidate-ownership.test.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts src/renderer/src/lib/browser/palette/browser-page-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/simulator-tab-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-tabs-sync-mirror-identity.test.ts src/shared/workspace-session/workspace-session-schema.test.ts\"", + "Audit3359 historical original commands object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/cmd-j/worktree-checks-review-index.test.ts src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx src/renderer/src/lib/workspace/search/palette/cmd-j-host-qualified-candidate-ownership.test.ts src/renderer/src/lib/browser/palette/browser-palette-page-entries.test.ts src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts src/renderer/src/lib/browser/palette/browser-page-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/simulator-tab-palette-activation.test.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts src/renderer/src/lib/simulator/launch/open-mobile-emulator-tab.test.ts src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-tabs-sync-mirror-identity.test.ts src/shared/workspace-session/workspace-session-schema.test.ts\"", + "Audit3359 historical original testFiles object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts\"", + "Audit3359 historical original assertionRefs object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"file\": \"src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts\",\n \"assertions\": [\n \"same-id folder simulator reuse selects the active owning host\",\n \"inactive local simulator creation remains host-stamped amid a collision\",\n \"an explicitly owned simulator is reused before its matching worktree row hydrates\"\n ]\n }", + "Audit3359 historical original evidenceRuns object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"date\": \"2026-08-20\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/ensure-simulator-tab-behavior.test.ts src/renderer/src/lib/palette-repo-resolution.test.ts\",\n \"result\": \"failed\",\n \"durationSeconds\": 0.8,\n \"summary\": \"The final-review oracle failed 4/16 before the follow-up: same-id folder simulator reuse selected no owning tab, inactive local simulator creation was unstamped, the paired SSH/runtime alias resolved local metadata, and an explicit unknown owner fell back locally. Historical command preserved after the test-value audit removed the palette repo resolver suite. currentCommand is an administrative link to a remaining gate command; this historical run has not validated that command or equivalent coverage.\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts\"\n }", + "Audit3359 historical original evidenceRuns object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"date\": \"2026-08-20\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/palette-repo-resolution.test.ts\",\n \"result\": \"failed\",\n \"durationSeconds\": 0.1,\n \"summary\": \"The final reviewer repo-label oracle failed 1/6 before the follow-up: a paired SSH worktree resolved the local bare-id repository instead of its runtime-owned repository. Historical command preserved after the test-value audit removed the palette repo resolver suite. currentCommand is an administrative link to a remaining gate command; this historical run has not validated that command or equivalent coverage.\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts\"\n }", + "Audit3359 historical original evidenceRuns object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"date\": \"2026-08-20\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/palette-repo-resolution.test.ts\",\n \"result\": \"failed\",\n \"durationSeconds\": 0.1,\n \"summary\": \"The final clean-round fail-closed oracle failed 1/7 before the follow-up: an unavailable explicit runtime owner borrowed physical SSH repository metadata. Historical command preserved after the test-value audit removed the palette repo resolver suite. currentCommand is an administrative link to a remaining gate command; this historical run has not validated that command or equivalent coverage.\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts\"\n }" ], "demotionRule": "Cannot promote if a same-id sibling tab duplicates, disappears, activates another host, or if ambiguous unstamped ownership is guessed." }, @@ -2587,14 +2518,14 @@ "providers": ["orca-server", "direct-ssh"], "coveredPlatforms": ["macos"], "coveredProviders": ["orca-server", "direct-ssh"], - "coverageNotes": "Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/lib/ephemeral-vm-failed-create-cleanup.test.ts: removes the imported project setup before destroying its VM; retains the VM when setup deletion throws; retains the VM when setup deletion reports no result. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Exact retired assertionRefs, preserved as historical objects only: {\n \"file\": \"src/renderer/src/lib/ephemeral-vm-failed-create-cleanup.test.ts\",\n \"assertions\": [\"failed or unconfirmed project-host rollback prevents provider destroy\"]\n } Historical prior account (preserved verbatim): Audit1634 removes low-value IPC, filesystem and runtime projections, argument inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained cancellation, ownership, authorization, filesystem and SQLite boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1627 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1441 removes the complete renderer VM-runtime settings suite: display filter/status/SSH-retry flags, cleanup and stop RPC-to-toast/dialog plumbing, manual-copy plumbing and polling toast silence. The suite did not execute provider teardown or process cancellation. Its rendered stop/retry and hidden-SSH display alarms are intentionally retired; no equivalent replacement or fresh reduced-selector runtime result is claimed. Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Audit1417 intentionally deletes src/renderer/src/lib/ephemeral-vm-workspace-target.test.ts: Loses wrapper-level host rebinding, incompatible provisioned-root refusal and best-effort cleanup-call alarms; all are mock-only orchestration projections. No equivalent replacement coverage or fresh result is claimed. Historical coverage account: Audit1342 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): A pinned exact-source harness runs the pre-#14352 reader and lifecycle service against baseline, affected-main, candidate, and fix-reverted stores. Platform-neutral tests cover store compatibility, user-cancellable cleanup, branch/ref adoption; audit885 removes the direct resume ownership predicate alarms. The direct-SSH provisioned-root Electron journey remains the live transport and destroy proof; this desktop sidecar is not mobile-facing and changes no RPC or remote wire payload. The test-value audit removed the renderer provisioned-root create-options suite. Its two incomplete-identity rejection assertions are lost: one omitted workspaceRunContext and other identity fields, and one supplied the context but omitted ephemeralVmExpectedRefHead. The suite did not test successful option mapping. Retained source-ref and lifecycle suites do not establish equivalent renderer guard coverage. Audit1342: src/renderer/src/lib/ephemeral-vm-runtime-cleanup.test.ts removed. Runtime/SSH ownership, encoded target, retry/failure/listing-error cleanup projection samples disappear. No equivalent replacement coverage is claimed.", + "coverageNotes": "Audit 3292 retires the direct-SSH failed-project retention, managed-server failed-project retention and ordinary confirmed managed-VM destruction/no-repo.rm examples from repos-ephemeral-vm-cleanup-retention.test.ts. Host-scoped same-workspace isolation and stale renderer catalog reconciliation remain byte-identical. These three supplied-result alarms are intentionally lost without equivalent replacement. Existing selectors/assertionRefs, unrelated cross-version rollback receipt and archived complete 122-case cleanup receipt remain exact; no fresh broad runtime, provider, platform or mixed-version result is claimed. Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/lib/ephemeral-vm-failed-create-cleanup.test.ts: removes the imported project setup before destroying its VM; retains the VM when setup deletion throws; retains the VM when setup deletion reports no result. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Exact retired assertionRefs, preserved as historical objects only: {\n \"file\": \"src/renderer/src/lib/ephemeral-vm-failed-create-cleanup.test.ts\",\n \"assertions\": [\"failed or unconfirmed project-host rollback prevents provider destroy\"]\n } Historical prior account (preserved verbatim): Audit1634 removes low-value IPC, filesystem and runtime projections, argument inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained cancellation, ownership, authorization, filesystem and SQLite boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1627 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1441 removes the complete renderer VM-runtime settings suite: display filter/status/SSH-retry flags, cleanup and stop RPC-to-toast/dialog plumbing, manual-copy plumbing and polling toast silence. The suite did not execute provider teardown or process cancellation. Its rendered stop/retry and hidden-SSH display alarms are intentionally retired; no equivalent replacement or fresh reduced-selector runtime result is claimed. Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Audit1417 intentionally deletes src/renderer/src/lib/ephemeral-vm-workspace-target.test.ts: Loses wrapper-level host rebinding, incompatible provisioned-root refusal and best-effort cleanup-call alarms; all are mock-only orchestration projections. No equivalent replacement coverage or fresh result is claimed. Historical coverage account: Audit1342 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): A pinned exact-source harness runs the pre-#14352 reader and lifecycle service against baseline, affected-main, candidate, and fix-reverted stores. Platform-neutral tests cover store compatibility, user-cancellable cleanup, branch/ref adoption; audit885 removes the direct resume ownership predicate alarms. The direct-SSH provisioned-root Electron journey remains the live transport and destroy proof; this desktop sidecar is not mobile-facing and changes no RPC or remote wire payload. The test-value audit removed the renderer provisioned-root create-options suite. Its two incomplete-identity rejection assertions are lost: one omitted workspaceRunContext and other identity fields, and one supplied the context but omitted ephemeralVmExpectedRefHead. The suite did not test successful option mapping. Retained source-ref and lifecycle suites do not establish equivalent renderer guard coverage. Audit1342: src/renderer/src/lib/ephemeral-vm-runtime-cleanup.test.ts removed. Runtime/SSH ownership, encoded target, retry/failure/listing-error cleanup projection samples disappear. No equivalent replacement coverage is claimed.", "motivatingLinks": [ "https://linear.app/stably/issue/STA-4274", "https://github.com/stablyai/orca/pull/14352", "https://github.com/stablyai/orca/issues/13044" ], "invariant": "A sidecar written by the new build cannot make the previous production build lose otherwise compatible VM runtimes. Downgrade lifecycle writes remain authoritative after re-upgrade, provisioned-root metadata remains recoverable, and corrupt or future feature metadata is preserved without poisoning the rollback-readable v1 store. Destroy attempts have no automatic wall-clock cutoff; a user stop terminates the process tree, retains cleanup ownership, and permits a fresh retry. Provider failure retains the SSH/project context needed for safe cleanup. Unrecoverable recipe context releases only the hidden SSH registration while preserving lifecycle/provider metadata. Provisioned-root create receives the source ref's pinned commit, adoption verifies the requested branch/ref, and resume preserves the connection mode plus stable SSH ownership identity while allowing endpoint rotation.", - "oracle": "Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/lib/ephemeral-vm-failed-create-cleanup.test.ts: removes the imported project setup before destroying its VM; retains the VM when setup deletion throws; retains the VM when setup deletion reports no result. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Exact retired assertionRefs, preserved as historical objects only: {\n \"file\": \"src/renderer/src/lib/ephemeral-vm-failed-create-cleanup.test.ts\",\n \"assertions\": [\"failed or unconfirmed project-host rollback prevents provider destroy\"]\n } Historical prior account (preserved verbatim): Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Historical pre-audit oracle account for changed sources: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Write one ordinary schema-v1 runtime and one provisioned-root runtime. Require the exact pre-#14352 reader to return both, run the old destroy lifecycle against the projected provisioned record, then require the candidate to retain the cleaned state while restoring schema-v2 and checkout-mode metadata. The same old reader must reject affected-main and fix-reverted bytes. Malformed, oversized, unknown-record, and future-version feature sidecars must leave rollback-compatible records accessible and must not be overwritten during compatible lifecycle mutations. Require destroy to have no implicit deadline, stop a hung destroy through the public desktop action, require cleanup_failed plus a fresh successful retry, prove provider or project-host rollback failure retains every ownership record required to retry, and prove missing recipe context cannot leave an unremovable hidden SSH registration. Supply the source ref's captured commit to create, reject a provisioned checkout on the wrong branch/ref, and reject a resume that changes connection mode or SSH ownership.", + "oracle": "Audit 3292 retires the direct-SSH failed-project retention, managed-server failed-project retention and ordinary confirmed managed-VM destruction/no-repo.rm examples from repos-ephemeral-vm-cleanup-retention.test.ts. Host-scoped same-workspace isolation and stale renderer catalog reconciliation remain byte-identical. These three supplied-result alarms are intentionally lost without equivalent replacement. Existing selectors/assertionRefs, unrelated cross-version rollback receipt and archived complete 122-case cleanup receipt remain exact; no fresh broad runtime, provider, platform or mixed-version result is claimed. Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/lib/ephemeral-vm-failed-create-cleanup.test.ts: removes the imported project setup before destroying its VM; retains the VM when setup deletion throws; retains the VM when setup deletion reports no result. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Exact retired assertionRefs, preserved as historical objects only: {\n \"file\": \"src/renderer/src/lib/ephemeral-vm-failed-create-cleanup.test.ts\",\n \"assertions\": [\"failed or unconfirmed project-host rollback prevents provider destroy\"]\n } Historical prior account (preserved verbatim): Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Historical pre-audit oracle account for changed sources: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Write one ordinary schema-v1 runtime and one provisioned-root runtime. Require the exact pre-#14352 reader to return both, run the old destroy lifecycle against the projected provisioned record, then require the candidate to retain the cleaned state while restoring schema-v2 and checkout-mode metadata. The same old reader must reject affected-main and fix-reverted bytes. Malformed, oversized, unknown-record, and future-version feature sidecars must leave rollback-compatible records accessible and must not be overwritten during compatible lifecycle mutations. Require destroy to have no implicit deadline, stop a hung destroy through the public desktop action, require cleanup_failed plus a fresh successful retry, prove provider or project-host rollback failure retains every ownership record required to retry, and prove missing recipe context cannot leave an unremovable hidden SSH registration. Supply the source ref's captured commit to create, reject a provisioned checkout on the wrong branch/ref, and reject a resume that changes connection mode or SSH ownership.", "commands": [ "node config/scripts/runtime-verification/ephemeral-store/run-ephemeral-vm-runtime-store-rollback-repro.mjs config/scripts/runtime-verification/ephemeral-store/ephemeral-vm-runtime-store-cross-version.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/shared/ephemeral-vm-runtime-store.test.ts src/shared/ephemeral-vm-runtime-store-rollback.test.ts src/shared/ephemeral-vm-recipe-process.test.ts src/main/ephemeral-vm/runtime-service.test.ts src/main/ephemeral-vm/recipe-runner.test.ts src/main/ephemeral-vm/runtime-ssh-cleanup.test.ts src/main/ipc/ephemeral-vm-runtime-handler-cleanup.test.ts src/main/ipc/ephemeral-vm-provision-cancel.test.ts src/main/ipc/ephemeral-vm-provisioned-root-ref.test.ts src/main/ipc/ephemeral-vm.test.ts src/renderer/src/store/repos/repos-ephemeral-vm-cleanup-retention.test.ts", @@ -2721,7 +2652,8 @@ "Audit1417 intentionally deletes src/renderer/src/lib/ephemeral-vm-workspace-target.test.ts: Loses wrapper-level host rebinding, incompatible provisioned-root refusal and best-effort cleanup-call alarms; all are mock-only orchestration projections. No equivalent replacement coverage or fresh result is claimed.", "Audit1853 accepts removal of the runtime-ssh-cleanup.test.ts alarm for repairing cleanup_failed/provider-succeeded records that already lack a target ID. No equivalent replacement coverage is claimed. Keep the surviving cleanup selector and unchanged cross-version rollback receipt; the historical 2026-08-14 122-case cleanup receipt remains archived verbatim in knownGaps.", "Audit1863 removes the standalone default-source-ref provisioning example. Its direct default-ref pinning alarm is intentionally lost; selected-ref pinning and invalid-ref cases remain without an equivalent replacement claim. Focused survivor execution does not validate the broad rollback selector or physical cross-version provisioning. Existing receipts retain their original commands and counts.", - "Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/lib/ephemeral-vm-failed-create-cleanup.test.ts: removes the imported project setup before destroying its VM; retains the VM when setup deletion throws; retains the VM when setup deletion reports no result. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Exact retired assertionRefs, preserved as historical objects only: {\n \"file\": \"src/renderer/src/lib/ephemeral-vm-failed-create-cleanup.test.ts\",\n \"assertions\": [\"failed or unconfirmed project-host rollback prevents provider destroy\"]\n }" + "Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/lib/ephemeral-vm-failed-create-cleanup.test.ts: removes the imported project setup before destroying its VM; retains the VM when setup deletion throws; retains the VM when setup deletion reports no result. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Exact retired assertionRefs, preserved as historical objects only: {\n \"file\": \"src/renderer/src/lib/ephemeral-vm-failed-create-cleanup.test.ts\",\n \"assertions\": [\"failed or unconfirmed project-host rollback prevents provider destroy\"]\n }", + "Audit 3292 retires the direct-SSH failed-project retention, managed-server failed-project retention and ordinary confirmed managed-VM destruction/no-repo.rm examples from repos-ephemeral-vm-cleanup-retention.test.ts. Host-scoped same-workspace isolation and stale renderer catalog reconciliation remain byte-identical. These three supplied-result alarms are intentionally lost without equivalent replacement. Existing selectors/assertionRefs, unrelated cross-version rollback receipt and archived complete 122-case cleanup receipt remain exact; no fresh broad runtime, provider, platform or mixed-version result is claimed." ], "demotionRule": "Demote if a new write fails the pinned rollback reader, a downgrade lifecycle mutation is lost after re-upgrade, malformed/future metadata overwrites recoverable bytes, ordinary v1 bytes change, user stop cannot settle a destroy process tree, cleanup loses retry ownership, an unrecoverable context leaves a permanent hidden SSH registration, or the focused gate flakes without an identified harness defect." }, @@ -2842,7 +2774,7 @@ "id": "editor.restored-sibling-owner-reparent", "title": "Restored sibling tabs migrate filesystem authority before becoming editable", "maturity": "experimental", - "protection": "partial", + "protection": "none", "owner": "editor-runtime", "layer": "renderer-store-controller-contract", "surfaces": [ @@ -2852,63 +2784,30 @@ ], "platforms": ["macos", "linux", "windows"], "providers": ["local", "ssh", "paired-runtime"], - "coveredPlatforms": ["macos"], - "coveredProviders": ["local", "ssh", "paired-runtime"], - "coverageNotes": "Deterministic store/controller tests cover local, direct-SSH, paired-runtime identity, folder workspaces, queue quiescence, stale route and connection-generation rejection, authoritative active-workspace projection, owner-derived IDs, drafts and editor maps, tab/group placement, exact watch replacement, change/delete/rename correlation, explicit save, autosave, collision refusal without activation reconciliation, provenance, and restart hot-exit persistence. Live headed/headless paired-runtime and post-establish Electron IPC remain uncollected. The test-value audit removed the standalone runtime-workspace file-route suite. Its direct same-host sibling, folder-root, exact-SSH, outside-path and directory-routing alarms are lost. Retained editor lifecycle contracts do not establish equivalent selector coverage; historical run commands and results remain historical. The test-value audit narrows restored-editor-owner-reparent.test.ts by removing standalone unrelated-explorer-reveal, duplicate-tab repair/refusal, clean/dirty collision-table, watcher-target projection, folder-workspace context and direct-SSH provenance examples. Their exact scalar/ID/reference, selector and route/generation-field alarms are intentionally lost. The dirty collision variant did not assert preservation of its destination draft, and the main-owned duplicate-tab branch checked a synthetic missing-group refusal rather than duplicate repair. Remaining authored cases still check coupled dirty-state migration, subscribed activation, hot-exit roundtrip, rejection without destination reconciliation, mounted watch replacement and destination event correlation. They are not equivalent replacements for the deleted alarms. Historical executed commands, counts and results remain unchanged; no new live host, process restart or platform evidence is claimed.", + "coveredPlatforms": [], + "coveredProviders": [], + "coverageNotes": "Audit3359 keeps two restored-editor-owner-reparent cases covering coupled dirty-editor/draft/preview/main-group migration and hot-exit serialization/hydration. The subscribed activation, collision refusal and mounted watch replacement/destination-event correlation alarms are intentionally lost without equivalent replacement. The complete compound dated receipt is retired verbatim. With no active receipt, protection and covered scope are cleared and prospective command/test-file/assertion selectors are retired; their complete originals and prior red/green/flake accounts remain historical in knownGaps. The retained reparent cases and unchanged save-lifecycle source remain reachable through broad unit execution, not active evidence for this gate. No fresh provider, filesystem restart, historical-import, mobile, mixed-version or cross-platform validation is claimed. Deterministic store/controller tests cover local, direct-SSH, paired-runtime identity, folder workspaces, queue quiescence, stale route and connection-generation rejection, authoritative active-workspace projection, owner-derived IDs, drafts and editor maps, tab/group placement, exact watch replacement, change/delete/rename correlation, explicit save, autosave, collision refusal without activation reconciliation, provenance, and restart hot-exit persistence. Live headed/headless paired-runtime and post-establish Electron IPC remain uncollected. The test-value audit removed the standalone runtime-workspace file-route suite. Its direct same-host sibling, folder-root, exact-SSH, outside-path and directory-routing alarms are lost. Retained editor lifecycle contracts do not establish equivalent selector coverage; historical run commands and results remain historical. The test-value audit narrows restored-editor-owner-reparent.test.ts by removing standalone unrelated-explorer-reveal, duplicate-tab repair/refusal, clean/dirty collision-table, watcher-target projection, folder-workspace context and direct-SSH provenance examples. Their exact scalar/ID/reference, selector and route/generation-field alarms are intentionally lost. The dirty collision variant did not assert preservation of its destination draft, and the main-owned duplicate-tab branch checked a synthetic missing-group refusal rather than duplicate repair. Remaining authored cases still check coupled dirty-state migration, subscribed activation, hot-exit roundtrip, rejection without destination reconciliation, mounted watch replacement and destination event correlation. They are not equivalent replacements for the deleted alarms. Historical executed commands, counts and results remain unchanged; no new live host, process restart or platform evidence is claimed.", "motivatingLinks": [ "https://github.com/stablyai/orca/issues/11304", "https://github.com/stablyai/orca/pull/11369" ], "invariant": "A restored absolute path owned by a same-host sibling workspace cannot read, save, watch, or persist until old saves drain, the exact route and host generations are revalidated, and one authoritative activation transaction installs the sibling owner, target projection, editor state, reconciliation, and first-activation terminal preparation; collisions and stale routes fail before activation preparation or reconciliation.", - "oracle": "Hold an old-owner save in flight, start migration, then remove the sibling, change a folder root, or reconnect SSH and require owner migration to fail closed after quiescence. On a stable route require one coherent target-workspace projection, first-activation terminal generation preparation, destination authority for explicit save and autosave, exact watch replacement, destination-only change/delete/rename handling, owner-derived state rekeys, and hot-exit restart ownership. Seed an invalid destination tab/group model before a collision and require the target projection to remain byte-identical.", - "commands": [ - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/editor/hydration/restored-editor-owner-reparent.test.ts src/renderer/src/components/editor/restored-editor-owner-save-lifecycle.test.ts" - ], - "testFiles": [ - "src/renderer/src/store/slices/editor/hydration/restored-editor-owner-reparent.test.ts", - "src/renderer/src/components/editor/restored-editor-owner-save-lifecycle.test.ts" - ], - "assertionRefs": [ - { - "file": "src/renderer/src/store/slices/editor/hydration/restored-editor-owner-reparent.test.ts", - "assertions": [ - "one atomic commit rekeys owner-derived editor, preview, draft, cursor, view, tab, group, active, reveal, focus, provenance, and persistence state", - "active reparenting uses the centralized workspace activation transaction for terminal, browser, pending-creation, explorer, first-activation, and post-commit state", - "source watch unsubscribes once, destination watch subscribes once, and only destination change/delete/rename events reach the file", - "a destination collision fails closed without changing current selection or reconciling destination tabs and groups" - ] - }, - { - "file": "src/renderer/src/components/editor/restored-editor-owner-save-lifecycle.test.ts", - "assertions": [ - "migration waits for the old save queue and routes later explicit and automatic saves through the destination worktree", - "a removed sibling, changed folder root, or changed direct-SSH generation after quiescence rejects migration without changing ownership" - ] - } - ], - "evidenceRuns": [ - { - "date": "2026-08-03", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/restored-editor-owner-reparent.test.ts src/renderer/src/components/editor/restored-editor-owner-save-lifecycle.test.ts src/renderer/src/lib/runtime-workspace-file-route.test.ts", - "result": "passed", - "durationSeconds": 3, - "summary": "Three deterministic files passed 20 lifecycle, stale-route, activation, ownership, host, collision, persistence, watch, and save tests.", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/editor/hydration/restored-editor-owner-reparent.test.ts src/renderer/src/components/editor/restored-editor-owner-save-lifecycle.test.ts" - } - ], + "oracle": "Audit3359 keeps two restored-editor-owner-reparent cases covering coupled dirty-editor/draft/preview/main-group migration and hot-exit serialization/hydration. The subscribed activation, collision refusal and mounted watch replacement/destination-event correlation alarms are intentionally lost without equivalent replacement. The complete compound dated receipt is retired verbatim. With no active receipt, protection and covered scope are cleared and prospective command/test-file/assertion selectors are retired; their complete originals and prior red/green/flake accounts remain historical in knownGaps. The retained reparent cases and unchanged save-lifecycle source remain reachable through broad unit execution, not active evidence for this gate. No fresh provider, filesystem restart, historical-import, mobile, mixed-version or cross-platform validation is claimed. Hold an old-owner save in flight, start migration, then remove the sibling, change a folder root, or reconnect SSH and require owner migration to fail closed after quiescence. On a stable route require one coherent target-workspace projection, first-activation terminal generation preparation, destination authority for explicit save and autosave, exact watch replacement, destination-only change/delete/rename handling, owner-derived state rekeys, and hot-exit restart ownership. Seed an invalid destination tab/group model before a collision and require the target projection to remain byte-identical.", + "commands": [], + "testFiles": [], + "assertionRefs": [], + "evidenceRuns": [], "runtimeBudget": { "p95Seconds": 5, "scope": "focused renderer store/controller contract on a local development runner" }, "flakeHistory": { "status": "unknown", - "evidence": "One local deterministic run is recorded; CI and soak history have not started." + "evidence": "Audit3359 retires the sole dated compound receipt. No fresh execution or soak history validates the reduced selector; original flake account is preserved verbatim as history." }, "redGreenEvidence": { - "status": "complete", - "evidence": "The final2 verifier's byte-identical post-quiescence lifecycle scope passed 21/21 on 7890271160 and failed 7 tests on f92db196a1; base e08eba674c, published 1bcfe3bcb0, and revert b3627461ab were structurally red. The permanent collision oracle is in test blob ac62a89c671a0c8f081ebf06736715bd2150ce9f (SHA-256 a61970ace80be1cb56f781aee6f878a8446c6c4527f9eb0cd0c151d8df96bf50). The same byte-identical blob is structurally red on base, published, and revert, behaviorally red on rejected final2 candidate 7890271160 because pre-commit reconciliation removes the stale destination tab, and green on implementation b72a838cdc; the full permanent gate passes 20/20." + "status": "missing", + "evidence": "Audit3359 changes the referenced test source and retires collision/watch/activation oracles. No fresh red/green proof applies to the reduced selector. The complete prior account is preserved verbatim in knownGaps as historical only." }, "performanceBudget": { "required": true, @@ -2924,7 +2823,18 @@ "Cold many-repo main-process sibling discovery remains a separately measured follow-up.", "Registered-workspace symlink policy remains inherited and unchanged.", "The test-value audit removed the standalone runtime-workspace file-route suite. Its direct same-host sibling, folder-root, exact-SSH, outside-path and directory-routing alarms are lost. Retained editor lifecycle contracts do not establish equivalent selector coverage; historical run commands and results remain historical.", - "The test-value audit narrows restored-editor-owner-reparent.test.ts by removing standalone unrelated-explorer-reveal, duplicate-tab repair/refusal, clean/dirty collision-table, watcher-target projection, folder-workspace context and direct-SSH provenance examples. Their exact scalar/ID/reference, selector and route/generation-field alarms are intentionally lost. The dirty collision variant did not assert preservation of its destination draft, and the main-owned duplicate-tab branch checked a synthetic missing-group refusal rather than duplicate repair. Remaining authored cases still check coupled dirty-state migration, subscribed activation, hot-exit roundtrip, rejection without destination reconciliation, mounted watch replacement and destination event correlation. They are not equivalent replacements for the deleted alarms. Historical executed commands, counts and results remain unchanged; no new live host, process restart or platform evidence is claimed." + "The test-value audit narrows restored-editor-owner-reparent.test.ts by removing standalone unrelated-explorer-reveal, duplicate-tab repair/refusal, clean/dirty collision-table, watcher-target projection, folder-workspace context and direct-SSH provenance examples. Their exact scalar/ID/reference, selector and route/generation-field alarms are intentionally lost. The dirty collision variant did not assert preservation of its destination draft, and the main-owned duplicate-tab branch checked a synthetic missing-group refusal rather than duplicate repair. Remaining authored cases still check coupled dirty-state migration, subscribed activation, hot-exit roundtrip, rejection without destination reconciliation, mounted watch replacement and destination event correlation. They are not equivalent replacements for the deleted alarms. Historical executed commands, counts and results remain unchanged; no new live host, process restart or platform evidence is claimed.", + "Audit3359 keeps two restored-editor-owner-reparent cases covering coupled dirty-editor/draft/preview/main-group migration and hot-exit serialization/hydration. The subscribed activation, collision refusal and mounted watch replacement/destination-event correlation alarms are intentionally lost without equivalent replacement. The complete compound dated receipt is retired verbatim. With no active receipt, protection and covered scope are cleared and prospective command/test-file/assertion selectors are retired; their complete originals and prior red/green/flake accounts remain historical in knownGaps. The retained reparent cases and unchanged save-lifecycle source remain reachable through broad unit execution, not active evidence for this gate. No fresh provider, filesystem restart, historical-import, mobile, mixed-version or cross-platform validation is claimed.", + "Audit3359 historical original assertionRefs object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"file\": \"src/renderer/src/store/slices/editor/hydration/restored-editor-owner-reparent.test.ts\",\n \"assertions\": [\n \"one atomic commit rekeys owner-derived editor, preview, draft, cursor, view, tab, group, active, reveal, focus, provenance, and persistence state\",\n \"active reparenting uses the centralized workspace activation transaction for terminal, browser, pending-creation, explorer, first-activation, and post-commit state\",\n \"source watch unsubscribes once, destination watch subscribes once, and only destination change/delete/rename events reach the file\",\n \"a destination collision fails closed without changing current selection or reconciling destination tabs and groups\"\n ]\n }", + "Audit3359 historical original evidenceRuns object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"date\": \"2026-08-03\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/restored-editor-owner-reparent.test.ts src/renderer/src/components/editor/restored-editor-owner-save-lifecycle.test.ts src/renderer/src/lib/runtime-workspace-file-route.test.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 3,\n \"summary\": \"Three deterministic files passed 20 lifecycle, stale-route, activation, ownership, host, collision, persistence, watch, and save tests.\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/editor/hydration/restored-editor-owner-reparent.test.ts src/renderer/src/components/editor/restored-editor-owner-save-lifecycle.test.ts\"\n }", + "Audit3359 historical original protection object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"partial\"", + "Audit3359 historical original coveredPlatforms object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\"macos\"]", + "Audit3359 historical original coveredProviders object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\"local\", \"ssh\", \"paired-runtime\"]", + "Audit3359 historical original redGreenEvidence object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"status\": \"complete\",\n \"evidence\": \"The final2 verifier's byte-identical post-quiescence lifecycle scope passed 21/21 on 7890271160 and failed 7 tests on f92db196a1; base e08eba674c, published 1bcfe3bcb0, and revert b3627461ab were structurally red. The permanent collision oracle is in test blob ac62a89c671a0c8f081ebf06736715bd2150ce9f (SHA-256 a61970ace80be1cb56f781aee6f878a8446c6c4527f9eb0cd0c151d8df96bf50). The same byte-identical blob is structurally red on base, published, and revert, behaviorally red on rejected final2 candidate 7890271160 because pre-commit reconciliation removes the stale destination tab, and green on implementation b72a838cdc; the full permanent gate passes 20/20.\"\n }", + "Audit3359 historical original flakeHistory object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"status\": \"unknown\",\n \"evidence\": \"One local deterministic run is recorded; CI and soak history have not started.\"\n }", + "Audit3361 gate38 prospective commands selector retired; complete original preserved verbatim as historical only:\n[\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/editor/hydration/restored-editor-owner-reparent.test.ts src/renderer/src/components/editor/restored-editor-owner-save-lifecycle.test.ts\"\n ]", + "Audit3361 gate38 prospective testFiles selector retired; complete original preserved verbatim as historical only:\n[\n \"src/renderer/src/store/slices/editor/hydration/restored-editor-owner-reparent.test.ts\",\n \"src/renderer/src/components/editor/restored-editor-owner-save-lifecycle.test.ts\"\n ]", + "Audit3361 gate38 prospective assertionRefs selector retired; complete original preserved verbatim as historical only:\n[\n {\n \"file\": \"src/renderer/src/store/slices/editor/hydration/restored-editor-owner-reparent.test.ts\",\n \"assertions\": [\n \"coupled dirty-editor ID, draft, preview and main-group migration remains coherent\",\n \"hot-exit serialization and hydration preserve migrated editor ownership and dirty state\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/editor/restored-editor-owner-save-lifecycle.test.ts\",\n \"assertions\": [\n \"migration waits for the old save queue and routes later explicit and automatic saves through the destination worktree\",\n \"a removed sibling, changed folder root, or changed direct-SSH generation after quiescence rejects migration without changing ownership\"\n ]\n }\n ]" ], "demotionRule": "Keep experimental or demote if migration can race a save, retain source authority, fan out watches, lose dirty/editor state, accept an owner-generation change, merge a collision, or the focused contract flakes without a product or harness bug." }, @@ -4202,10 +4112,10 @@ "providers": ["remote-runtime"], "coveredPlatforms": ["macos"], "coveredProviders": ["remote-runtime"], - "coverageNotes": "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Deterministic main-IPC contract tests cover disconnect-driven close delivery, exactly-once close, per-subscription teardown isolation against a failing socket close and a throwing liveness probe, containment of a throwing renderer send on the unguarded host-close path, and continued suppression of stale payloads from a retired transport. A headed paired-server journey (real Orca host plus a separate paired Orca desktop client) covers hidden-but-mounted reveal, cold-parked reveal, and cold-parked reveal across a disconnect/reconnect. Live Linux and Windows paired-server evidence and real sleep/wake transport loss remain uncollected.", + "coverageNotes": "Audit3375 composes root-adopted3370/independent3371 and3373/independent3374: intentionally retires79 authored registrations/84 expanded cases, including39 whole suites, without equivalent replacement. Lost alarms include federation field/parser inventories; Claude rejected-key precedence, credential clone redaction, managed-versus-user hook preservation and CLI defaults; setting/status/activity projections, mocked SSH/notification/reveal/Linear refusal, fake-clock reconnect and noise; image-fold artifact visibility, paste eligibility, setup trust, scripted ACP error-to-journal publication and ligature cache tuple aliasing; plus supplied folder-runner uniqueness, mobile host-overlay/credential/update/preference races, status/markup/title/keyed-row projections, subscriber cleanup, cancellation/close/refusal/link-issue and mirror suppression alarms. Retained3373 merger contiguity, dual-clock overdue-resume exactly-once, rejected-paste IPC sink and annotation schema roundtrip remain bounded. Retained actual HTTP/OSC status composition, destructive sibling-filesystem isolation, external contrast invariant and fixture CSS pixel intervention remain narrower. Original reviewed87authored/92expanded become9/9; current OpenCode suite adds two preserved upstream cases and the synthetic-title suite gained one Cursor policy mock-call case, independently reviewed for removal in root3378; current90/95 become11/11. That Cursor suppression/ready-frame regression alarm is intentionally lost; it does not observe native title ownership or tab flicker. For3370 only the peer was independently blind, with author exposure explicit;3373/3374 both blind pins were verified. This broad root unit command selects the reduced root unit suite; UNIT_INCLUDE excludes mobile tests, which require the existing mobile runner; retained Playwright component-pixel spec uses its separate existing headless fixture runner and is not validated by the broad unit command. No fresh execution, actual agent/shell/provider, OS material/focus, historical import equivalence, mobile, mixed-version or cross-platform evidence is claimed. All dated receipts retain their original scope. Audit3368 composes root-adopted3363/3364 and3367/3369: intentionally retires181 authored registrations/196 expanded cases, including28 whole suites, without equivalent replacement. Lost alarms include hibernation attention/liveness/backoff/sequential teardown and inventory, host launch compatibility/legacy/Kimi/resource cleanup, terminal recovery parser/pause/quarantine/remount, window-visibility omission-fence lifetime, launch-option rendered Start, sleeping-resume saved recipe/WSL quoting/cancellation, plus removed project/window/input variants. Additional tiny-suite losses include sentence/label/field/default inventories, credential omission, Windows argument/environment mapping, URI decoding, diagnostics, provider classification and fake-clock callback/parser examples. Retained ten registrations/twelve expanded cases include two literal Unicode Mn/Cf zero-width range guards in the actual character-range algorithm and protect narrower delayed editor bytes/destructive ownership, mounted hidden collision repair, ten transport epochs, duplicate-command refusal, caller timeout typing, executor unknown-opener refusal and failed-chunk user bytes. This broad unit command selects the reduced suite; no fresh runtime, real provider/network/PTY, filesystem restart, native UI, historical import equivalence, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3362 composes root-adopted3358/independent3360: intentionally retires129 authored registrations/140 expanded cases, including four whole suites, without equivalent replacement. Lost alarms include supplied orphan-adoption retry/malformed inventory/cancellation; fake-terminal replay parser/wedge/disposal callbacks; all-host catalog metadata and Windows preferences; host keepalive/protocol/stale/settings failures; and removed exact-stop/suppression, source save lifetime, diff-note queue, rename/editor close, input flood/chunk refusal/limits, purge and creation examples. Retained18 registrations/21 expanded cases protect narrower ownership, generation, dirty-state, queue convergence, encoding and attachment-lease outcomes. No replacement or keeper quota claim. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY/xterm parser, disk restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3359 composes root-adopted source3355/independent3356: intentionally retires130 authored registrations/139 expanded cases, including eight whole suites, without equivalent replacement. Lost alarms include strict create naming/capability/legacy payloads; supplied transport host replacement, deadline reattach, create-handoff and split activation; agent-session fork/clipboard/platform flags; shutdown cleared-scrollback/unmounted bindings; simulator host-collision/selection/shutdown; and removed editor, catalog, mutation, launch and status examples. Retained12 adverse-ordering/state-consequence cases are narrower and do not replace all removed alarms. Two queue absences receive zero removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY, filesystem restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3349 composes adopted batches3343,3345 and refreshed3354: intentionally retires234 authored registrations/294 expanded cases, including13 whole suites, without equivalent replacement. Lost alarms include supplied terminal reconnect/replacement/typeahead/mirror/result and snapshot examples; synthetic render-desync persistence/recovery; worktree listing/owner/catalog/lineage/removal and activation/creation examples; host-scoped PR and task-record projections; editor diff/status/comment and UI send-target examples; automation observation/wake, supplied sleep/deadline clock and native-chat completion/notification/relaunch samples; held-tab layout and cleanup/progress guard examples. Retained adverse-ordering and wire-boundary cases are narrower and do not replace all removed alarms. The already-upstream visibility-resume deletion receives zero new removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH, native process/power/GPU, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3342 composes adopted source batches3333/3334,3336/3337 and3340/3341: intentionally retires180 authored registrations/263 expanded cases, including seven whole suites, without equivalent replacement. Lost alarms include corrupt editor hydration; mobile editor/diff publication and privacy projections; stale-resubscribe routing; model-picker projection/refetch/retry/fallback; editor check-details and frame property inventories; latched-pane cleanup/quiescence; client create replay identity/options/compatibility; and removed owner, async routing, terminal and layout examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts keep their original scope. Audit3335 composes adopted source unions3327/3328 and3330/3332: intentionally retires100 authored registrations/123 expanded cases, including ten whole suites, without equivalent replacement. Lost alarms include seeded host persistence/contention and stale-host cleanup; browser snapshot assembly; mocked wake/DPR callbacks and frame budgets; preflight projections; palette authority/cache suppression, URL intent and saved-title cross-repo collisions; metadata coverage/set patch and dropdown assembly; and removed terminal, worktree, review-refresh and owner-routing examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI/GPU/focus, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain only their original scope. Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed. Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed. Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed. Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical. Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims. Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands. Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Deterministic main-IPC contract tests cover disconnect-driven close delivery, exactly-once close, per-subscription teardown isolation against a failing socket close and a throwing liveness probe, containment of a throwing renderer send on the unguarded host-close path, and continued suppression of stale payloads from a retired transport. A headed paired-server journey (real Orca host plus a separate paired Orca desktop client) covers hidden-but-mounted reveal, cold-parked reveal, and cold-parked reveal across a disconnect/reconnect. Live Linux and Windows paired-server evidence and real sleep/wake transport loss remain uncollected.", "motivatingLinks": ["tests/e2e/paired-remote-terminal-parked-reveal-interactivity.spec.ts"], "invariant": "Every renderer-held runtime subscription receives exactly one terminal close event when its transport is retired, including when the retirement advanced the transport generation first, and a single failing teardown never abandons that environment's remaining subscriptions nor escapes into the transport that reported the close. Payload frames from a retired transport stay suppressed. A revealed remote terminal therefore reattaches over a live multiplex connection: its buffer restores, typed input reaches the host PTY, the echo paints without a tab flip, and the PTY converges on the revealed pane grid.", - "oracle": "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): The main IPC contract test subscribes terminal.multiplex through the real handler, disconnects the environment, and asserts the renderer received exactly one {type: close} subscription event. Two isolation tests subscribe a second stream to the same environment and make the first one fail -- in its socket close, and in the liveness probe inside notifyClosed -- then assert the disconnect does not throw, both transports closed, and every close the renderer could still receive was delivered. A third drives a host-initiated close through the transport callback, which is the one notifyClosed call site with no surrounding guard, with a renderer send that throws, and asserts it cannot escape into the WebSocket close handler. A fourth test asserts that after retirement a late response frame is not forwarded and a late transport close does not re-send. The paired-server journey runs three reveal scenarios against one real host and one real paired desktop client, and for each records buffer restore, host-side receipt of the typed marker through an out-of-band host sink file, live paint without a tab flip, and PTY-versus-pane grid convergence.", + "oracle": "Audit3375 composes root-adopted3370/independent3371 and3373/independent3374: intentionally retires79 authored registrations/84 expanded cases, including39 whole suites, without equivalent replacement. Lost alarms include federation field/parser inventories; Claude rejected-key precedence, credential clone redaction, managed-versus-user hook preservation and CLI defaults; setting/status/activity projections, mocked SSH/notification/reveal/Linear refusal, fake-clock reconnect and noise; image-fold artifact visibility, paste eligibility, setup trust, scripted ACP error-to-journal publication and ligature cache tuple aliasing; plus supplied folder-runner uniqueness, mobile host-overlay/credential/update/preference races, status/markup/title/keyed-row projections, subscriber cleanup, cancellation/close/refusal/link-issue and mirror suppression alarms. Retained3373 merger contiguity, dual-clock overdue-resume exactly-once, rejected-paste IPC sink and annotation schema roundtrip remain bounded. Retained actual HTTP/OSC status composition, destructive sibling-filesystem isolation, external contrast invariant and fixture CSS pixel intervention remain narrower. Original reviewed87authored/92expanded become9/9; current OpenCode suite adds two preserved upstream cases and the synthetic-title suite gained one Cursor policy mock-call case, independently reviewed for removal in root3378; current90/95 become11/11. That Cursor suppression/ready-frame regression alarm is intentionally lost; it does not observe native title ownership or tab flicker. For3370 only the peer was independently blind, with author exposure explicit;3373/3374 both blind pins were verified. This broad root unit command selects the reduced root unit suite; UNIT_INCLUDE excludes mobile tests, which require the existing mobile runner; retained Playwright component-pixel spec uses its separate existing headless fixture runner and is not validated by the broad unit command. No fresh execution, actual agent/shell/provider, OS material/focus, historical import equivalence, mobile, mixed-version or cross-platform evidence is claimed. All dated receipts retain their original scope. Audit3368 composes root-adopted3363/3364 and3367/3369: intentionally retires181 authored registrations/196 expanded cases, including28 whole suites, without equivalent replacement. Lost alarms include hibernation attention/liveness/backoff/sequential teardown and inventory, host launch compatibility/legacy/Kimi/resource cleanup, terminal recovery parser/pause/quarantine/remount, window-visibility omission-fence lifetime, launch-option rendered Start, sleeping-resume saved recipe/WSL quoting/cancellation, plus removed project/window/input variants. Additional tiny-suite losses include sentence/label/field/default inventories, credential omission, Windows argument/environment mapping, URI decoding, diagnostics, provider classification and fake-clock callback/parser examples. Retained ten registrations/twelve expanded cases include two literal Unicode Mn/Cf zero-width range guards in the actual character-range algorithm and protect narrower delayed editor bytes/destructive ownership, mounted hidden collision repair, ten transport epochs, duplicate-command refusal, caller timeout typing, executor unknown-opener refusal and failed-chunk user bytes. This broad unit command selects the reduced suite; no fresh runtime, real provider/network/PTY, filesystem restart, native UI, historical import equivalence, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3362 composes root-adopted3358/independent3360: intentionally retires129 authored registrations/140 expanded cases, including four whole suites, without equivalent replacement. Lost alarms include supplied orphan-adoption retry/malformed inventory/cancellation; fake-terminal replay parser/wedge/disposal callbacks; all-host catalog metadata and Windows preferences; host keepalive/protocol/stale/settings failures; and removed exact-stop/suppression, source save lifetime, diff-note queue, rename/editor close, input flood/chunk refusal/limits, purge and creation examples. Retained18 registrations/21 expanded cases protect narrower ownership, generation, dirty-state, queue convergence, encoding and attachment-lease outcomes. No replacement or keeper quota claim. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY/xterm parser, disk restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3359 composes root-adopted source3355/independent3356: intentionally retires130 authored registrations/139 expanded cases, including eight whole suites, without equivalent replacement. Lost alarms include strict create naming/capability/legacy payloads; supplied transport host replacement, deadline reattach, create-handoff and split activation; agent-session fork/clipboard/platform flags; shutdown cleared-scrollback/unmounted bindings; simulator host-collision/selection/shutdown; and removed editor, catalog, mutation, launch and status examples. Retained12 adverse-ordering/state-consequence cases are narrower and do not replace all removed alarms. Two queue absences receive zero removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY, filesystem restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3349 composes adopted batches3343,3345 and refreshed3354: intentionally retires234 authored registrations/294 expanded cases, including13 whole suites, without equivalent replacement. Lost alarms include supplied terminal reconnect/replacement/typeahead/mirror/result and snapshot examples; synthetic render-desync persistence/recovery; worktree listing/owner/catalog/lineage/removal and activation/creation examples; host-scoped PR and task-record projections; editor diff/status/comment and UI send-target examples; automation observation/wake, supplied sleep/deadline clock and native-chat completion/notification/relaunch samples; held-tab layout and cleanup/progress guard examples. Retained adverse-ordering and wire-boundary cases are narrower and do not replace all removed alarms. The already-upstream visibility-resume deletion receives zero new removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH, native process/power/GPU, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3342 composes adopted source batches3333/3334,3336/3337 and3340/3341: intentionally retires180 authored registrations/263 expanded cases, including seven whole suites, without equivalent replacement. Lost alarms include corrupt editor hydration; mobile editor/diff publication and privacy projections; stale-resubscribe routing; model-picker projection/refetch/retry/fallback; editor check-details and frame property inventories; latched-pane cleanup/quiescence; client create replay identity/options/compatibility; and removed owner, async routing, terminal and layout examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts keep their original scope. Audit3335 composes adopted source unions3327/3328 and3330/3332: intentionally retires100 authored registrations/123 expanded cases, including ten whole suites, without equivalent replacement. Lost alarms include seeded host persistence/contention and stale-host cleanup; browser snapshot assembly; mocked wake/DPR callbacks and frame budgets; preflight projections; palette authority/cache suppression, URL intent and saved-title cross-repo collisions; metadata coverage/set patch and dropdown assembly; and removed terminal, worktree, review-refresh and owner-routing examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI/GPU/focus, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain only their original scope. Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed. Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed. Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed. Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical. Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims. Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands. Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): The main IPC contract test subscribes terminal.multiplex through the real handler, disconnects the environment, and asserts the renderer received exactly one {type: close} subscription event. Two isolation tests subscribe a second stream to the same environment and make the first one fail -- in its socket close, and in the liveness probe inside notifyClosed -- then assert the disconnect does not throw, both transports closed, and every close the renderer could still receive was delivered. A third drives a host-initiated close through the transport callback, which is the one notifyClosed call site with no surrounding guard, with a renderer send that throws, and asserts it cannot escape into the WebSocket close handler. A fourth test asserts that after retirement a late response frame is not forwarded and a late transport close does not re-send. The paired-server journey runs three reveal scenarios against one real host and one real paired desktop client, and for each records buffer restore, host-side receipt of the typed marker through an out-of-band host sink file, live paint without a tab flip, and PTY-versus-pane grid convergence.", "commands": [ "pnpm exec vitest run --config config/vitest.config.ts", "pnpm exec playwright test tests/e2e/paired-remote-terminal-parked-reveal-interactivity.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1" @@ -4273,6 +4183,7 @@ "Add real sleep/wake and network-loss transport drops alongside the explicit disconnect trigger." ], "knownGaps": [ + "Launch direct-owner cleanup current scope: This gate’s unfiltered unit command now selects a suite reduced by 82 whole registrations / 159 potential table examples in 10 whole test Programs, including 8 registrations / 15 examples from five once-registered create-message factory closures. Lost alarms include frozen first-message/options and legacy-host fallback; distinct actions and redelivery; uncertain/refused/reloaded input custody, Retry and late proof; rich prompt/attachment upload Stop/close and handback; ordinary draft/editor/IME/StrictMode lifetime and accepted topology; provisional fallback tab placement/group/pin/order and rich worktree handoff. Four whole consent/resume-identity cases remain in two Programs; they do not replace these alarms. This entry governs current reduced-unit scope and qualifies any broader implication of unchanged oracle/coverageNotes history. Entire dated evidenceRuns, original commands/currentCommand values, counts/results and existing history retain their original scopes only; no fresh execution, transferred pass, replacement equivalence or prior upstream-removal credit is claimed.", "Audit2133 current-parent preparation (988 authored removals; independently reviewed2099/2107/2115/2116 decisions; upstream clear-buffer and recovery-image regressions retained): Intentionally retire these low-value alarms without replacement: src/main/persistence/worktree-sort-order-write.test.ts: re-ranks every writable row when a blocked row sits in the requested order. src/main/runtime/construction/orca-runtime.test.ts: remove only literal registration import/call pairs await import('../orca-runtime-tests/worktree-setup-and-startup.spec'), await import('../orca-runtime-tests/gitlab-and-pr-bases.spec'); no additional authored credit. src/main/runtime/orca-runtime-tests/targeting-and-resilience.spec.ts: routes tab switch and capture start by explicit page id; accepts focus on tab switch without altering bridge args (focus is main-side concern); keeps terminal cwd resolution fail-soft when the provider is unavailable. src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-04.spec.ts: drops the bounded scan cache when orphan-cleanup removal completes; clears optimistic reconcile tokens when a CLI worktree removal succeeds; emits drift without mutating when the fetched base fast-forwards created HEAD; emits base_changed without mutation when the fetched base rewrote history; skips stale-token reconciles without mutating or emitting stale status; emits unknown without mutation when fetch fails or the base ref is missing. src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-03.spec.ts: routes runtime preserved-branch force-delete through the selected WSL project runtime; replies to a waiting client with the error of a delete that fails after acceptance; treats forced runtime deletion of an already-missing unregistered worktree as cleanup; treats normal runtime deletion of an already-missing unregistered worktree as cleanup. src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-02.spec.ts: warns that a missing-repo removal only forgot the workspace; restores runtime watchers when CLI worktree deletion fails after teardown; does not re-spend the drain budget on a removal after a wedged install was abandoned; routes runtime worktree removal through the selected WSL project runtime; force-deletes a branch that was preserved by runtime worktree removal. src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases-part-02.spec.ts: records GitLab pasted-project recents only after successful runtime lookup; threads explicit origin preference through runtime WSL PR base resolution; resolves local GitLab fork MR bases from the target project MR head ref; captures the fork MR head from a dedicated ref, not the shared FETCH_HEAD; keeps the durable MR head when the head fetch fails but the local ref resolves; routes runtime GitLab fork MR base git calls through the selected WSL project runtime. src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases.spec.ts: passes SSH connection ids through GitLab task operations; routes runtime GitLab issue, MR, work-item, and todo actions through the selected WSL project runtime; routes runtime GitLab MR details, review-management, job, and pasted URL actions through the selected WSL project runtime; normalizes runtime GitLab issue list arguments like the desktop IPC path. src/main/runtime/orca-runtime-tests/worktree-setup-and-startup-part-03.spec.ts: does not warn when setup is explicitly skipped for CLI-created worktrees; puts the agent a create starts in the first default tab, as the window does; keeps the 8s main-runtime startup readiness budget for agents without an override; gives OpenCode the 20s main-runtime startup readiness budget; launches explicit startup agents with prompts for CLI-created worktrees. src/main/runtime/orca-runtime-tests/worktree-setup-and-startup.spec.ts: returns a setup launch payload for CLI-created worktrees when hooks are explicitly enabled; does not hand the window a setup main never tried to start; passes the selected Windows setup shell into runtime runner generation; follows normal setup policy for CLI-created worktrees without activating them; uses returned WSL setup shell metadata when runtime spawns setup; uses the shell-aware setup runner for windowless creates without a startup command; reports the in-process setup hook as running when nothing can launch the runner. src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-02.spec.ts: coalesces two clients sleeping the same host worktree; stops exactly the expected live PTYs for a worktree; explains a refused workspace close instead of throwing the raw refusal enum. src/main/runtime/orca-runtime-tests/mobile-summaries-part-03.spec.ts: marks the desktop-active worktree as isActive; includes SSH-backed worktrees in the mobile worktree summary; caches repeated malformed path misses before normalizing them again. src/main/runtime/orca-runtime-tests/mobile-summaries-part-02.spec.ts: keeps title-only foreground work ahead of monitoring in another pane; keeps a local hook row while a connected PTY still backs its pane; keeps an OSC row via its connected PTY after the pane binding is cleared. src/main/runtime/orca-runtime-tests/mobile-summaries.spec.ts: resolves files through a source-visible linked-checkout worktree; marks saved session tabs with live PTYs as host sidebar activity; attributes live legacy PTYs from saved layout bindings when their panes are hidden; marks saved browser tabs as host sidebar activity like desktop; falls back to the path-keyed GitHub cache entry; includes folder workspaces in compact worktree summaries for mobile; attaches inline agent rows from the latest OSC 9999 status; projects monitoring over a title-derived working status. src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-03.spec.ts: pushes to an idle pane when the only live waiter filters out the message type; resolves a registered waiter without PTY-injecting when the leaf is already idle; keeps already-idle status after tui-idle wait for immediate message delivery; resolves message waiters when notifyMessageArrived is called; does not resolve type-filtered message waiters for unrelated message types; removes message waiter abort listeners after message arrival; resolves message waiters on timeout when no message arrives. src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-02.spec.ts: delivers pending mail via notifyMessageArrived when the recipient is already idle; does not keep retrying when every pending row was already pointed; repoints pending rows restored with a live-idle coordinator. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-13.spec.ts: rolls back a half-created terminal whose surface never publishes. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-12.spec.ts: rejects startup prompts for agents that require post-ready stdin; uses portable Unix quoting for mobile agent launch commands in WSL project runtimes; keeps PowerShell quoting for mobile agent launch commands in Windows host runtimes; uses cmd.exe quoting for mobile agent launch commands in local Windows host runtimes; publishes headless mobile session agent identity with synthesized PTY status; rejects disabled mobile session agent launches before spawning; validates mobile terminal insertion anchors before resolving agent launch commands. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-11.spec.ts: coalesces a reconnect close burst onto one authoritative PTY inventory; keeps an explicit user close destructive while the PTY is live; builds mobile session agent launch commands on the runtime host; injects mobile quick-command prompts into the host-built agent startup command. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-10.spec.ts: closes persisted headless terminal parents before any prior list call; tears down a serve-owned headless tab on close while a renderer is attached so it cannot resurrect; defers a renderer-published pending tab to the renderer instead of tearing it down; returns a delegated close outcome with no selection tombstone when the renderer owns the outcome; tears down a runtime pending shell the renderer never adopted on close. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-08.spec.ts: materializes a plain shell when the pending tab has no launch agent; hydrates legacy persisted terminal tabs without layout entries; reads and indexes the full agent-status snapshot once per mobile projection; kills persisted SSH PTYs when closing hydrated headless tabs before pane metadata is restored; materializes hydrated pending headless terminals with the persisted session identity. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-07.spec.ts: hydrates a persisted SSH-owned pane before an attached renderer publishes its graph. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-05.spec.ts: publishes the desktop's tab name over the live agent title, and the live title without one; uses fresh neutral PTY titles over stale mobile snapshot and OSC titles; operates PTY-backed mobile session terminals without a renderer graph; reuses pane close for live PTYs that do not own a renderer tab; lists PTY-backed mobile session terminals without a renderer graph; shows and resolves active PTY-backed mobile session terminals without a renderer graph. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-04.spec.ts: creates mobile session terminals for folder workspaces in a headless runtime server; spawns fresh headless SSH mobile session terminals instead of reattaching synthetic local ids; hydrates headless mobile session terminals from the host workspace session; keeps live headless mobile session terminals when a desktop renderer publishes without them; publishes laptop-created remote runtime split terminals to phone session tabs. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-02.spec.ts: does not report headless wake degradation without sleeping records; does not wake slept agents for non-mobile session-only activation; does not rewrite unread metadata when a mobile activation finds the worktree already read; returns unread:false from worktree.ps after a mobile activation clears the flag; materializes pending mobile session terminals without focusing desktop clients; closes browser mobile session tabs when addressed by browser workspace id. src/main/runtime/orca-runtime-tests/mobile-session-tabs.spec.ts: resolves mobile terminal surfaces by exact split leaf; closes the matching mobile terminal UUID leaf without closing the whole tab; closes the whole mobile terminal tab when addressed by parent tab id; activates the active split leaf when addressed by parent tab id; clears unread metadata on mobile worktree activation without focusing desktop clients; wakes slept agents on the host renderer when a phone activates a worktree. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-05.spec.ts: publishes the hook provider session on a headless mobile tab so native chat can address the transcript; recovers the agent type from the hook row when the pane was launched without an agent hint; reads one agent-status snapshot per projection, not one per terminal tab; waits for unknown-launch foreground owner before publishing Pi-compatible mobile status; keeps Pi-compatible mobile session status as Pi for an unknown-launch foreground pi PTY; keeps renderer-vetted mobile agent status for custom-titled terminals. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-04.spec.ts: publishes terminal surface agent status for paired web clients; preserves authoritative OMP identity for Pi-compatible remote terminal snapshots; normalizes a remote OMP title without republishing omitted launch identity; skips the foreground-process probe when the PTY launch agent is already known; probes the foreground process only on a status transition for unknown launch agents; passes the client signal and the slept-worktree refusal to the spawn. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-03.spec.ts: does not use stale runtime-created PTY status when a neutral PTY title exists; recognizes runtime-created Codex PTY handles from the ready prompt; recognizes runtime-created Antigravity PTY handles from the ready prompt; recognizes live leaf Antigravity terminals from the ready prompt; recognizes a later Antigravity header with a prompt but no model line; keeps mobile terminal surfaces visible while their leaf handle is pending. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-02.spec.ts: lets Claude agents management titles clear stale runtime-created title status; does not recognize live Claude agents panes from a Claude foreground process; does not let stale tab-level agent titles override current neutral pane titles; lists live terminals with fresh pane titles over stale tab titles; lets adopted neutral pane titles use non-shell foreground fallback; lets adopted neutral pane titles retry wrapper foregrounds until recognized; authorizes settled CLI prompts only after positive %s foreground identity; does not recognize arbitrary foreground TUIs as running agents; lets live neutral pane titles retry wrapper foregrounds until recognized; lets current Claude agents PTY titles override stale runtime-created OSC titles; does not let stale Claude agents OSC titles suppress current PTY title activity. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status.spec.ts: keeps preallocated terminal handles valid across renderer reloads; preserves runtime-created PTY process identity after graph unavailable; keeps prompt bindings fenced across runtime restarts without provider incarnation; recognizes runtime-created PTY handles with agent launch titles; does not treat a bare Cursor Agent native title as a running agent session; uses stale runtime-created PTY status when there is no title or foreground evidence. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-07.spec.ts: keeps orphaned list and show writability aligned with the send gate. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-04.spec.ts: cancels a coalesced SSH worker recovery retry when its provider disconnects. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-03.spec.ts: retries renderer reveal before clearing an adopted legacy worker sleeping record. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-02.spec.ts: recovers exported ORCA_TERMINAL_HANDLE from discovered live PTY sessions. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-12.spec.ts: applies ANSI erase-from-start line controls in retained previews; applies ANSI stripping for private or intermediate CSI line controls; applies ANSI stripping for unsupported erase-line modes; reveals an agent terminal under the pane the caller reserved; keeps a fresh %s pane host-owned when a desktop window is available; keeps desktop publication %s separate from the reserved host spawn; mints its own pane when the reserved leaf is malformed, and reports the one it used; starts an agent terminal with the model the caller picked; starts an agent terminal without a model flag when no pick was made; attributes a startup-agent launch named %s as %s; attributes a fresh agent session the host builds as unknown; leaves a bare agent command the user typed out of launch attribution. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-11.spec.ts: trims oversized terminal output bursts without per-line array shifts; builds terminal previews without mapping the full retained tail; keeps recent PTY replay output capped without needing previous data for large chunks; applies terminal redraw controls before retaining previews; applies ANSI terminal redraw controls before retaining previews; retains multi-line ANSI footer redraws instead of appending old frames; keeps the cursor column when erasing full lines in multi-line redraws; applies ANSI split redraw controls without leaking raw params. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-10.spec.ts: returns renderer visible screen lines through terminal.read RPC JSON result; separates composer drafts from provider-owned terminal screens. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-09.spec.ts: reports an in-flight PTY focus as not navigated when its notifier disappears; reports graph-leaf focus as not navigated without a host notifier; grounds the provider mode tracker before a later chunk, in the emulator order; grounds an in-flight provider snapshot capture so it cannot publish the pre-reset screen; waits for terminal exit and resolves with the exit status; keeps terminal read payloads bounded while retained output remains pageable; trims terminal read preview character budget without per-line array shifts. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-08.spec.ts: submits a silent Claude composer once after the bounded render fallback; chunks large terminal.send text before provider writes; yields chunked terminal input through immediates between writes; yields while validating accepted large terminal.send text before provider writes; reveals a background terminal session when focusing its handle; replays captured launch config when focusing a background agent session; reveals background terminal sessions with the freshest PTY title; renames background terminal handles without requiring a visible tab; keeps a background terminal handle stable while reveal adoption is racing. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-07.spec.ts: resolves tui-idle when a stale Codex prompt is followed by Antigravity readiness; returns an agent-neutral blocked wait result for update prompts; returns an agent-neutral blocked wait result for workspace trust prompts; returns an agent-neutral blocked wait result for cwd selection prompts; returns a blocked wait result for Codex model migration prompts; returns a blocked wait result for Codex startup hook review prompts; returns an agent-neutral blocked wait result for generic interactive prompts; splits text and enter writes for background terminal handles; types the lead line for %s: %s; submits through the agent-specific PTY timing policy for %s. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-06.spec.ts: waits for exit on background terminal handles; keeps retained PTY transcript memory when controller refresh fails; resolves tui-idle from an Antigravity ready prompt preview; resolves Antigravity ready prompts with newline-heavy pasted tails without splitting; resolves live-leaf tui-idle from an Antigravity ready prompt preview. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-03.spec.ts: spawns the available Qoder command for a captured same-session resume: %s; does not use the local Windows shell setting for remote Windows bare agent creates; matches canonical bare agent commands when a command override is configured; keeps non-bare agent command terminal creates unchanged; keeps disabled bare agent command terminal creates unchanged; injects runtime hook receiver env into terminal sessions; creates background terminal sessions for a $label; creates background terminal sessions for a $label; enables Claude Agent Teams only for direct Claude launches when configured in-process; reveals Claude Agent Teams launches with the rewritten launch config; preserves Claude Agent Teams for sequenced Claude launches. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness.spec.ts: creates visible terminal sessions without asking the renderer to focus a tab; asks the pty controller for the requested shell instead of a startup command; knows the agent a flagged launch command names before any process read; retires a flagged command pane identity when the command exits; retires only receipted restored PTY authority on command completion and exit; forgets synthetic handles when disconnected PTY records are pruned. src/main/runtime/orca-runtime-tests/headless-snapshots.spec.ts: returns OSC titles from headless main terminal snapshots; adopts renderer-seeded titles into headless main terminal snapshots; returns cwd metadata from seeded headless main terminal snapshots; adopts OSC7 host metadata from seeded headless terminal scrollback; falls back to the renderer snapshot for hidden-output recovery without headless state; keeps an empty headless snapshot authoritative for hidden-output recovery; advances the absolute output sequence across a daemon stream gap; emits explicit OSC 9999 agent status from runtime PTY data. src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-02.spec.ts: falls back to the provider snapshot for a restored PTY with no mounted renderer; falls back to the available mirror when authoritative provider history is unavailable; keeps an empty renderer snapshot when the provider has no retained content; keeps restored provider history authoritative after later live output; uses provider alternate-screen state while a partial model is unsafe; prefers the tracked title over the headless emulator lastTitle; keeps the cursor-agent literal in record-fallback snapshots only without a tracker title; touches mobile snapshots once for decorative spinner ticks, again on idle. src/main/runtime/orca-runtime-tests/local-worktree-creation-part-02.spec.ts: creates a same-repo PR branch override from a resolved head SHA and matching push target; skips broad remote fetch for an existing full-SHA PR base; creates a selected Bitbucket PR branch override from a matching remote branch; suffixes an existing PR when a matching push target lacks selected PR metadata; suffixes a matching push target branch when selected PR metadata has no PR number; suffixes a matching push target branch when the existing PR is different; suffixes a selected PR remote conflict when the PR lookup fails; checks out an unused runtime PR branch only when it is at the resolved head SHA; suffixes only the runtime worktree path when an exact PR branch checkout path exists. src/main/runtime/orca-runtime-tests/local-worktree-creation.spec.ts: returns runtime local base update suggestions from addWorktree; creates a runtime local worktree from a usable persisted local branch base; does not create a runtime local worktree when the refresh fails and no local base ref exists; creates a branchNameOverride worktree from the selected matching remote base ref. src/main/runtime/integrations/skill/orca-runtime-skill-recovery.test.ts: continues skill management after startup recovery fails. src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-detached-routing.spec.ts: uses bounded ownership lookup for direct arrivals while the agent cannot take input; wakes a bound Run waiter when same-Run direct mail arrives; keeps an unowned detached-recipient message in its direct mailbox; uses primary-key lookups for bounded routing updates. src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-delivery.test.ts: remove only literal registration import/call pairs import './orchestration-mailbox-pointer-cli-command.spec'; no additional authored credit. src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-pointer-cli-command.spec.ts: renders the %s CLI command in a mailbox pointer. src/main/runtime/rpc/methods/terminal/terminal-multiplex-link-estimate.test.ts: sizes a slow high-latency link near twice its bandwidth-delay product; never paces a LAN, even when its client parses slowly; never paces a fast link; returns to legacy windows when the path RTT jumps. src/main/runtime/rpc/methods/terminal/terminal-snapshot-scrollback-rows.test.ts: steps down the row ladder when history is over the byte budget; tries the larger first row count, then the usual ladder within the same byte budget. src/main/runtime/rpc/server/pairing/network/windows-default-route-interfaces.test.ts: returns unknown when route inspection fails or emits malformed data; does not inspect routes outside Windows. src/main/runtime/rpc/server/pairing/pairing-offer-owner-cli.test.ts: is refused to a paired %s client; reports a failed widening instead of advertising an unreachable address. src/main/runtime/rpc/terminal-multiplex-end-verdict.test.ts: reports exited only when the owning runtime completes the exit waiter; reports unverifiable when the runtime cannot observe the exit waiter; reports unverifiable when a disconnected PTY resolves with unknown liveness. src/main/runtime/session-graph/headless-runtime-graph.spec.ts: lets a session tab inventory settle on a host no renderer publishes for. src/main/runtime/session-graph/runtime-graph-standing-contracts.test.ts: remove only literal registration import/call pairs import { registerHeadlessRuntimeGraphTests } from './headless-runtime-graph.spec', registerHeadlessRuntimeGraphTests(); no additional authored credit. src/main/runtime/session-tabs/structured-conversation-tab-title.test.ts: bumps the stored snapshot version only when the title changes. src/main/runtime/session-tabs/terminal-close-observed-exit.test.ts: keeps the healthy aggregate verification and delayed physical exit behavior; uses a stamped exit for the incarnation that was actually being closed. src/main/runtime/terminal/identity/terminal-identity-probe.test.ts: answers live for a structured worker without touching the PTY graph; answers live for a PTY handle the runtime still holds; runs the full leaf check for a handle with no live PTY; answers not-live for a stale handle; propagates \"could not look\" rather than reporting it as a dead handle. src/main/runtime/terminal/layout/paired-desktop-server-writes-layout-owner.test.ts: names the tab in main’s layout through terminal.rename; takes a window-style layout.apply close as already stopped, so the terminal runs on. src/main/runtime/terminal/lifecycle/pty-lifecycle-generation-retention.test.ts: retains no lifecycle generation after a spawn/exit cycle. src/main/runtime/terminal/lifecycle/run-terminal-user-open.test.ts: reads a freshly spawned terminal as used once a user opens its tab, not on a probe; keeps the open mark on the process a user open starts. src/main/runtime/terminal/surface/terminal-surface-replies-window.test.ts: from a desktop window that mounts both panes; from a server with no window. src/main/runtime/terminal/surface/workspace-layout-projection.test.ts: carries views for a partition that holds none yet. src/main/runtime/terminal/view/terminal-subscribe-exit-waiter-leak.test.ts: releases a signalled exit-waiter when the signal aborts. src/main/runtime/terminal/wait/orca-runtime-exact-worker-provider-session.test.ts: selects a local hook status for a local pane. src/main/runtime/terminal/wait/prime-agent-screen-readiness-transcripts.test.ts: keeps the footer and the bare caret on screen mid-turn; %s: the screen alone reads ready during %s. src/main/runtime/workspaces/startup/runtime-worktree-agent-startup.test.ts: uses per-launch arguments and preserves launch telemetry; attributes a startup agent whose caller named no surface as unknown; launches %s bare for an absent or blank prompt; attributes a %s draft launch named %s as %s; merges an automation's extras over the host defaults; threads worktree-create extras into the startup build; returns an enabled requested agent without detecting; returns the default when nothing was requested; detects instead of using the default when the requested agent is disabled; starts no agent when the default is blank; detects an enabled agent on this host when nothing usable was named; starts no agent when detection finds none. src/main/runtime/workspaces/startup/runtime-worktree-startup-readiness.test.ts: pastes and submits through composer readiness, never typing raw input; types the follow-up on WSL or SSH-to-Windows once the agent is in front, as before; cleans up the deadline when the composer was already captured; a draft that is not submitted is pasted on the box cursor, as before; takes the box after the grace when the row never comes, whatever repaints; takes the box at the deadline when the grace would outlast the budget; lets a dialog on screen veto a grace; refuses the deadline inside a pending grace while a shell is in front; takes the box at the deadline inside a pending grace with the agent in front; takes the box at the deadline after a refused grace once the agent is in front. src/main/skills/skill-install-transaction.test.ts: installs, previews unchanged bytes, and updates a clean receipt-owned skill; preserves the old version after a %s filesystem failure. src/main/speech/model-manager-download-resume.test.ts: requests the remaining bytes when a clean range response ends before the file total; bounds a server that advances by pathologically tiny segments forever. src/main/ssh/config/ssh-config-parser.test.ts: parses a basic host block; parses multiple host blocks; skips wildcard-only Host entries; skips Host entries with only pattern characters; parses IdentityFile with ~ expansion; parses Windows-style IdentityFile with ~ expansion; parses quoted scalar values like OpenSSH; parses equals-form scalar directives; parses IdentityAgent with ~ expansion; parses IdentitiesOnly; parses GSSAPIAuthentication; keeps the first GSSAPIAuthentication value like OpenSSH; parses ProxyCommand, ProxyUseFdpass, and ProxyJump; ignores comments and blank lines; handles case-insensitive keywords; stops current block on Match directive; returns empty array for empty input; creates one parsed host per concrete alias on a multi-pattern Host line; applies identity agent settings to every concrete alias on a multi-pattern Host line; defaults port to 22 for invalid port values; converts hosts to SshTarget objects; uses host alias as hostname when HostName is missing; skips hosts that are already imported; defaults username to empty string when not specified; carries through identityFile, identityAgent, identitiesOnly, proxyCommand, and jumpHost; carries through gssapiAuthentication; imports duplicate aliases only once and keeps the first concrete host; maps hosts for the picker and flags aliases already in Orca; de-dupes aliases and defaults missing fields; parses hostname, user, port from ssh -G output; collects multiple identity files; parses forwardagent yes; defaults port to 22 when missing; returns empty hostname when missing; returns undefined user when missing; handles empty output; skips lines without spaces; parses proxycommand and filters \"none\"; parses proxyusefdpass yes; parses proxyjump and filters \"none\"; handles ~ expansion in identity file paths; handles Windows-style ~ expansion in identity file paths; parses identityagent with ~ expansion; preserves identityagent none so auth can disable agent fallback; parses identitiesonly yes; parses gssapiauthentication; parses controlmaster options and filters controlpath none. src/main/ssh/config/ssh-known-hosts-source.test.ts: splits the space-separated list ssh -G prints on one line; expands ~ in a reported path; keeps a double-quoted path containing spaces whole; falls back to the default files when ssh -G reported nothing; drops an explicit none without falling back to the defaults; splits both known_hosts lists on one line each; reads StrictHostKeyChecking, including accept-new; reads HostKeyAlias and prefers it for the lookup; reads the non-default port; reports that the lookup came from an alias, so the port is not appended; reports no alias when the dialed host is used; unions the entries of every file; skips a path that is a directory; returns nothing when no file can be read; reports nothing unreadable when every file parses; does not count an empty file as unreadable; prefers HostKeyAlias over the resolved hostname; uses the dialed host, because a resolved hostname can just echo the label; still prefers an explicit HostKeyAlias over the dialed host; falls back to the dialed host when nothing was resolved; is rejoined when the split fragments resolve to nothing; leaves a single unresolvable path alone rather than inventing one; expands the __PROGRAMDATA__ token rather than passing it through as a path; does not rewrite a path that merely BEGINS with the token characters; keeps a drive-letter path with mixed separators intact; splits a spaced Windows home into the fragments the rejoin has to put back. src/main/ssh/config/ssh-known-hosts.test.ts: reads the algorithm from the blob rather than trusting the line; rejects %s; refuses a malformed blob: %s; uses the bare host on the default port; tries the bracketed form first and falls back to bare off-port; matches an exact line; matches case-insensitively; reports a changed key of the same type; reports unknown for %s; matches any host in a comma list; matches the bracketed form on its port; does not apply a bracketed entry to the default port; falls back to a bare line when off-port; never reports a change from the fallback pass; matches a bare literal on the default port; matches a bracketed literal on its port; reports a change for a literal; handles %s; still reports a change for a different key on a revoked host; skips a line carrying an unrecognised marker; does not report a change when only another key type is on file; matches within the same type; accepts CRLF terminators; skips blanks, comments and surrounding whitespace; accepts a hit regardless of which file holds it (%s); never brackets the alias, whatever the port; still brackets an ordinary host on a non-default port; matches a bare alias entry on a non-default port; still accepts the unmodified key field; accepts a hashed entry whose salt is a full SHA1 digest; still accepts the unmutated ssh-keygen -H vector; falls back to the bare host line on a non-default port, as ssh did; refuses a key type it has not seen for a host it knows, as ssh did. src/main/ssh/connection/ssh-connect-config.test.ts: returns undefined when no default keys exist; returns the first existing key file; probes regular and FIDO2 keys in stable default order; keeps a regular default ahead of a malformed FIDO2 default; uses target host/port/username; falls back to resolved config when target fields are empty; keeps imported endpoint fields as the fallback when ssh -G is unavailable; sets readyTimeout to CONNECT_TIMEOUT_MS; sets keepaliveInterval to 15s; enables keyboard-interactive auth so MFA challenges can be answered; uses agent auth when no explicit key and SSH_AUTH_SOCK is set; enables agent forwarding when OpenSSH config requests it and an agent is available; does not enable agent forwarding without a usable agent; resolves IdentityAgent SSH_AUTH_SOCK from the environment; uses the Windows OpenSSH agent pipe when no environment socket is available on Windows; wraps agent auth with IdentityFile filtering when IdentitiesOnly is enabled; applies a manual target IdentitiesOnly setting when ssh -G reports it off; includes unencrypted target.identityFile auth when an agent is available; defers encrypted target.identityFile auth when an agent is available; uses keyFile auth when target.identityFile is set and no agent is available; includes unencrypted resolved identityFile auth when an agent is available; defers a default-path resolved identityFile to the no-agent retry; offers the keyboard-interactive challenge when the agent defers no key; provides fallback key when no agent is available; can force private key inclusion for the post-agent fallback path; falls back to resolved proxyCommand; returns structured jump-host config for target.jumpHost; returns structured jump-host config for resolved proxyJump; returns undefined when no proxy is configured. src/main/ssh/connection/ssh-connection-auth-fallback.test.ts: resolves OpenSSH config using configHost when present; tries ssh-agent before reading an explicit private key; falls back to direct private key auth when agent auth fails; falls back to direct private key auth after too many agent authentication failures; answers bounded keyboard-interactive challenges such as Duo 2FA. src/main/ssh/connection/ssh-connection-store.test.ts: lists picker suppression aliases without consulting re-adoption tombstones; getTarget delegates to store; addTarget generates an id and persists; saves the CLI control switch as given, with no consent stamp; addTarget stamps source as manual by default; addTarget preserves an explicitly provided source; inserts a new config host stamped as ssh-config; asks the parser for all hosts — reconciliation happens in the store; updates an existing config-sourced target when the port changed; refreshes gssapiAuthentication on sync; never overwrites a manual target that owns the alias; does not rewrite an unchanged config-sourced target; returns empty array when nothing changed; tombstones a deleted config-sourced host so re-import skips it; suppresses a deleted manual target from config discovery; re-adding a deleted host reclaims its alias so sync stops suppressing it; editing a target reclaims its alias from the deleted set; records a tombstone when removing any user-facing target; re-adopts orphaned repos when the same host is re-added. src/main/ssh/connection/ssh-connection.test.ts: transitions to connected on successful connect; captures the negotiated SSH server key fingerprint; allows concurrent exec commands for ssh2 transport; removes startup listeners after ssh2 connect succeeds; scopes lifecycle events and pending handshake timers to one mock client; enables TCP_NODELAY on the new ssh2 client after a reconnect cycle; transitions through connecting → connected states; reports error state on connection failure; disconnect cleans up and sets state to disconnected; getTarget returns a copy of the target; getState returns a copy of the state; throws when connecting a disposed connection. src/main/ssh/orcad-migration-stuck-host-profiles.test.ts: never leaves a running terminal behind; is offered only when leaving saved state behind would clear the refusal. src/main/ssh/orcad-runtime-maintenance.test.ts: keeps a connect from retrying a build an explicit Update also failed; offers Force when Update was refused by policy; forwards anew after an activation, since the new slot may bind another port; passes a refusal through and leaves the server linked; forwards anew once a serving slot is restored, which may have bound another port. src/main/ssh/port-forwarding/ssh-port-forward.test.ts: reports the port the OS bound when an ssh2 forward asks for port 0; adds an ssh2 port forward and returns entry; adds a system SSH port forward when no ssh2 client is available; reports the port a system SSH forward resolved when asked for port 0; passes resolved OpenSSH config to system SSH port forwards; disposes a system SSH tunnel when removing the forward; lists forwards filtered by connectionId; removes a forward by id; awaits forward close when removing a forward for user actions; returns null when removing nonexistent forward; removes all forwards for a connection; dispose removes all forwards; stores label in the entry; preserves the existing id when updating a forward succeeds. src/main/ssh/ssh-channel-multiplexer.test.ts: sends a JSON-RPC request and resolves on response; assigns unique request IDs; sends notifications without expecting a response; dispatches incoming notifications to handler; sends one keepalive frame per cadence tick; drives keepalive sends AND dead-link detection from a single interval; resolves false immediately on a disposed mux; throws on request after dispose; reports isDisposed correctly; clears registered handlers on dispose; does not retain handlers registered after dispose. src/main/ssh/system-transport/system-ssh-forward-process.test.ts: spawns exactly the argv the orphan matcher is given, LogLevel=INFO included; runs port forwards unmultiplexed even when ssh_config disables muxing; preserves manual target port and identity options in the forwarded ssh command; does not spawn ssh when the requested local forward port is already in use; spawns ssh after the requested local forward port preflight succeeds; resolves startup after the grace period when ssh keeps running; sends SIGTERM then SIGKILL when the process does not exit; does not resolve stop until the process exits. src/main/ssh/system-transport/system-ssh-loopback-route.test.ts: dials the held forward ahead of the alias so OpenSSH keeps these over ssh_config; drops a manual target's own port and proxies, which would fight the route; never routes a forward, whose argv must stay stable for orphan recovery; %s → %s; opens the forward over the real proxy, then proves a login over the route; lands the forward on the sshd and known_hosts name the direct route resolved; holds the forward with server-alive probes; never lets the background forward or probe ask for credentials; starts no forward when admission refuses the route; stops the forward when sshd refuses logins over it; stops the whole forward process tree on Windows, once; reports a forward that already exited before anyone listened for it. src/main/startup/browser-process-user-agent-ordering.test.ts: explains admission refusal before a desktop launch exits; explains an orcad holding the profile instead of exiting silently; does not acquire profile admission for a duplicate launch; executes after the dev app name and before later preflight work; exits and releases admission after pending profile move recovery fails; keeps Linux background startup failures console-only and immediate; keeps Linux serve startup failures console-only and immediate. src/main/startup/quit/quit-path-durable-write-blocking.test.ts: store.flushAsync() issues no synchronous fs syscalls; store.flushAsync() also moves the active-view and github-cache sidecars off the thread; stats.flushAsync() issues no synchronous fs syscalls; Grok session cleanup issues no synchronous fs syscalls; stats.flushAsync() closes out live agents before it returns, not when its write lands; a stalled mount leaves the event loop live instead of parking it; store.flushAsync() is one idempotent final barrier; store.flushAsync() resolves instead of throwing when the profile mount rejects writes. src/main/stats/agent-session-transition-recorder.test.ts: counts a hook-only agent that never writes an agent-shaped terminal title; never opens a session from a replayed or disk-restored working status; still closes a live session when the terminating status arrives as a replay; counts one session per turn across repeated working/done cycles; closes an open session when its pane is torn down; bounds the mirror and closes what it evicts; stops the session when the main agent settles and only a watch loop holds the row working; keeps the session open while a subagent outlives the main agent, and closes it when the child settles; dates the stop by the evidence when a shell outlives the last subagent; opens a new session dated by the observation when the main agent resumes after monitoring; never dates a reopen before the close a fact-less OSC repaint caused; dates the first live row after a restored one by the evidence, not the restored clock; treats an unchanged answer as a snapshot, never a transition; opens only on a live working edge; closes only a session it opened. src/main/text-generation/commit-message-text-generation-model-discovery.test.ts: returns static catalog models without spawning for static agents; discovers dynamic models through the agent CLI; discovers dynamic models through the configured agent command override; falls back to static models when dynamic discovery returns no parseable models; falls back to the first discovered non-Pi model when its static default is unavailable. src/main/text-generation/pull-request-context.test.ts: does not fetch unrelated fork remotes before generating PR context; bounds exact remote-ref probe concurrency for a large remote list; reports no branch change because PR context preparation is read-only; keeps a remote-qualified base when the selected base includes the remote. src/main/text-generation/source-control-local-process.test.ts: asks the supervisor to stop and leaves its group to it; signals nothing once the supervisor has exited; stops an agent that ignores its stdin end through its supervisor. src/main/updater/linux-package/linux-package-update-recovery.test.ts: retains the downloaded package with the digest from the event metadata; requires a string downloaded path; accepts an uppercase extension; requires a non-empty string version; matches an absolute file URL by basename; accepts duplicate entries that agree on the digest; refuses an entry with a missing or non-string digest; refuses a digest that is not base64 at all; refuses a malformed percent-encoded URL; refuses a missing or non-array file list; tolerates a non-object event; replaces the retained artifact with a newer download; keeps the retained artifact when a new download has no usable digest; keeps the retained artifact when an unrelated download event arrives; clears the retained artifact; preserves the artifact across a recheck of the same version; clears the artifact when another version takes over; preserves the artifact for an unknown or empty version; is a no-op without a retained artifact; returns the built command and package file name for a verified package; reports missing without a retained artifact; propagates a package-manager discovery failure; rejects a well-formed digest that belongs to another file; never hashes a package that a malformed digest failed to arm; rejects a path outside the cache root; rejects the cache root itself; rejects a package in the updater directory itself; rejects a pending directory that is a symlink out of the cache; performs one hash pass for concurrent requests; revalidates once the in-flight pass settles; does not reuse an in-flight pass for a different artifact; starts a fresh proof when the same package is captured again; returns the verified package path; returns missing without a retained artifact. src/main/updater/releases/updater-prerelease-feed-readiness.test.ts: accepts a GitHub %s asset redirect as ready; reports a GitHub asset request error as unavailable; reports not-ready with a verified last-good tag when the newest assets are unavailable; does not classify a non-positive tag limit as feed unavailability; reproduces the v1.4.142 publishing incident as not-ready; reports transport failures as unavailable instead of not-ready; treats an explicit asset 404 as not-ready when another asset is unavailable; accepts absolute manifest asset URLs without rewriting them to release asset paths; returns not-ready with an older ready update as last-good while newest is publishing. src/main/updater/releases/updater-release-builds.test.ts: lists hourly builds from the dedicated repo, newest first; lists daily builds from the dedicated repo, newest first; separates stable from rc in the shared main repo; skips drafts and unparseable tags; keeps a composed release title and drops one that repeats the tag; hides builds that published no artifact for this platform; returns an empty list when no build has this platform artifact; keeps mac builds visible on macOS regardless of the Windows leg; resolves the platform installer download url; leaves the installer url null when the release published no installer; tolerates a release whose assets are missing or malformed; sends the local gh token as a bearer header when one is available; sends no authorization header when gh has no token; retries unauthenticated once when GitHub rejects the token; does not retry a 401 that was already unauthenticated; falls back to the per-IP bucket when the token is rate limited and tells the gh breaker; reports a secondary limit carrying retry-after without retrying or tripping the breaker; records a primary limit in the token scope %s; keeps %s authenticated when only %s is blocked; skips the token while its scope %s is blocked; surfaces a rate limit with its reset time and a sign-in hint when unauthenticated; omits the sign-in hint when the rate-limited request was authenticated; treats 429 as a rate limit; reports a 403 without rate-limit headers as a plain HTTP error; reports a missing hourly repo distinctly; is null when GitHub sent no reset; prefers retry-after over the primary reset epoch; falls back to the primary reset epoch when there is no retry-after; reads retry-after as seconds; reads retry-after as an HTTP date; pins an hourly tag at the hourly repo download path; pins a daily tag at the daily repo download path; pins a stable tag at the main repo download path; rejects a tag that is not a version. src/main/updater/updater.build-channel-selection.test.ts: uses the display label in the unsupported-platform %s pinned-build error; still pins %s from an unsigned Windows dev build; restores ordinary release checks after local build selection fails; opts into the RC channel when checkForUpdatesFromMenu is called with includePrerelease; pins the generic feed to a perf-tagged prerelease when requested; surfaces no-update feedback when no newer perf-tagged prerelease exists; keeps prerelease publishing-window misses on the generic retry path; leaves the feed URL alone for a normal user-initiated check. src/main/updater/updater.check-preflight.test.ts: ignores a stale update-not-available event after a new check starts preflight; deduplicates repeated manual checks while the immediate checking status is active. src/main/updater/updater.prerelease-fallback.test.ts: retries a prerelease check once against the previous feed tag when the manifest is missing; surfaces a promise-only prerelease fallback failure after the primary error event. src/main/updater/updater.publishing-window-feed.test.ts: repins the generic feed to the newest RC tag for a prerelease user; repins the generic feed to a newer stable tag for a prerelease user; pins a stable fallback when Atom has no newer prerelease; uses last-good concrete feed when a user-initiated check lands during publishing; can offer an older fully published update while the newest release is publishing; keeps background publishing-window fallback on the short retry cadence. src/main/updater/updater.quit-and-install.test.ts: surfaces an accepted retry before electron-updater emits download progress; defers quitAndInstall and runs its launcher within the launch PATH scope; runs pre-quit cleanup before local PTY cleanup during update install; keeps optional pre-quit cleanup fail-and-continue behavior by default; ignores duplicate quitAndInstall requests while the shared delay is pending; arms the forced-exit watchdog once the install commits; disarms the forced-exit watchdog when sync install error recovery keeps the app open. src/main/window/createMainWindow-markdown-editor-focus.test.ts: ignores traffic light sync IPC on non-macOS; still intercepts Cmd+Shift+B and Cmd+Alt+B when the markdown editor is focused; coerces non-boolean setMarkdownEditorFocused payloads to false; opens a table-aware context menu synchronously without a renderer query; builds the plain edit menu for the one right-click the renderer marks as plain text. src/main/window/createMainWindow-renderer-crash-recovery.test.ts: notifies the caller when the renderer process is gone; passes the renderer webContents id through crash recording and recovery callbacks; forwards expected renderer teardowns so the recorder can diagnose suppression; reloads the app shell after an unexpected renderer process loss; does not reload after renderer loss when recovery is disabled; stops auto-reloading after a rapid renderer crash loop trips the breaker. src/main/window/dashboard-popout-window.test.ts: updates the title after language initialization and unsubscribes when closed; lets its preload expose saved WSL hosts in serve-only, and passes nothing otherwise; creates a native-frame window with the shared preload and no webview surface; shows the window on ready-to-show; loads the prod file entry; loads the dev server URL when in dev; focuses the existing window instead of creating a second one; trusts only the live popout webContents; restores a minimized window when re-requested; restores valid persisted bounds; discards off-screen persisted bounds and falls back to defaults; persists bounds on resize after the debounce, guarding near-minimum sizes; keeps saving bounds after a vetoed quit and freezes them only on an allowed quit; closeDashboardPopout closes an open window; applies the persisted app zoom level on dom-ready; follows app zoom changes while open and unsubscribes on close; zoomDashboardPopoutIfFocused steps the popout zoom only while focused; handles the zoom-in chord via before-input-event and ignores other keys; handles mouse-wheel zoom requests outside before-input-event; respects zoom keybinding overrides for keyboard and mouse-wheel paths. src/main/window/dropped-path-preparation.test.ts: opens and stores each unique source once as drop size grows tenfold; passes ordinary paths without copying for %s; preserves ordinary successes and copied successes when another file fails; serializes copy requests from different owners; reports all lost paths without a shared reason when their failures differ. src/main/window/main-window-updater-deferred-setup.test.ts: releases all 64 completed fallback handles without repeating initialization; keeps setup after ready-to-show and releases its fallback afterward; preserves the 15-second fallback when first paint never arrives; preserves destroyed-window guard reads before and at the fallback deadline; keeps the exact %s error and releases its completed fallback; keeps the exact fallback %s error without retrying initialization; preserves pending manual setup after failed ready registration; keeps setup options, live store reads, nudge writes and required quit flush. src/main/worker-threads/worker-thread-request-queue.test.ts: posts one request at a time and in the order it was dispatched; fires a posted call at its own deadline; stops respawning and fails the rest of the queue once deaths hit the cap; clears the death count when a fresh burst starts from full idle. src/main/workspace-hooks/hooks-setup-runner-script.test.ts: builds Windows runners for newline-heavy scripts without line-array splitting; builds POSIX runners without regex-wide CRLF normalization; writes POSIX setup runners for shebang-declared scripts on native Windows paths; keeps batch setup scripts on cmd.exe when the terminal is Git Bash; hands a Git Bash pane a launch command MSYS cannot rewrite for a cmd runner; replays interpreter flags declared on the shebang line; preserves cmd.exe setup runner semantics for configured cmd users; keeps POSIX runner behavior on POSIX platforms; waits when either local or project policy requires completed setup; marks setup-runner terminals for the always-on credential guard; maps git-bash to POSIX setup launch metadata on Windows; falls back to the cmd runner when the git-bash setting has no installed Git Bash; keeps the cmd runner for a non-Git bash such as Cygwin; keeps the cmd runner for a bare bash whose flavor cannot be resolved; uses the POSIX runner for a bare bash that resolves to Git Bash; uses the POSIX runner for an extension-less Git Bash path; preserves the existing cmd runner for PowerShell terminals; preserves cmd setup compatibility when a Windows-host project has a WSL shell setting; classifies an installed explicit Git Bash executable as a POSIX runner; falls back to the cmd runner when the explicit Git Bash path no longer exists. src/main/workspaces/catalog/repo-git-remote-identity-enrichment.test.ts: schedules remote identity enrichment without blocking the caller; probes a drive project whose runtime is WSL %s; sweeps a local repo: %s; probes an SSH row that carries only executionHostId on its own host; keeps same-path rows on two different SSH hosts from sharing one backoff; coalesces concurrent probes for the same repo location; caches no-identity probes briefly so list calls do not retry every time; does not rewrite the no-remote marker on a later retry; resolves a settled no-remote repo once it gains a remote; does not re-probe a resolved identity before the refresh window elapses; re-probes a resolved identity after the refresh window elapses; bounds re-probes per sweep so a large repo list drains gradually; forgets a removed repo location so its deadline cannot outlive the repo; keeps a surviving repo backoff when a sibling repo is removed; probes again when the same location is re-added after its probe was retired; coalesces concurrent sweeps instead of running one pass per list call. src/main/workspaces/creation/preparation/worktree-create-preparation.test.ts: preserves create priority through claim probes on %s; starts the checkout only once the async workspace root resolves; still deduplicates when both callers await the same pending root lookup; namespaces native Windows preparation directories for long paths; deduplicates preparation for the same repo, base, runtime, and workspace root; does not spend a divergence walk when the base matches exactly; claims when the two sides spell the same ref differently; evicts a repo's own stale preparation before another repo's; still discards armed checkouts when the project runtime needs repair; routes preparation and finalization through the selected WSL runtime; retries stale cleanup after a transient listing failure; does not discard a detached worktree with caller-controlled preparation metadata; does not re-arm after an isolated create; re-arms a preparation once creates arrive in a burst; holds the re-arm checkout until the create runs the deferred thunk; starts one explicit prefetch after the create completes; does not re-arm when finalization failed; reports a pending create while a stale-cleanup scan is running. src/main/workspaces/removal/local-worktree-removal-recovery.test.ts: recovers Git for Windows partial filesystem deletion failures; finishes a clean non-force deletion after Git leaves a Windows directory behind; recovers localized Windows failures after Git already removed the registration; does not recover unrelated localized failures while Git still owns the row; finishes a macOS deletion Git deregistered before failing with Directory not empty; leaves an orphaned checkout to the orphan cleanup instead of deleting it; prunes and strictly verifies on the selected WSL host without deleting files or branches. src/main/workspaces/removal/worktree-removal-safety.test.ts: rejects deleting a worktree that contains another registered worktree; rejects POSIX home directories even when host homedir has a different path shape; refuses a home the host reported even when no path rule recognises it; refuses the Windows host's home directory from a POSIX client; refuses the Windows host's home directory even when the host reported nothing. src/main/wsl/discovery/distro-catalog.test.ts: retries asynchronous discovery after a transient wsl.exe failure; retries synchronous discovery after a transient wsl.exe failure; retries asynchronous discovery after wsl.exe reports no distros yet; retries synchronous discovery after wsl.exe reports no distros yet; bounds the wsl.exe spawn rate while no distros are installed; bounds the asynchronous spawn rate while no distros are installed; still caches a non-empty distro list for the process lifetime; re-probes a docker-desktop-only machine once a user distro can appear; backs off while the list keeps coming back empty; backs off after repeated distro-list failures; caps the empty-list backoff at five minutes; keeps reporting an empty result after it goes stale; keeps reporting a known distro list indefinitely; bounds cached homes while retaining the most recently used distros; still lists distros, and an excluded distro home probe fails like any other probe; gives the async home probe time for a cold boot instead of killing it at 5 s; retries availability after a probe timeout instead of latching false; bounds the probe rate while the failure window is open; caches a successful probe for the process lifetime; names an explicit spawn directory, so no deleted cwd can read as ENOENT; shares one wsl.exe spawn between concurrent probes; keeps reporting the last observed answer after it goes stale; holds a definitive failure far longer than a timeout when %s; backs off after repeated probe failures; re-probes a seeded retryable failure once its window lapses; re-probes availability once a distro list succeeds after %s; does not drop an availability failure for an empty distro list; keeps reporting unavailable off Windows without probing. src/main/wsl/discovery/wsl-distro-holder.test.ts: runs a busybox-safe loop through --exec and names the distro; spawns a detached-style holder, records it, and waits for the distro to run; a holder exiting with code 1 notes its distro may have stopped (E9); rejects a pid whose command line is not our holder for that distro; cleans up stale and corrupt records; keeps a holder and its record when release cannot verify it; reports unverifiable when the command line is unreadable even with a matching pid; release kills a verified holder and removes its record; release never kills a pid that is no longer our holder; reports a spawned holder exit so liveness can re-check. src/main/wsl/filesystem/wsl-guest-drive-mountinfo.test.ts: skips 9p shares that are not drvfs, and malformed lines. src/main/wsl/orcad/wsl-orcad-deploy-app-update.test.ts: plans the update on the census the running orcad reports, not an unknown one; forwards force to the update planner; does not serve the incumbent past a refusal that is not a wait; does not re-activate the build this host rolled back from; labels the launch with the build the adoption found serving, not the stale record; defers while another run holds the host fence; lets an explicit force deploy past both skips; names a newer host refusal apart from a rolled-back one, so only Force is offered; updates an older host as before, without asking to adopt it; never asks the incumbent when it already runs this build. src/renderer/src/components/agent/agent-launch-picker-acquisition.test.ts: keeps a completed listing usable when the host rejects the wait parameter. src/renderer/src/components/feature-tips/feature-tip-telemetry.test.ts: delivers to chat-default users in all targeting while holding out not-switched users. src/renderer/src/components/native-chat/composer/pickers/use-native-chat-side-chat-command.test.ts: completes the row on a pick, even when the command is already typed; ignores a pick of the row while side chats are unavailable. src/renderer/src/components/native-chat/media/images/native-chat-image-copy.test.ts: explains a too-large refusal that arrives through the IPC error prefix. src/renderer/src/components/native-chat/messages/actions/native-chat-fork-launch.test.ts: keeps the question with the caller and says once that it never went; tells the user to check the side chat when delivery is unconfirmed; reports a delivered question as sent, silently. src/renderer/src/components/native-chat/messages/actions/native-chat-side-chat-fork-point.test.ts: decides each of %i tool-only turns once per layout, and nothing without a listener. src/renderer/src/components/native-chat/messages/actions/use-native-chat-fork.test.tsx: places a side chat whose question was %s: %o. src/renderer/src/components/terminal-pane/provider-notices/agent-presence/agent-terminal-presence.test.ts: calls back once for %s; stops watching once unsubscribed. src/renderer/src/components/terminal-pane/pty-connection/emulation/pty-connection-mode2031-raw-subscription.spec.ts: records a mode 2031 subscribe from the raw chunk boundary without answering. src/renderer/src/components/terminal-pane/pty-connection/input/pty-connection-deferred-input-forwarding.spec.ts: routes terminal input through deferPtyInput so the host can withhold it; forwards terminal input directly when the host supplies no deferPtyInput. src/renderer/src/components/terminal-pane/pty-connection/notifications/pty-connection-terminal-bell-attention.spec.ts: forwards onBell to pane attention and notification policy; hands the bell to the attention module with its pane even when pane attention is off. src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-dropped-output-snapshot-healing.spec.ts: repaints from the main-owned snapshot when main drops pending output at the cap. src/renderer/src/components/terminal-pane/pty-connection/output/pty-connection-fresh-native-follow-reset.spec.ts: retries a fresh-spawn native follow reset when renderer dimensions return. src/renderer/src/components/terminal-pane/pty-connection/spawn/unbound-pane-spawn-recovery.test.ts: requests a tab remount for an unbound spawn; leaves recovery to a remote transport that armed its own retry; requests a remount when the transport reports no recovery of its own; settles the spawn as failed before requesting a remount; prefers the restored leaf id when reporting the anomaly; falls back to the pane leaf id when no restored leaf exists. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-foreground-agent.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionDeferredInputForwardingTests } from '../input/pty-connection-deferred-input-forwarding.spec', registerPtyConnectionDeferredInputForwardingTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts: structural support changed only; no new authored removal credit. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionFreshNativeFollowResetTests } from '../output/pty-connection-fresh-native-follow-reset.spec', registerPtyConnectionFreshNativeFollowResetTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionTerminalBellAttentionTests } from '../notifications/pty-connection-terminal-bell-attention.spec', registerPtyConnectionTerminalBellAttentionTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-delivery-interest.test.ts: registers interest on the first sidecar and releases on the last unsubscribe; releases sidecar interest only once for repeated unsubscribes; does not let an eager pre-mount buffer defeat hidden delivery gating; keeps eager buffers outside delivery interest when the PTY exits before mount; lets a sidecar exclusively own interest while an eager buffer overlaps. src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-push-reattach.test.ts: blackholed delivery reproduces the wedge: no handler dispatch, no ACK ever. src/renderer/src/components/terminal-pane/pty-transport/ipc/ipc-pty-opencode-model.test.ts: sends preferences to the execution host and attaches only to its returned PTY; preserves one operation ID across a lost reply and reconnect; preserves ordinary raw startup and captured-session attachment. src/renderer/src/components/terminal-pane/pty-transport/output/pty-side-effect-pending-census.test.ts: sums registered gauges and drops disposed ones; ignores a repeated dispose instead of dropping another gauge; stops tracking new gauges past the cap so a missed dispose cannot grow it; tracks a live output processor queue through enqueue, drain, and dispose; excludes cleared consumed entries from retention after a bounded drain. src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-prebind-discard-notice.test.ts: says nothing once the pane is closed. src/renderer/src/components/terminal-pane/render-health/terminal-webgl-atlas-recovery.test.ts: refreshes after each scheduled atlas reset; falls back to a timeout when animation frames are unavailable; continues recovery when a manager throws after scheduling. src/renderer/src/components/terminal-pane/snapshots/pty-buffer-serializer.test.ts: tracks a remounted quiet title source even when the stale owner unregisters later; preserves the renderer-parsed output sequence in the response; preserves a pending escape tail for snapshot replay; routes a host's Reset Terminal request to the pane that owns the PTY. src/renderer/src/components/terminal-pane/snapshots/saved-terminal-output-replay.test.ts: marks panes with restored scrollback for fresh-shell viewport blanking. src/renderer/src/components/terminal-pane/viewport/split-right-white-screen.test.ts: recovers a 0x0 spawn whose container is briefly unmeasurable then settles. src/renderer/src/components/terminal-pane/viewport/visibility/stale-document-visibility.test.ts: removes global listeners when the last pane unregisters. src/renderer/src/components/ui/security-surface-theme-contrast.test.tsx: keeps trust text readable on a host-owned dialog surface; applies the hostile surface to ordinary dialogs, so the case above is exercised. src/renderer/src/components/use-terminal-parking-pass.test.tsx: does not queue a render when a pass produces the same parking sets; keeps parking transitions working under StrictMode. src/renderer/src/hooks/client-workspace-view-report.test.ts: reports an away user’s screen with no presence, and renews as soon as input returns; retries a failed send, empty or not, no sooner than a refresh. src/renderer/src/hooks/ipc-events/terminal-request-ipc-bridge-placement.test.ts: is new work in a workspace with no live terminal: its first bind moves it up in Recent. src/renderer/src/hooks/use-bundled-skill-install.test.tsx: ignores a repeated click while the install runs; retries the last requested skills on this host. src/renderer/src/hooks/useGitHubSlugMetadata.assignee-reuse.test.tsx: adds seeds to a successful empty list but not to loading or failed results; retains seed projection after expiry and fetches fresh metadata for a new reader. src/renderer/src/hooks/useSettingsNavigationMetadata.language-switch.test.tsx: retranslates the settings nav labels when the UI language changes live. src/renderer/src/lib/codex-stale-pane-account-identity.test.ts: keeps the prompt when the roster read fails and every label collapses. src/renderer/src/lib/image-blob-png.test.ts: downscales a pasted image above the pixel cap; releases its temporary URL on a decode error; releases its temporary URL when PNG encoding fails or exceeds the byte cap. src/renderer/src/lib/react-commit-cascade-store-write-samples.test.ts: names callers above the frame the write came from; restores Error.stackTraceLimit when the capture throws; stops collecting after the sample cap when captureStackTrace is unavailable; caps reported changed keys from a single wide write. src/renderer/src/lib/work-items/linear/linear-issue-context-snapshot.test.ts: applies the rendered text hard cap last and reserves the final overflow marker. src/renderer/src/runtime/rpc/targets/use-worktree-runtime-target.test.ts: keeps the runtime target identity stable across unrelated store writes. src/renderer/src/runtime/source-control/git/runtime-git-branch-client.test.ts: keeps creation available on old hosts and explains the missing operation; preserves landed warnings and direct collision recovery data; propagates remote discovery failure instead of a false empty page. src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-key-reuse.test.ts: reuses unchanged worktree tab projections when one worktree title changes; bumps only the changed worktree version when a sibling stays byte-identical. src/renderer/src/store/repos/repos-catalog-request-coordination.test.ts: shares safe-auto fork sync cooldown attempts across store instances. src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-batch.test.ts: collapses a 193-workspace hydration to one store write; leaves the store byte-identical to the per-workspace path; re-reconciling the batched result is a no-op, as it is for the per-workspace path. src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-fixture.ts: dedicated zero-case helper retirement; no authored test credit. src/renderer/src/store/slices/worktrees/metadata/update-worktrees-meta.test.ts: persists each batch metadata update to its workspace owner. src/renderer/src/store/slices/worktrees/metadata/worktree-meta-rename.test.ts: dismisses a rename error on its capable remote owner; clears pending first-agent rename when the title is updated. src/renderer/src/store/terminals/store-sleep-shutdown-order.test.ts: orders capture, guards, handlers, main's stop, commit, cleanup, and exit settlement. src/renderer/src/store/terminals/terminal-first-tab-publication.test.ts: publishes the first terminal and root tab group atomically; publishes the first terminal and root tab group atomically, then marks it starting in main. src/renderer/src/store/terminals/workspace-terminal-reconnect-hydration.test.ts: restores daemon terminal wake hints before declaring the session ready. src/renderer/src/web/web-runtime-connection-auth-framing.test.ts: keeps legacy framing for sockets that cannot absorb a refused attempt. src/shared/terminal/appearance/terminal-font-weight-windows-regular.test.ts: moves the old Windows default to Regular once and queues the notice; keeps custom weights and fresh profiles without a notice; leaves macOS and Linux profiles untouched. tests/e2e/claude-agent-row-view.unit.test.ts: updates a mounted compact workflow description through the subscribed production parent; bounds upstream active-SSH visits for $population records, fallback=$fallback; derives %s destinations without requiring type or a workflow child ID; terminates a $path parent $status with no third request or intermediate toast; does not recover a first child %s. tests/e2e/cross-version-wire/agent-permission-legacy-spawn.unit.test.ts: keeps exact legacy ordering when structured creation cannot express afterTabId; can create a terminal without selecting the target worktree; preserves the legacy fresh-agent path when host authority is unavailable. tests/e2e/paired-instant-browser-tab.spec.ts: shows a paired browser tab before its create RPC resolves, then keeps it as one tab; adopts a paired browser tab without rebuilding its chrome. tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts: bounds host publication and renderer application across remote worktrees; globally caps decorative freshness while every working status stays fresh. tests/e2e/session-tabs/mobile-session-active-performance.unit.test.ts: bounds saved-order publication selection at N and 10N without rematerializing navigation; bounds admitted placement reconciliation during supported reads at N and 10N; bounds selection input visits at 50 and 500 rows, including unavailable-target projection; keeps publication scoped to a changed worktree and shared by listeners at N and 10N; bounds preserved-chat merge and runtime-owned hydration at N and 10N (legacy=%s); bounds actual native retirement and shared delivery work at N and 10N. tests/e2e/session-tabs/mobile-session-active-publication.unit.test.ts: does not substitute a preserved row for an unavailable explicit legacy selection; resolves main-layout group selection %s (omitted group=%s). tests/e2e/structured-agent-session-launch-admission.unit.test.ts: opens a direct caller's terminal with the caller's own CLI arguments on a decline; opens the chat on the server that admitted it; opens only the terminal when this machine declines, without a notice; opens a new agent tab's terminal with the typed prompt when the caller names none; opens the chat, not a terminal, when this machine cannot resolve a new workspace yet; keeps its terminal fallback, as before. tests/e2e/structured-attention-prompt-relay.unit.test.ts: settles once per relayed prompt, not on every later status update. tests/e2e/structured-attention-read-retirement.unit.test.ts: Mark read on a chat never opened withdraws the prompt alert it surfaced; Mark read on a chat hidden since an earlier view covers the newer prompt it surfaced; reads a newly accepted visible prompt without sending an RPC for text-only updates. tests/e2e/structured-chat-tab-lifetime-cost.unit.test.ts: counts real raw stores, unrelated window publications and captured cleanup at %i chats; counts complete supplied-member sweep and separate final retirement at S=%i N=%i. tests/e2e/structured-session-workspace-authority.unit.test.ts: bounds actual target reveal across %i repo roots and metadata aliases. tests/e2e/terminal-agent-pane-launch.unit.test.ts: starts the host's planned command once, at the pane's size, and says it started; plans a pane whose prompt the window submits without the startup update prompt; preserves caller shell-ready delivery only for a connection-scoped adapter ($connectionId); starts no shell on plan failure (original failure: $returnLaunchFailure); cannot confirm a start whose provider answer was lost. tests/e2e/terminal-parked-memory.spec.ts: releases renderer terminal memory when hidden tabs park. tests/e2e/terminal-shortcuts.spec.ts: @headful Codex-like background output stays visible without disabling WebGL in auto mode; Shift with Russian layout text reaches the PTY as Cyrillic under kitty keyboard reporting. tests/e2e/terminal-split-activation-latency.spec.ts: records attributed CWD, spawn, bind, fixture-ready, input, and echo phases. tests/e2e/terminal-split-activation-latency-phases.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-main-probe.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-artifact.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-report.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-tab-switch-visual-restore.spec.ts: restores skipped hidden Grok output on light tab resume. tests/e2e/web-runtime-session-terminal-host-authority.unit.test.ts: delivers independent %s effort through the real prepared web callback; keeps same-ID local and runtime worktrees on the selected runtime owner; creates paired web agents through host authority so activation is mirrored; delivers generated continuation context after host-authoritative creation; seeds the chat composer for a draft that rode in on the launch command. Current changed source bytes, wrapper registrations and reduced selectors have no fresh execution or red/green credit. Unrelated surviving receipt objects keep their original narrow scope; current literal graph reachability does not establish historical import closure or equivalent replacement coverage. Current conservative command/import graph reaches src/main/persistence/worktree-sort-order-write.test.ts, src/main/runtime/construction/orca-runtime.test.ts, src/main/runtime/orca-runtime-tests/targeting-and-resilience.spec.ts, src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-04.spec.ts, src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-03.spec.ts, src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-02.spec.ts, src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases-part-02.spec.ts, src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases.spec.ts, src/main/runtime/orca-runtime-tests/worktree-setup-and-startup-part-03.spec.ts, src/main/runtime/orca-runtime-tests/worktree-setup-and-startup.spec.ts, src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-summaries-part-03.spec.ts, src/main/runtime/orca-runtime-tests/mobile-summaries-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-summaries.spec.ts, src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-03.spec.ts, src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-13.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-12.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-11.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-10.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-08.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-07.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-05.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-04.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-05.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-04.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-03.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-02.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-07.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-04.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-03.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-02.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-12.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-11.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-10.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-09.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-08.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-07.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-06.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-03.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness.spec.ts, src/main/runtime/orca-runtime-tests/headless-snapshots.spec.ts, src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-02.spec.ts, src/main/runtime/orca-runtime-tests/local-worktree-creation-part-02.spec.ts, src/main/runtime/orca-runtime-tests/local-worktree-creation.spec.ts, src/main/runtime/integrations/skill/orca-runtime-skill-recovery.test.ts, src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-detached-routing.spec.ts, src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-delivery.test.ts, src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-pointer-cli-command.spec.ts, src/main/runtime/rpc/methods/terminal/terminal-multiplex-link-estimate.test.ts, src/main/runtime/rpc/methods/terminal/terminal-snapshot-scrollback-rows.test.ts, src/main/runtime/rpc/server/pairing/network/windows-default-route-interfaces.test.ts, src/main/runtime/rpc/server/pairing/pairing-offer-owner-cli.test.ts, src/main/runtime/rpc/terminal-multiplex-end-verdict.test.ts, src/main/runtime/session-graph/headless-runtime-graph.spec.ts, src/main/runtime/session-graph/runtime-graph-standing-contracts.test.ts, src/main/runtime/session-tabs/structured-conversation-tab-title.test.ts, src/main/runtime/session-tabs/terminal-close-observed-exit.test.ts, src/main/runtime/terminal/identity/terminal-identity-probe.test.ts, src/main/runtime/terminal/layout/paired-desktop-server-writes-layout-owner.test.ts, src/main/runtime/terminal/lifecycle/pty-lifecycle-generation-retention.test.ts, src/main/runtime/terminal/lifecycle/run-terminal-user-open.test.ts, src/main/runtime/terminal/surface/terminal-surface-replies-window.test.ts, src/main/runtime/terminal/surface/workspace-layout-projection.test.ts, src/main/runtime/terminal/view/terminal-subscribe-exit-waiter-leak.test.ts, src/main/runtime/terminal/wait/orca-runtime-exact-worker-provider-session.test.ts, src/main/runtime/terminal/wait/prime-agent-screen-readiness-transcripts.test.ts, src/main/runtime/workspaces/startup/runtime-worktree-agent-startup.test.ts, src/main/runtime/workspaces/startup/runtime-worktree-startup-readiness.test.ts, src/main/skills/skill-install-transaction.test.ts, src/main/speech/model-manager-download-resume.test.ts, src/main/ssh/config/ssh-config-parser.test.ts, src/main/ssh/config/ssh-known-hosts-source.test.ts, src/main/ssh/config/ssh-known-hosts.test.ts, src/main/ssh/connection/ssh-connect-config.test.ts, src/main/ssh/connection/ssh-connection-auth-fallback.test.ts, src/main/ssh/connection/ssh-connection-store.test.ts, src/main/ssh/connection/ssh-connection.test.ts, src/main/ssh/orcad-migration-stuck-host-profiles.test.ts, src/main/ssh/orcad-runtime-maintenance.test.ts, src/main/ssh/port-forwarding/ssh-port-forward.test.ts, src/main/ssh/ssh-channel-multiplexer.test.ts, src/main/ssh/system-transport/system-ssh-forward-process.test.ts, src/main/ssh/system-transport/system-ssh-loopback-route.test.ts, src/main/startup/browser-process-user-agent-ordering.test.ts, src/main/startup/quit/quit-path-durable-write-blocking.test.ts, src/main/stats/agent-session-transition-recorder.test.ts, src/main/text-generation/commit-message-text-generation-model-discovery.test.ts, src/main/text-generation/pull-request-context.test.ts, src/main/text-generation/source-control-local-process.test.ts, src/main/updater/linux-package/linux-package-update-recovery.test.ts, src/main/updater/releases/updater-prerelease-feed-readiness.test.ts, src/main/updater/releases/updater-release-builds.test.ts, src/main/updater/updater.build-channel-selection.test.ts, src/main/updater/updater.check-preflight.test.ts, src/main/updater/updater.prerelease-fallback.test.ts, src/main/updater/updater.publishing-window-feed.test.ts, src/main/updater/updater.quit-and-install.test.ts, src/main/window/createMainWindow-markdown-editor-focus.test.ts, src/main/window/createMainWindow-renderer-crash-recovery.test.ts, src/main/window/dashboard-popout-window.test.ts, src/main/window/dropped-path-preparation.test.ts, src/main/window/main-window-updater-deferred-setup.test.ts, src/main/worker-threads/worker-thread-request-queue.test.ts, src/main/workspace-hooks/hooks-setup-runner-script.test.ts, src/main/workspaces/catalog/repo-git-remote-identity-enrichment.test.ts, src/main/workspaces/creation/preparation/worktree-create-preparation.test.ts, src/main/workspaces/removal/local-worktree-removal-recovery.test.ts, src/main/workspaces/removal/worktree-removal-safety.test.ts, src/main/wsl/discovery/distro-catalog.test.ts, src/main/wsl/discovery/wsl-distro-holder.test.ts, src/main/wsl/filesystem/wsl-guest-drive-mountinfo.test.ts, src/main/wsl/orcad/wsl-orcad-deploy-app-update.test.ts, src/renderer/src/components/agent/agent-launch-picker-acquisition.test.ts, src/renderer/src/components/feature-tips/feature-tip-telemetry.test.ts, src/renderer/src/components/native-chat/composer/pickers/use-native-chat-side-chat-command.test.ts, src/renderer/src/components/native-chat/media/images/native-chat-image-copy.test.ts, src/renderer/src/components/native-chat/messages/actions/native-chat-fork-launch.test.ts, src/renderer/src/components/native-chat/messages/actions/native-chat-side-chat-fork-point.test.ts, src/renderer/src/components/native-chat/messages/actions/use-native-chat-fork.test.tsx, src/renderer/src/components/terminal-pane/provider-notices/agent-presence/agent-terminal-presence.test.ts, src/renderer/src/components/terminal-pane/pty-connection/emulation/pty-connection-mode2031-raw-subscription.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/input/pty-connection-deferred-input-forwarding.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/notifications/pty-connection-terminal-bell-attention.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-dropped-output-snapshot-healing.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/output/pty-connection-fresh-native-follow-reset.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/spawn/unbound-pane-spawn-recovery.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-foreground-agent.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts, src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-delivery-interest.test.ts, src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-push-reattach.test.ts, src/renderer/src/components/terminal-pane/pty-transport/ipc/ipc-pty-opencode-model.test.ts, src/renderer/src/components/terminal-pane/pty-transport/output/pty-side-effect-pending-census.test.ts, src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-prebind-discard-notice.test.ts, src/renderer/src/components/terminal-pane/render-health/terminal-webgl-atlas-recovery.test.ts, src/renderer/src/components/terminal-pane/snapshots/pty-buffer-serializer.test.ts, src/renderer/src/components/terminal-pane/snapshots/saved-terminal-output-replay.test.ts, src/renderer/src/components/terminal-pane/viewport/split-right-white-screen.test.ts, src/renderer/src/components/terminal-pane/viewport/visibility/stale-document-visibility.test.ts, src/renderer/src/components/ui/security-surface-theme-contrast.test.tsx, src/renderer/src/components/use-terminal-parking-pass.test.tsx, src/renderer/src/hooks/client-workspace-view-report.test.ts, src/renderer/src/hooks/ipc-events/terminal-request-ipc-bridge-placement.test.ts, src/renderer/src/hooks/use-bundled-skill-install.test.tsx, src/renderer/src/hooks/useGitHubSlugMetadata.assignee-reuse.test.tsx, src/renderer/src/hooks/useSettingsNavigationMetadata.language-switch.test.tsx, src/renderer/src/lib/codex-stale-pane-account-identity.test.ts, src/renderer/src/lib/image-blob-png.test.ts, src/renderer/src/lib/react-commit-cascade-store-write-samples.test.ts, src/renderer/src/lib/work-items/linear/linear-issue-context-snapshot.test.ts, src/renderer/src/runtime/rpc/targets/use-worktree-runtime-target.test.ts, src/renderer/src/runtime/source-control/git/runtime-git-branch-client.test.ts, src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-key-reuse.test.ts, src/renderer/src/store/repos/repos-catalog-request-coordination.test.ts, src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-batch.test.ts, src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-fixture.ts, src/renderer/src/store/slices/worktrees/metadata/update-worktrees-meta.test.ts, src/renderer/src/store/slices/worktrees/metadata/worktree-meta-rename.test.ts, src/renderer/src/store/terminals/store-sleep-shutdown-order.test.ts, src/renderer/src/store/terminals/terminal-first-tab-publication.test.ts, src/renderer/src/store/terminals/workspace-terminal-reconnect-hydration.test.ts, src/renderer/src/web/web-runtime-connection-auth-framing.test.ts, src/shared/terminal/appearance/terminal-font-weight-windows-regular.test.ts, tests/e2e/claude-agent-row-view.unit.test.ts, tests/e2e/cross-version-wire/agent-permission-legacy-spawn.unit.test.ts, tests/e2e/paired-instant-browser-tab.spec.ts, tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts, tests/e2e/session-tabs/mobile-session-active-performance.unit.test.ts, tests/e2e/session-tabs/mobile-session-active-publication.unit.test.ts, tests/e2e/structured-agent-session-launch-admission.unit.test.ts, tests/e2e/structured-attention-prompt-relay.unit.test.ts, tests/e2e/structured-attention-read-retirement.unit.test.ts, tests/e2e/structured-chat-tab-lifetime-cost.unit.test.ts, tests/e2e/structured-session-workspace-authority.unit.test.ts, tests/e2e/terminal-agent-pane-launch.unit.test.ts, tests/e2e/terminal-parked-memory.spec.ts, tests/e2e/terminal-shortcuts.spec.ts, tests/e2e/terminal-split-activation-latency.spec.ts, tests/e2e/terminal-split-activation-latency-phases.ts, tests/e2e/terminal-split-activation-latency-main-probe.ts, tests/e2e/terminal-split-activation-latency-artifact.ts, tests/e2e/terminal-split-activation-latency-report.ts, tests/e2e/terminal-tab-switch-visual-restore.spec.ts, tests/e2e/web-runtime-session-terminal-host-authority.unit.test.ts. Unresolved local/computed edges remain explicit debt.", "Audit2095 current-parent preparation2126 (approved2092/2093 removals; source refresh2109/independent2112): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-03.spec.ts: rejects exact terminal stop for multiple expected PTYs before stopping anything; omits stale renderer leaves when fresh PTY liveness is required; omits unbound renderer placeholders when fresh PTY liveness is required; captures the event method before the nested sleep receipt changes it; returns the close receipt without requiring a PTY stop; uses the same stop result as an empty explicit stop. src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-04.spec.ts: builds a compact worktree summary from persisted and live runtime state; reads the linked-PR state from the renderer repoId-keyed GitHub cache; carries persisted worktree host ownership in mobile summaries; emits only instance- and boundary-validated lineage parents in mobile summaries; resolves WSL platforms only for repos represented in mobile summaries; omits worktrees hidden by the host visibility policy from mobile summaries; applies linked-checkout source visibility to mobile summaries. src/main/runtime/orca-runtime-tests/hooks-and-hosted-review-part-02.spec.ts: routes runtime GitHub PR details and actions through the selected WSL project runtime; passes SSH connection context through hosted review creation flows; routes local WSL project hosted review flows through runtime git options; treats SSH worktree drift as unknown without local git probes. src/main/runtime/orca-runtime-tests/terminal-listing.spec.ts: emits one mobile session terminal tab per live PTY even if two tabs resolve to it; resolves projected split authority from the parent layout PTY binding; keeps explicit-id terminal lists from resolving all worktrees; keeps explicit-id cold-cache terminal lists from classifying unrelated same-repo worktrees; keeps unknown bare terminal-list ids on the no-scan exact-id path; matches explicit-id cwd PTYs for folder workspace instance IDs; routes PTY output through the PTY leaf index in large terminal graphs. src/main/runtime/orca-runtime-tests/window-authority.spec.ts: claims the first window as authoritative and ignores later windows; transfers authority from the headless sentinel to the first real window; relays terminal browser launches only while headless owns the graph; marks live headless PTYs for renderer reattach before desktop promotion; reports the activation gate state while no desktop window is available; bumps the epoch and enters reloading when the authoritative window reloads; can mark the graph ready for the authoritative window; drops back to unavailable and clears authority when the window disappears; hands the graph back to headless when a promoted serve window closes (#27292); keeps a crashed promoted serve renderer on its own window while the window is open; stays unavailable during initial loads before a graph is published. src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-routing-races.spec.ts: stops paged routing when the check is cancelled; keeps an unfiltered redrive unrestricted when reservations merge; keeps an unfiltered parked delivery unrestricted when reservations merge; uses a bounded indexed pane lookup for reminted Dispatch identity. src/main/runtime/workspaces/removal/worktree-teardown-unstopped-pty.test.ts: removes the reported wedged automation workspace without --force; clears PTY state once a failed stop is proven to have exited; names only the PTYs that are actually live, not every failed stop; warns with the specific sweep failure, not the generic deadline; still fails closed on a sweep-level failure without force. src/main/skills/bundled-skill-install/layouts.test.ts: links into a project only where its agent folder already exists; reads a pending cloud transaction as busy and a cloud receipt as another skill. src/main/skills/skill-upload-session-service.test.ts: joins concurrent disposal callers through exact cleanup completion. src/main/source-control/hosted-review-creation.test.ts: creates the pull request after fresh main-process validation passes; routes local WSL git and GitHub review creation through the selected runtime; creates a pull request on a GitHub Enterprise Server remote (#8312); creates a GitLab merge request after fresh main-process validation passes; creates an Azure DevOps pull request after fresh main-process validation passes; creates a Gitea pull request after fresh main-process validation passes. src/main/source-control/hosted-review-execution-host-routing.test.ts: reads a GitHub review on the SSH host a row names only in executionHostId; reads a GitLab review on the executionHostId host when connectionId names a different one; does not dial this client for a runtime row whose nested target shares a local name; keeps a runtime row with no nested target on this process (self-addressed stamp); keeps a legacy connectionId-only SSH row on its target; does not share a cached answer between two rows at one path on different hosts; creates a Bitbucket review locally for a runtime row rather than dialing its nested target; reports creation eligibility from the executionHostId-only SSH host; resolves the GitHub slug for a repo listing on the row it is asked about; refuses to dial a runtime host from this process; answers with the SSH target for both spellings and local otherwise; reads a runtime stamp on a row in this store as self-addressing, not a second machine. src/main/source-control/hosted-review-inflight-invalidation.test.ts: keeps other hosts, paths and their pending promises isolated. src/main/speech/model-manager.test.ts: requires pinned, internally consistent metadata for every model file; verifies downloaded model file hashes before installation; rejects non-HTTPS model downloads; marks OpenAI transcription models ready only when an API key is configured. src/main/ssh/connection/ssh-connection-sftp-namespace.test.ts: writes to the SFTP namespace path discovered on the same session; uploads the bundle into the SFTP namespace directory; issues no discovery requests when the caller supplies no mapping; ignores a mapping on a Windows host; never resolves on the system-SSH transport; leaves writeBuffer and openFileUploadSession on the shell path; keeps the shell path when discovery is inconclusive; preserves a session-limit channel-open error unchanged. src/main/ssh/connection/ssh-connection-system-transport.test.ts: uses system SSH transport when ProxyUseFdpass is resolved by OpenSSH; allows concurrent exec commands for system SSH with an Orca ControlMaster socket; keeps concurrent exec commands disabled for system SSH without a reusable socket; uses system SSH transport for ProxyCommand targets before ssh2 auth; keeps the original ssh2 reachability error when the system SSH probe fails; reports the system SSH failure when ssh2 cannot negotiate with the host; uses system transport for target or resolved OpenSSH proxy directives; allows an environment override for e2e coverage; ignores stale imported proxy fields when fresh OpenSSH config has no proxy. src/main/ssh/orcad-migration-catalog-client.test.ts: keeps each server project’s execution host, so a nested SSH row is never read as local; reads the server’s folder workspaces and the groups that place them on a host; sends and validates the %s operation; validates an abort result without letting it erase committed state; validates a committed receipt against the requested manifest; rejects malformed stage timestamps and abort envelopes; fails closed for method absence, malformed identity, and invalid pairing; refuses a destination without the capability before sending any migration request; reads method-not-found as the same refusal, not as a lost answer. src/main/ssh/runtime-ssh-access.test.ts: persists intent then claim before connecting and publishes redacted authenticated access; names the saved dependency when dependent state blocks an SSH access link; handles lost link responses without connecting or verifying again; invalidates old transport only after authenticated access is published; rejects changed request tuple after a completed link; rejects provisioning and missing durable generations without connecting; treats a lost successful unlink response as an idempotent no-op; hashes connection identity, not display state or owner; strictly validates ports and request IDs. src/main/startup/cli-launch-redirect.test.ts: detects a launch that received the unpacked CLI entrypoint; ignores normal desktop launches; ignores the entrypoint when it is only the executable itself (argv[0]); applies on Linux too; strips injected Chromium switches before node-mode CLI arguments; keeps user flags after the command and malformed boolean assignments; does not treat a later positional entrypoint path as the launcher; redirects a direct binary launch with no AppImage env at all; strips Chromium switches node mode would reject; preserves desktop-shaped switches after the command; leaves direct serve in-process but redirects its help; treats help as a CLI launch even without a command; treats %s as a CLI launch even without a command; does not treat a value of %s as a CLI early-exit flag; does not treat a serve option value as a help request; does not reinterpret help after the argument terminator; leaves a plain desktop launch alone; skips flag values when looking for the command positional; preserves a project selector in %j; does not apply the command form on macOS or Windows; never redirects an unpackaged build; runs the in-package CLI in Electron node mode with sanitized env; refuses to redirect twice so a dropped ELECTRON_RUN_AS_NODE cannot loop; reports a missing CLI entrypoint instead of booting the desktop app; execs a direct serve into the CLI so it keeps its pid and honours profile and supervise; keeps ORCA_USER_DATA_PATH for a direct serve without --user-data-dir; serves in-process when this runtime cannot exec or the exec fails; never execs the --serve child the CLI itself spawns, or serve on other platforms; surfaces a spawn failure as a non-zero exit; re-execs a direct --serve onto X11 when Electron resolved Wayland; leaves $name alone. src/main/startup/main-process-runtime-launch-activation.test.ts: marks startup settled for the launch record only after the window has loaded and settled; loads SSH targets on a windowless serve before paired clients can connect (#25886); pins the serve listener to loopback only for orcad browser sidecars (sidecar=$sidecar, #31895); saves Codex auth before a headless serve update restart, like the desktop does. src/main/startup/run-electron-vite-dev.test.ts: forwards dev instance identity to electron-vite; prepares userData orca and orca-dev wrappers for dev terminals; consumes the stable-name flag before forwarding args to electron-vite. src/main/updater/releases/updater-prerelease-feed.test.ts: returns the newest stable tag when the user is on an RC and a newer stable exists; returns the newest RC tag when no stable is newer than the current RC; can exclude prerelease tags for stable-channel checks; probes the %s %s platform manifest; returns null for stable-channel checks when only prereleases are newer; returns null when nothing in the feed is newer than the current version; ignores entries with unparseable tags; returns null when the fetch is not ok; returns null when the fetch throws; picks semver-newest across a mixed-order feed; ignores perf-tagged prereleases for regular RC checks; reports no RC update when only perf-tagged prereleases are newer; picks the semver-newest perf-tagged prerelease; matches only literal rc.N.perf prerelease tags for perf checks; reports no perf update instead of falling back to stable or RC tags; returns a bounded fallback candidate after the newest newer tag; returns null when the only newer tag has a manifest but its asset still 404s; requires a known old timestamp for a stable-fallback tag. src/main/updater/updater-events.test.ts: hands the whole downloaded event to artifact capture; publishes manual-install recovery after a %s download; publishes the normal downloaded state for AppImage builds; blocks downloaded-state handling when the packaged marker is unusable; passes the actual updater error into the install-failure handler; keeps manual-install recovery when a later check finds only the installed release; drops the artifact when another version takes over the cycle; ignores a downloaded event for an older target; accepts a matching event when the pending cache target was cleared; drops the artifact when progress reports a different pending version. src/main/updater/updater-linux-package-recovery-actions.test.ts: rejects both actions while no package-install recovery is active; validates the retained package on every invocation; restores recovery after a recheck resolves without a terminal event; restores recovery after a recheck fails; restores recovery when a pinned check resolves to the current version; restores recovery when resolving a pinned check fails; clears recovery for both actions once the package is gone; resolves %s as a result and keeps the card usable instead of rejecting; keeps recovery available after a transient read failure. src/main/updater/updater.check-settlement.test.ts: leaves a dismissed release update on the release source; surfaces net::ERR_FAILED to user-initiated checks with a friendly message; shows checking immediately for a user-initiated check while feed pinning is pending; keeps background checks event-driven before checking-for-update fires. src/main/usage/usage-provider-store-lifecycle.test.ts: persists identities for a whole first scan with one write; skips disabled and fresh matching states; invalidates prior sources on fingerprint changes and reuses them for forced scans. src/main/window/createMainWindow-close-confirmation.test.ts: clears the quit latch when the renderer prevents unload; does not notify the crash recorder when renderer teardown follows a confirmed window close; allows close when Electron reports a crashed webContents; requests confirmation for a hung-but-alive renderer instead of bypassing. src/main/workspaces/catalog/worktree-identity-persistence.test.ts: stores independent metadata for colliding locators on two hosts; projects canonical-only metadata for exactly one host; keeps canonical metadata current for legacy writers on a known owner; removes only the selected legacy-owner metadata when locators collide; keeps the canonical identity stable when the locator changes; leaves other hosts at the old locator when one host renames its folder. src/main/wsl/filesystem/wsl-drive-unc-conversion-startup.test.ts: leaves a journaled conversion untouched with the gate closed, %s. src/main/wsl/orcad/wsl-orcad-deploy.test.ts: holds the distro before it deploys and launches, and reports what C5 dials; passes its connect-state read (%s) on as hints; applies the SSH census and downgrade admission to the first deploy; refuses a WSL 1 distro before holding it or touching its files; tells an unregistered distro how to find the installed ones, before holding anything; surfaces an unsupported libc as the SSH host refusal does; starts an already-active slot the distro stop ended, instead of reporting it ready; deploys over an adopted unrecorded orcad under the SSH terminal gate, never a fresh launch; reports the adopted instance once the same version is serving; returns a deferral rather than launching over live terminals; hands a failed first deploy to the fresh-install cleanup before reporting it. src/main/zcode/zcode-v2-plan-credentials.test.ts: prefers migrated credentials over a stale legacy account; keeps legacy support when no personal v2 file exists; honors the upstream personal config override independently of the credential directory; does not borrow credentials from another execution host; preserves the protected Orca key priority even if v2 is corrupt; rejects upstream-invalid selection %j without legacy fallback; accepts a valid optional reasoning level; rejects upstream-invalid rule containers %j without legacy fallback; accepts a valid selected-provider empty personal rule and smart model rule; cannot establish selected credentials from %s rules; leaves encrypted CLI files unchanged across repeated account reads. tests/e2e/automation-terminal-launch.unit.test.ts: launches explicit Chat for %s through the common entry and keeps its actual fallback; does not apply stored Terminal extras to Chat; forwards only complete Chat-consumed values, with no Terminal startup base; refuses an expired admission without minting another launch identity; records the actual chat identity and delegates new workspace setup and provenance. tests/e2e/github-project-provider-columns.unit.test.ts: renders %s through one bounded items request on a named cloud host; preserves zero and complete counters: %j; preserves populated and legacy rows through shared sorting, grouping and cells. tests/e2e/structured-agent-session-launch-continuation.unit.test.ts: carries renderer lifetime through host intent to the real %s provider builders. tests/e2e/terminal-account-restart.unit.test.ts: replaces a tombstoned owner while its persisted pane binding has not yet been cleared; paired restart retains the old owner (host authority: %s). tests/e2e/terminal-hidden-view-parking.spec.ts: does not park excluded tabs; reproduces a static frame byte-for-byte across 25 park/reveal cycles. tests/e2e/terminal-long-table-scroll-restore.spec.ts: reproduces long markdown table artifacts after workspace switch and scroll; keeps narrow wrapped signer markdown table coherent after restore and scroll; keeps real emoji markdown table right edge clean after restore and scroll. tests/e2e/terminal-long-table-fixtures.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-paste-ownership.spec.ts: Windows multiline keyboard paste normalizes terminal newlines with one PTY owner; right-click paste sends clipboard text to the focused terminal exactly once. tests/e2e/terminal-raw-emoji-table-scroll-restore.spec.ts: uses WebGL by default for ordinary terminal output when available @terminal-rendering-golden. tests/e2e/terminal-windows-shell-paste-ownership.spec.ts: cmd.exe default terminal keyboard paste preserves exact content with one PTY owner; Git Bash default terminal keyboard paste preserves POSIX-shaped content with one PTY owner; WSL terminal keyboard paste preserves Linux shell content with one PTY owner. tests/e2e/workspace-board-lane-virtualization.spec.ts: mounts a window of cards for a large lane and keeps lane indexes; renders later lane indexes after the lane scrolls. Current changed source bytes, wrapper registrations and reduced selectors have no fresh execution or red/green credit. Unrelated surviving receipt objects keep their original narrow scope; current literal graph reachability does not establish historical import closure or equivalent replacement coverage. Current conservative command/import graph reaches src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-03.spec.ts, src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-04.spec.ts, src/main/runtime/orca-runtime-tests/hooks-and-hosted-review-part-02.spec.ts, src/main/runtime/orca-runtime-tests/terminal-listing.spec.ts, src/main/runtime/orca-runtime-tests/window-authority.spec.ts, src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-routing-races.spec.ts, src/main/runtime/workspaces/removal/worktree-teardown-unstopped-pty.test.ts, src/main/skills/bundled-skill-install/layouts.test.ts, src/main/skills/skill-upload-session-service.test.ts, src/main/source-control/hosted-review-creation.test.ts, src/main/source-control/hosted-review-execution-host-routing.test.ts, src/main/source-control/hosted-review-inflight-invalidation.test.ts, src/main/speech/model-manager.test.ts, src/main/ssh/connection/ssh-connection-sftp-namespace.test.ts, src/main/ssh/connection/ssh-connection-system-transport.test.ts, src/main/ssh/orcad-migration-catalog-client.test.ts, src/main/ssh/runtime-ssh-access.test.ts, src/main/startup/cli-launch-redirect.test.ts, src/main/startup/main-process-runtime-launch-activation.test.ts, src/main/startup/run-electron-vite-dev.test.ts, src/main/updater/releases/updater-prerelease-feed.test.ts, src/main/updater/updater-events.test.ts, src/main/updater/updater-linux-package-recovery-actions.test.ts, src/main/updater/updater.check-settlement.test.ts, src/main/usage/usage-provider-store-lifecycle.test.ts, src/main/window/createMainWindow-close-confirmation.test.ts, src/main/workspaces/catalog/worktree-identity-persistence.test.ts, src/main/wsl/filesystem/wsl-drive-unc-conversion-startup.test.ts, src/main/wsl/orcad/wsl-orcad-deploy.test.ts, src/main/zcode/zcode-v2-plan-credentials.test.ts, tests/e2e/automation-terminal-launch.unit.test.ts, tests/e2e/github-project-provider-columns.unit.test.ts, tests/e2e/structured-agent-session-launch-continuation.unit.test.ts, tests/e2e/terminal-account-restart.unit.test.ts, tests/e2e/terminal-hidden-view-parking.spec.ts, tests/e2e/terminal-long-table-scroll-restore.spec.ts, tests/e2e/terminal-long-table-fixtures.ts, tests/e2e/terminal-paste-ownership.spec.ts, tests/e2e/terminal-raw-emoji-table-scroll-restore.spec.ts, tests/e2e/terminal-windows-shell-paste-ownership.spec.ts, tests/e2e/workspace-board-lane-virtualization.spec.ts. Unresolved local/computed edges remain explicit debt.", "Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded.", @@ -4306,7 +4217,21 @@ "Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed.", "Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed.", "Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed.", - "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired." + "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired.", + "Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands.", + "Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims.", + "Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical.", + "Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed.", + "Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed.", + "Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed.", + "Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed.", + "Audit3335 composes adopted source unions3327/3328 and3330/3332: intentionally retires100 authored registrations/123 expanded cases, including ten whole suites, without equivalent replacement. Lost alarms include seeded host persistence/contention and stale-host cleanup; browser snapshot assembly; mocked wake/DPR callbacks and frame budgets; preflight projections; palette authority/cache suppression, URL intent and saved-title cross-repo collisions; metadata coverage/set patch and dropdown assembly; and removed terminal, worktree, review-refresh and owner-routing examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI/GPU/focus, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain only their original scope.", + "Audit3342 composes adopted source batches3333/3334,3336/3337 and3340/3341: intentionally retires180 authored registrations/263 expanded cases, including seven whole suites, without equivalent replacement. Lost alarms include corrupt editor hydration; mobile editor/diff publication and privacy projections; stale-resubscribe routing; model-picker projection/refetch/retry/fallback; editor check-details and frame property inventories; latched-pane cleanup/quiescence; client create replay identity/options/compatibility; and removed owner, async routing, terminal and layout examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts keep their original scope.", + "Audit3349 composes adopted batches3343,3345 and refreshed3354: intentionally retires234 authored registrations/294 expanded cases, including13 whole suites, without equivalent replacement. Lost alarms include supplied terminal reconnect/replacement/typeahead/mirror/result and snapshot examples; synthetic render-desync persistence/recovery; worktree listing/owner/catalog/lineage/removal and activation/creation examples; host-scoped PR and task-record projections; editor diff/status/comment and UI send-target examples; automation observation/wake, supplied sleep/deadline clock and native-chat completion/notification/relaunch samples; held-tab layout and cleanup/progress guard examples. Retained adverse-ordering and wire-boundary cases are narrower and do not replace all removed alarms. The already-upstream visibility-resume deletion receives zero new removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH, native process/power/GPU, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3359 composes root-adopted source3355/independent3356: intentionally retires130 authored registrations/139 expanded cases, including eight whole suites, without equivalent replacement. Lost alarms include strict create naming/capability/legacy payloads; supplied transport host replacement, deadline reattach, create-handoff and split activation; agent-session fork/clipboard/platform flags; shutdown cleared-scrollback/unmounted bindings; simulator host-collision/selection/shutdown; and removed editor, catalog, mutation, launch and status examples. Retained12 adverse-ordering/state-consequence cases are narrower and do not replace all removed alarms. Two queue absences receive zero removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY, filesystem restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3362 composes root-adopted3358/independent3360: intentionally retires129 authored registrations/140 expanded cases, including four whole suites, without equivalent replacement. Lost alarms include supplied orphan-adoption retry/malformed inventory/cancellation; fake-terminal replay parser/wedge/disposal callbacks; all-host catalog metadata and Windows preferences; host keepalive/protocol/stale/settings failures; and removed exact-stop/suppression, source save lifetime, diff-note queue, rename/editor close, input flood/chunk refusal/limits, purge and creation examples. Retained18 registrations/21 expanded cases protect narrower ownership, generation, dirty-state, queue convergence, encoding and attachment-lease outcomes. No replacement or keeper quota claim. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY/xterm parser, disk restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3368 composes root-adopted3363/3364 and3367/3369: intentionally retires181 authored registrations/196 expanded cases, including28 whole suites, without equivalent replacement. Lost alarms include hibernation attention/liveness/backoff/sequential teardown and inventory, host launch compatibility/legacy/Kimi/resource cleanup, terminal recovery parser/pause/quarantine/remount, window-visibility omission-fence lifetime, launch-option rendered Start, sleeping-resume saved recipe/WSL quoting/cancellation, plus removed project/window/input variants. Additional tiny-suite losses include sentence/label/field/default inventories, credential omission, Windows argument/environment mapping, URI decoding, diagnostics, provider classification and fake-clock callback/parser examples. Retained ten registrations/twelve expanded cases include two literal Unicode Mn/Cf zero-width range guards in the actual character-range algorithm and protect narrower delayed editor bytes/destructive ownership, mounted hidden collision repair, ten transport epochs, duplicate-command refusal, caller timeout typing, executor unknown-opener refusal and failed-chunk user bytes. This broad unit command selects the reduced suite; no fresh runtime, real provider/network/PTY, filesystem restart, native UI, historical import equivalence, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3375 composes root-adopted3370/independent3371 and3373/independent3374: intentionally retires79 authored registrations/84 expanded cases, including39 whole suites, without equivalent replacement. Lost alarms include federation field/parser inventories; Claude rejected-key precedence, credential clone redaction, managed-versus-user hook preservation and CLI defaults; setting/status/activity projections, mocked SSH/notification/reveal/Linear refusal, fake-clock reconnect and noise; image-fold artifact visibility, paste eligibility, setup trust, scripted ACP error-to-journal publication and ligature cache tuple aliasing; plus supplied folder-runner uniqueness, mobile host-overlay/credential/update/preference races, status/markup/title/keyed-row projections, subscriber cleanup, cancellation/close/refusal/link-issue and mirror suppression alarms. Retained3373 merger contiguity, dual-clock overdue-resume exactly-once, rejected-paste IPC sink and annotation schema roundtrip remain bounded. Retained actual HTTP/OSC status composition, destructive sibling-filesystem isolation, external contrast invariant and fixture CSS pixel intervention remain narrower. Original reviewed87authored/92expanded become9/9; current OpenCode suite adds two preserved upstream cases and the synthetic-title suite gained one Cursor policy mock-call case, independently reviewed for removal in root3378; current90/95 become11/11. That Cursor suppression/ready-frame regression alarm is intentionally lost; it does not observe native title ownership or tab flicker. For3370 only the peer was independently blind, with author exposure explicit;3373/3374 both blind pins were verified. This broad root unit command selects the reduced root unit suite; UNIT_INCLUDE excludes mobile tests, which require the existing mobile runner; retained Playwright component-pixel spec uses its separate existing headless fixture runner and is not validated by the broad unit command. No fresh execution, actual agent/shell/provider, OS material/focus, historical import equivalence, mobile, mixed-version or cross-platform evidence is claimed. All dated receipts retain their original scope." ], "demotionRule": "Demote if a retired runtime transport can leave a renderer subscription without a close event, if a close is delivered more than once, if one failing teardown strands its sibling subscriptions, if payload frames from a retired transport reach the renderer, or if a revealed remote terminal can stay blank or reject input after a reconnect." }, @@ -4424,7 +4349,7 @@ "providers": ["remote-runtime"], "coveredPlatforms": ["macos"], "coveredProviders": [], - "coverageNotes": "Audit3108: doc-preview-grants.test.ts now retains only the stale grant-rejection race: a late rejected grant request must not evict a newer grant registry entry, witnessed by later revocation of grant-2. Retire stable minted-location and outside-workspace POSIX/Windows request-projection alarms without replacement. The direct nonempty grant selector remains unchanged; no real grant-server/file authorization, SSH/HTML delivery or native-focus result is claimed. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2043: Remove the registration-wait, webview-security, preview-authorization, guest-lifecycle and grant-IPC unit suites and the sibling-directory assertion reference. Runtime and browser capability consumers also lose removed imported examples. Remaining document-policy, file-reader and grant-registry assertions do not replace those alarms. Preserve the 27 independent dated receipts at their original unchanged selectors; reduced prospective unit selectors have no fresh result or equivalent replacement claim. Historical prior account (preserved verbatim): Audit1973: Delete the browser RPC forwarding/schema/scalar suite and its prospective selector. Preserve all27 unrelated dated receipts; no actual browser operation alarm is replaced. Whole original changed dated receipts are retired, never narrowed or transferred. This metadata review claims no fresh execution, equivalent replacement, provider/PTY, live remote/mobile, rendered, cross-platform, soak or measured-budget result. Historical prior account (preserved verbatim): Audit1925 (sources1922/1923): The complete terminal-file-link-actions suite is removed. Lose supplied local/remote menu-row inventories, browser label/order/download/reveal callback forwarding, platform-copy and source-group pinning examples. No OS reveal/download, real remote preview or browser navigation was exercised; the other real document-preview sources are not equivalent replacements. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1899 replays sealed Audit1895: workspace-doc-history.test.ts is entirely removed from its current command and testFiles. Supplied recency/dedupe/cap/title/identity examples and the10000-row getter-read budget alarm are intentionally lost. No current assertionRef or active receipt selects that file. Unrelated active receipts and all prior gap literals remain verbatim; no replacement history/index-work coverage or new browser/paired-preview gate execution is claimed. Historical coverage account before Audit1899: Audit1853 reduces LinkActionPopover.test.tsx and archives its complete 2026-09-06 mixed-selector receipt. The lost copy/open-state and Settings callback-order/omission alarms are accepted without equivalent replacement coverage. No fresh execution of this gate is credited. Audit1709 removes low-value test definitions and retires affected assertion or execution-receipt claims without equivalent replacement coverage. Per-source reviews bound retained behavior and injected/native/remote limits. Unchanged assertions and receipts keep their original scope; gates lacking current active evidence are downgraded. Historical scope before this audit: Audit1687 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1630 removes low-value Git, GitHub/GitLab and IPC projections, argument inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained cancellation, ownership, authorization, filesystem and SQLite boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1571 removes mock forwarding, capability/schema inventories, private predicates, supplied error/result replays, and filesystem-mocked persistence checks without equivalent replacement claims. Retained changed tests also exercise real local permission-file reread, registry proxy rollback/credential retirement, site display recovery, and pending sender/credential/document admission with injected Electron/UI producers. Retained network tests exercise owned stream credit/cleanup, generation and retirement fences, real loopback proxy/SOCKS bytes and file-backed binding state. SSH/WSL/paired runtime, native sessions, authority producers and storage clears remain injected; simulated relaunch uses filesystem mocks. The unchanged profile-retirement suite was statically reviewed and not rerun. No actual SSH/WSL runtime, native Chromium jar deletion, durable process restart, remote DNS or external site proof. Receipts selecting changed tests are retired and unaffected receipts remain unchanged. Historical scope before this audit: Audit1568 removes API inventories, supplied mock-value/forwarding assertions, implementation-shape tables and negative/setup cases that do not reach their intended boundary, without equivalent replacement claims. Retained changed definitions exercise owned manager lifetime/queue/refcount/clamp and real synthetic process/files/staging boundaries. Seventeen unchanged native Electron definitions across this combined audit are statically reviewed and not rerun. Changed native suites exercise local popup wire/cookie/session and clean/native process-identity behavior; known popup-admission flaws remain unfixed. Unit native/event/session/registry inputs remain injected. No actual OS focus, registry/host execution, CRX verification or durable restart proof. Receipts selecting changed tests are retired and unaffected receipts remain unchanged. Historical scope before this audit: Audit1564 retires copied cookie key recipes, mock bridge/preview forwarding and flag tables, source-spelling/script inventories and setup-only alarms without equivalent replacement coverage. Retained changed cases exercise actual scoped SQLite merge/rollback/schema refusal, owned cancellation and grant authority/canonical containment, ranged response consistency, replacement guest ownership and executed guest-script promise/DOM cleanup behavior. Session, host response, geometry/observer and transport producers remain injected where documented. One unchanged native extension definition is not rerun locally; no actual remote filesystem, native layout/focus or authentication claim. Receipts selecting modified tests are retired; unaffected exact-selector receipts remain unchanged. Historical scope before this audit: Audit1412 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Audit1386 changes referenced sources; no new execution result validates reduced selectors. Retained unchanged receipts apply only to unchanged commands. Historical coverage: Audit1308 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): A macOS desktop host and a separate paired Electron client exercise the Explorer preview action end to end: the document renders inside the client-local orca-preview guest, the client gains exactly one browser workspace and it is the document one, the host's own page registry and tab snapshot gain nothing, the split does not take focus from the source editor, an explicit click activates the preview, and closing it with its X leaves the editor and terminal intact. Both host oracles are read in a run where an ordinary URL browser tab from the same client does arrive in them, because a host that cannot project browser pages at all would otherwise answer the absence question the same way. A second journey quits that client with a document tab open and relaunches it on the same profile, which is the restore the user's original report turned on: the same workspace row comes back blank and named by the document, renders again, and does so over a grant URL that differs from the one that was quit. The same journey pins the guest URL to the orca-preview scheme, so a regression back to file:// or to a host browser page is visible. The rewritten journey caught a live gap the old one could not see: since previews became browser pages they had no chrome to hand focus to their guest, so main refused every reported link click as coming from an unfocused guest and the one route out of a preview was dead. Main's own log answered it — registered true, grant live, focused false — after the embedder reported the anchor really taking six real presses. The pane now hands focus over when it is the reader's surface, and the journey routes. The preview's own components moved out of the editor folder into browser-pane/workspace-doc/ with this change, since a preview is a browser pane and no longer an editor one; their i18n keys keep the historical auto.components.editor.HtmlDocPreview prefix rather than dropping thirty translated strings across four locales for a tidier key path. Seven gate commands named those files by their old paths and were re-issued at the new ones, and the nine dated runs behind them were retired rather than left naming files that are no longer there, on the same principle this gate already applied twice: vitest treats a missing named file as a filter and exits 0, so such a command reports green while silently running only the half that still exists. Each retired record's finding is carried into the replacement run recorded below it, including the red half of the entry/subresource pair, which was re-measured by re-applying its mutant at the new path rather than being dropped. The fence over the page-management channels was decided channel by channel before it was built, and that decision record is: of the 23 channels that can name a page, 6 are allowed for a workspace-document page — the tool channels the reader drives, which reach it through the one authority that reads both halves of the registry — 9 refuse (download accept and cancel, devtools, certificate proceed, client page metadata publish, viewport override, WebAuthn account response, registration probe, registration repair), 3 cannot name a page at all because they take a profile or a worktree instead, and the rest are the registration and activation doors, refused on membership. What shipped is not the per-channel guard that classification implies: eleven call sites read the browsing map directly, so a guard per channel is exactly the caller-flag seam that has to be remembered at every future call site. The registry was split in two instead, which makes the classification structural — a document guest is absent from the browsing map, so every refusing channel refuses by absence rather than by a guard, and a channel added later inherits the refusal without being classified at all. Unit contracts cover grant scoping and path containment, per-owner read routing, refusal of a truncated or over-cap read, the old-server binary degradation, scheme admission on will-attach-webview, the guest navigation policy, the plan layer's local/SSH/paired/out-of-worktree routing, and the distinct sentence the reader sees for each failure reason. The paired browser-creation surfaces this gate still owns — capability rejection cleanup, canonical page identity, reconciliation rollback, close convergence — keep their existing headed and headless journeys. Linux and Windows live journeys remain gaps. A refused subresource is a notice on a rendered document rather than a failure panel, since only the entry document's failure leaves the reader with nothing; the entry document is served as text by every owner and cannot be refused for its format at all. Grants die with the renderer document that minted them, at window creation and on every reload, because the renderer holds the only record of which preview owns which grant. The mint and revoke channels answer only the trusted renderer, and a preview tab is never republished to mobile clients, which have no grant to read it with. External URLs leave the preview only via a trusted user click on an anchor while the preview is focused; script-driven navigation and popups reach nothing. The guest's navigation sinks are deny-only and route no URL at all, and the guest carries a preview-only preload, pinned by will-attach-webview and denied to every other attach path, whose capture-phase click handler reports an anchor's URL to main; main answers only a report from a preview guest with a live bound grant that is the focused contents, and only for http(s). Two earlier reader-facing records from 2026-08-26, which measured a shape where a subresource failure was filtered out and the panel still carried an unsupported-asset sentence, were retired with that shape rather than left contradicting the 10/10 runs of the command they share. Two more were retired on the same principle when the external-link design changed: a record showing that removing a recent-input gate let the unattended document open two browser tabs, and a record showing that dropping the webview's allowpopups attribute left a target=_blank press with nothing to route. Both measured machinery that no longer exists — the input gate could not tell a script's navigation from the click it followed, which is the case now recorded below, and the preload intercepts the press before Chromium considers a popup at all, so allowpopups was removed. WebRTC is fenced by the guest's IP-handling policy alone: this Chromium answers a webrtc content-security-policy directive as unrecognized and gathers candidates anyway, so the directive is deliberately absent from the served policy and a unit assertion keeps it out. A standalone Electron probe on the same version gathered 7 candidates including a STUN reflexive one without the policy and 0 with it. Two command paths this gate used to carry no longer exist, and their structured evidence was retired with them rather than left naming files that are no longer there: vitest treats a missing named file as a filter and exits 0, so such a command reports green while silently running only the half that still exists. The first is src/renderer/src/lib/file-preview-capability-cleanup.test.ts, deleted in STA-5557 when HTML previews stopped creating paired browser tabs: on 2026-08-12 its five-assertion STA-4063 oracle ran red 5/5 on scan e4c278eb52 and on main bc2e30000b, partially green 2/5 on pre-fix PR #14100, and green 5/5 on candidate 14b5877a75; the surviving half of that oracle is web-runtime-browser-capability-cleanup.test.ts, still commanded above. The second is tests/e2e/paired-remote-html-browser-focus.spec.ts, renamed in STA-5557 to paired-remote-html-preview-local-render.spec.ts because the journey no longer proves anything about browser focus: its 2026-08-12 runs established the owning-runtime routing and no-focus-steal behavior of the then-current browser-tab preview (red on main 346e59c879 and a90a18d43d, green on candidates d05217c40d and b7de9c0961, red again with only the side-preview focus or routing seam disabled), and its 2026-08-26 runs are recorded below under the current path. An adversarial pass after the journey landed found four coverage gaps rather than shipping defects, and all four are pinned here. The page url had a third door: the navigation commit wrote whatever url was reported, unfenced, and while nothing reaches it for a document page today it sat one report away from giving a document page a URL that persistence, the publish boundary and the address bar all read. The group projection was the load-bearing half of the mobile publish boundary that no test had: removing it alone left the whole suite green, because no test in it had tab groups, while the phone payload gained a group whose order and active tab named a document tab it was never sent. The focus handoff was covered only in the narrowing direction, so widening it — dropping the page-activity check, or either half of the reader-surface check — survived both suites. And the handoff itself was offered once and never again, so another app taking the front left the preview's one route out shut until the pane remounted, which is a desktop gap rather than a test-only one. The standalone capability-cleanup and browser-placement ledger suites were removed, including their mixed-version rejection, cleanup transfer, capacity and partition alarms. web-runtime-session.test.ts no longer supplies browser creation, rollback or recovery assertions. The grouped workspace-document exclusion remains; the separate no-group publication example was removed. Existing live/browser-store evidence does not establish equivalent replacement alarms. Earlier descriptions of the removed fixtures and their run results are historical. The client-owned-placement and layout-groups suites are removed. The broad mirror fixture no longer supplies preview placement/reservation/move assertions. Browser rows retain pre-response replay and real local-workspace reuse; focus intent retains response ordering and exact-leaf sibling ordering. Supplied browser-layout and placement/focus projection alarms are lost; retained evidence is narrower and not equivalent. The test-value audit retires renderer grant-release mock ledgers, direct creation/title/session-field copies, notification/onboarding calls and several placement/per-page projections. Canonical-ID rejection, document reopen/restore and preview URL fences remain; they do not prove close-to-registry revocation or replace every lost alarm. Historical execution evidence is unchanged. The test-value audit removed the direct legacy editor-preview hydration example from tabs-hydration.test.ts. Dropping legacy preview chrome while preserving the same-document ordinary editor no longer has that alarm. The surviving corrupt-id deduplication case does not cover that migration, and retained preview journeys are not equivalent replacement coverage. Historical run counts and migration mutation findings describe the earlier suite. Audit1308: src/renderer/src/components/editor/EditorPanelShell.header.test.tsx removed. Header visibility and mocked editor-surface inventory alarms disappear. No equivalent replacement coverage is claimed. Audit1312 removes low-value imported specs from aggregate test drivers; old whole-driver execution receipts are archived. Retained registrations are unchanged. No equivalent replacement coverage is claimed. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1386: src/renderer/src/lib/doc-preview-grants.test.ts reduced. Repeated-mount mint count, ordinary release/remint and failed-mint cache retry standalone alarms removed; no actual grant server/access test. No equivalent replacement coverage is claimed. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. The existing primary-selector receipt and its claims remain scoped to their unchanged sources; the broad optional command has no new execution result. Audit1412: src/main/browser/guest-lifecycle/manager/browser-manager-guest-policy-profile.test.ts removed. Loses workspace-document in-grant navigation/popup refusal, cleanup/re-attach, cross-registry guest authorization and browsing-map separation alarms. No equivalent browser policy coverage is claimed. No equivalent replacement coverage is claimed. Audit1421 removes browser-address-bar-suggestions.test.ts. Document suggestion title/path matching, recency merging and path-prefix ranking alarms are lost. No equivalent replacement coverage is claimed. Historical receipts remain scoped to unchanged selectors; the reduced command has no new execution result. Audit2452 removes the whole fake-effect browser-close routing suite. Active selectors and assertion references no longer select it. Its requested-worktree default close, sibling-page close and explicit missing-page typed reply alarms are intentionally retired without equivalent replacement. Prior dated receipts remain unchanged and scoped to their original sources; no fresh execution of the reduced gate, rendered browser, live remote, mobile or cross-platform validation is claimed.", + "coverageNotes": "Audit3342 retires the complete mobile editor/diff tab-publication projection suite: editor/diff serialization, workspace-document privacy withholding, pending/focus and capability/options projections are intentionally lost without equivalent replacement. The surviving focused selectors are unexecuted in this source composition. Six complete compound macOS receipts whose command fields select the changed source are retired verbatim as history; their other selected tests receive no promoted evidence. Other dated receipts keep their original scope; no fresh runtime/UI/mobile/mixed-version or cross-platform validation is claimed. Audit3335 retires the complete three-case browser-tabs snapshot assembly suite: canonical snapshot replay/placement/focus, local host-page adoption and unstamped host echo leaving a local page untouched alarms are intentionally lost without equivalent replacement. The surviving focused selector is unexecuted in this source composition. Unrelated dated receipts keep their original scope; no fresh runtime/network, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit 3301 removes the caller-chat-target precedence over host selection example from web-session-tabs-sync-focus-intent.test.ts. The snapshot-before-RPC replay and split-sibling-first exact-leaf focus cases remain unchanged and match the existing assertion reference. Preserve current selectors, assertion references, unrelated active receipts and complete archived history. These mocked state-composition survivors provide no equivalent replacement, rendered, native, network or fresh execution proof. Audit3108: doc-preview-grants.test.ts now retains only the stale grant-rejection race: a late rejected grant request must not evict a newer grant registry entry, witnessed by later revocation of grant-2. Retire stable minted-location and outside-workspace POSIX/Windows request-projection alarms without replacement. The direct nonempty grant selector remains unchanged; no real grant-server/file authorization, SSH/HTML delivery or native-focus result is claimed. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2043: Remove the registration-wait, webview-security, preview-authorization, guest-lifecycle and grant-IPC unit suites and the sibling-directory assertion reference. Runtime and browser capability consumers also lose removed imported examples. Remaining document-policy, file-reader and grant-registry assertions do not replace those alarms. Preserve the 27 independent dated receipts at their original unchanged selectors; reduced prospective unit selectors have no fresh result or equivalent replacement claim. Historical prior account (preserved verbatim): Audit1973: Delete the browser RPC forwarding/schema/scalar suite and its prospective selector. Preserve all27 unrelated dated receipts; no actual browser operation alarm is replaced. Whole original changed dated receipts are retired, never narrowed or transferred. This metadata review claims no fresh execution, equivalent replacement, provider/PTY, live remote/mobile, rendered, cross-platform, soak or measured-budget result. Historical prior account (preserved verbatim): Audit1925 (sources1922/1923): The complete terminal-file-link-actions suite is removed. Lose supplied local/remote menu-row inventories, browser label/order/download/reveal callback forwarding, platform-copy and source-group pinning examples. No OS reveal/download, real remote preview or browser navigation was exercised; the other real document-preview sources are not equivalent replacements. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1899 replays sealed Audit1895: workspace-doc-history.test.ts is entirely removed from its current command and testFiles. Supplied recency/dedupe/cap/title/identity examples and the10000-row getter-read budget alarm are intentionally lost. No current assertionRef or active receipt selects that file. Unrelated active receipts and all prior gap literals remain verbatim; no replacement history/index-work coverage or new browser/paired-preview gate execution is claimed. Historical coverage account before Audit1899: Audit1853 reduces LinkActionPopover.test.tsx and archives its complete 2026-09-06 mixed-selector receipt. The lost copy/open-state and Settings callback-order/omission alarms are accepted without equivalent replacement coverage. No fresh execution of this gate is credited. Audit1709 removes low-value test definitions and retires affected assertion or execution-receipt claims without equivalent replacement coverage. Per-source reviews bound retained behavior and injected/native/remote limits. Unchanged assertions and receipts keep their original scope; gates lacking current active evidence are downgraded. Historical scope before this audit: Audit1687 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1630 removes low-value Git, GitHub/GitLab and IPC projections, argument inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained cancellation, ownership, authorization, filesystem and SQLite boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1571 removes mock forwarding, capability/schema inventories, private predicates, supplied error/result replays, and filesystem-mocked persistence checks without equivalent replacement claims. Retained changed tests also exercise real local permission-file reread, registry proxy rollback/credential retirement, site display recovery, and pending sender/credential/document admission with injected Electron/UI producers. Retained network tests exercise owned stream credit/cleanup, generation and retirement fences, real loopback proxy/SOCKS bytes and file-backed binding state. SSH/WSL/paired runtime, native sessions, authority producers and storage clears remain injected; simulated relaunch uses filesystem mocks. The unchanged profile-retirement suite was statically reviewed and not rerun. No actual SSH/WSL runtime, native Chromium jar deletion, durable process restart, remote DNS or external site proof. Receipts selecting changed tests are retired and unaffected receipts remain unchanged. Historical scope before this audit: Audit1568 removes API inventories, supplied mock-value/forwarding assertions, implementation-shape tables and negative/setup cases that do not reach their intended boundary, without equivalent replacement claims. Retained changed definitions exercise owned manager lifetime/queue/refcount/clamp and real synthetic process/files/staging boundaries. Seventeen unchanged native Electron definitions across this combined audit are statically reviewed and not rerun. Changed native suites exercise local popup wire/cookie/session and clean/native process-identity behavior; known popup-admission flaws remain unfixed. Unit native/event/session/registry inputs remain injected. No actual OS focus, registry/host execution, CRX verification or durable restart proof. Receipts selecting changed tests are retired and unaffected receipts remain unchanged. Historical scope before this audit: Audit1564 retires copied cookie key recipes, mock bridge/preview forwarding and flag tables, source-spelling/script inventories and setup-only alarms without equivalent replacement coverage. Retained changed cases exercise actual scoped SQLite merge/rollback/schema refusal, owned cancellation and grant authority/canonical containment, ranged response consistency, replacement guest ownership and executed guest-script promise/DOM cleanup behavior. Session, host response, geometry/observer and transport producers remain injected where documented. One unchanged native extension definition is not rerun locally; no actual remote filesystem, native layout/focus or authentication claim. Receipts selecting modified tests are retired; unaffected exact-selector receipts remain unchanged. Historical scope before this audit: Audit1412 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Audit1386 changes referenced sources; no new execution result validates reduced selectors. Retained unchanged receipts apply only to unchanged commands. Historical coverage: Audit1308 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): A macOS desktop host and a separate paired Electron client exercise the Explorer preview action end to end: the document renders inside the client-local orca-preview guest, the client gains exactly one browser workspace and it is the document one, the host's own page registry and tab snapshot gain nothing, the split does not take focus from the source editor, an explicit click activates the preview, and closing it with its X leaves the editor and terminal intact. Both host oracles are read in a run where an ordinary URL browser tab from the same client does arrive in them, because a host that cannot project browser pages at all would otherwise answer the absence question the same way. A second journey quits that client with a document tab open and relaunches it on the same profile, which is the restore the user's original report turned on: the same workspace row comes back blank and named by the document, renders again, and does so over a grant URL that differs from the one that was quit. The same journey pins the guest URL to the orca-preview scheme, so a regression back to file:// or to a host browser page is visible. The rewritten journey caught a live gap the old one could not see: since previews became browser pages they had no chrome to hand focus to their guest, so main refused every reported link click as coming from an unfocused guest and the one route out of a preview was dead. Main's own log answered it — registered true, grant live, focused false — after the embedder reported the anchor really taking six real presses. The pane now hands focus over when it is the reader's surface, and the journey routes. The preview's own components moved out of the editor folder into browser-pane/workspace-doc/ with this change, since a preview is a browser pane and no longer an editor one; their i18n keys keep the historical auto.components.editor.HtmlDocPreview prefix rather than dropping thirty translated strings across four locales for a tidier key path. Seven gate commands named those files by their old paths and were re-issued at the new ones, and the nine dated runs behind them were retired rather than left naming files that are no longer there, on the same principle this gate already applied twice: vitest treats a missing named file as a filter and exits 0, so such a command reports green while silently running only the half that still exists. Each retired record's finding is carried into the replacement run recorded below it, including the red half of the entry/subresource pair, which was re-measured by re-applying its mutant at the new path rather than being dropped. The fence over the page-management channels was decided channel by channel before it was built, and that decision record is: of the 23 channels that can name a page, 6 are allowed for a workspace-document page — the tool channels the reader drives, which reach it through the one authority that reads both halves of the registry — 9 refuse (download accept and cancel, devtools, certificate proceed, client page metadata publish, viewport override, WebAuthn account response, registration probe, registration repair), 3 cannot name a page at all because they take a profile or a worktree instead, and the rest are the registration and activation doors, refused on membership. What shipped is not the per-channel guard that classification implies: eleven call sites read the browsing map directly, so a guard per channel is exactly the caller-flag seam that has to be remembered at every future call site. The registry was split in two instead, which makes the classification structural — a document guest is absent from the browsing map, so every refusing channel refuses by absence rather than by a guard, and a channel added later inherits the refusal without being classified at all. Unit contracts cover grant scoping and path containment, per-owner read routing, refusal of a truncated or over-cap read, the old-server binary degradation, scheme admission on will-attach-webview, the guest navigation policy, the plan layer's local/SSH/paired/out-of-worktree routing, and the distinct sentence the reader sees for each failure reason. The paired browser-creation surfaces this gate still owns — capability rejection cleanup, canonical page identity, reconciliation rollback, close convergence — keep their existing headed and headless journeys. Linux and Windows live journeys remain gaps. A refused subresource is a notice on a rendered document rather than a failure panel, since only the entry document's failure leaves the reader with nothing; the entry document is served as text by every owner and cannot be refused for its format at all. Grants die with the renderer document that minted them, at window creation and on every reload, because the renderer holds the only record of which preview owns which grant. The mint and revoke channels answer only the trusted renderer, and a preview tab is never republished to mobile clients, which have no grant to read it with. External URLs leave the preview only via a trusted user click on an anchor while the preview is focused; script-driven navigation and popups reach nothing. The guest's navigation sinks are deny-only and route no URL at all, and the guest carries a preview-only preload, pinned by will-attach-webview and denied to every other attach path, whose capture-phase click handler reports an anchor's URL to main; main answers only a report from a preview guest with a live bound grant that is the focused contents, and only for http(s). Two earlier reader-facing records from 2026-08-26, which measured a shape where a subresource failure was filtered out and the panel still carried an unsupported-asset sentence, were retired with that shape rather than left contradicting the 10/10 runs of the command they share. Two more were retired on the same principle when the external-link design changed: a record showing that removing a recent-input gate let the unattended document open two browser tabs, and a record showing that dropping the webview's allowpopups attribute left a target=_blank press with nothing to route. Both measured machinery that no longer exists — the input gate could not tell a script's navigation from the click it followed, which is the case now recorded below, and the preload intercepts the press before Chromium considers a popup at all, so allowpopups was removed. WebRTC is fenced by the guest's IP-handling policy alone: this Chromium answers a webrtc content-security-policy directive as unrecognized and gathers candidates anyway, so the directive is deliberately absent from the served policy and a unit assertion keeps it out. A standalone Electron probe on the same version gathered 7 candidates including a STUN reflexive one without the policy and 0 with it. Two command paths this gate used to carry no longer exist, and their structured evidence was retired with them rather than left naming files that are no longer there: vitest treats a missing named file as a filter and exits 0, so such a command reports green while silently running only the half that still exists. The first is src/renderer/src/lib/file-preview-capability-cleanup.test.ts, deleted in STA-5557 when HTML previews stopped creating paired browser tabs: on 2026-08-12 its five-assertion STA-4063 oracle ran red 5/5 on scan e4c278eb52 and on main bc2e30000b, partially green 2/5 on pre-fix PR #14100, and green 5/5 on candidate 14b5877a75; the surviving half of that oracle is web-runtime-browser-capability-cleanup.test.ts, still commanded above. The second is tests/e2e/paired-remote-html-browser-focus.spec.ts, renamed in STA-5557 to paired-remote-html-preview-local-render.spec.ts because the journey no longer proves anything about browser focus: its 2026-08-12 runs established the owning-runtime routing and no-focus-steal behavior of the then-current browser-tab preview (red on main 346e59c879 and a90a18d43d, green on candidates d05217c40d and b7de9c0961, red again with only the side-preview focus or routing seam disabled), and its 2026-08-26 runs are recorded below under the current path. An adversarial pass after the journey landed found four coverage gaps rather than shipping defects, and all four are pinned here. The page url had a third door: the navigation commit wrote whatever url was reported, unfenced, and while nothing reaches it for a document page today it sat one report away from giving a document page a URL that persistence, the publish boundary and the address bar all read. The group projection was the load-bearing half of the mobile publish boundary that no test had: removing it alone left the whole suite green, because no test in it had tab groups, while the phone payload gained a group whose order and active tab named a document tab it was never sent. The focus handoff was covered only in the narrowing direction, so widening it — dropping the page-activity check, or either half of the reader-surface check — survived both suites. And the handoff itself was offered once and never again, so another app taking the front left the preview's one route out shut until the pane remounted, which is a desktop gap rather than a test-only one. The standalone capability-cleanup and browser-placement ledger suites were removed, including their mixed-version rejection, cleanup transfer, capacity and partition alarms. web-runtime-session.test.ts no longer supplies browser creation, rollback or recovery assertions. The grouped workspace-document exclusion remains; the separate no-group publication example was removed. Existing live/browser-store evidence does not establish equivalent replacement alarms. Earlier descriptions of the removed fixtures and their run results are historical. The client-owned-placement and layout-groups suites are removed. The broad mirror fixture no longer supplies preview placement/reservation/move assertions. Browser rows retain pre-response replay and real local-workspace reuse; focus intent retains response ordering and exact-leaf sibling ordering. Supplied browser-layout and placement/focus projection alarms are lost; retained evidence is narrower and not equivalent. The test-value audit retires renderer grant-release mock ledgers, direct creation/title/session-field copies, notification/onboarding calls and several placement/per-page projections. Canonical-ID rejection, document reopen/restore and preview URL fences remain; they do not prove close-to-registry revocation or replace every lost alarm. Historical execution evidence is unchanged. The test-value audit removed the direct legacy editor-preview hydration example from tabs-hydration.test.ts. Dropping legacy preview chrome while preserving the same-document ordinary editor no longer has that alarm. The surviving corrupt-id deduplication case does not cover that migration, and retained preview journeys are not equivalent replacement coverage. Historical run counts and migration mutation findings describe the earlier suite. Audit1308: src/renderer/src/components/editor/EditorPanelShell.header.test.tsx removed. Header visibility and mocked editor-surface inventory alarms disappear. No equivalent replacement coverage is claimed. Audit1312 removes low-value imported specs from aggregate test drivers; old whole-driver execution receipts are archived. Retained registrations are unchanged. No equivalent replacement coverage is claimed. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1386: src/renderer/src/lib/doc-preview-grants.test.ts reduced. Repeated-mount mint count, ordinary release/remint and failed-mint cache retry standalone alarms removed; no actual grant server/access test. No equivalent replacement coverage is claimed. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. The existing primary-selector receipt and its claims remain scoped to their unchanged sources; the broad optional command has no new execution result. Audit1412: src/main/browser/guest-lifecycle/manager/browser-manager-guest-policy-profile.test.ts removed. Loses workspace-document in-grant navigation/popup refusal, cleanup/re-attach, cross-registry guest authorization and browsing-map separation alarms. No equivalent browser policy coverage is claimed. No equivalent replacement coverage is claimed. Audit1421 removes browser-address-bar-suggestions.test.ts. Document suggestion title/path matching, recency merging and path-prefix ranking alarms are lost. No equivalent replacement coverage is claimed. Historical receipts remain scoped to unchanged selectors; the reduced command has no new execution result. Audit2452 removes the whole fake-effect browser-close routing suite. Active selectors and assertion references no longer select it. Its requested-worktree default close, sibling-page close and explicit missing-page typed reply alarms are intentionally retired without equivalent replacement. Prior dated receipts remain unchanged and scoped to their original sources; no fresh execution of the reduced gate, rendered browser, live remote, mobile or cross-platform validation is claimed.", "motivatingLinks": [ "https://linear.app/stably/issue/STA-5557/remote-html-preview-render-workspace-files-locally-over-the-file", "https://linear.app/stably/issue/STA-3872/unable-to-open-html-files-in-remote-server", @@ -4435,20 +4360,20 @@ "https://github.com/stablyai/orca/pull/13876" ], "invariant": "Opening one HTML preview from a paired client renders the workspace document in exactly one client-local browser tab, located by that document and served over the orca-preview scheme. The client gains exactly that one browser workspace and it is the document one — blank where a URL page carries a URL, named by the document, with the chip naming the file — while the host gains no browser page at all, neither in its own page registry nor in the tab snapshot its clients publish into. The preview occupies its own split without taking focus from the source editor; an explicit click activates it, and closing it removes only the preview. Following a document from a file link is the other half of that switch and does move the reader to it, tab group included, whether the preview is new or already open, because opening a file is a request to look at it. A document tab quit with the client comes back as the same row on a grant the relaunched client mints afresh. A preview is named by the browser page it is open in, not by a namespace of its own, and the page registry has two halves: a workspace-document guest is registered in its own map and is absent from the browsing one entirely. That absence is the fence. Page, session and profile management, agent tab enumeration and command targeting, download routing and certificate attribution all read the browsing map directly, in more places than a per-channel guard could be remembered in, so none of them can name a document page and none of them carries a guard. Browser tools the reader drives (element grab, hover describe, selection capture, the annotation viewport bridge) are the one operation that legitimately spans the halves, and they go through the single authority that reads both, keyed by the page and its hosting renderer. The halves are disjoint in both directions: browsing registration refuses a page the document half already holds, and minting a grant refuses a page the browsing half already holds, so one id can never name a surface in both. The headless backend acts on that refusal by destroying the window it had already opened rather than leaving a policy-less page behind an id nothing can drive, keeping nothing under that id for its own shutdown to hand back. Registration refuses on the same terms when the guest it was asked about is already gone. The exit door is guarded in both its halves: a preview withdraws by revoking its grant and never through the unregister channel, so a page the document half holds arriving there is refused before either the registration teardown or the grab-state disposal beside it, which would otherwise drop the intent an in-flight preview grab compares by identity and leave that grab answering ok without ever arming its guest. A bridge request whose guest does not resolve is refused without tearing down the page it named, so a misaddressed request cannot cancel a healthy page's in-flight downloads and grabs. The annotation viewport bridge resolves its guest when its serialized op actually runs rather than when the request arrived, so a cross-process navigation while it waited cannot leave the bridge installed in a retired guest while the reader looks at a new one. State main keys by a preview's page is disposed when that page's grant is revoked, which is the only signal a preview's surface is gone. A tool asking for a page whose guest has not attached yet waits for that registration and arms when it arrives, rather than answering not-ready at the reader; that wait resolves only the request already naming this page, never the worktree-wide or any-tab waits the CLI and agents use to ask for a browser tab to drive. Handing the previewed document to the reader's own machine routes on the owners its grant was minted against — the file's own connection owner and the worktree's own runtime owner, neither read from the tab's stored fields. Only a document proven to live on this machine reaches the client OS; one with a resolved remote owner is downloaded first; and one whose owner cannot be resolved at all, workspace root included, is refused with a message naming that, because the download route would otherwise read the same absolute path on the client and hand back a same-named local file under the remote document's name. A runtime-owned path that falls outside its worktree root is refused by that route itself and surfaces as a failure toast rather than a download. Nothing the document does writes a file to this machine either: the preview partition denies downloads outright instead of routing them through the browser download flow, which has no page to attribute a preview's bytes to and would otherwise reserve a name in this desktop's Downloads folder and write them there unprompted. That refusal is visible to the reader and invisible to the document: the preview's shell carries a fixed sentence saying downloads are off, published at most once per preview per interval so a document asking in a loop cannot fill Orca's chrome, while the page itself gets back exactly what it got before, which is nothing. The sentence names no file, because the document chooses the name it offers; and a refusal never takes the document away the way an entry document's own failure does, whatever it names. A preview is a browser tab, not an editor tab in a preview mode: it is named the way a browser tab is named — by the document it shows when that document declares a title, and by the file it shows when it does not — while the chip goes on naming the file and the host whatever the document calls itself. A title is refused on the same terms the url is: a document that declares none has Chromium report the grant URL as its title, and that title is stored, mirrored onto the tab and written to disk, so anything carrying the scheme falls back to the file instead. It is created by the preview action as a page located by its document, it carries the workspace-relative path copy the editor's path header owned, and closing it revokes the grant that made the document readable while a URL tab closing beside it revokes nothing. Chrome persisted by builds that made previews editor tabs is dropped on restore rather than coming back naming a surface no restore can produce, and the ordinary editor tab for the same document is left alone. A document tab is held back at the mobile publish boundary — no client holds its grant, and the wire has no tab kind for it — while an ordinary browser tab beside it still publishes. It is held back from the group projection that publishes tab order, recency and group activity as well as from the tab list itself, so no published group names a tab the phone is never sent. A browser page can be located by a workspace document instead of a URL, and the document is the whole of its stored identity. The grant and the orca-preview URL that document is served over are minted when the page mounts and replaced by a hard reload, so neither is ever written to the page's url, mirrored onto its tab, persisted or published: such a page's url is the blank URL from creation through restore, including when a session written elsewhere carries a grant URL in, and what the session carries is the worktree and path a restored page mints afresh against today's owners. Every door onto a page's url holds that line — creation, the title update, and the navigation commit alike — so a report about a document page cannot give it a URL it never had, and the title fallback and the loading affordance follow the url each door actually wrote. The mirror carries the document too, so a tab entry cannot go on naming a document its active page has left. Every guest in the app is policy-attached through one door: a workspace document takes a restricted profile there rather than a separate installer beside it, so the attachment bookkeeping that door owns — what registration refuses, and what teardown frees — covers a preview on the same terms as a browsing page, and a preview takes none of the browsing machinery that door installs. That authority answers from the moment the embedder hands the guest over rather than only after a later navigation: the guest binds to the grant it is already showing, so the tools reach the document the reader opened and not just one they navigated to. A read the host reports as truncated or over-cap is refused rather than served partially, and a document outside the paired worktree is refused with a message naming that boundary instead of a bare read failure. The rendered document reaches nothing off-machine on its own: every served response carries a self-only content security policy, the preview session cancels any request that is not in-document, subframes cannot navigate outside the grant, a guest no document has yet bound to a grant may not navigate at all, the guest gathers no ICE candidates, and an SSH path that canonicalizes outside the grant root is refused before it is read. The one route out is a link the reader presses: a trusted click on an anchor, reported by the preview's own preload from a guest still bound to a live grant, leaves through the configured browser destination and captured source route — and only after the reader confirms the exact destination URL, so a document cannot spend a single stray press exfiltrating what it can read into a link it authored. The preview hands its guest that focus itself whenever it is the surface the reader is in — a browsing page gets it from the chrome around it, and a preview has no chrome to get it from — and it does so only then, so a preview mounted behind a terminal or an editor never takes the keyboard from what the reader is actually in. It offers again when the window itself takes focus back and nothing in the embedder has claimed that focus, because another app coming to the front lands focus on the embedder rather than the guest and the route out would otherwise stay shut until something remounted the pane — while the same window focus also arrives when the reader presses a tab, that being the guest's own blur returning, and taking focus back from there would fight the reader for their own click. Nothing else does. A navigation or popup the document starts by itself is swallowed whatever else is happening, including immediately after a genuine press elsewhere in the document, so a page that can read its grant cannot hand it to a browser tab; a middle click opens nothing; and a fragment link is answered inside the document. A preview attach carries the preview preload and no renderer-supplied one, and no other attach path can acquire it. A subresource the workspace will not send degrades the document to a notice naming that file, never to a failure panel over a page that rendered. A grant outlives neither the tab that owns it nor the renderer document that minted it, and only the trusted renderer can mint or revoke one. For the browser creations this gate still owns, owner-pinned creation returns the canonical host page identity before navigation readiness; delayed navigation cannot turn a created page into an unidentifiable failure or a duplicate retry. Capability rejection before host mutation must preserve the original error, issue no RPC, surface a failure toast, and remove only a caller-declared newly-created empty split. Post-create reconciliation failure requires exact rollback; ambiguous rollback rejects without local fallback.", - "oracle": "Audit3108: doc-preview-grants.test.ts now retains only the stale grant-rejection race: a late rejected grant request must not evict a newer grant registry entry, witnessed by later revocation of grant-2. Retire stable minted-location and outside-workspace POSIX/Windows request-projection alarms without replacement. The direct nonempty grant selector remains unchanged; no real grant-server/file authorization, SSH/HTML delivery or native-focus result is claimed. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2043: Remove the registration-wait, webview-security, preview-authorization, guest-lifecycle and grant-IPC unit suites and the sibling-directory assertion reference. Runtime and browser capability consumers also lose removed imported examples. Remaining document-policy, file-reader and grant-registry assertions do not replace those alarms. Preserve the 27 independent dated receipts at their original unchanged selectors; reduced prospective unit selectors have no fresh result or equivalent replacement claim. Historical prior account (preserved verbatim): Audit1973: Delete the browser RPC forwarding/schema/scalar suite and its prospective selector. Preserve all27 unrelated dated receipts; no actual browser operation alarm is replaced. Whole original changed dated receipts are retired, never narrowed or transferred. This metadata review claims no fresh execution, equivalent replacement, provider/PTY, live remote/mobile, rendered, cross-platform, soak or measured-budget result. Historical prior account (preserved verbatim): Audit1925 (sources1922/1923): The complete terminal-file-link-actions suite is removed. Lose supplied local/remote menu-row inventories, browser label/order/download/reveal callback forwarding, platform-copy and source-group pinning examples. No OS reveal/download, real remote preview or browser navigation was exercised; the other real document-preview sources are not equivalent replacements. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1709 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Audit1687 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Audit1421 narrows renderer unit coverage as recorded in coverageNotes. Prior oracle descriptions are historical for the changed suite. The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Retained unchanged-selector receipts are the only current execution evidence. Reduced-source assertions await validation. Historical prior oracle: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): In paired Electron, write an HTML fixture that declares its own title on the host, invoke the Explorer preview action on the client, and require the document text to be readable out of the orca-preview guest before judging any absence. With that presence established, require the client to hold exactly one browser workspace more than its baseline and that workspace to be the document one: page and tab url blank, the document path mirrored onto both, the tab named by the document's title, the chip naming the file, no editor row of the retired preview species anywhere, and the guest URL carrying the orca-preview scheme. Ask the host through its own page registry as well as through the tab snapshot, and in the same run open an ordinary URL browser tab from the same client and require that one to arrive in both — the presence precondition without which “the host gained nothing” is satisfied just as well by an oracle that cannot see browser pages at all. Require the preview to sit in a group other than the source editor's while the active group and tab remain the source editor's. Then click away to the terminal, click the preview tab, require it to reactivate and still render, close it with its own X, and require the document tab to be gone while the host still holds only the URL tab and the source group, source editor and terminal survive. Quit the client with a document tab open and relaunch it on the same profile: require the same workspace row to come back, blank and named by the document, rendering the document again over a grant URL that differs from the one that was quit, with no preview-scheme or document-named page anywhere in what the host holds. Prove the halves are live by flipping one product property at a time and requiring the run to fail: publish document workspaces to the host like ordinary ones, and stop mirroring the document onto the workspace row. Have the fixture document attempt its own egress on every load — an unattended window.open and location.href to an off-machine URL, plus an inline ICE gathering probe — and require the same baseline counts and a candidate count of zero, so the document's own attempts are measured rather than assumed. Then, as a separate phase after the close oracle has already run, bring the client window to the front, press the document's heading with a real mouse event, and require the document to report that the same press drove it to attempt a second window.open and location.href while both browser counts stay at that phase's baseline and nothing routes — the case a recent-input gate cannot distinguish from the press's own effect. Only then press the target=_blank link with a real mouse event and require both a recorded routing call that returned success and a browser count above that baseline, with the preview tab still open. Drive the preload's click policy as a unit oracle over a real document: a dispatched click, a trusted press on an external anchor, an anchor reached through what it wraps, an SVG animated href, a sibling preview link, fragment and percent-encoded fragment targets, a bare hash, and a middle click. Create a browser page located by a workspace document, handing creation a live grant URL, and require its stored url, its mirrored tab url and the written session payload all to be blank with no orca-preview string anywhere in what was written, while an ordinary page created the same way keeps the URL it was given and asks for the address bar the document page never does. Parse the written page and tab through the session schema and require the document to survive both halves. Hydrate them back and require the document page to return blank and still named — including when its page row was salvaged away and only the tab's own copy remains, and when a foreign session carried a grant URL into both rows. Drive the mirror across a page switch out of the document and back, and across a repair in which the document is the only mirrored field that differs. Name a document page from its document and require the tab to take that name, name it with an empty title and require the file, name it with a live grant URL and require the file again with no preview scheme anywhere in the written session, and require an ordinary blank browser tab beside it to still be called New Tab. Dispatch a title update out of a rendered preview's own guest and require it to reach the page state while the identity chip still reads the document's workspace-relative path. Attach a browsing guest and a workspace-document guest through the same method in one run and require the browsing one to take clicked-link routing, popup handling and auth-identity detach tracking while the document guest takes none of them, stays inside the grant it is showing, denies every window it asks for, and is dropped from the page-keyed document registry by the same teardown that frees its id for a later attach. Register a browsing guest and attach a workspace-document guest in one run against the real manager, require the one door to answer each page with the guest of its own half, and require the document page to be absent from the browsing map and from its enumeration. Drive both browsing registration entry points with a page the document half already holds and require them to register nothing, and drive the mint channel with a page the browsing half already holds and require it to refuse; and drive the offscreen one with a guest that is missing and with one already destroyed, requiring the same refusal. Arm a grab on a live preview target, drive the unregister channel at that same target in the window before the queued operation runs, and require the grab to reach the guest anyway — then drive the same sequence for an ordinary browser page and require its grab state to be disposed after all. Hold one viewport-bridge op open, queue a second behind it, swap the page's guest while that second op waits, and require the injection to land in the guest the page has then. Revoke a grant after a tool has run against its page and require that page's grab state to be cancelled and disposed. Ask a tool for a document page whose guest has not attached, require the request to park in the registration wait, attach the guest, and require the same request to arm on it; require a page nothing ever renders to answer not-ready once that wait elapses. With a document open, ask a tool for a browsing page id and require it to be answered by the browsing half or not at all, with the same channel reaching the document guest under the page it really renders. Drive open-externally for a document whose per-file owner is remote while the workspace-scoped owner is unresolved, for a runtime-owned worktree whose preview tab carries no runtime id of its own, and for a worktree that resolves no runtime owner while the tab still carries one, requiring the download route in each; and for an owner that cannot be resolved at all, and for an unknown workspace root while nothing names another host, requiring a refusal that neither opens nor downloads. Drive the headless backend with a page the document half already holds and require it to reject, destroy the window, and unregister nothing — then shut the backend down and require it still to have unregistered nothing. Navigate a bound preview guest at a second grant through both latch events and require it to stay on the grant it bound to. Mount a preview while a renderer drag is already in flight and require its guest to be click-through at the moment it is appended, not a turn later. Render the editor panel shell in each remaining tab mode and require the path header exactly where the surface does not already name itself. Drive the preview action and require a browser tab located by the document rather than an editor tab, require a second open of the same document to activate the tab it is already in, and require closing that tab to revoke its grant while a URL tab closed beside it revokes none. Publish a worktree holding a document tab and a URL tab and require only the URL tab to reach the mobile snapshot. Install the shared partition policies for a preview partition and for an ordinary browsing partition in the same run, fire each one's own will-download listener, and require the preview's to cancel while the browsing one still reaches the download router — then require the preview protocol installer to be what asks for that deny. In the same run, require the cancelled download to raise a reader-facing notice and the routed one to raise none. require the guest registry to name the bound grant for a live preview guest and nothing for a contents that is not one, has committed no document, or is gone. Drive the shell with a refusal and require one fixed sentence, still one row after three more refusals, standing beside an asset failure rather than being counted with it, gone behind the failure panel, and ignored when it names another preview's grant. Drive the main-side report gate directly for a sender that is no preview guest, a guest with no bound or a revoked grant, a genuine press Electron's webview focus flag misreports as unfocused, and non-web URLs; drive the reader-facing confirmation for accept, cancel, and a confirmed tab the browser refuses; and drive will-attach-webview in both preload directions. Run the per-owner reader, grant-containment, scheme-admission, guest-policy, and plan-routing contracts as unit oracles, including a host-reported truncation, an over-cap binary, and an out-of-worktree paired path. Drive the reader-facing component with the payloads the reader can actually produce — the entry document fails only as truncated or unreadable, a subresource additionally as a refused format — and require the asset case to leave the guest mounted. Drive the closed-tab cleanup hook, the window installer, and the grant IPC handlers directly, requiring the grant to be released when the preview tab closes, cleared at window creation and on a cross-document main-frame navigation, and refused to any sender that is not the trusted renderer. For the browser creations this gate still owns, run the unchanged contract oracle for direct create and side-preview callers with absent status, unknown capabilities, and a mixed-version host, requiring the original unsupported error or visible toast, zero RPCs, and no retained new split; hold a real navigation response beyond the 15-second client deadline after host creation and require the first RPC to return the exact host inventory page ID, one host page, and no retry; repeat reconciliation faults against headless serve and retain the separate exact-page reconciliation rollback oracle. Audit2452 removes the whole fake-effect browser-close routing suite. Active selectors and assertion references no longer select it. Its requested-worktree default close, sibling-page close and explicit missing-page typed reply alarms are intentionally retired without equivalent replacement. Prior dated receipts remain unchanged and scoped to their original sources; no fresh execution of the reduced gate, rendered browser, live remote, mobile or cross-platform validation is claimed.", + "oracle": "Audit3342 retires the complete mobile editor/diff tab-publication projection suite: editor/diff serialization, workspace-document privacy withholding, pending/focus and capability/options projections are intentionally lost without equivalent replacement. The surviving focused selectors are unexecuted in this source composition. Six complete compound macOS receipts whose command fields select the changed source are retired verbatim as history; their other selected tests receive no promoted evidence. Other dated receipts keep their original scope; no fresh runtime/UI/mobile/mixed-version or cross-platform validation is claimed. Audit3335 retires the complete three-case browser-tabs snapshot assembly suite: canonical snapshot replay/placement/focus, local host-page adoption and unstamped host echo leaving a local page untouched alarms are intentionally lost without equivalent replacement. The surviving focused selector is unexecuted in this source composition. Unrelated dated receipts keep their original scope; no fresh runtime/network, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit 3301 removes the caller-chat-target precedence over host selection example from web-session-tabs-sync-focus-intent.test.ts. The snapshot-before-RPC replay and split-sibling-first exact-leaf focus cases remain unchanged and match the existing assertion reference. Preserve current selectors, assertion references, unrelated active receipts and complete archived history. These mocked state-composition survivors provide no equivalent replacement, rendered, native, network or fresh execution proof. Audit3108: doc-preview-grants.test.ts now retains only the stale grant-rejection race: a late rejected grant request must not evict a newer grant registry entry, witnessed by later revocation of grant-2. Retire stable minted-location and outside-workspace POSIX/Windows request-projection alarms without replacement. The direct nonempty grant selector remains unchanged; no real grant-server/file authorization, SSH/HTML delivery or native-focus result is claimed. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2043: Remove the registration-wait, webview-security, preview-authorization, guest-lifecycle and grant-IPC unit suites and the sibling-directory assertion reference. Runtime and browser capability consumers also lose removed imported examples. Remaining document-policy, file-reader and grant-registry assertions do not replace those alarms. Preserve the 27 independent dated receipts at their original unchanged selectors; reduced prospective unit selectors have no fresh result or equivalent replacement claim. Historical prior account (preserved verbatim): Audit1973: Delete the browser RPC forwarding/schema/scalar suite and its prospective selector. Preserve all27 unrelated dated receipts; no actual browser operation alarm is replaced. Whole original changed dated receipts are retired, never narrowed or transferred. This metadata review claims no fresh execution, equivalent replacement, provider/PTY, live remote/mobile, rendered, cross-platform, soak or measured-budget result. Historical prior account (preserved verbatim): Audit1925 (sources1922/1923): The complete terminal-file-link-actions suite is removed. Lose supplied local/remote menu-row inventories, browser label/order/download/reveal callback forwarding, platform-copy and source-group pinning examples. No OS reveal/download, real remote preview or browser navigation was exercised; the other real document-preview sources are not equivalent replacements. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1709 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Audit1687 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Audit1421 narrows renderer unit coverage as recorded in coverageNotes. Prior oracle descriptions are historical for the changed suite. The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Retained unchanged-selector receipts are the only current execution evidence. Reduced-source assertions await validation. Historical prior oracle: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): In paired Electron, write an HTML fixture that declares its own title on the host, invoke the Explorer preview action on the client, and require the document text to be readable out of the orca-preview guest before judging any absence. With that presence established, require the client to hold exactly one browser workspace more than its baseline and that workspace to be the document one: page and tab url blank, the document path mirrored onto both, the tab named by the document's title, the chip naming the file, no editor row of the retired preview species anywhere, and the guest URL carrying the orca-preview scheme. Ask the host through its own page registry as well as through the tab snapshot, and in the same run open an ordinary URL browser tab from the same client and require that one to arrive in both — the presence precondition without which “the host gained nothing” is satisfied just as well by an oracle that cannot see browser pages at all. Require the preview to sit in a group other than the source editor's while the active group and tab remain the source editor's. Then click away to the terminal, click the preview tab, require it to reactivate and still render, close it with its own X, and require the document tab to be gone while the host still holds only the URL tab and the source group, source editor and terminal survive. Quit the client with a document tab open and relaunch it on the same profile: require the same workspace row to come back, blank and named by the document, rendering the document again over a grant URL that differs from the one that was quit, with no preview-scheme or document-named page anywhere in what the host holds. Prove the halves are live by flipping one product property at a time and requiring the run to fail: publish document workspaces to the host like ordinary ones, and stop mirroring the document onto the workspace row. Have the fixture document attempt its own egress on every load — an unattended window.open and location.href to an off-machine URL, plus an inline ICE gathering probe — and require the same baseline counts and a candidate count of zero, so the document's own attempts are measured rather than assumed. Then, as a separate phase after the close oracle has already run, bring the client window to the front, press the document's heading with a real mouse event, and require the document to report that the same press drove it to attempt a second window.open and location.href while both browser counts stay at that phase's baseline and nothing routes — the case a recent-input gate cannot distinguish from the press's own effect. Only then press the target=_blank link with a real mouse event and require both a recorded routing call that returned success and a browser count above that baseline, with the preview tab still open. Drive the preload's click policy as a unit oracle over a real document: a dispatched click, a trusted press on an external anchor, an anchor reached through what it wraps, an SVG animated href, a sibling preview link, fragment and percent-encoded fragment targets, a bare hash, and a middle click. Create a browser page located by a workspace document, handing creation a live grant URL, and require its stored url, its mirrored tab url and the written session payload all to be blank with no orca-preview string anywhere in what was written, while an ordinary page created the same way keeps the URL it was given and asks for the address bar the document page never does. Parse the written page and tab through the session schema and require the document to survive both halves. Hydrate them back and require the document page to return blank and still named — including when its page row was salvaged away and only the tab's own copy remains, and when a foreign session carried a grant URL into both rows. Drive the mirror across a page switch out of the document and back, and across a repair in which the document is the only mirrored field that differs. Name a document page from its document and require the tab to take that name, name it with an empty title and require the file, name it with a live grant URL and require the file again with no preview scheme anywhere in the written session, and require an ordinary blank browser tab beside it to still be called New Tab. Dispatch a title update out of a rendered preview's own guest and require it to reach the page state while the identity chip still reads the document's workspace-relative path. Attach a browsing guest and a workspace-document guest through the same method in one run and require the browsing one to take clicked-link routing, popup handling and auth-identity detach tracking while the document guest takes none of them, stays inside the grant it is showing, denies every window it asks for, and is dropped from the page-keyed document registry by the same teardown that frees its id for a later attach. Register a browsing guest and attach a workspace-document guest in one run against the real manager, require the one door to answer each page with the guest of its own half, and require the document page to be absent from the browsing map and from its enumeration. Drive both browsing registration entry points with a page the document half already holds and require them to register nothing, and drive the mint channel with a page the browsing half already holds and require it to refuse; and drive the offscreen one with a guest that is missing and with one already destroyed, requiring the same refusal. Arm a grab on a live preview target, drive the unregister channel at that same target in the window before the queued operation runs, and require the grab to reach the guest anyway — then drive the same sequence for an ordinary browser page and require its grab state to be disposed after all. Hold one viewport-bridge op open, queue a second behind it, swap the page's guest while that second op waits, and require the injection to land in the guest the page has then. Revoke a grant after a tool has run against its page and require that page's grab state to be cancelled and disposed. Ask a tool for a document page whose guest has not attached, require the request to park in the registration wait, attach the guest, and require the same request to arm on it; require a page nothing ever renders to answer not-ready once that wait elapses. With a document open, ask a tool for a browsing page id and require it to be answered by the browsing half or not at all, with the same channel reaching the document guest under the page it really renders. Drive open-externally for a document whose per-file owner is remote while the workspace-scoped owner is unresolved, for a runtime-owned worktree whose preview tab carries no runtime id of its own, and for a worktree that resolves no runtime owner while the tab still carries one, requiring the download route in each; and for an owner that cannot be resolved at all, and for an unknown workspace root while nothing names another host, requiring a refusal that neither opens nor downloads. Drive the headless backend with a page the document half already holds and require it to reject, destroy the window, and unregister nothing — then shut the backend down and require it still to have unregistered nothing. Navigate a bound preview guest at a second grant through both latch events and require it to stay on the grant it bound to. Mount a preview while a renderer drag is already in flight and require its guest to be click-through at the moment it is appended, not a turn later. Render the editor panel shell in each remaining tab mode and require the path header exactly where the surface does not already name itself. Drive the preview action and require a browser tab located by the document rather than an editor tab, require a second open of the same document to activate the tab it is already in, and require closing that tab to revoke its grant while a URL tab closed beside it revokes none. Publish a worktree holding a document tab and a URL tab and require only the URL tab to reach the mobile snapshot. Install the shared partition policies for a preview partition and for an ordinary browsing partition in the same run, fire each one's own will-download listener, and require the preview's to cancel while the browsing one still reaches the download router — then require the preview protocol installer to be what asks for that deny. In the same run, require the cancelled download to raise a reader-facing notice and the routed one to raise none. require the guest registry to name the bound grant for a live preview guest and nothing for a contents that is not one, has committed no document, or is gone. Drive the shell with a refusal and require one fixed sentence, still one row after three more refusals, standing beside an asset failure rather than being counted with it, gone behind the failure panel, and ignored when it names another preview's grant. Drive the main-side report gate directly for a sender that is no preview guest, a guest with no bound or a revoked grant, a genuine press Electron's webview focus flag misreports as unfocused, and non-web URLs; drive the reader-facing confirmation for accept, cancel, and a confirmed tab the browser refuses; and drive will-attach-webview in both preload directions. Run the per-owner reader, grant-containment, scheme-admission, guest-policy, and plan-routing contracts as unit oracles, including a host-reported truncation, an over-cap binary, and an out-of-worktree paired path. Drive the reader-facing component with the payloads the reader can actually produce — the entry document fails only as truncated or unreadable, a subresource additionally as a refused format — and require the asset case to leave the guest mounted. Drive the closed-tab cleanup hook, the window installer, and the grant IPC handlers directly, requiring the grant to be released when the preview tab closes, cleared at window creation and on a cross-document main-frame navigation, and refused to any sender that is not the trusted renderer. For the browser creations this gate still owns, run the unchanged contract oracle for direct create and side-preview callers with absent status, unknown capabilities, and a mixed-version host, requiring the original unsupported error or visible toast, zero RPCs, and no retained new split; hold a real navigation response beyond the 15-second client deadline after host creation and require the first RPC to return the exact host inventory page ID, one host page, and no retry; repeat reconciliation faults against headless serve and retain the separate exact-page reconciliation rollback oracle. Audit2452 removes the whole fake-effect browser-close routing suite. Active selectors and assertion references no longer select it. Its requested-worktree default close, sibling-page close and explicit missing-page typed reply alarms are intentionally retired without equivalent replacement. Prior dated receipts remain unchanged and scoped to their original sources; no fresh execution of the reduced gate, rendered browser, live remote, mobile or cross-platform validation is claimed.", "commands": [ - "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/browser/client-pages/orca-runtime-browser.test.ts src/renderer/src/runtime/web-session-tabs-sync/navigation/web-session-tabs-sync-focus-intent.test.ts src/renderer/src/runtime/web-session-tabs-sync/placement/web-session-tabs-sync-browser-tabs.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/browser/client-pages/orca-runtime-browser.test.ts src/renderer/src/runtime/web-session-tabs-sync/navigation/web-session-tabs-sync-focus-intent.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/document-preview/doc-preview-grant-registry.test.ts src/main/browser/document-preview/doc-preview-file-reader.test.ts src/main/browser/document-preview/doc-preview-guest-policy.test.ts src/main/browser/document-preview/doc-preview-failure-notice.test.ts src/shared/document-preview/doc-preview-scheme.test.ts src/renderer/src/lib/browser/documents/doc-preview-grants.test.ts src/renderer/src/components/browser-pane/workspace-doc/doc-preview-external-link-confirmation.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/sessions/partition-policies/browser-session-partition-policies.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/sessions/partition-policies/browser-session-partition-policies.test.ts src/main/browser/document-preview/doc-preview-guest-policy.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/document-preview/doc-preview-guest-policy.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx src/shared/document-preview/doc-preview-scheme.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/document-preview/doc-preview-guest-policy.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/guest-lifecycle/manager/viewport/browser-manager-annotation-bridge.test.ts src/shared/document-preview/doc-preview-scheme.test.ts src/renderer/src/components/browser-pane/workspace-doc/doc-preview-document-actions.test.ts src/renderer/src/components/browser-pane/workspace-doc/use-doc-preview-guest-tools.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/guest-lifecycle/manager/viewport/browser-manager-annotation-bridge.test.ts src/main/browser/backends/offscreen-browser-backend-lifecycle.test.ts src/main/browser/document-preview/doc-preview-guest-policy.test.ts src/shared/document-preview/doc-preview-scheme.test.ts src/renderer/src/components/browser-pane/workspace-doc/doc-preview-document-actions.test.ts src/renderer/src/components/browser-pane/workspace-doc/use-doc-preview-guest-tools.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/link-actions/LinkActionPopover.test.tsx src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/guest-lifecycle/manager/viewport/browser-manager-annotation-bridge.test.ts src/shared/document-preview/doc-preview-scheme.test.ts src/renderer/src/components/browser-pane/workspace-doc/use-doc-preview-guest-tools.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", + "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/guest-lifecycle/manager/viewport/browser-manager-annotation-bridge.test.ts src/main/browser/backends/offscreen-browser-backend-lifecycle.test.ts src/main/browser/document-preview/doc-preview-guest-policy.test.ts src/shared/document-preview/doc-preview-scheme.test.ts src/renderer/src/components/browser-pane/workspace-doc/use-doc-preview-guest-tools.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/link-actions/LinkActionPopover.test.tsx", "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/guest-lifecycle/manager/viewport/browser-manager-annotation-bridge.test.ts src/main/browser/backends/offscreen-browser-backend-lifecycle.test.ts src/main/browser/document-preview/doc-preview-guest-policy.test.ts src/shared/document-preview/doc-preview-scheme.test.ts src/renderer/src/components/browser-pane/workspace-doc/use-doc-preview-guest-tools.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-page-conversion.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-conversion-publish.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", "SKIP_BUILD=1 ORCA_E2E_WEB_CLIENT=1 ORCA_E2E_FORCE_HEADFUL=1 pnpm exec playwright test tests/e2e/paired-preview-address-bar-convergence.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1 --reporter=list", @@ -4473,22 +4398,19 @@ "src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts", "src/main/browser/guest-lifecycle/manager/viewport/browser-manager-annotation-bridge.test.ts", "src/main/browser/backends/offscreen-browser-backend-lifecycle.test.ts", - "src/renderer/src/components/browser-pane/workspace-doc/doc-preview-document-actions.test.ts", "src/renderer/src/components/browser-pane/workspace-doc/use-doc-preview-guest-tools.test.ts", "src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", "src/shared/document-preview/doc-preview-scheme.test.ts", "src/renderer/src/lib/browser/documents/doc-preview-grants.test.ts", "src/renderer/src/components/browser-pane/workspace-doc/doc-preview-external-link-confirmation.test.ts", "src/renderer/src/components/link-actions/LinkActionPopover.test.tsx", - "src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts", "src/renderer/src/store/slices/browser/pages/browser-page-conversion.test.ts", "src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-conversion-publish.test.ts", "tests/e2e/paired-remote-html-preview-local-render.spec.ts", "tests/e2e/paired-preview-address-bar-convergence.spec.ts", "tests/e2e/paired-browser-create-navigation-deadline.spec.ts", "tests/e2e/paired-browser-creation-reconciliation-failure.spec.ts", - "src/renderer/src/runtime/web-session-tabs-sync/navigation/web-session-tabs-sync-focus-intent.test.ts", - "src/renderer/src/runtime/web-session-tabs-sync/placement/web-session-tabs-sync-browser-tabs.test.ts" + "src/renderer/src/runtime/web-session-tabs-sync/navigation/web-session-tabs-sync-focus-intent.test.ts" ], "assertionRefs": [ { @@ -4555,12 +4477,6 @@ "a document navigation report leaves its URL blank, its title standing and nothing loading; its session excludes preview URLs" ] }, - { - "file": "src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts", - "assertions": [ - "keeps a workspace document out of published tab groups as well as the tab list" - ] - }, { "file": "src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", "assertions": [ @@ -4584,13 +4500,6 @@ "headed and headless hosts preserve the unrelated editor and terminal without local fallback" ] }, - { - "file": "src/renderer/src/runtime/web-session-tabs-sync/placement/web-session-tabs-sync-browser-tabs.test.ts", - "assertions": [ - "replays a pre-response browser snapshot after canonical placement and focus are known", - "reuses a local browser workspace that already points at the host page" - ] - }, { "file": "src/renderer/src/runtime/web-session-tabs-sync/navigation/web-session-tabs-sync-focus-intent.test.ts", "assertions": [ @@ -4600,66 +4509,6 @@ } ], "evidenceRuns": [ - { - "date": "2026-08-27", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.test.tsx src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "result": "failed", - "durationSeconds": 7, - "summary": "The adversarial pass answered the request for its own group-projection probe after this round landed, and it had measured a third observable this test was missing: the held-back group also has to leave the published layout tree, or the phone renders a split whose second pane can never hold anything. Adopted as a fourth assertion and re-run against the same sole delta, which now fails on the dangling-reference check and, with that check blinded, on the layout alone — group-left and group-right against the group-right the clean tree publishes. The two probes agreed on everything else, including that the tab list is unchanged under this mutant, which is why an assertion reading only the tab list cannot reach the site at all." - }, - { - "date": "2026-08-27", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.test.tsx src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "result": "passed", - "durationSeconds": 3, - "summary": "The adversarial pass's four coverage findings, landed and pinned: 58/58. The third url door now keeps a document page blank and names it by its document, the group projection holds a document back from published groups as well as from the tab list, the pane's focus handoff is pinned in the widening direction as well as the narrowing one, and the handoff is re-offered when the window takes focus back." - }, - { - "date": "2026-08-27", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.test.tsx src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "result": "failed", - "durationSeconds": 3, - "summary": "Three sole-delta mutants on the third url door, each failing only the new store test: committing the reported url onto a document page, dropping the document from the title normalizer there (which renames the tab New Tab, since a blank url is what that fallback reads), and marking a blank document page loading. The ordinary-page half of the same test passes under all three, so the door is pinned as a document-only refusal rather than as a door that writes nothing." - }, - { - "date": "2026-08-27", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.test.tsx src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "result": "failed", - "durationSeconds": 3, - "summary": "Two sole-delta mutants on the mobile publish boundary. Dropping the document from the group projection's browser ids fails only the new grouped test — the tab list stays correct because the per-tab guard still refuses the tab, and what breaks is a published group whose order and active tab name a tab the phone is never sent. This is the survivor the adversarial pass reported: it survives the whole suite without this test, because no other test in it has tab groups. Dropping the per-tab guard instead fails only the ungrouped test, so the two halves of the boundary are pinned separately." - }, - { - "date": "2026-08-27", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.test.tsx src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "result": "failed", - "durationSeconds": 3, - "summary": "Three sole-delta mutants widening the focus handoff, the direction the adversarial pass found uncovered: dropping the page-activity half, dropping the active-tab-type half, and dropping the active-browser-tab half each fail exactly one of the pane's refusals — the inactive page, the terminal in front, and the other browser tab respectively. The presence half of that test passes under all three, so a pane that had stopped offering focus at all would still fail rather than pass the refusals vacuously." - }, - { - "date": "2026-08-27", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.test.tsx src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx", - "result": "failed", - "durationSeconds": 3, - "summary": "One sole-delta mutant dropping the window-focus re-offer: the guest is focused once at mount and never again after the window comes back, which is the desktop gap behind it — another app taking the front leaves the preview's only route out shut until the pane remounts. It fails only the new re-offer test, and the refusing-preview case beside it stays green, so the re-offer is pinned as gated rather than unconditional." - }, { "date": "2026-08-27", "runner": "local", @@ -4937,7 +4786,21 @@ "D01 final candidate whole-registration policy removes retired module selectors and obsolete assertion descriptions prospectively. Existing unaffected receipts retain their original scope; reduced selectors have no new execution or equivalent replacement claim. Retired named modules: [\"src/preload/doc-preview-link-interception.test.ts\",\"src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.failure-message.test.tsx\"]. Retired compound assertion refs, preserved as historical data: [{\"file\":\"src/renderer/src/components/browser-pane/workspace-doc/doc-preview-external-link-confirmation.test.ts\",\"assertions\":[\"an external preview link shows the reader its exact destination and becomes a browser tab only after confirmation\",\"a declined confirmation opens nothing, and a confirmed tab that is refused or fails outright surfaces instead of being dropped\"]}]", "Audit2452 removes the whole fake-effect browser-close routing suite. Active selectors and assertion references no longer select it. Its requested-worktree default close, sibling-page close and explicit missing-page typed reply alarms are intentionally retired without equivalent replacement. Prior dated receipts remain unchanged and scoped to their original sources; no fresh execution of the reduced gate, rendered browser, live remote, mobile or cross-platform validation is claimed. Retired assertion reference: {\"file\":\"src/renderer/src/hooks/useIpcEvents-close-routing-browser-pages.test.ts\",\"assertions\":[\"closing an absent renderer page returns browser_tab_not_found instead of an untyped failure\"]}", "Audit3108: doc-preview-grants.test.ts now retains only the stale grant-rejection race: a late rejected grant request must not evict a newer grant registry entry, witnessed by later revocation of grant-2. Retire stable minted-location and outside-workspace POSIX/Windows request-projection alarms without replacement. The direct nonempty grant selector remains unchanged; no real grant-server/file authorization, SSH/HTML delivery or native-focus result is claimed.", - "File/document owner layout retires the complete workspace-doc-address-input unit suite because its sole mixed case asserts internal catalog-enumeration work. The current-workspace HTML-resolution alarm is lost; no equivalent replacement coverage or pass for the reduced unit selector is claimed. Historical receipts and all remaining selectors/assertions retain their original scope." + "File/document owner layout retires the complete workspace-doc-address-input unit suite because its sole mixed case asserts internal catalog-enumeration work. The current-workspace HTML-resolution alarm is lost; no equivalent replacement coverage or pass for the reduced unit selector is claimed. Historical receipts and all remaining selectors/assertions retain their original scope.", + "Module-layout wave2 intentionally retires complete prohibited owning registrations in src/renderer/src/components/browser-pane/workspace-doc/doc-preview-document-actions.test.ts. Lost alarms: A resolved remote file owner taking precedence over an unresolved workspace owner would lose its routing alarm. A project published on two hosts refusing to open an ambiguous local copy would lose its refusal alarm. An unresolved document refusing both local open and remote download, and including its path in the refusal, would lose the existing alarm. An unknown workspace root preventing an accidental local document open would lose its guard alarm. A restored document using its recorded runtime owner when the worktree resolves none would lose its existing fallback alarm. A restored tab without a recorded owner consulting the resolved worktree owner would lose its existing fallback alarm. No equivalent replacement coverage or reduced-selector pass is claimed.", + "Audit 3301 removes the caller-chat-target precedence over host selection example from web-session-tabs-sync-focus-intent.test.ts. The snapshot-before-RPC replay and split-sibling-first exact-leaf focus cases remain unchanged and match the existing assertion reference. Preserve current selectors, assertion references, unrelated active receipts and complete archived history. These mocked state-composition survivors provide no equivalent replacement, rendered, native, network or fresh execution proof.", + "Audit3335 retires the complete three-case browser-tabs snapshot assembly suite: canonical snapshot replay/placement/focus, local host-page adoption and unstamped host echo leaving a local page untouched alarms are intentionally lost without equivalent replacement. The surviving focused selector is unexecuted in this source composition. Unrelated dated receipts keep their original scope; no fresh runtime/network, rendered UI, mobile, mixed-version or cross-platform validation is claimed.", + "Audit3342 retires the complete mobile editor/diff tab-publication projection suite: editor/diff serialization, workspace-document privacy withholding, pending/focus and capability/options projections are intentionally lost without equivalent replacement. The surviving focused selectors are unexecuted in this source composition. Six complete compound macOS receipts whose command fields select the changed source are retired verbatim as history; their other selected tests receive no promoted evidence. Other dated receipts keep their original scope; no fresh runtime/UI/mobile/mixed-version or cross-platform validation is claimed.", + "Audit3342 historical original commands object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\"", + "Audit3342 historical original commands object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/link-actions/LinkActionPopover.test.tsx src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts\"", + "Audit3342 historical original testFiles object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n\"src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts\"", + "Audit3342 historical original assertionRefs object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n{\n \"file\": \"src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts\",\n \"assertions\": [\n \"keeps a workspace document out of published tab groups as well as the tab list\"\n ]\n }", + "Audit3342 historical original evidenceRuns object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n{\n \"date\": \"2026-08-27\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.test.tsx src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\",\n \"result\": \"failed\",\n \"durationSeconds\": 7,\n \"summary\": \"The adversarial pass answered the request for its own group-projection probe after this round landed, and it had measured a third observable this test was missing: the held-back group also has to leave the published layout tree, or the phone renders a split whose second pane can never hold anything. Adopted as a fourth assertion and re-run against the same sole delta, which now fails on the dangling-reference check and, with that check blinded, on the layout alone — group-left and group-right against the group-right the clean tree publishes. The two probes agreed on everything else, including that the tab list is unchanged under this mutant, which is why an assertion reading only the tab list cannot reach the site at all.\"\n }", + "Audit3342 historical original evidenceRuns object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n{\n \"date\": \"2026-08-27\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.test.tsx src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\",\n \"result\": \"passed\",\n \"durationSeconds\": 3,\n \"summary\": \"The adversarial pass's four coverage findings, landed and pinned: 58/58. The third url door now keeps a document page blank and names it by its document, the group projection holds a document back from published groups as well as from the tab list, the pane's focus handoff is pinned in the widening direction as well as the narrowing one, and the handoff is re-offered when the window takes focus back.\"\n }", + "Audit3342 historical original evidenceRuns object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n{\n \"date\": \"2026-08-27\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.test.tsx src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\",\n \"result\": \"failed\",\n \"durationSeconds\": 3,\n \"summary\": \"Three sole-delta mutants on the third url door, each failing only the new store test: committing the reported url onto a document page, dropping the document from the title normalizer there (which renames the tab New Tab, since a blank url is what that fallback reads), and marking a blank document page loading. The ordinary-page half of the same test passes under all three, so the door is pinned as a document-only refusal rather than as a door that writes nothing.\"\n }", + "Audit3342 historical original evidenceRuns object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n{\n \"date\": \"2026-08-27\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.test.tsx src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\",\n \"result\": \"failed\",\n \"durationSeconds\": 3,\n \"summary\": \"Two sole-delta mutants on the mobile publish boundary. Dropping the document from the group projection's browser ids fails only the new grouped test — the tab list stays correct because the per-tab guard still refuses the tab, and what breaks is a published group whose order and active tab name a tab the phone is never sent. This is the survivor the adversarial pass reported: it survives the whole suite without this test, because no other test in it has tab groups. Dropping the per-tab guard instead fails only the ungrouped test, so the two halves of the boundary are pinned separately.\"\n }", + "Audit3342 historical original evidenceRuns object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n{\n \"date\": \"2026-08-27\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.test.tsx src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\",\n \"result\": \"failed\",\n \"durationSeconds\": 3,\n \"summary\": \"Three sole-delta mutants widening the focus handoff, the direction the adversarial pass found uncovered: dropping the page-activity half, dropping the active-tab-type half, and dropping the active-browser-tab half each fail exactly one of the pane's refusals — the inactive page, the terminal in front, and the other browser tab respectively. The presence half of that test passes under all three, so a pane that had stopped offering focus at all would still fail rather than pass the refusals vacuously.\"\n }", + "Audit3342 historical original evidenceRuns object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n{\n \"date\": \"2026-08-27\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.test.tsx src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx\",\n \"result\": \"failed\",\n \"durationSeconds\": 3,\n \"summary\": \"One sole-delta mutant dropping the window-focus re-offer: the guest is focused once at mount and never again after the window comes back, which is the desktop gap behind it — another app taking the front leaves the preview's only route out shut until the pane remounts. It fails only the new re-offer test, and the refusing-preview case beside it stays green, so the re-offer is pinned as gated rather than unconditional.\"\n }" ], "demotionRule": "Demote if a paired HTML preview creates a browser workspace on either side, renders from anything other than the orca-preview scheme, serves a read the host reported as truncated or over-cap, serves a document without the self-only content security policy, lets the preview session carry an off-machine request, reads an SSH path that canonicalizes outside its grant root, steals focus from the source editor when it opens, removes unrelated editor or terminal state on close, hides a document that rendered because one subresource was refused, leaves a grant readable after the tab or renderer that owns it is gone, mints one for a sender that is not the trusted renderer, opens a browser tab for a navigation the document started with no one at the keyboard, or lets the guest gather an ICE candidate; or if a paired browser creation this gate still owns produces duplicate client or host identities or loses its requested split." }, @@ -6067,6 +5930,9 @@ "Keep missing-proof mixed-version behavior identical to the incumbent client path." ], "knownGaps": [ + "NEXT65 current scope qualification: The NEXT65 knownGaps entries below govern the changed selectors and qualify any broader coverage implication in this gate’s unchanged oracle/coverageNotes narratives. Those narratives and preserved dated evidenceRuns retain their historical text and original exact execution scopes only; no fresh execution, transferred pass or equivalent replacement coverage is claimed. Upstream case removals remain upstream; original NEXT65 proposal descriptions grant no duplicate retirement credit.", + "NEXT65 active selector scope reduction (including directory-selected whole-file retirements): src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts. Remove complete registrations or registrar files within the selected scope for src/renderer/src/components/terminal-pane/pty-connection/reattach/pty-connection-daemon-snapshot-replay.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/emulation/pty-connection-mode-2031-subscriptions.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/geometry/pty-connection-visibility-resume-size.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/reattach/pty-connection-stale-daemon-snapshot-replay.spec.ts. Intentionally lose these named regression alarms without replacement: catches a subscribed pane up once per mode change across repeated reconnects — Mode2031 theme reporting catch-up/deduplication across repeated reconnects loses this direct protocol example.; defers to the viewer holding the grid, then catches up once on release — Held-grid viewer deferral and one catch-up/current-mode resending on release lose this direct protocol example.; repairs grid drift with a trailing probe when output stops inside the settled interval — A trailing drift probe after the last output frame loses this direct alarm.; skips foreground grid drift repair while mobile owns the PTY without a fit override — Mobile driver ownership suppressing foreground drift repair without override loses this direct alarm.; reports desktop geometry without resizing while a mobile-fit override is active — Desktop geometry reporting without resizing a mobile-owned grid loses this direct alarm.; defers a remote-desktop viewport claim until structural replay completes — Remote-desktop viewport claim waiting for structural replay completion loses this direct alarm.; skips observed desktop reassertion while mobile owns the PTY without a fit override — Observed desktop reassertion suppression under mobile ownership loses this direct alarm.; queues re-asserted resizes while pane resize holds are active — Resize hold release flushing the latest reasserted grid loses this direct alarm.; reasserts a remote grid only when visible (%s) — Visible-only remote grid reassertion loses its visible and hidden examples.; claims a focused visible remote mirror once when its passive fit hold arrives — Focused visible passive mirror claiming once, with unfocused and late repeat suppression, loses this direct sequence alarm.; does NOT re-assert while a mobile-fit override parks the PTY at phone dims — Phone fit hold suppressing visibility-resume PTY reassertion loses this direct alarm.; does NOT forward when the pane is hidden again before getSize resolves (stale hop) — Late size lookup after re-hide refusing a hidden-tab SIGWINCH loses this direct adverse-ordering alarm.; clears the captured pen for a normal-buffer fallback reattach — Fallback normal-buffer reattach clearing captured pen and dirty background loses this direct example.; waits for a recovered destination fit before forwarding its grid or live output — Recovered destination fitting before forwarding grid or live output loses this direct example.; suppresses the deferred reattach grid push when mobile claims the PTY while hidden — Mobile takeover while hidden suppressing deferred reattach grid forwarding loses this direct example.; drops stale callbacks but delivers fresh replacement output after an old replay clear — Fresh replacement output winning over stale callbacks after old replay clear loses this direct example.. Surviving parent statements and sibling registrations are preserved, but these reduced parent selectors have no fresh execution or transferred historical pass. Unrelated complete dated receipts retain only their original exact scopes; no equivalent replacement, rendered UI, provider, mobile, or cross-platform coverage is claimed.", + "NEXT65 historical original active parent-selector fields (verbatim native JSON values; not current coverage):\ncommands: [\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/daemon/shell-readiness/testing/terminal-shell-recovery-barrier.test.ts src/main/daemon/sessions/testing/session-shell-recovery.test.ts src/main/daemon/sessions/testing/session.test.ts src/main/daemon/terminal-host/testing/terminal-host-concurrent-create.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts src/main/daemon/history/restoration/testing/daemon-restore-scrollback-depth.test.ts src/main/daemon/history/restoration/testing/terminal-checkpoint-serializer.test.ts src/main/providers/agent-foreground-process.test.ts src/main/runtime/construction/orca-runtime.test.ts src/main/runtime/terminal/layout/mobile-presence-lock.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/shared/terminal/protocol/escape/terminal-partial-escape-tail.test.ts src/shared/terminal/protocol/escape/terminal-partial-escape-tail.fuzz.test.ts --reporter=dot\",\n \"pnpm exec vitest run --config config/vitest.config.ts tests/e2e/cross-version-wire/cross-version-terminal-wire.unit.test.ts --reporter=dot\",\n \"pnpm exec electron-vite build --mode e2e\",\n \"SKIP_BUILD=1 pnpm exec playwright test tests/e2e/terminal-hidden-child-tui-kill-mode-reset.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\"\n ]\ntestFiles: [\n \"src/main/daemon/shell-readiness/testing/terminal-shell-recovery-barrier.test.ts\",\n \"src/main/daemon/sessions/testing/session-shell-recovery.test.ts\",\n \"src/main/daemon/sessions/testing/session.test.ts\",\n \"src/main/daemon/terminal-host/testing/terminal-host-concurrent-create.test.ts\",\n \"src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts\",\n \"src/main/daemon/history/restoration/testing/daemon-restore-scrollback-depth.test.ts\",\n \"src/main/daemon/history/restoration/testing/terminal-checkpoint-serializer.test.ts\",\n \"src/main/providers/agent-foreground-process.test.ts\",\n \"src/main/runtime/construction/orca-runtime.test.ts\",\n \"src/main/runtime/terminal/layout/mobile-presence-lock.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"src/shared/terminal/protocol/escape/terminal-partial-escape-tail.test.ts\",\n \"src/shared/terminal/protocol/escape/terminal-partial-escape-tail.fuzz.test.ts\",\n \"tests/e2e/cross-version-wire/cross-version-terminal-wire.unit.test.ts\",\n \"tests/e2e/terminal-hidden-child-tui-kill-mode-reset.spec.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"src/main/daemon/sessions/testing/session-shell-recovery.test.ts\",\n \"assertions\": [\n \"post-kill shell output survives into the normalized snapshot instead of the discarded alt buffer\",\n \"a snapshot taken during a split escape keeps the pending tail intact and stale proof is revoked by the completing bytes\"\n ]\n },\n {\n \"file\": \"src/shared/terminal/protocol/escape/terminal-partial-escape-tail.fuzz.test.ts\",\n \"assertions\": [\n \"the pending tail this gate threads over the wire folds identically at every code-unit split of the combined stream, including boundaries landing inside oscEsc/stringEsc\",\n \"the split sweep runs over an alphabet carrying CAN, SUB, doubled ESC inside OSC/DCS/SOS/PM/APC, BEL, C1 ST, NUL, DEL, intermediates, CJK, astral, and lone surrogates\"\n ]\n },\n {\n \"file\": \"tests/e2e/terminal-hidden-child-tui-kill-mode-reset.spec.ts\",\n \"assertions\": [\n \"normal exit and cleanup-free SIGKILL both restore a visible clean shell marker\",\n \"renderer logical buffer is normal and mouse tracking is disabled after host-proven recovery\",\n \"real pointer input writes no SGR mouse report to the surviving shell\",\n \"an unrelated pane remains live\"\n ]\n }\n ]", "Audit3077 deletes the Kitty restore/reset integration suite and its registrar. The input-and-repaint driver remains populated; the retired emission/mirror/host-request alarms have no equivalent replacement.", "Audit3061 retires the park-model supplied snapshot suite and nominal mode, cursor, focus, geometry and remote resume metadata variants. Their distinct alarms are intentionally lost; six retained mode/remote cases preserve selected tail-order, authority and parse-readiness boundaries without equivalent replacement. Existing selectors and dated evidence retain their original scope.", "Audit3053 reduces hidden-replay coverage by retiring nominal overlap, resize, cursor metadata and standalone stalled-restore variants. Timeout, overflow, identity/generation fences and retained live-output coordination remain; the removed alarms are intentionally lost without equivalent replacement. Existing commands, assertion references and dated evidence retain their original scope.", @@ -6364,7 +6230,7 @@ "providers": ["local", "daemon", "ssh", "runtime"], "coveredPlatforms": ["macos"], "coveredProviders": ["local", "daemon", "ssh", "runtime"], - "coverageNotes": "Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit1904 reduces persistence-pty-binding-reconciliation from six to four definitions, intentionally losing legacy remap-load and first-binding projection alarms. Current selector/testFile remains valid, with no selected-source assertionRef or active matching receipt. The six unchanged close/continuity receipts keep their exact original scope; no new broad gate or replacement evidence is claimed. Historical prior account (preserved verbatim): Audit1683 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1674 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1630 removes low-value Git, GitHub/GitLab and IPC projections, argument inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained cancellation, ownership, authorization, filesystem and SQLite boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1627 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Live macOS Electron tests prove exact local PTY disappearance after parked-tab close and detached-pgid descendant death after agent close. A deterministic final-pane interleaving now proves durable tab retirement commits before externally owned PTY teardown can publish graph loss, and preserves an unrelated live canary through duplicate exit retirement. Deterministic tests also cover final-pane CLI close durability and same-incarnation handle continuity; persisted-empty restart suppression remains historical Electron evidence, alongside replacement and hard graph-loss stale fencing, preallocated-handle supersession, daemon and SSH routing, local/daemon pending-snapshot ownership across natural exit, stale-root descendant-signal suppression, graceful-to-immediate kill upgrades, duplicate-kill completion sharing, locale-stable bounded/fresh/coalesced process-table reads, deadline-safe successor scans, cycle-safe linear descendant traversal, target-only escalation indexing, 32-wide bulk teardown, source-scan timestamp identity, same-second PID ambiguity, ordinary runtime close ownership, unified-only hydration, split ownership, pane detach transfer, restart alias hydration, and late-hook suppression; live Linux, Windows, WSL, SSH, and remote-runtime process evidence remains pending. A paired macOS Electron journey (real attached-window desktop host plus a separate real paired desktop client, isolated profiles) covers the inverse authority direction for host-created terminals: a renderer graph sync must not retire a tab that `orca terminal create` made. The retained paired journey covers the incident shape the real CLI produces - a repo's FIRST host-created terminal, since src/cli/handlers/terminal.ts sends no clientMutationId. The repeated target-after-unrelated-terminal journey was retired; its separate ordering alarm is no longer provided. An earlier reading of this gate called a preceding host-created terminal and a `clientMutationId` protective; main-process instrumentation refuted that. The renderer's stale session write deleted the host tab from persistence in every variant, and only the delete's timing relative to the measured sync differed, so those rows were false negatives of a single-sync oracle. The defect was in persistence: persistPtyBinding did not raise the repo's terminal topology fence for the first host-admitted tab, leaving the renderer's pre-create tab list free to replay over it. Elapsed time and paired-client mirroring never decided anything. A windowless `orca serve` parity arm runs the identical oracle and passes on both the merge-base and the branch, confirming that topology does not exhibit the defect (the gate it turns on is window-conditioned) and that making the host binding unconditional did not regress it. All of this is macOS-local only. The reported incident occurred on a physical Windows host; we did not run against one. The claim that the mechanism is platform-independent rests on the authoritative-window gate and publication-epoch inheritance being OS-agnostic, not on Windows evidence, so no ConPTY, Windows window-lifecycle, update, or sleep behavior is covered here. The synthetic default-tabs unit suite was retired: its explicit-empty/default-tab assertions no longer supply unit evidence. This retirement supplies no new persisted-restart, runtime-routing, cross-platform, or mobile evidence; existing historical runs and counts remain historical. The test-value audit removes the isolated re-retirement-token/epoch, activity-cutoff, idle-reattach and sibling-restore examples. The cited exact retirement and chained-detach cases remain unchanged, alongside closed-tab revival fencing and alias churn bounds. Their retained evidence is not equivalent coverage for every removed permutation; historical execution evidence is unchanged. The test-value audit removed shared-owner snapshot/cold-restore reference examples, a direct absent-tab PTY-index update, caller-supplied host-owned teardown boolean/no-dispatch, and a single local-provider rejection example. It also removed hand-built detach-retention comparator examples for different runs, handles, provider identities, and handle-less rows without independent identity ingress. Their specific snapshot, missing-tab, host-decision, rejection-count, and comparator alarms are lost. Current exact authority/ordering and chained-detach cases remain retained; they do not establish equivalent coverage for the removed examples. Historical commands, counts, results, and red-green narratives remain historical. The test-value audit retires terminals-explicit-empty-hydration.test.ts in full: its direct git/folder empty-tombstone assertions and literal-flag auto-create helper check are lost. The store test never mounted the initial-terminal effect or performed a persisted restart. The audit also removes terminal-tab-retirement.test.ts pure ownership/alias/routing plan inventories and sleeping-record map assertions; its former 100-tab scan-count case was subsequently retired too; no assertion remains in that suite. These retained and historical cases do not establish equivalent tombstone, default-create, provider teardown, cross-platform, or mobile coverage. Historical commands, results, counts, and red-green narratives remain historical. The subsequent test-value audit deletes the remaining terminal-tab-retirement.test.ts suite. Its 100-tab case asserted only returned plan count and one outer scan per ownership store; it never inspected per-tab plans or provider teardown. Those direct cardinality/work-count alarms are intentionally lost. Historical executed commands, results, counts and red-green narratives remain historical; no equivalent replacement or new runtime, platform or mobile evidence is claimed. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1392: src/main/agent-hooks/server-pane-authority.test.ts reduced. Retires one duplicate-transfer no-op listener count and latest pty/timestamp callback fixture. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result.", + "coverageNotes": "Audit3323 (reconciled source audit3320) intentionally retires seven low-value renderer authority/retirement examples: retires one pane, clears resume authority, and rejects late status without harming siblings — Late status reviving a retired pane, sibling damage, or resume authority left behind.; can retire live pane authority while retaining its sleeping session — Retiring live authority accidentally dropping a retained sleeping session.; keeps a physical pane routed through chained detaches until its current owner closes — Chained detach alias routing broken after original owner closes, or alias survives final close.; forgets routing aliases for purged tabs — Purged-tab routing aliases lingering.; retires split, relay, deferred, and pending sessions for a parked tab — Split, relay, deferred or pending session omitted from teardown, sleeping-record sibling damaged, parked disposer skipped.; retires parked ownership before teardown and sweeps published state before unified close — Parked cleanup/provider teardown/state removal/sweep/unified-close ordering changes.; starts mixed provider teardown and classifies both rejection kinds after synchronous retirement — Mixed teardown failures blocking retirement, or local/runtime warning counts misclassified.. Remove the exact-pane-retirement and chained-detach assertion references because their source cases are gone. Other retained cases do not replace these alarms. Preserve all dated evidenceRuns and prior history with their original source scope; no fresh execution or historical import-closure equivalence is claimed. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit1904 reduces persistence-pty-binding-reconciliation from six to four definitions, intentionally losing legacy remap-load and first-binding projection alarms. Current selector/testFile remains valid, with no selected-source assertionRef or active matching receipt. The six unchanged close/continuity receipts keep their exact original scope; no new broad gate or replacement evidence is claimed. Historical prior account (preserved verbatim): Audit1683 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1674 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1630 removes low-value Git, GitHub/GitLab and IPC projections, argument inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained cancellation, ownership, authorization, filesystem and SQLite boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1627 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Live macOS Electron tests prove exact local PTY disappearance after parked-tab close and detached-pgid descendant death after agent close. A deterministic final-pane interleaving now proves durable tab retirement commits before externally owned PTY teardown can publish graph loss, and preserves an unrelated live canary through duplicate exit retirement. Deterministic tests also cover final-pane CLI close durability and same-incarnation handle continuity; persisted-empty restart suppression remains historical Electron evidence, alongside replacement and hard graph-loss stale fencing, preallocated-handle supersession, daemon and SSH routing, local/daemon pending-snapshot ownership across natural exit, stale-root descendant-signal suppression, graceful-to-immediate kill upgrades, duplicate-kill completion sharing, locale-stable bounded/fresh/coalesced process-table reads, deadline-safe successor scans, cycle-safe linear descendant traversal, target-only escalation indexing, 32-wide bulk teardown, source-scan timestamp identity, same-second PID ambiguity, ordinary runtime close ownership, unified-only hydration, split ownership, pane detach transfer, restart alias hydration, and late-hook suppression; live Linux, Windows, WSL, SSH, and remote-runtime process evidence remains pending. A paired macOS Electron journey (real attached-window desktop host plus a separate real paired desktop client, isolated profiles) covers the inverse authority direction for host-created terminals: a renderer graph sync must not retire a tab that `orca terminal create` made. The retained paired journey covers the incident shape the real CLI produces - a repo's FIRST host-created terminal, since src/cli/handlers/terminal.ts sends no clientMutationId. The repeated target-after-unrelated-terminal journey was retired; its separate ordering alarm is no longer provided. An earlier reading of this gate called a preceding host-created terminal and a `clientMutationId` protective; main-process instrumentation refuted that. The renderer's stale session write deleted the host tab from persistence in every variant, and only the delete's timing relative to the measured sync differed, so those rows were false negatives of a single-sync oracle. The defect was in persistence: persistPtyBinding did not raise the repo's terminal topology fence for the first host-admitted tab, leaving the renderer's pre-create tab list free to replay over it. Elapsed time and paired-client mirroring never decided anything. A windowless `orca serve` parity arm runs the identical oracle and passes on both the merge-base and the branch, confirming that topology does not exhibit the defect (the gate it turns on is window-conditioned) and that making the host binding unconditional did not regress it. All of this is macOS-local only. The reported incident occurred on a physical Windows host; we did not run against one. The claim that the mechanism is platform-independent rests on the authoritative-window gate and publication-epoch inheritance being OS-agnostic, not on Windows evidence, so no ConPTY, Windows window-lifecycle, update, or sleep behavior is covered here. The synthetic default-tabs unit suite was retired: its explicit-empty/default-tab assertions no longer supply unit evidence. This retirement supplies no new persisted-restart, runtime-routing, cross-platform, or mobile evidence; existing historical runs and counts remain historical. The test-value audit removes the isolated re-retirement-token/epoch, activity-cutoff, idle-reattach and sibling-restore examples. The cited exact retirement and chained-detach cases remain unchanged, alongside closed-tab revival fencing and alias churn bounds. Their retained evidence is not equivalent coverage for every removed permutation; historical execution evidence is unchanged. The test-value audit removed shared-owner snapshot/cold-restore reference examples, a direct absent-tab PTY-index update, caller-supplied host-owned teardown boolean/no-dispatch, and a single local-provider rejection example. It also removed hand-built detach-retention comparator examples for different runs, handles, provider identities, and handle-less rows without independent identity ingress. Their specific snapshot, missing-tab, host-decision, rejection-count, and comparator alarms are lost. Current exact authority/ordering and chained-detach cases remain retained; they do not establish equivalent coverage for the removed examples. Historical commands, counts, results, and red-green narratives remain historical. The test-value audit retires terminals-explicit-empty-hydration.test.ts in full: its direct git/folder empty-tombstone assertions and literal-flag auto-create helper check are lost. The store test never mounted the initial-terminal effect or performed a persisted restart. The audit also removes terminal-tab-retirement.test.ts pure ownership/alias/routing plan inventories and sleeping-record map assertions; its former 100-tab scan-count case was subsequently retired too; no assertion remains in that suite. These retained and historical cases do not establish equivalent tombstone, default-create, provider teardown, cross-platform, or mobile coverage. Historical commands, results, counts, and red-green narratives remain historical. The subsequent test-value audit deletes the remaining terminal-tab-retirement.test.ts suite. Its 100-tab case asserted only returned plan count and one outer scan per ownership store; it never inspected per-tab plans or provider teardown. Those direct cardinality/work-count alarms are intentionally lost. Historical executed commands, results, counts and red-green narratives remain historical; no equivalent replacement or new runtime, platform or mobile evidence is claimed. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1392: src/main/agent-hooks/server-pane-authority.test.ts reduced. Retires one duplicate-transfer no-op listener count and latest pty/timestamp callback fixture. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result.", "motivatingLinks": [ "https://linear.app/stably/issue/STA-4327", "https://github.com/stablyai/orca/pull/14590", @@ -6373,7 +6239,7 @@ "https://github.com/stablyai/orca/issues/14524" ], "invariant": "Close permanently removes the owned provider session, agent descendants, persisted tab/layout authority, and resume authority even when no TerminalPane is mounted; final-pane CLI close commits durable tab retirement before PTY stop can publish graph loss, does not acknowledge before that retirement, and treats the later exit retirement as idempotent. Workspace-wide CLI close applies that same durable contract to every terminal in exactly one worktree, including pinned and persisted-only surfaces, without touching sibling-worktree PTYs or resume records. A persisted explicit-empty state prevents initial-tab fallback from repopulating the workspace after reload or restart. A handle remains valid while the same provider-attested PTY incarnation survives renderer reload or re-key, and becomes stale without adopting a replacement incarnation. A terminating id remains reserved through natural exit, duplicate callers await the same completion, and immediate teardown upgrades any graceful request without signalling a recycled PID or a descendant tree after root ownership is lost; process-table work is locale-stable, bounded, fresh for each post-start request, same-turn coalesced, and begins within the requesting caller's deadline, including bulk worktree cleanup; detach and park preserve ownership; aliases prevent a detached agent's immutable physical pane key from being retired with its former tab.", - "oracle": "Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit1904 reduces persistence-pty-binding-reconciliation from six to four definitions, intentionally losing legacy remap-load and first-binding projection alarms. Current selector/testFile remains valid, with no selected-source assertionRef or active matching receipt. The six unchanged close/continuity receipts keep their exact original scope; no new broad gate or replacement evidence is claimed. Historical prior account (preserved verbatim): Audit1683 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Audit1674 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Capture exact tab, pane, PTY, handle, incarnation, and persisted layout identities. Final-pane terminal.close must invoke one durability-acknowledged tab retirement before exact PTY teardown; controlled PTY exit and graph removal afterward must remain idempotent, omit the target from persistence and provider inventory, and leave an unrelated canary handle live. terminal.closeAll must force-retire every pinned and unpinned target surface, clear its persisted agent-resume and incarnation records, await authoritative PTY exit, preserve a sibling worktree's tab, PTY, and resume authority, and return an unverifiable failure instead of claiming exit when the owning host does not confirm a stop. The ordinary path stays pending until the persisted row is removed and never falls back to the fire-and-forget pane event; reload/restart must keep the explicitly emptied worktree at zero terminal tabs and provider sessions. Reloading the renderer with the same tab/pane/PTY/incarnation must keep the handle readable; changing only the incarnation behind the same PTY id, losing the authoritative graph, or superseding the renderer handle with a preallocated handle must reject the old handle with terminal_handle_stale. Parked-close tests prove the exact PTY disappears; descendant/process tests keep natural exits reserved, upgrade teardown safely, bound/coalesce process-table work, and protect recycled identities.", + "oracle": "Audit3323 (reconciled source audit3320) intentionally retires seven low-value renderer authority/retirement examples: retires one pane, clears resume authority, and rejects late status without harming siblings — Late status reviving a retired pane, sibling damage, or resume authority left behind.; can retire live pane authority while retaining its sleeping session — Retiring live authority accidentally dropping a retained sleeping session.; keeps a physical pane routed through chained detaches until its current owner closes — Chained detach alias routing broken after original owner closes, or alias survives final close.; forgets routing aliases for purged tabs — Purged-tab routing aliases lingering.; retires split, relay, deferred, and pending sessions for a parked tab — Split, relay, deferred or pending session omitted from teardown, sleeping-record sibling damaged, parked disposer skipped.; retires parked ownership before teardown and sweeps published state before unified close — Parked cleanup/provider teardown/state removal/sweep/unified-close ordering changes.; starts mixed provider teardown and classifies both rejection kinds after synchronous retirement — Mixed teardown failures blocking retirement, or local/runtime warning counts misclassified.. Remove the exact-pane-retirement and chained-detach assertion references because their source cases are gone. Other retained cases do not replace these alarms. Preserve all dated evidenceRuns and prior history with their original source scope; no fresh execution or historical import-closure equivalence is claimed. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit1904 reduces persistence-pty-binding-reconciliation from six to four definitions, intentionally losing legacy remap-load and first-binding projection alarms. Current selector/testFile remains valid, with no selected-source assertionRef or active matching receipt. The six unchanged close/continuity receipts keep their exact original scope; no new broad gate or replacement evidence is claimed. Historical prior account (preserved verbatim): Audit1683 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Audit1674 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Capture exact tab, pane, PTY, handle, incarnation, and persisted layout identities. Final-pane terminal.close must invoke one durability-acknowledged tab retirement before exact PTY teardown; controlled PTY exit and graph removal afterward must remain idempotent, omit the target from persistence and provider inventory, and leave an unrelated canary handle live. terminal.closeAll must force-retire every pinned and unpinned target surface, clear its persisted agent-resume and incarnation records, await authoritative PTY exit, preserve a sibling worktree's tab, PTY, and resume authority, and return an unverifiable failure instead of claiming exit when the owning host does not confirm a stop. The ordinary path stays pending until the persisted row is removed and never falls back to the fire-and-forget pane event; reload/restart must keep the explicitly emptied worktree at zero terminal tabs and provider sessions. Reloading the renderer with the same tab/pane/PTY/incarnation must keep the handle readable; changing only the incarnation behind the same PTY id, losing the authoritative graph, or superseding the renderer handle with a preallocated handle must reject the old handle with terminal_handle_stale. Parked-close tests prove the exact PTY disappears; descendant/process tests keep natural exits reserved, upgrade teardown safely, bound/coalesce process-table work, and protect recycled identities.", "commands": [ "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/terminal/surface/orca-runtime-terminal-close-continuity.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/construction/orca-runtime.test.ts", @@ -6465,13 +6331,6 @@ "pane authority transfer accepts only the canonical legacy/scoped runtime handle bound to the authoritative pane" ] }, - { - "file": "src/renderer/src/store/slices/agent-status/agent-pane-authority.test.ts", - "assertions": [ - "exact pane retirement removes resume and launch authority while preserving siblings", - "chained detach keeps physical hooks and resume authority routed to the current owner until that owner closes" - ] - }, { "file": "src/main/runtime/workspaces/removal/worktree-teardown.test.ts", "assertions": [ @@ -6566,7 +6425,8 @@ "Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime.test.ts: ordinary registration cleanup removes only await import('./orca-runtime-tests/mobile-session-tabs-part-14.spec'). src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-03.spec.ts: arms the stale-title timer for a seeded working title; arms the Command Code scrape from the noted spawn command; prefers the tracked title over a stale renderer lastTitle in the hydration seed; writes recent output into the current runtime output map; uses a later title handler replacement with the runtime receiver; calls the current injected listener with the runtime receiver; keeps optional reconciliation lazy after its callback is removed. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-14.spec.ts: lists them, so a paired client can mirror a migrated editor; closes one by retiring it from the host session; keeps an unsaved draft unless the close is forced; shares aggregate work but leaves a replacement pending promise alone; lets a targeted refresh finish while an aggregate refresh waits; refuses a close when the store lacks %s before the guard; keeps a later missing %s on the original caught failure path. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed.", "Audit2061 (sources2059/2060): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime.test.ts: ordinary registration cleanup removes only await import('./orca-runtime-tests/mobile-session-tabs-headless-chat-rebuild.spec'); await import('./orca-runtime-tests/mobile-session-tabs-cold-serve-hydrate.spec'); await import('./orca-runtime-tests/worktree-removal-execution-host.spec'); await import('./orca-runtime-tests/terminal-spawn-dispatch.spec'). src/main/runtime/orca-runtime-tests/headless-snapshots-part-02.spec.ts: replaces a cwd parsed before late WSL context with the provider cwd; keeps a live WSL cwd that arrives during late-context snapshot recovery; infers local reconstructed WSL context from a WSL UNC worktree; clears stale terminal file URI hostnames after empty-host OSC7 cwd updates; serializes SSH headless OSC7 cwd as POSIX when the desktop runtime is on Windows; keeps Windows SSH OSC7 cwd as a drive path when the desktop runtime is POSIX; serializes Windows SSH headless OSC7 cwd as a drive path on POSIX desktops; infers restored SSH connection identity from app-scoped PTY ids. src/main/runtime/orca-runtime-tests/mobile-session-tabs-headless-chat-rebuild.spec.ts: survives the rebuild that closing a saved editor tab forces; keeps its place in the tab order when the host lists the workspace again; lists tabs to phones in the order desktop clients draw after a rebuild; keeps the place a window gave a chat across a graph resend before the chat is restored. src/main/runtime/orca-runtime-tests/mobile-session-tabs-cold-serve-hydrate.spec.ts: lists every persisted terminal of a windowless host after a cold restart; lists every persisted terminal in the all-worktrees inventory after a cold restart; lists persisted editor tabs beside the terminals after a cold restart; restores a persisted split group layout on the cold rebuild; restores the saved active group of a split even when it is not the first group; falls back to the active tab group when the saved active group was not restored; keeps the headless group active when there is no persisted split; keeps phone and CLI creates in the group they joined across a cold restart. src/main/runtime/orca-runtime-tests/worktree-removal-failed-retry.spec.ts: lists the leftover with its error, though Git no longer does; takes the normal delete once Git registers a checkout at the path again; joins a retry another client started while this Delete listed Git; shows the failed row with its error, not the scan cached before the delete. src/main/runtime/orca-runtime-tests/worktree-removal-execution-host.spec.ts: refuses an SSH row whose host is unreachable instead of deleting here; refuses a runtime row with no nested SSH target rather than deleting locally; refuses a runtime row that also names a nested SSH target; retains runtime purge dispatch in a recovery job; uses the runtime helper override before resuming an interrupted removal; uses the runtime helper override before retrying a failed removal; captures the watcher callback and retains its job-host receiver; reads the current runtime removal queue. src/main/runtime/orca-runtime-tests/terminal-spawn-dispatch.spec.ts: reports the spawn request before it leaves for the pty controller; reports it even when the spawn itself then fails; does not report it when the create fails before any spawn request; captures the admission method before reading the incarnation; captures the record method before evaluating its state object; skips database payload serialization when no database exists; skips a throwing database payload when no database exists; keeps the database method and receiver captured before its payload; captures the canonical map method before a binding getter changes it; completes the captured replacement fence without another map lookup. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed.", "Module layout policy correction: retire the remaining program-status-osc.spec.ts event-projection case (production/mock-derived pane-key oracle) and sign-in timeout case (real setTimeout wait with Date-only fake clocks). The runtime test registrar no longer imports that file. No replacement coverage or fresh execution is claimed for these losses; historical receipts retain their original source scope.", - "Module layout policy correction: retire the two remaining worktree-ps-agent-row-dismissal.spec.ts registrations. The remint/dismissal/exit case computed expected snapshotVersion increments from a production snapshot and used real-clock vi.waitFor; the legacy OSC case derived its expected paneKey from the production layout-owner switch. The runtime registrar no longer imports this file. These public projection scenarios have no replacement coverage or fresh execution claimed; all historical receipts and earlier loss notes retain their original source scope." + "Module layout policy correction: retire the two remaining worktree-ps-agent-row-dismissal.spec.ts registrations. The remint/dismissal/exit case computed expected snapshotVersion increments from a production snapshot and used real-clock vi.waitFor; the legacy OSC case derived its expected paneKey from the production layout-owner switch. The runtime registrar no longer imports this file. These public projection scenarios have no replacement coverage or fresh execution claimed; all historical receipts and earlier loss notes retain their original source scope.", + "Audit3323 (reconciled source audit3320) intentionally retires seven low-value renderer authority/retirement examples: retires one pane, clears resume authority, and rejects late status without harming siblings — Late status reviving a retired pane, sibling damage, or resume authority left behind.; can retire live pane authority while retaining its sleeping session — Retiring live authority accidentally dropping a retained sleeping session.; keeps a physical pane routed through chained detaches until its current owner closes — Chained detach alias routing broken after original owner closes, or alias survives final close.; forgets routing aliases for purged tabs — Purged-tab routing aliases lingering.; retires split, relay, deferred, and pending sessions for a parked tab — Split, relay, deferred or pending session omitted from teardown, sleeping-record sibling damaged, parked disposer skipped.; retires parked ownership before teardown and sweeps published state before unified close — Parked cleanup/provider teardown/state removal/sweep/unified-close ordering changes.; starts mixed provider teardown and classifies both rejection kinds after synchronous retirement — Mixed teardown failures blocking retirement, or local/runtime warning counts misclassified.. Remove the exact-pane-retirement and chained-detach assertion references because their source cases are gone. Other retained cases do not replace these alarms. Preserve all dated evidenceRuns and prior history with their original source scope; no fresh execution or historical import-closure equivalence is claimed." ], "demotionRule": "Keep experimental or demote to protection none if exact PTY disappearance flakes, a sibling/detached pane is retired, late hooks can recreate closed authority, or a renderer graph sync retires a host-created tab that no explicit close retired." }, @@ -7058,6 +6918,9 @@ "Keep disjoint provider inventories, refresh isolation, launch authority, and bounded in-flight state green." ], "knownGaps": [ + "NEXT65 current scope qualification: The NEXT65 knownGaps entries below govern the changed selectors and qualify any broader coverage implication in this gate’s unchanged oracle/coverageNotes narratives. Those narratives and preserved dated evidenceRuns retain their historical text and original exact execution scopes only; no fresh execution, transferred pass or equivalent replacement coverage is claimed. Upstream case removals remain upstream; original NEXT65 proposal descriptions grant no duplicate retirement credit.", + "NEXT65 active selector scope reduction (including directory-selected whole-file retirements): src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts. Remove complete registrations or registrar files within the selected scope for src/renderer/src/components/terminal-pane/pty-connection/spawn/pty-connection-split-spawn.spec.ts. Intentionally lose these named regression alarms without replacement: clears the mobile-fit pane binding when the pane connection is disposed — Pane dispose clearing the mobile-fit binding and PTY dataset loses this direct example.; continues post-spawn size reconcile after a transient mobile presence lock — Size reconciliation continuing after a transient phone-presence lock loses this direct example.; spawns the delayed primary pane of an issue-command split when its sibling owns the tab PTY fallback — Delayed primary split spawning independently after a sibling acquires tab fallback loses this direct example.; does not reuse a sibling split pane pending spawn after remount — Remounted primary adopting its own pending PTY rather than the sibling spawn loses this direct example.; replays a stable-pane adoption without submitting the resume command — Stable-pane adoption replay preserving replay-before-live ordering and suppressing resume command loses this direct example.; forwards focus and hover reports without claiming a parked mirror (#26469) — Passive focus/hover forwarding without stealing mirror ownership, then intended Ctrl+C/click claiming, loses this direct example.. Surviving parent statements and sibling registrations are preserved, but these reduced parent selectors have no fresh execution or transferred historical pass. Unrelated complete dated receipts retain only their original exact scopes; no equivalent replacement, rendered UI, provider, mobile, or cross-platform coverage is claimed.", + "NEXT65 historical original active parent-selector fields (verbatim native JSON values; not current coverage):\ncommands: [\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/hooks/useDetectedAgents.test.tsx src/renderer/src/store/slices/agent-inventory/detected-agents.test.ts src/renderer/src/store/slices/agent-inventory/local-detected-agent-state.test.ts src/renderer/src/store/project-groups/repos-project-group-create-race.test.ts src/renderer/src/store/project-groups/repos-project-groups-delete.test.ts src/renderer/src/store/project-groups/repos-project-groups-owner-routing.test.ts src/renderer/src/store/projects/repos-project-host-capability.test.ts src/renderer/src/store/projects/repos-project-host-lifecycle.test.ts src/renderer/src/store/repos/repos-remove-project-purge-leak.test.ts src/renderer/src/store/repos/repos-update-serialization.test.ts src/renderer/src/lib/agent-session/launch/new-tab/launch-agent-in-new-tab.test.ts --reporter=verbose\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts --reporter=dot\",\n \"Headed Electron/CDP STA-4027 journey on Orca environment windows 2 with a selected Ubuntu-24.04 WSL project and local Floating Workspace\"\n ]\ntestFiles: [\n \"src/renderer/src/hooks/useDetectedAgents.test.tsx\",\n \"src/renderer/src/store/slices/agent-inventory/detected-agents.test.ts\",\n \"src/renderer/src/store/slices/agent-inventory/local-detected-agent-state.test.ts\",\n \"src/renderer/src/store/project-groups/repos-project-group-create-race.test.ts\",\n \"src/renderer/src/store/project-groups/repos-project-groups-delete.test.ts\",\n \"src/renderer/src/store/project-groups/repos-project-groups-owner-routing.test.ts\",\n \"src/renderer/src/store/projects/repos-project-host-capability.test.ts\",\n \"src/renderer/src/store/projects/repos-project-host-lifecycle.test.ts\",\n \"src/renderer/src/store/repos/repos-remove-project-purge-leak.test.ts\",\n \"src/renderer/src/store/repos/repos-update-serialization.test.ts\",\n \"src/renderer/src/lib/agent-session/launch/new-tab/launch-agent-in-new-tab.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"src/renderer/src/hooks/useDetectedAgents.test.tsx\",\n \"assertions\": [\n \"the active WSL project advertises only its WSL agent while Floating advertises only the native-host agent\",\n \"Floating refresh preserves both scoped inventories and does not overwrite the legacy active-project inventory\"\n ]\n },\n {\n \"file\": \"src/renderer/src/store/slices/agent-inventory/local-detected-agent-state.test.ts\",\n \"assertions\": [\n \"same-context callers deduplicate without cached broadcast fanout\",\n \"refresh supersedes stale detection and failed cold refresh remains retryable\",\n \"project removal evicts in-flight context state\"\n ]\n },\n {\n \"file\": \"src/renderer/src/store/repos/repos-remove-project-purge-leak.test.ts\",\n \"assertions\": [\n \"removing one project evicts its authority-scoped agent inventory without disturbing another project\"\n ]\n },\n {\n \"file\": \"src/renderer/src/lib/agent-session/launch/new-tab/launch-agent-in-new-tab.test.ts\",\n \"assertions\": [\n \"the advertised Floating agent launches in a Floating tab with null runtime ownership and no paired-runtime create call\"\n ]\n }\n ]", "Audit3069 retires nominal spawn/resume/banner wiring, first-fit and lookup-budget variants, private pending-map checks, the split-CWD disposal suite and startup command/draft baseline variants. Distinct regression alarms are intentionally lost without equivalent replacement; retained ownership, cancellation and recovery cases remain. Existing selectors and dated evidence retain their original scope. The retired Floating local IPC/WSL routing alias is removed; the separate StrictMode pending-spawn adoption alias remains.", "Audit3061 retires the park-model supplied snapshot suite and nominal mode, cursor, focus, geometry and remote resume metadata variants. Their distinct alarms are intentionally lost; six retained mode/remote cases preserve selected tail-order, authority and parse-readiness boundaries without equivalent replacement. Existing selectors and dated evidence retain their original scope.", "Audit2133 current-parent preparation (988 authored removals; independently reviewed2099/2107/2115/2116 decisions; upstream clear-buffer and recovery-image regressions retained): Intentionally retire these low-value alarms without replacement: src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionTerminalBellAttentionTests } from '../notifications/pty-connection-terminal-bell-attention.spec', registerPtyConnectionTerminalBellAttentionTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-connection/notifications/pty-connection-terminal-bell-attention.spec.ts: forwards onBell to pane attention and notification policy; hands the bell to the attention module with its pane even when pane attention is off. Current changed source bytes, wrapper registrations and reduced selectors have no fresh execution or red/green credit. Unrelated surviving receipt objects keep their original narrow scope; current literal graph reachability does not establish historical import closure or equivalent replacement coverage. Current conservative command/import graph reaches src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts, src/renderer/src/components/terminal-pane/pty-connection/notifications/pty-connection-terminal-bell-attention.spec.ts. Unresolved local/computed edges remain explicit debt.", @@ -7137,7 +7000,7 @@ "id": "agent-session.provider-ownership", "title": "Provider sessions are resumed once per workspace ownership claim", "maturity": "experimental", - "protection": "partial", + "protection": "none", "owner": "agent-session", "layer": "cross-boundary", "surfaces": [ @@ -7150,9 +7013,9 @@ ], "platforms": ["macos", "linux", "windows"], "providers": ["local", "daemon", "ssh", "wsl", "remote-runtime"], - "coveredPlatforms": ["macos"], - "coveredProviders": ["local", "daemon", "remote-runtime"], - "coverageNotes": "Audit2236: pane-fit.test.ts is reduced to terminal-identity reveal, stale-handle replacement ownership and withheld-animation-frame completion. The existing withheld-frame assertion remains exact; additional scheduling/breadcrumb, cancellation, display-none and synthetic metric examples are removed. No new execution or equivalent replacement coverage is claimed. Historical dated receipts and budgets are preserved verbatim and do not validate these reduced source bytes. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit1685 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1683 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1627 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1623 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Audit1417 intentionally deletes src/renderer/src/components/terminal-pane/pty-connection-hidden-tui-snapshot-replay.spec.ts: Loses rich hidden snapshot sequence replay/grid resize and forced repaint after hidden snapshot alarms, including live-trigger deduplication. No equivalent replacement coverage or fresh result is claimed. Historical coverage account: Renderer ownership/dedupe contracts cover provider-session claims. Local and daemon attach-only contracts prove an existing stable-pane owner is adopted without provider creation, while remote-runtime transport contracts preserve adopted ownership through cancellation. The Electron oracle covers a local macOS runtime and daemon with real agent, Setup, and unrelated-canary processes; SSH, WSL, paired-server, Linux, and Windows remain contract-only or unrun. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1391: src/renderer/src/components/terminal-pane/pty-connection-remote-pause-drop-notice.spec.ts reduced. Lose repeated quiet switches avoiding snapshots and legacy host without drop-report capability requesting a snapshot. Retained imported registrar uses fake transport/xterm writes, exercising real gap/restore lifecycle rather than actual terminal rendering. No equivalent replacement coverage is claimed. The existing primary-selector receipt and its claims remain scoped to their unchanged sources; the broad optional command has no new execution result. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result.", + "coveredPlatforms": [], + "coveredProviders": [], + "coverageNotes": "Audit3368 retires whole sleeping-agent-resume and host-session-launch suites: provider-claim/deduplication, stable-pane reattach, recipe/WSL startup, callback/cancel/create-close and compatibility examples are intentionally lost without equivalent replacement. The sole dated receipt is retired verbatim. With no active evidence, protection/platform/provider evidence clears and ALL commands/testFiles/assertionRefs are retired as complete original arrays in historical gaps, including selectors of surviving other sources; those sources remain in the broad suite. Prior red/green/flake accounts are historical only. No fresh runtime/provider/process/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit2236: pane-fit.test.ts is reduced to terminal-identity reveal, stale-handle replacement ownership and withheld-animation-frame completion. The existing withheld-frame assertion remains exact; additional scheduling/breadcrumb, cancellation, display-none and synthetic metric examples are removed. No new execution or equivalent replacement coverage is claimed. Historical dated receipts and budgets are preserved verbatim and do not validate these reduced source bytes. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit1685 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1683 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1627 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1623 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Audit1417 intentionally deletes src/renderer/src/components/terminal-pane/pty-connection-hidden-tui-snapshot-replay.spec.ts: Loses rich hidden snapshot sequence replay/grid resize and forced repaint after hidden snapshot alarms, including live-trigger deduplication. No equivalent replacement coverage or fresh result is claimed. Historical coverage account: Renderer ownership/dedupe contracts cover provider-session claims. Local and daemon attach-only contracts prove an existing stable-pane owner is adopted without provider creation, while remote-runtime transport contracts preserve adopted ownership through cancellation. The Electron oracle covers a local macOS runtime and daemon with real agent, Setup, and unrelated-canary processes; SSH, WSL, paired-server, Linux, and Windows remain contract-only or unrun. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1391: src/renderer/src/components/terminal-pane/pty-connection-remote-pause-drop-notice.spec.ts reduced. Lose repeated quiet switches avoiding snapshots and legacy host without drop-report capability requesting a snapshot. Retained imported registrar uses fake transport/xterm writes, exercising real gap/restore lifecycle rather than actual terminal rendering. No equivalent replacement coverage is claimed. The existing primary-selector receipt and its claims remain scoped to their unchanged sources; the broad optional command has no new execution result. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result.", "motivatingLinks": [ "https://github.com/stablyai/orca/pull/6800", "https://github.com/stablyai/orca/pull/5240", @@ -7162,100 +7025,22 @@ "https://github.com/stablyai/orca/pull/11819" ], "invariant": "Workspace activation, launch, restore, sleep, hibernate, dedupe, clearing, mount, remount, and reconnect code must not replay or resume a provider session id already owned, queued, pending, live, or durably bound to a host PTY in that workspace. A renderer with missing projection state must adopt the exact runtime-owned PTY for the original tab and leaf rather than create a replacement.", - "oracle": "Current assertionRefs retain separate provider-session non-replay and exact-PTY adoption checks in resume-sleeping-agent-session, completed-worker-retirement-resume, remote-runtime-pty-transport-host-session-launch and live-background-terminal-mount-authority. This batch changes only pane-fit's contribution: its three surviving cases check terminal-identity reveal, stale-handle replacement and withheld-frame completion; they do not prove provider-session ownership or exact-PTY adoption. Other assertionRefs and selectors remain unchanged; no fresh execution of those separate contracts is claimed. Audit2236: pane-fit.test.ts is reduced to terminal-identity reveal, stale-handle replacement ownership and withheld-animation-frame completion. The existing withheld-frame assertion remains exact; additional scheduling/breadcrumb, cancellation, display-none and synthetic metric examples are removed. No new execution or equivalent replacement coverage is claimed. Historical dated receipts and budgets are preserved verbatim and do not validate these reduced source bytes. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit1685 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Audit1683 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Historical pre-audit oracle account for changed sources: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Renderer-state tests assert provider-session ownership across preserved and queued panes. Main/provider contracts assert atomic attach-only adoption, stable host/worktree/tab/leaf identity, no fresh spawn on adoption, and safe paired-runtime cancellation. The Electron oracle creates inactive runtime-owned Codex and Setup PTYs plus an unrelated canary, seeds an exact resumable provider session, removes only the target renderer projections, and activates the workspace. It requires byte-stable handle, PTY, incarnation, tab, leaf, process PID, renderer graph, persisted binding, runtime id, graph epoch, and daemon PID across first mount and reload; PID-specific DOM keyboard I/O must remain live with one launch, zero resume argv, zero signals, zero interruption text, and no canary mutation.", - "commands": [ - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts tests/e2e/completed-worker-retirement-resume.unit.test.ts --reporter=verbose", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts src/main/providers/local-pty/local-pty-provider-spawn-session.test.ts src/main/daemon/terminal-host/testing/terminal-host.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts src/main/ipc/pty/pty-pane-reservation-settlement.test.ts src/main/runtime/construction/orca-runtime.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts", - "pnpm exec electron-vite build --mode e2e && SKIP_BUILD=1 pnpm exec playwright test tests/e2e/live-background-terminal-mount-authority.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1", - "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/agent-session/lifecycle/structured-agent-cli-writers.test.ts src/main/runtime/rpc/methods/structured-sessions/creation/structured-agent-session-adoption-replay.test.ts src/main/providers/agent-foreground-process-git-bash.win32.test.ts" - ], - "testFiles": [ - "src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts", - "tests/e2e/completed-worker-retirement-resume.unit.test.ts", - "src/main/providers/local-pty/local-pty-provider-spawn-session.test.ts", - "src/main/daemon/terminal-host/testing/terminal-host.test.ts", - "src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts", - "src/main/ipc/pty/pty-pane-reservation-settlement.test.ts", - "src/main/runtime/construction/orca-runtime.test.ts", - "src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts", - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts", - "tests/e2e/live-background-terminal-mount-authority.spec.ts", - "src/main/runtime/agent-session/lifecycle/structured-agent-cli-writers.test.ts", - "src/main/runtime/rpc/methods/structured-sessions/creation/structured-agent-session-adoption-replay.test.ts", - "src/main/providers/agent-foreground-process-git-bash.win32.test.ts" - ], - "assertionRefs": [ - { - "file": "src/main/runtime/rpc/methods/structured-sessions/creation/structured-agent-session-adoption-replay.test.ts", - "assertions": ["captures source before routing (unary=%s)"] - }, - { - "file": "src/main/providers/agent-foreground-process-git-bash.win32.test.ts", - "assertions": ["sets aside a detached ssh-agent for adoption, but not a background job"] - }, - { - "file": "tests/e2e/completed-worker-retirement-resume.unit.test.ts", - "assertions": [ - "completed and explicitly retired workers retain no provider-resume authority on first workspace activation", - "the original tab, leaf, PTY, provider session, release state, replacement count, queued resume argv, emitted restored banner, and unrelated canary remain exact across restart" - ] - }, - { - "file": "src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts", - "assertions": [ - "preserved panes claim their provider session and only stale duplicates are cleared", - "one launch per provider session: skipped duplicates are cleared instead of relaunched", - "active stable-pane records owned by preserved or visible panes are not resumed again", - "hibernated stable panes with cleared live PTY bindings are skipped" - ] - }, - { - "file": "src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts", - "assertions": [ - "same-generation explicit reattach drains the authoritative snapshot before immediate live bytes and ACKs their delivery credit" - ] - }, - { - "file": "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts", - "assertions": [ - "paired-runtime stable-pane adoption reports reattach without fresh-spawn ownership", - "cancellation after a paired-runtime adoption cannot close the original owner" - ] - }, - { - "file": "tests/e2e/live-background-terminal-mount-authority.spec.ts", - "assertions": [ - "first mount and renderer reload preserve exact agent and Setup handle, PTY, incarnation, tab, leaf, and PID identity", - "PID-specific keyboard input and output remain user-visible in both mounted panes", - "runtime inventory, renderer graph, persisted session, runtime epoch, and daemon PID converge without replacement or resume", - "the unrelated canary remains writable and receives no signal across target projection repair" - ] - } - ], - "evidenceRuns": [ - { - "date": "2026-07-03", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/resume-sleeping-agent-session.test.ts", - "result": "passed", - "durationSeconds": 1.9, - "summary": "1 test file(s) passed, 30 tests passed on main@1282f5c2d in a clean checkout.", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts" - } - ], + "oracle": "Audit3368 retires whole sleeping-agent-resume and host-session-launch suites: provider-claim/deduplication, stable-pane reattach, recipe/WSL startup, callback/cancel/create-close and compatibility examples are intentionally lost without equivalent replacement. The sole dated receipt is retired verbatim. With no active evidence, protection/platform/provider evidence clears and ALL commands/testFiles/assertionRefs are retired as complete original arrays in historical gaps, including selectors of surviving other sources; those sources remain in the broad suite. Prior red/green/flake accounts are historical only. No fresh runtime/provider/process/UI/mobile/mixed-version/cross-platform evidence is claimed. Current assertionRefs retain separate provider-session non-replay and exact-PTY adoption checks in resume-sleeping-agent-session, completed-worker-retirement-resume, remote-runtime-pty-transport-host-session-launch and live-background-terminal-mount-authority. This batch changes only pane-fit's contribution: its three surviving cases check terminal-identity reveal, stale-handle replacement and withheld-frame completion; they do not prove provider-session ownership or exact-PTY adoption. Other assertionRefs and selectors remain unchanged; no fresh execution of those separate contracts is claimed. Audit2236: pane-fit.test.ts is reduced to terminal-identity reveal, stale-handle replacement ownership and withheld-animation-frame completion. The existing withheld-frame assertion remains exact; additional scheduling/breadcrumb, cancellation, display-none and synthetic metric examples are removed. No new execution or equivalent replacement coverage is claimed. Historical dated receipts and budgets are preserved verbatim and do not validate these reduced source bytes. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit1685 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Audit1683 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Historical pre-audit oracle account for changed sources: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Renderer-state tests assert provider-session ownership across preserved and queued panes. Main/provider contracts assert atomic attach-only adoption, stable host/worktree/tab/leaf identity, no fresh spawn on adoption, and safe paired-runtime cancellation. The Electron oracle creates inactive runtime-owned Codex and Setup PTYs plus an unrelated canary, seeds an exact resumable provider session, removes only the target renderer projections, and activates the workspace. It requires byte-stable handle, PTY, incarnation, tab, leaf, process PID, renderer graph, persisted binding, runtime id, graph epoch, and daemon PID across first mount and reload; PID-specific DOM keyboard I/O must remain live with one launch, zero resume argv, zero signals, zero interruption text, and no canary mutation.", + "commands": [], + "testFiles": [], + "assertionRefs": [], + "evidenceRuns": [], "runtimeBudget": { "p95Seconds": 180, "scope": "focused renderer/main/provider contracts plus one isolated Electron mount-and-reload journey" }, "flakeHistory": { "status": "unknown", - "evidence": "The renderer gate has prior local evidence; the stable-pane Electron oracle is new and needs CI soak before blocking promotion." + "evidence": "Audit3368 retires sole active dated receipt. No fresh execution/soak validates current coverage; complete original account preserved verbatim as history." }, "redGreenEvidence": { "status": "missing", - "evidence": "Audit2133 current-parent preparation: Changed test bytes/selectors have no fresh red/green validation. Unrelated retained-source historical evidence keeps its original scope. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Changed test bytes/selectors have no fresh red/green validation. Unrelated retained-source historical evidence keeps its original scope. Historical prior account (preserved verbatim): Renderer tests encode provider-session dedupe across active, inactive, queued, and live claims. The cross-boundary Electron oracle is constructed for byte-identical latest-main, candidate, and candidate-revert runs; record those three terminal results before promoting this gate." + "evidence": "Audit3368 changes/deletes referenced sources. No fresh red/green proof validates reduced coverage; original complete account preserved verbatim in knownGaps as history." }, "performanceBudget": { "required": true, @@ -7268,6 +7053,9 @@ "Record byte-identical latest-main, candidate, and candidate-revert Electron results." ], "knownGaps": [ + "NEXT65 current scope qualification: The NEXT65 knownGaps entries below govern the changed selectors and qualify any broader coverage implication in this gate’s unchanged oracle/coverageNotes narratives. Those narratives and preserved dated evidenceRuns retain their historical text and original exact execution scopes only; no fresh execution, transferred pass or equivalent replacement coverage is claimed. Upstream case removals remain upstream; original NEXT65 proposal descriptions grant no duplicate retirement credit.", + "NEXT65 active selector scope reduction (including directory-selected whole-file retirements): src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts. Remove complete registrations or registrar files within the selected scope for src/renderer/src/components/terminal-pane/pty-connection/reattach/pty-connection-daemon-snapshot-replay.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/reattach/pty-connection-stale-daemon-snapshot-replay.spec.ts. Intentionally lose these named regression alarms without replacement: clears the captured pen for a normal-buffer fallback reattach — Fallback normal-buffer reattach clearing captured pen and dirty background loses this direct example.; waits for a recovered destination fit before forwarding its grid or live output — Recovered destination fitting before forwarding grid or live output loses this direct example.; suppresses the deferred reattach grid push when mobile claims the PTY while hidden — Mobile takeover while hidden suppressing deferred reattach grid forwarding loses this direct example.; drops stale callbacks but delivers fresh replacement output after an old replay clear — Fresh replacement output winning over stale callbacks after old replay clear loses this direct example.. Surviving parent statements and sibling registrations are preserved, but these reduced parent selectors have no fresh execution or transferred historical pass. Unrelated complete dated receipts retain only their original exact scopes; no equivalent replacement, rendered UI, provider, mobile, or cross-platform coverage is claimed.", + "NEXT65 historical original active parent-selector fields (verbatim native JSON values; not current coverage):\ncommands: [\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts tests/e2e/completed-worker-retirement-resume.unit.test.ts --reporter=verbose\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts src/main/providers/local-pty/local-pty-provider-spawn-session.test.ts src/main/daemon/terminal-host/testing/terminal-host.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts src/main/ipc/pty/pty-pane-reservation-settlement.test.ts src/main/runtime/construction/orca-runtime.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts\",\n \"pnpm exec electron-vite build --mode e2e && SKIP_BUILD=1 pnpm exec playwright test tests/e2e/live-background-terminal-mount-authority.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/agent-session/lifecycle/structured-agent-cli-writers.test.ts src/main/runtime/rpc/methods/structured-sessions/creation/structured-agent-session-adoption-replay.test.ts src/main/providers/agent-foreground-process-git-bash.win32.test.ts\"\n ]\ntestFiles: [\n \"src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts\",\n \"tests/e2e/completed-worker-retirement-resume.unit.test.ts\",\n \"src/main/providers/local-pty/local-pty-provider-spawn-session.test.ts\",\n \"src/main/daemon/terminal-host/testing/terminal-host.test.ts\",\n \"src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts\",\n \"src/main/ipc/pty/pty-pane-reservation-settlement.test.ts\",\n \"src/main/runtime/construction/orca-runtime.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts\",\n \"tests/e2e/live-background-terminal-mount-authority.spec.ts\",\n \"src/main/runtime/agent-session/lifecycle/structured-agent-cli-writers.test.ts\",\n \"src/main/runtime/rpc/methods/structured-sessions/creation/structured-agent-session-adoption-replay.test.ts\",\n \"src/main/providers/agent-foreground-process-git-bash.win32.test.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"src/main/runtime/rpc/methods/structured-sessions/creation/structured-agent-session-adoption-replay.test.ts\",\n \"assertions\": [\"captures source before routing (unary=%s)\"]\n },\n {\n \"file\": \"src/main/providers/agent-foreground-process-git-bash.win32.test.ts\",\n \"assertions\": [\"sets aside a detached ssh-agent for adoption, but not a background job\"]\n },\n {\n \"file\": \"tests/e2e/completed-worker-retirement-resume.unit.test.ts\",\n \"assertions\": [\n \"completed and explicitly retired workers retain no provider-resume authority on first workspace activation\",\n \"the original tab, leaf, PTY, provider session, release state, replacement count, queued resume argv, emitted restored banner, and unrelated canary remain exact across restart\"\n ]\n },\n {\n \"file\": \"src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts\",\n \"assertions\": [\n \"preserved panes claim their provider session and only stale duplicates are cleared\",\n \"one launch per provider session: skipped duplicates are cleared instead of relaunched\",\n \"active stable-pane records owned by preserved or visible panes are not resumed again\",\n \"hibernated stable panes with cleared live PTY bindings are skipped\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"assertions\": [\n \"same-generation explicit reattach drains the authoritative snapshot before immediate live bytes and ACKs their delivery credit\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts\",\n \"assertions\": [\n \"paired-runtime stable-pane adoption reports reattach without fresh-spawn ownership\",\n \"cancellation after a paired-runtime adoption cannot close the original owner\"\n ]\n },\n {\n \"file\": \"tests/e2e/live-background-terminal-mount-authority.spec.ts\",\n \"assertions\": [\n \"first mount and renderer reload preserve exact agent and Setup handle, PTY, incarnation, tab, leaf, and PID identity\",\n \"PID-specific keyboard input and output remain user-visible in both mounted panes\",\n \"runtime inventory, renderer graph, persisted session, runtime epoch, and daemon PID converge without replacement or resume\",\n \"the unrelated canary remains writable and receives no signal across target projection repair\"\n ]\n }\n ]", "Audit3053 reduces hidden-replay coverage by retiring nominal overlap, resize, cursor metadata and standalone stalled-restore variants. Timeout, overflow, identity/generation fences and retained live-output coordination remain; the removed alarms are intentionally lost without equivalent replacement. Existing commands, assertion references and dated evidence retain their original scope.", "Audit2236: pane-fit.test.ts is reduced to terminal-identity reveal, stale-handle replacement ownership and withheld-animation-frame completion. The existing withheld-frame assertion remains exact; additional scheduling/breadcrumb, cancellation, display-none and synthetic metric examples are removed. No new execution or equivalent replacement coverage is claimed. Historical dated receipts and budgets are preserved verbatim and do not validate these reduced source bytes.", "Audit2145 accepts removal of canned runtime metadata/guard/forwarding, fake in-memory persistence, private work-count and wrapper-duplication tests from the construction/orca-runtime.test.ts aggregate, plus the two automation run-context guards from runtime-workspace-launch-contracts.test.ts. Retained race, framing, physical completion and ownership callbacks remain byte-identical. Existing commands remain valid selectors; historical receipts stay unchanged and provide no fresh validation or replacement coverage for the reduced suites.", @@ -7296,7 +7084,17 @@ "Audit2061 (sources2059/2060): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime.test.ts: ordinary registration cleanup removes only await import('./orca-runtime-tests/mobile-session-tabs-headless-chat-rebuild.spec'); await import('./orca-runtime-tests/mobile-session-tabs-cold-serve-hydrate.spec'); await import('./orca-runtime-tests/worktree-removal-execution-host.spec'); await import('./orca-runtime-tests/terminal-spawn-dispatch.spec'). src/main/runtime/orca-runtime-tests/headless-snapshots-part-02.spec.ts: replaces a cwd parsed before late WSL context with the provider cwd; keeps a live WSL cwd that arrives during late-context snapshot recovery; infers local reconstructed WSL context from a WSL UNC worktree; clears stale terminal file URI hostnames after empty-host OSC7 cwd updates; serializes SSH headless OSC7 cwd as POSIX when the desktop runtime is on Windows; keeps Windows SSH OSC7 cwd as a drive path when the desktop runtime is POSIX; serializes Windows SSH headless OSC7 cwd as a drive path on POSIX desktops; infers restored SSH connection identity from app-scoped PTY ids. src/main/runtime/orca-runtime-tests/mobile-session-tabs-headless-chat-rebuild.spec.ts: survives the rebuild that closing a saved editor tab forces; keeps its place in the tab order when the host lists the workspace again; lists tabs to phones in the order desktop clients draw after a rebuild; keeps the place a window gave a chat across a graph resend before the chat is restored. src/main/runtime/orca-runtime-tests/mobile-session-tabs-cold-serve-hydrate.spec.ts: lists every persisted terminal of a windowless host after a cold restart; lists every persisted terminal in the all-worktrees inventory after a cold restart; lists persisted editor tabs beside the terminals after a cold restart; restores a persisted split group layout on the cold rebuild; restores the saved active group of a split even when it is not the first group; falls back to the active tab group when the saved active group was not restored; keeps the headless group active when there is no persisted split; keeps phone and CLI creates in the group they joined across a cold restart. src/main/runtime/orca-runtime-tests/worktree-removal-failed-retry.spec.ts: lists the leftover with its error, though Git no longer does; takes the normal delete once Git registers a checkout at the path again; joins a retry another client started while this Delete listed Git; shows the failed row with its error, not the scan cached before the delete. src/main/runtime/orca-runtime-tests/worktree-removal-execution-host.spec.ts: refuses an SSH row whose host is unreachable instead of deleting here; refuses a runtime row with no nested SSH target rather than deleting locally; refuses a runtime row that also names a nested SSH target; retains runtime purge dispatch in a recovery job; uses the runtime helper override before resuming an interrupted removal; uses the runtime helper override before retrying a failed removal; captures the watcher callback and retains its job-host receiver; reads the current runtime removal queue. src/main/runtime/orca-runtime-tests/terminal-spawn-dispatch.spec.ts: reports the spawn request before it leaves for the pty controller; reports it even when the spawn itself then fails; does not report it when the create fails before any spawn request; captures the admission method before reading the incarnation; captures the record method before evaluating its state object; skips database payload serialization when no database exists; skips a throwing database payload when no database exists; keeps the database method and receiver captured before its payload; captures the canonical map method before a binding getter changes it; completes the captured replacement fence without another map lookup. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed.", "Module layout policy correction: retire the remaining program-status-osc.spec.ts event-projection case (production/mock-derived pane-key oracle) and sign-in timeout case (real setTimeout wait with Date-only fake clocks). The runtime test registrar no longer imports that file. No replacement coverage or fresh execution is claimed for these losses; historical receipts retain their original source scope.", "Module layout policy correction: retire the two remaining worktree-ps-agent-row-dismissal.spec.ts registrations. The remint/dismissal/exit case computed expected snapshotVersion increments from a production snapshot and used real-clock vi.waitFor; the legacy OSC case derived its expected paneKey from the production layout-owner switch. The runtime registrar no longer imports this file. These public projection scenarios have no replacement coverage or fresh execution claimed; all historical receipts and earlier loss notes retain their original source scope.", - "Module-layout wave1 intentionally retires complete prohibited owning registrations in src/renderer/src/lib/pane-manager/pane-fit.test.ts. Lost alarms: runs the continuation when the reveal fit arrives on a different pane object; does not let a stale handle cancel its deferred replacement; resolves failure when hidden-window animation frames are withheld. No equivalent replacement coverage or pass for a reduced selector is claimed. All unrelated selectors and historical receipts retain their original scope." + "Module-layout wave1 intentionally retires complete prohibited owning registrations in src/renderer/src/lib/pane-manager/pane-fit.test.ts. Lost alarms: runs the continuation when the reveal fit arrives on a different pane object; does not let a stale handle cancel its deferred replacement; resolves failure when hidden-window animation frames are withheld. No equivalent replacement coverage or pass for a reduced selector is claimed. All unrelated selectors and historical receipts retain their original scope.", + "Audit3368 retires whole sleeping-agent-resume and host-session-launch suites: provider-claim/deduplication, stable-pane reattach, recipe/WSL startup, callback/cancel/create-close and compatibility examples are intentionally lost without equivalent replacement. The sole dated receipt is retired verbatim. With no active evidence, protection/platform/provider evidence clears and ALL commands/testFiles/assertionRefs are retired as complete original arrays in historical gaps, including selectors of surviving other sources; those sources remain in the broad suite. Prior red/green/flake accounts are historical only. No fresh runtime/provider/process/UI/mobile/mixed-version/cross-platform evidence is claimed.", + "Audit3368 historical original commands object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts tests/e2e/completed-worker-retirement-resume.unit.test.ts --reporter=verbose\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts src/main/providers/local-pty/local-pty-provider-spawn-session.test.ts src/main/daemon/terminal-host/testing/terminal-host.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts src/main/ipc/pty/pty-pane-reservation-settlement.test.ts src/main/runtime/construction/orca-runtime.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts\",\n \"pnpm exec electron-vite build --mode e2e && SKIP_BUILD=1 pnpm exec playwright test tests/e2e/live-background-terminal-mount-authority.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/agent-session/lifecycle/structured-agent-cli-writers.test.ts src/main/runtime/rpc/methods/structured-sessions/creation/structured-agent-session-adoption-replay.test.ts src/main/providers/agent-foreground-process-git-bash.win32.test.ts\"\n ]", + "Audit3368 historical original testFiles object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\n \"src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts\",\n \"tests/e2e/completed-worker-retirement-resume.unit.test.ts\",\n \"src/main/providers/local-pty/local-pty-provider-spawn-session.test.ts\",\n \"src/main/daemon/terminal-host/testing/terminal-host.test.ts\",\n \"src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts\",\n \"src/main/ipc/pty/pty-pane-reservation-settlement.test.ts\",\n \"src/main/runtime/construction/orca-runtime.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts\",\n \"tests/e2e/live-background-terminal-mount-authority.spec.ts\",\n \"src/main/runtime/agent-session/lifecycle/structured-agent-cli-writers.test.ts\",\n \"src/main/runtime/rpc/methods/structured-sessions/creation/structured-agent-session-adoption-replay.test.ts\",\n \"src/main/providers/agent-foreground-process-git-bash.win32.test.ts\"\n ]", + "Audit3368 historical original assertionRefs object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\n {\n \"file\": \"src/main/runtime/rpc/methods/structured-sessions/creation/structured-agent-session-adoption-replay.test.ts\",\n \"assertions\": [\"captures source before routing (unary=%s)\"]\n },\n {\n \"file\": \"src/main/providers/agent-foreground-process-git-bash.win32.test.ts\",\n \"assertions\": [\"sets aside a detached ssh-agent for adoption, but not a background job\"]\n },\n {\n \"file\": \"tests/e2e/completed-worker-retirement-resume.unit.test.ts\",\n \"assertions\": [\n \"completed and explicitly retired workers retain no provider-resume authority on first workspace activation\",\n \"the original tab, leaf, PTY, provider session, release state, replacement count, queued resume argv, emitted restored banner, and unrelated canary remain exact across restart\"\n ]\n },\n {\n \"file\": \"src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts\",\n \"assertions\": [\n \"preserved panes claim their provider session and only stale duplicates are cleared\",\n \"one launch per provider session: skipped duplicates are cleared instead of relaunched\",\n \"active stable-pane records owned by preserved or visible panes are not resumed again\",\n \"hibernated stable panes with cleared live PTY bindings are skipped\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"assertions\": [\n \"same-generation explicit reattach drains the authoritative snapshot before immediate live bytes and ACKs their delivery credit\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts\",\n \"assertions\": [\n \"paired-runtime stable-pane adoption reports reattach without fresh-spawn ownership\",\n \"cancellation after a paired-runtime adoption cannot close the original owner\"\n ]\n },\n {\n \"file\": \"tests/e2e/live-background-terminal-mount-authority.spec.ts\",\n \"assertions\": [\n \"first mount and renderer reload preserve exact agent and Setup handle, PTY, incarnation, tab, leaf, and PID identity\",\n \"PID-specific keyboard input and output remain user-visible in both mounted panes\",\n \"runtime inventory, renderer graph, persisted session, runtime epoch, and daemon PID converge without replacement or resume\",\n \"the unrelated canary remains writable and receives no signal across target projection repair\"\n ]\n }\n ]", + "Audit3368 historical original evidenceRuns object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\n {\n \"date\": \"2026-07-03\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/resume-sleeping-agent-session.test.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 1.9,\n \"summary\": \"1 test file(s) passed, 30 tests passed on main@1282f5c2d in a clean checkout.\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts\"\n }\n ]", + "Audit3368 historical original protection object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"partial\"", + "Audit3368 historical original coveredPlatforms object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\"macos\"]", + "Audit3368 historical original coveredProviders object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n[\"local\", \"daemon\", \"remote-runtime\"]", + "Audit3368 historical original redGreenEvidence object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"status\": \"missing\",\n \"evidence\": \"Audit2133 current-parent preparation: Changed test bytes/selectors have no fresh red/green validation. Unrelated retained-source historical evidence keeps its original scope. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Changed test bytes/selectors have no fresh red/green validation. Unrelated retained-source historical evidence keeps its original scope. Historical prior account (preserved verbatim): Renderer tests encode provider-session dedupe across active, inactive, queued, and live claims. The cross-boundary Electron oracle is constructed for byte-identical latest-main, candidate, and candidate-revert runs; record those three terminal results before promoting this gate.\"\n }", + "Audit3368 historical original flakeHistory object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"status\": \"unknown\",\n \"evidence\": \"The renderer gate has prior local evidence; the stable-pane Electron oracle is new and needs CI soak before blocking promotion.\"\n }" ], "demotionRule": "Demote or quarantine if failures are non-actionable or if a duplicate resume escape occurs outside the modeled matrix." }, @@ -7322,7 +7120,7 @@ "providers": ["local", "daemon", "ssh", "wsl", "remote-runtime"], "coveredPlatforms": ["macos"], "coveredProviders": ["local", "daemon", "ssh", "wsl", "remote-runtime"], - "coverageNotes": "Audit2694 source-only review: Remove14 authored/14 expanded cases in the renderer completion wrapper family, including the complete bell/query-reply/stale-input factory, without replacement. Retain29 authored/34 expanded cases with unchanged callback bodies. Three removals are the existing pending2203 overlap and must be adopted/count-reconciled once; eleven are fresh removals. No current-source runtime or gate execution is supplied by this packet; dated evidence retains its original source scope and does not validate the reduced factory bytes. No equivalent replacement, physical provider, mixed-version, mobile, rendered UI, cross-platform, soak or measured-performance result is claimed. The existing command and testFiles selector retain tests/pty-connection-completion-and-notification.test.ts; no wrapper-specific assertionRef is removed. Historical selector results do not validate its changed reachable factories. Historical prior account (preserved verbatim): Audit2709 removes src/renderer/src/runtime/web-session-tabs-sync/inventory/remote-runtime-session-tabs-inflight.test.ts: intentionally retire waiting out an older inventory and sharing a fresh post-operation request among concurrent callers. No equivalent replacement or fresh execution is claimed. Dated receipts remain historical evidence for their unchanged selectors only; they do not validate the reduced commands or full current gate. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2003: Delete the complete pure orphan-topology suite and its file membership; preserve the other selectors from its combined command after archiving the original command string. Lost alarms are synthetic current-layout preservation, one-anchor grafting and ambiguous-anchor appending examples. Do not transfer their ownership/topology scope to sibling suites. Preserve all5 independent historical receipts exactly. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, physical provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1983: Delete the mocked agent-session suite and its prospective selector and aliases. Retire all3 whole dated changed-selector receipts, preserving their original raw objects in historical gaps without transferring counts or durations. Preserve5 unrelated receipts. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Partial agent-operation service suite retains only concurrent retry joining with changed-fingerprint conflict. Retire its complete three-title assertion object: old-owner legacy fallback before side effects, nested SSH Pi transcript refusal and completed/ambiguous physical-commit replay fences are no longer backed. Other probe/launch option/ledger/failure/remote-inventory examples disappear as detailed below. No actual provider spawn, live SSH or physical commit proof is retained by this source. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1911: The complete provider PTY-inspection mock suite is removed: missing-provider rejection, stale-PTY renderer unverifiable mapping, preserved supplied renderer failures, and supplied transport-loss mapping alarms are intentionally lost. No actual terminal teardown, daemon error or remote transport was exercised. Only the deleted explicit source tokens, testFile and whole assertionRef are removed. Meaningful remaining source selectors/assertions and unaffected dated receipts retain their original scope. No equivalent replacement, fresh reduced-gate, native/platform/provider, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1627 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1623 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1495 intentionally deletes the orphan-owner suite: explicit owner/host predicate examples are retired; no equivalent replacement coverage or fresh result is claimed. Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Audit1417 intentionally deletes src/renderer/src/components/terminal-pane/agent-completion-coordinator-pending-title-inspection.test.ts: Loses obsolete pending title process races, inspection failure suppression, explicit completion precedence and delayed remote inspection alarms. No equivalent replacement coverage or fresh result is claimed. Historical coverage account: Audit1342 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Audits1301 and1308 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Deterministic macOS tests cover controller claims, daemon and SSH/relay operation replay, mixed-version selection, runtime ownership, exact provisional handoff, durable terminal retirement, two independent viewer mirrors, guarded adoption of legacy live PTYs, and completion classification when either the outer remote transport or authoritative host/provider process inspection becomes unreachable. The adoption harness models v1.4.150 agent/setup/shell tabs, current-generation restart and reconnect, exact handle/incarnation/worktree/host checks, topology CAS, competing clients, split-pane/group restoration, WSL ownership, and SSH owner rejection. The secondary parity repro runs independent clients against one headless remote Orca runtime over encrypted pairing and a real daemon-backed PTY, with tokened fixture-process identity separated from unrelated Codex app-server startup probes. The automated primary topology runs an isolated headed macOS Orca desktop server plus a separate paired web client and proves viewer-local fresh/resume focus, exact legacy placement, writable PTYs, unrelated-terminal survival, and host/client cleanup. SSH coverage is provider/relay contract and fault-injection coverage only; it does not substitute for paired-server coverage. Live Windows, Linux, WSL, SSH, and physical paired-Linux hosts remain gaps. The isolated intent-owner ledger suite was removed. web-runtime-session.test.ts retains exact post-create handoff confirmation only; its previous fresh/resume presentation and publication-replay assertions are no longer current references. Those direct owner-partition, cap and RPC/focus alarms are lost; other agent-session evidence does not establish equivalence. Structured handoff and adopted-leaf focus references now point to their dedicated surviving fixtures. Mixed-version recovery retains actual old-host recovery followed by a new CLI tab; its unsupported/missing-evidence tables are removed. Orphan recovery retains in-flight adoption-conflict serialization only; previous topology/pruning and absence/adoption examples are removed. These removed projection, capability and adoption-shape alarms are lost; retained cases do not replace them. Audit1301: src/renderer/src/runtime/remote-runtime-session-tabs-inflight.test.ts reduced. Direct dedupe eviction/count and equal receipt-position sample loses authored alarm. No equivalent replacement coverage is claimed. Audit1308: src/renderer/src/runtime/web-session-tabs-sync-agent-handoff.test.ts removed. Exact provisional replacement and post-create exit confirmation handoff pipeline alarms disappear. No equivalent replacement coverage is claimed. Audit1313: src/main/runtime/terminal-orphan-topology.test.ts: Retain actual topology merge algorithms preserving disjoint subtrees and grafted/ambiguous shared anchors with independent expected trees. Remove duplicate leaf validator and empty/no-change passthrough examples. Lose basic validation and no-group/noop characterization; no renderer layout proof. Reduced selectors require fresh validation; prior full-suite receipts do not validate removed or changed coverage. No equivalent replacement or physical-provider claim. Audit1342: src/renderer/src/components/terminal-pane/pty-connection-completion-and-notification.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result.", + "coverageNotes": "Audit3368 retires the whole host-session-launch unit source, including host-authority/create/ensure/legacy/Kimi/refusal/draft/options/prompt/cancel/kill/shared-disconnect and passive-sleep output callback alarms, without equivalent replacement. Its unit command token and test-file entry retire. Five unrelated macOS receipts remain verbatim and keep only their original scope; no fresh changed-selector/runtime/provider/process/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit3359 retires the whole create-handoff suite. Supplied disposition, late completion, close-callback and metadata-bookkeeping alarms are intentionally lost without equivalent replacement; the compound unit selector and test-file entry narrow accordingly. Five unrelated macOS receipts retain their original scope. No fresh runtime, process-deduplication, physical provider/network, historical-import, mobile, mixed-version or cross-platform validation is claimed. Audit 3301 removes the caller-chat-target precedence over host selection example from web-session-tabs-sync-focus-intent.test.ts. The snapshot-before-RPC replay and split-sibling-first exact-leaf focus cases remain unchanged and match the existing assertion reference. Preserve current selectors, assertion references, unrelated active receipts and complete archived history. These mocked state-composition survivors provide no equivalent replacement, rendered, native, network or fresh execution proof. Audit2694 source-only review: Remove14 authored/14 expanded cases in the renderer completion wrapper family, including the complete bell/query-reply/stale-input factory, without replacement. Retain29 authored/34 expanded cases with unchanged callback bodies. Three removals are the existing pending2203 overlap and must be adopted/count-reconciled once; eleven are fresh removals. No current-source runtime or gate execution is supplied by this packet; dated evidence retains its original source scope and does not validate the reduced factory bytes. No equivalent replacement, physical provider, mixed-version, mobile, rendered UI, cross-platform, soak or measured-performance result is claimed. The existing command and testFiles selector retain tests/pty-connection-completion-and-notification.test.ts; no wrapper-specific assertionRef is removed. Historical selector results do not validate its changed reachable factories. Historical prior account (preserved verbatim): Audit2709 removes src/renderer/src/runtime/web-session-tabs-sync/inventory/remote-runtime-session-tabs-inflight.test.ts: intentionally retire waiting out an older inventory and sharing a fresh post-operation request among concurrent callers. No equivalent replacement or fresh execution is claimed. Dated receipts remain historical evidence for their unchanged selectors only; they do not validate the reduced commands or full current gate. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2003: Delete the complete pure orphan-topology suite and its file membership; preserve the other selectors from its combined command after archiving the original command string. Lost alarms are synthetic current-layout preservation, one-anchor grafting and ambiguous-anchor appending examples. Do not transfer their ownership/topology scope to sibling suites. Preserve all5 independent historical receipts exactly. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, physical provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1983: Delete the mocked agent-session suite and its prospective selector and aliases. Retire all3 whole dated changed-selector receipts, preserving their original raw objects in historical gaps without transferring counts or durations. Preserve5 unrelated receipts. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Partial agent-operation service suite retains only concurrent retry joining with changed-fingerprint conflict. Retire its complete three-title assertion object: old-owner legacy fallback before side effects, nested SSH Pi transcript refusal and completed/ambiguous physical-commit replay fences are no longer backed. Other probe/launch option/ledger/failure/remote-inventory examples disappear as detailed below. No actual provider spawn, live SSH or physical commit proof is retained by this source. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1911: The complete provider PTY-inspection mock suite is removed: missing-provider rejection, stale-PTY renderer unverifiable mapping, preserved supplied renderer failures, and supplied transport-loss mapping alarms are intentionally lost. No actual terminal teardown, daemon error or remote transport was exercised. Only the deleted explicit source tokens, testFile and whole assertionRef are removed. Meaningful remaining source selectors/assertions and unaffected dated receipts retain their original scope. No equivalent replacement, fresh reduced-gate, native/platform/provider, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1627 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1623 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1495 intentionally deletes the orphan-owner suite: explicit owner/host predicate examples are retired; no equivalent replacement coverage or fresh result is claimed. Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Audit1417 intentionally deletes src/renderer/src/components/terminal-pane/agent-completion-coordinator-pending-title-inspection.test.ts: Loses obsolete pending title process races, inspection failure suppression, explicit completion precedence and delayed remote inspection alarms. No equivalent replacement coverage or fresh result is claimed. Historical coverage account: Audit1342 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Audits1301 and1308 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Deterministic macOS tests cover controller claims, daemon and SSH/relay operation replay, mixed-version selection, runtime ownership, exact provisional handoff, durable terminal retirement, two independent viewer mirrors, guarded adoption of legacy live PTYs, and completion classification when either the outer remote transport or authoritative host/provider process inspection becomes unreachable. The adoption harness models v1.4.150 agent/setup/shell tabs, current-generation restart and reconnect, exact handle/incarnation/worktree/host checks, topology CAS, competing clients, split-pane/group restoration, WSL ownership, and SSH owner rejection. The secondary parity repro runs independent clients against one headless remote Orca runtime over encrypted pairing and a real daemon-backed PTY, with tokened fixture-process identity separated from unrelated Codex app-server startup probes. The automated primary topology runs an isolated headed macOS Orca desktop server plus a separate paired web client and proves viewer-local fresh/resume focus, exact legacy placement, writable PTYs, unrelated-terminal survival, and host/client cleanup. SSH coverage is provider/relay contract and fault-injection coverage only; it does not substitute for paired-server coverage. Live Windows, Linux, WSL, SSH, and physical paired-Linux hosts remain gaps. The isolated intent-owner ledger suite was removed. web-runtime-session.test.ts retains exact post-create handoff confirmation only; its previous fresh/resume presentation and publication-replay assertions are no longer current references. Those direct owner-partition, cap and RPC/focus alarms are lost; other agent-session evidence does not establish equivalence. Structured handoff and adopted-leaf focus references now point to their dedicated surviving fixtures. Mixed-version recovery retains actual old-host recovery followed by a new CLI tab; its unsupported/missing-evidence tables are removed. Orphan recovery retains in-flight adoption-conflict serialization only; previous topology/pruning and absence/adoption examples are removed. These removed projection, capability and adoption-shape alarms are lost; retained cases do not replace them. Audit1301: src/renderer/src/runtime/remote-runtime-session-tabs-inflight.test.ts reduced. Direct dedupe eviction/count and equal receipt-position sample loses authored alarm. No equivalent replacement coverage is claimed. Audit1308: src/renderer/src/runtime/web-session-tabs-sync-agent-handoff.test.ts removed. Exact provisional replacement and post-create exit confirmation handoff pipeline alarms disappear. No equivalent replacement coverage is claimed. Audit1313: src/main/runtime/terminal-orphan-topology.test.ts: Retain actual topology merge algorithms preserving disjoint subtrees and grafted/ambiguous shared anchors with independent expected trees. Remove duplicate leaf validator and empty/no-change passthrough examples. Lose basic validation and no-group/noop characterization; no renderer layout proof. Reduced selectors require fresh validation; prior full-suite receipts do not validate removed or changed coverage. No equivalent replacement or physical-provider claim. Audit1342: src/renderer/src/components/terminal-pane/pty-connection-completion-and-notification.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result.", "motivatingLinks": [ "https://github.com/stablyai/orca/issues/8878", "https://github.com/stablyai/orca/issues/9151", @@ -7332,10 +7130,10 @@ "https://github.com/stablyai/orca/pull/10193" ], "invariant": "For every claim-capable execution route, one provider-session identity has at most one live PTY owner and one canonical host surface across concurrent clients, retries, reconnects, and stale publications. For paired structured fresh and resume requests, the authenticated owning runtime creates in background without a renderer window; activate=true focuses the exact requested leaf only on the requesting viewer, while activate=false changes no viewer focus. A live orphan may be adopted only when the controller proves its exact handle and incarnation, its worktree and host owner match, no competing visual owner exists, and a host topology CAS wins. A viewer may classify completion only from successful host/provider inspection or explicit lifecycle evidence; transport, handle, or provider unavailability remains unknown and breaks any consecutive-idle proof. A physical exit retires that exact incarnation durably so stale client state and host restart cannot recreate it. Mixed-version routes select the unchanged legacy request before any authority side effect or execution-owner-local filesystem access.", - "oracle": "Audit2694 source-only review: Remove14 authored/14 expanded cases in the renderer completion wrapper family, including the complete bell/query-reply/stale-input factory, without replacement. Retain29 authored/34 expanded cases with unchanged callback bodies. Three removals are the existing pending2203 overlap and must be adopted/count-reconciled once; eleven are fresh removals. No current-source runtime or gate execution is supplied by this packet; dated evidence retains its original source scope and does not validate the reduced factory bytes. No equivalent replacement, physical provider, mixed-version, mobile, rendered UI, cross-platform, soak or measured-performance result is claimed. The existing command and testFiles selector retain tests/pty-connection-completion-and-notification.test.ts; no wrapper-specific assertionRef is removed. Historical selector results do not validate its changed reachable factories. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2003: Delete the complete pure orphan-topology suite and its file membership; preserve the other selectors from its combined command after archiving the original command string. Lost alarms are synthetic current-layout preservation, one-anchor grafting and ambiguous-anchor appending examples. Do not transfer their ownership/topology scope to sibling suites. Preserve all5 independent historical receipts exactly. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, physical provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1983: Delete the mocked agent-session suite and its prospective selector and aliases. Retire all3 whole dated changed-selector receipts, preserving their original raw objects in historical gaps without transferring counts or durations. Preserve5 unrelated receipts. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Partial agent-operation service suite retains only concurrent retry joining with changed-fingerprint conflict. Retire its complete three-title assertion object: old-owner legacy fallback before side effects, nested SSH Pi transcript refusal and completed/ambiguous physical-commit replay fences are no longer backed. Other probe/launch option/ledger/failure/remote-inventory examples disappear as detailed below. No actual provider spawn, live SSH or physical commit proof is retained by this source. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1911: The complete provider PTY-inspection mock suite is removed: missing-provider rejection, stale-PTY renderer unverifiable mapping, preserved supplied renderer failures, and supplied transport-loss mapping alarms are intentionally lost. No actual terminal teardown, daemon error or remote transport was exercised. Only the deleted explicit source tokens, testFile and whole assertionRef are removed. Meaningful remaining source selectors/assertions and unaffected dated receipts retain their original scope. No equivalent replacement, fresh reduced-gate, native/platform/provider, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Historical pre-audit oracle account for changed sources: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Race independent clients and repeated operation IDs, then assert one physical spawn and one canonical PTY/surface; inject exit-before-reply, provider disconnect, conflicting claim scope, old daemon/relay capabilities, reused handles, stale incarnations, owner mismatch, and topology revision conflict; assert safe adoption or explicit failure without a second spawn or wrong-process attachment. Run fresh/resume with activate true/false against an isolated headed desktop host and a separate paired client, then against isolated headless serve: assert host presentation stays background, only the requesting viewer focuses the exact leaf, inactive calls preserve client/DOM focus, a same-version publication replay cannot lose focus intent, and sibling-first split publication cannot consume exact-leaf intent. Restore legacy split panes and groups beside a newer host-owned tab, preserving exact predecessor/new/successor order, output, input, resize, titles, tab/leaf identity, active group, and multi-client convergence. For completion, drive a known running agent through outer transport loss, authoritative provider rejection, reconnect, explicit stop, real exit status, and successful hook completion; assert unavailable evidence never dispatches completion and two fresh authoritative idle samples are required after the gap. After exact exit, assert terminal and tab listings omit the surface, a stale publication cannot restore it, restart cannot resurrect it, exact tokened fixture PIDs are dead, and unrelated tabs/processes survive until scoped cleanup.", + "oracle": "Audit3368 retires the whole host-session-launch unit source, including host-authority/create/ensure/legacy/Kimi/refusal/draft/options/prompt/cancel/kill/shared-disconnect and passive-sleep output callback alarms, without equivalent replacement. Its unit command token and test-file entry retire. Five unrelated macOS receipts remain verbatim and keep only their original scope; no fresh changed-selector/runtime/provider/process/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit3359 retires the whole create-handoff suite. Supplied disposition, late completion, close-callback and metadata-bookkeeping alarms are intentionally lost without equivalent replacement; the compound unit selector and test-file entry narrow accordingly. Five unrelated macOS receipts retain their original scope. No fresh runtime, process-deduplication, physical provider/network, historical-import, mobile, mixed-version or cross-platform validation is claimed. Audit 3301 removes the caller-chat-target precedence over host selection example from web-session-tabs-sync-focus-intent.test.ts. The snapshot-before-RPC replay and split-sibling-first exact-leaf focus cases remain unchanged and match the existing assertion reference. Preserve current selectors, assertion references, unrelated active receipts and complete archived history. These mocked state-composition survivors provide no equivalent replacement, rendered, native, network or fresh execution proof. Audit2694 source-only review: Remove14 authored/14 expanded cases in the renderer completion wrapper family, including the complete bell/query-reply/stale-input factory, without replacement. Retain29 authored/34 expanded cases with unchanged callback bodies. Three removals are the existing pending2203 overlap and must be adopted/count-reconciled once; eleven are fresh removals. No current-source runtime or gate execution is supplied by this packet; dated evidence retains its original source scope and does not validate the reduced factory bytes. No equivalent replacement, physical provider, mixed-version, mobile, rendered UI, cross-platform, soak or measured-performance result is claimed. The existing command and testFiles selector retain tests/pty-connection-completion-and-notification.test.ts; no wrapper-specific assertionRef is removed. Historical selector results do not validate its changed reachable factories. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2003: Delete the complete pure orphan-topology suite and its file membership; preserve the other selectors from its combined command after archiving the original command string. Lost alarms are synthetic current-layout preservation, one-anchor grafting and ambiguous-anchor appending examples. Do not transfer their ownership/topology scope to sibling suites. Preserve all5 independent historical receipts exactly. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, physical provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1983: Delete the mocked agent-session suite and its prospective selector and aliases. Retire all3 whole dated changed-selector receipts, preserving their original raw objects in historical gaps without transferring counts or durations. Preserve5 unrelated receipts. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Partial agent-operation service suite retains only concurrent retry joining with changed-fingerprint conflict. Retire its complete three-title assertion object: old-owner legacy fallback before side effects, nested SSH Pi transcript refusal and completed/ambiguous physical-commit replay fences are no longer backed. Other probe/launch option/ledger/failure/remote-inventory examples disappear as detailed below. No actual provider spawn, live SSH or physical commit proof is retained by this source. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1911: The complete provider PTY-inspection mock suite is removed: missing-provider rejection, stale-PTY renderer unverifiable mapping, preserved supplied renderer failures, and supplied transport-loss mapping alarms are intentionally lost. No actual terminal teardown, daemon error or remote transport was exercised. Only the deleted explicit source tokens, testFile and whole assertionRef are removed. Meaningful remaining source selectors/assertions and unaffected dated receipts retain their original scope. No equivalent replacement, fresh reduced-gate, native/platform/provider, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Historical pre-audit oracle account for changed sources: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Race independent clients and repeated operation IDs, then assert one physical spawn and one canonical PTY/surface; inject exit-before-reply, provider disconnect, conflicting claim scope, old daemon/relay capabilities, reused handles, stale incarnations, owner mismatch, and topology revision conflict; assert safe adoption or explicit failure without a second spawn or wrong-process attachment. Run fresh/resume with activate true/false against an isolated headed desktop host and a separate paired client, then against isolated headless serve: assert host presentation stays background, only the requesting viewer focuses the exact leaf, inactive calls preserve client/DOM focus, a same-version publication replay cannot lose focus intent, and sibling-first split publication cannot consume exact-leaf intent. Restore legacy split panes and groups beside a newer host-owned tab, preserving exact predecessor/new/successor order, output, input, resize, titles, tab/leaf identity, active group, and multi-client convergence. For completion, drive a known running agent through outer transport loss, authoritative provider rejection, reconnect, explicit stop, real exit status, and successful hook completion; assert unavailable evidence never dispatches completion and two fresh authoritative idle samples are required after the gap. After exact exit, assert terminal and tab listings omit the surface, a stale publication cannot restore it, restart cannot resurrect it, exact tokened fixture PIDs are dead, and unrelated tabs/processes survive until scoped cleanup.", "commands": [ "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/runtime/web-session-tabs-sync/navigation/web-session-tabs-sync-focus-intent.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts src/shared/claimed-agent-pty-owner.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts src/main/runtime/session-construction/agent-session/orca-runtime-agent-session-operation.test.ts src/main/runtime/session-construction/agent-session/remote-agent-session-host-authority.integration.test.ts src/main/runtime/terminal/surface/orca-runtime-terminal-retirement.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/shared/claimed-agent-pty-owner.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts src/main/runtime/session-construction/agent-session/orca-runtime-agent-session-operation.test.ts src/main/runtime/session-construction/agent-session/remote-agent-session-host-authority.integration.test.ts src/main/runtime/terminal/surface/orca-runtime-terminal-retirement.test.ts", "pnpm exec vitest run --config config/vitest.config.ts tests/e2e/remote-terminal-tab-retirement.unit.test.ts", "pnpm run build:cli && pnpm run build:electron-vite && node config/scripts/diagnostics/remote-agent-authority/remote-agent-session-authority-repro.mjs", "node --check config/scripts/development/remote-session-cleanup/remote-agent-session-process-cleanup.mjs && node config/scripts/diagnostics/remote-agent-authority/remote-agent-session-authority-repro.mjs", @@ -7362,8 +7160,6 @@ "src/main/runtime/session-construction/agent-session/orca-runtime-agent-session-operation.test.ts", "src/main/runtime/session-construction/agent-session/remote-agent-session-host-authority.integration.test.ts", "src/main/runtime/terminal/surface/orca-runtime-terminal-retirement.test.ts", - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts", - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts", "tests/e2e/remote-agent-session-focus-authority.spec.ts", "config/scripts/diagnostics/remote-agent-authority/remote-agent-session-authority-repro.mjs", "config/scripts/development/remote-session-cleanup/remote-agent-session-process-cleanup.mjs", @@ -7591,7 +7387,14 @@ "Module layout policy correction: retire the remaining program-status-osc.spec.ts event-projection case (production/mock-derived pane-key oracle) and sign-in timeout case (real setTimeout wait with Date-only fake clocks). The runtime test registrar no longer imports that file. No replacement coverage or fresh execution is claimed for these losses; historical receipts retain their original source scope.", "Module layout policy correction: retire the two remaining worktree-ps-agent-row-dismissal.spec.ts registrations. The remint/dismissal/exit case computed expected snapshotVersion increments from a production snapshot and used real-clock vi.waitFor; the legacy OSC case derived its expected paneKey from the production layout-owner switch. The runtime registrar no longer imports this file. These public projection scenarios have no replacement coverage or fresh execution claimed; all historical receipts and earlier loss notes retain their original source scope.", "Audit2709 removes src/renderer/src/runtime/web-session-tabs-sync/inventory/remote-runtime-session-tabs-inflight.test.ts: intentionally retire waiting out an older inventory and sharing a fresh post-operation request among concurrent callers. No equivalent replacement or fresh execution is claimed. Dated receipts remain historical evidence for their unchanged selectors only; they do not validate the reduced commands or full current gate. Original prospective command before removal: pnpm exec vitest run --config config/vitest.config.ts src/shared/claimed-agent-pty-owner.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts src/main/runtime/session-construction/agent-session/orca-runtime-agent-session-operation.test.ts src/main/runtime/session-construction/agent-session/remote-agent-session-host-authority.integration.test.ts src/main/runtime/terminal/surface/orca-runtime-terminal-retirement.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts src/renderer/src/runtime/web-session-tabs-sync/inventory/remote-runtime-session-tabs-inflight.test.ts src/renderer/src/runtime/web-session-tabs-sync/inventory/web-runtime-session.test.ts", - "Module-layout wave1 intentionally retires complete prohibited owning registrations in src/renderer/src/runtime/web-session-tabs-sync/inventory/web-runtime-session.test.ts. Lost alarms: confirms only the exact handoff after its post-create list completes. No equivalent replacement coverage or pass for a reduced selector is claimed. All unrelated selectors and historical receipts retain their original scope." + "Module-layout wave1 intentionally retires complete prohibited owning registrations in src/renderer/src/runtime/web-session-tabs-sync/inventory/web-runtime-session.test.ts. Lost alarms: confirms only the exact handoff after its post-create list completes. No equivalent replacement coverage or pass for a reduced selector is claimed. All unrelated selectors and historical receipts retain their original scope.", + "Audit 3301 removes the caller-chat-target precedence over host selection example from web-session-tabs-sync-focus-intent.test.ts. The snapshot-before-RPC replay and split-sibling-first exact-leaf focus cases remain unchanged and match the existing assertion reference. Preserve current selectors, assertion references, unrelated active receipts and complete archived history. These mocked state-composition survivors provide no equivalent replacement, rendered, native, network or fresh execution proof.", + "Audit3359 retires the whole create-handoff suite. Supplied disposition, late completion, close-callback and metadata-bookkeeping alarms are intentionally lost without equivalent replacement; the compound unit selector and test-file entry narrow accordingly. Five unrelated macOS receipts retain their original scope. No fresh runtime, process-deduplication, physical provider/network, historical-import, mobile, mixed-version or cross-platform validation is claimed.", + "Audit3359 historical original commands object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/shared/claimed-agent-pty-owner.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts src/main/runtime/session-construction/agent-session/orca-runtime-agent-session-operation.test.ts src/main/runtime/session-construction/agent-session/remote-agent-session-host-authority.integration.test.ts src/main/runtime/terminal/surface/orca-runtime-terminal-retirement.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts\"", + "Audit3359 historical original testFiles object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts\"", + "Audit3368 retires the whole host-session-launch unit source, including host-authority/create/ensure/legacy/Kimi/refusal/draft/options/prompt/cancel/kill/shared-disconnect and passive-sleep output callback alarms, without equivalent replacement. Its unit command token and test-file entry retire. Five unrelated macOS receipts remain verbatim and keep only their original scope; no fresh changed-selector/runtime/provider/process/UI/mobile/mixed-version/cross-platform evidence is claimed.", + "Audit3368 historical original commands object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/shared/claimed-agent-pty-owner.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts src/main/runtime/session-construction/agent-session/orca-runtime-agent-session-operation.test.ts src/main/runtime/session-construction/agent-session/remote-agent-session-host-authority.integration.test.ts src/main/runtime/terminal/surface/orca-runtime-terminal-retirement.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts\"", + "Audit3368 historical original testFiles object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts\"" ], "demotionRule": "Keep experimental or demote if the focused gate flakes without a product or harness bug, if a retry can physically spawn twice, if a stale exit/publication can replace or resurrect a terminal, or if mixed-version fallback occurs after an authority side effect." }, @@ -7615,28 +7418,25 @@ "providers": ["local", "remote-runtime", "ssh", "wsl"], "coveredPlatforms": ["macos", "linux"], "coveredProviders": [], - "coverageNotes": "Audit2371 reduces all-host-folder-workspace-catalogs.test.ts by removing the repeated offline compatibility-probe budget and its incidental local-fallback/restored-owner samples, and catalog-settlement-notifications.test.ts by removing the four-route ten-equal-refresh notification/reference matrix. Those probe, quietness, identity and fallback alarms are intentionally lost. Remaining stale-response and revision-fencing examples do not supply equivalent replacement coverage. No fresh execution or red/green evidence validates the reduced sources; the four unrelated physical selected-runtime E2E receipts retain their original commands and scope. Historical prior account (preserved verbatim): Audit2360 removes src/renderer/src/hooks/useIpcEvents-terminal-create-surfacing.test.ts and its exclusive fake-effect harness. Lose local default-runtime persistence across navigation; focused/background terminal request/create/reveal and no-focus recovery; startup cwd/config/agent/view-mode forwarding; explicit runtime-session routing; remote/ambiguous/missing owner refusal; history focus; existing PTY reuse/title preservation; pending tab PTY/layout/identity adoption; split tree, focus, identity and telemetry samples. No equivalent replacement claimed. Changed selectors have no fresh execution or red/green credit. Unrelated retained receipt objects keep their original narrow scope. Historical prior account (preserved verbatim): Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/store/project-groups/nested-repository-operations.test.ts: routes local nested scan progress by scanId and unsubscribes after completion. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Historical prior account (preserved verbatim): Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1488 deletes NonGitFolderDialog tests. The hand-assembled scan/import pipelines, supplied host and folder outcomes, registration callback receipts and static host confirmation alarms are retired. No equivalent replacement coverage or fresh routing validation is claimed. Historical receipts and assertions describe their original sources only. Audit1487 deletes AddProjectFromFolderDialog and project-added-default-checkout tests and reduces AddRepoStartSteps to custom ArrowDown navigation. Mocked admission/activation and static host-control assertions are retired. No equivalent replacement coverage or fresh routing validation is claimed. Historical receipts and assertions below describe their original sources only. Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Audit1417 intentionally reduces src/renderer/src/store/slices/repos-stale-fetch.spec.ts: Loses startup catalog admission/reconnect preservation and settlement failure gating alarms. No equivalent replacement coverage or fresh result is claimed. Historical coverage account: Audit1391 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Audits1342 and1337 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Audit1320 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): This audit removes browser generic Active Server settings isolation and unknown-choice examples; their direct preference and rejection alarms are lost. Other routing evidence is not an equivalent replacement. Historical commands and results remain historical. Platform-neutral deterministic tests separate the durable Active Server preference from per-client connection, selected-workspace, browser-session, Add Project, and execution-host routing. The composed regression models Local desktop -> connect/navigate Windows 2 -> reveal a local terminal -> restart. Multi-client browser host overrides, multi-server profile caches, generic settings IPC rejection, local and remote workspace ownership, Add Project eligibility/owner capture/stale-result fencing, host-qualified group/folder/worktree identity, and restart reset of transient routing are covered. A visible macOS Orca desktop server plus separate paired Electron and web clients prove selected-runtime Add Project operations and disabled creation when the only listed host is blocked or unavailable; headless-server parity also passed. Live Linux, Windows, WSL, and SSH Add Project journeys remain uncollected. The static wrapper-rendering suite was removed during the low-value-test audit; its supplied-prop host-browser and control-visibility output assertions are no longer checked by that suite. This removal supplies no new runtime-routing evidence. The fake-React Clone hook unit suite was also retired: its captured-owner and same-ID sibling assertions no longer supply unit evidence. Historical run commands and counts remain historical; this retirement adds no runtime-routing, cross-platform, or mobile evidence. The test-value audit narrowed resolved-worktree-execution-host.test.ts to cache reuse and invalidation. Its direct hydrated-worktree, missing-folder, restored-owner, host-stamp and empty-runtime selection alarms are lost. Other routing and recovery suites do not establish equivalent selector coverage; historical run commands and results remain historical. The test-value audit narrowed worktree-runtime-owner.test.ts to deterministic owner-lookup work bounds with correct worktree/folder results and changed-collection invalidation. Its separate host/default/folder/mirror inventory alarms are lost; these retained in-memory checks establish no actual host delivery, restart or equivalent replacement coverage. Historical run commands and results remain historical. web-runtime-session.test.ts no longer supplies the terminal/browser/staged-browser explicit-host collision assertions formerly referenced here. Those direct routing alarms are lost; the remaining selector and live routing evidence does not establish equivalent replacement coverage. The test-value audit removes the direct host/provider/project-setup selector tables. selectors.test.ts retains only floating-tab/unread scan-cost checks, which supply no current Active Server routing evidence. Its separate missing-runtime/no-local-fallback and owner-choice alarms are lost; other gate evidence is not an equivalent replacement. Historical executed commands and results remain historical. browser.test.ts no longer supplies the host/profile projection examples. Current routing commands and references name the retained deferred host-list/import completion tests in browser-session-host-selection.test.ts instead. Its actual source supports stale-completion fencing; it does not establish the formerly listed multi-client selection or restart-reset claims. Other evidence is not an equivalent replacement; historical executed commands/counts/results remain historical. The test-value audit deletes repos-paired-runtime-add.test.ts. Its supplied-result assertion that an explicitly selected paired host receives repo.add with the selected path, folder kind and 15000ms timeout while native repos.add and pickFolder remain unused is intentionally lost. Other gate evidence is not an equivalent replacement. Historical executed commands, counts and results remain unchanged. The test-value audit narrows repos-selected-owner-routing.test.ts to an overlapping selected-runtime import/local refresh, reversed same-host folder replies, and group/folder replies crossing an actual pairing revision. Its separate same-ID host-partition, desktop-only pruning, sequential explicit-runtime preservation, and SSH scan/cancel forwarding alarms are intentionally lost. The stale-response case overwrites its group result before the final assertion, so it supplies only a folder stale-response alarm. The catalog-reconciliation caller also retires the refresh-identity and runtime-visibility-default registrars: their immediate reference/field/count, filter/dismissal, readoption-inventory, timestamp and settings/capability-copy/retention alarms are lost. No equivalent replacement or new live host, restart, platform or mobile evidence is claimed; historical executed commands, counts and results remain unchanged. The test-value audit removes the reversed-order direct worktree lookup example from selected-host-active-workspace-identity.test.ts. Its explicit-runtime path lookup with reversed same-ID catalog rows is intentionally lost; that example did not activate a workspace. After the subsequent audit, current assertions in this suite name only the retained local-first worktree activation; the selected-runtime folder/group host-echo example was removed. They are not equivalent replacements for the reversed-order lookup alarm. Historical executed commands, counts and results remain unchanged; no new live host, restart, platform or mobile evidence is claimed. The test-value audit narrows renderer store settings.test.ts by removing immediate authoritative-settings/response rebasing, checked-failure forwarding, best-effort logging, mobile-address/provider normalization, successful catalog-start, hand-seeded partial-status coverage and ghost-status filtering examples. Those direct response, normalization, error and catalog-projection alarms are intentionally lost. The runtime focus-switch resource/draft preservation, unreachable/incompatible refusal and held catalog coalescing/retry/staleness cases remain; they are not equivalent replacements for the removed alarms. Historical executed commands, counts and results remain unchanged; no new live host, restart, platform or mobile evidence is claimed. The test-value audit narrows worktrees-fetch-owner-routing.test.ts by removing default-local transport selection, ownerless runtime stamping, isolated force-local routing, and mocked mobile-denial/toast examples. Those direct routing, field and presentation alarms are lost. Retained concurrency and authority-fencing cases do not establish equivalent replacement coverage or live host, platform, restart or mobile evidence. Historical commands, counts and results remain unchanged. The test-value audit removes the separate paired-web host-switch resource-preservation example from renderer store settings.test.ts. Its explicit web-mode terminal/browser no-close and retained PTY/remote-browser-handle alarms are intentionally lost. The surviving desktop host-merge, resource/draft preservation, refusal and catalog retry/coalescing/staleness cases are not equivalent replacement coverage. Historical executed commands, counts and results remain unchanged; no new live host, restart, platform or mobile evidence is claimed. The test-value audit removes the selected-runtime folder/group activation example from selected-host-active-workspace-identity.test.ts. That large same-ID fixture only asserted that the explicit host argument was stored and read back; it did not check the chosen folder path, group or delivered operation. Its narrow non-rejection/host-echo alarm is intentionally lost. Only the local-first worktree case that independently checks the returned runtime path remains in this suite. Historical executed commands, counts and results remain unchanged; no equivalent replacement or new live-host evidence is claimed. The continued test-value audit narrows worktrees-fetch-owner-routing.test.ts by retiring the simple explicit-local duplicate-repo request and runtime-only host-stamping examples. Those exact request-option and supplied-row alarms are intentionally lost. The retained force-local sibling-preservation and project-setup stamping cases use different inputs and are not equivalent replacements. Historical commands, counts and results remain unchanged; no live-host, restart, platform or mobile evidence is added. The test-value audit removes the browser-settings host-option fallback helper suite. Its direct selected/default/empty-option preference alarms are lost; no browser session, host delivery or persistence was exercised there. Remaining routing evidence is not an equivalent replacement. Historical commands, counts and results remain historical. The test-value audit deletes paired-web-add-project-unavailable-host.spec.ts. Its injected blocked/unavailable-host disabled-action and no-local-option presentation alarms are intentionally lost. The snapshot sequence and null transport do not prove actual version negotiation or operation rejection. Other routing evidence is not an equivalent replacement; no new runtime, platform or mobile evidence is claimed. The two retired historical receipts and assertion reference are archived below with their original fields and results. Audit1320: src/renderer/src/components/settings/runtime-environments/catalog/RuntimeEnvironmentsPane.test.ts removed. Transport-up/runtime-down, failed-probe ready/reconnect/handshake and stale compatibility label/button state inventories lose alarms. No equivalent replacement coverage is claimed. Audit1342: src/renderer/src/components/sidebar/worktree-list/listing/host-filtering.test.ts removed. Runtime/SSH/default row ownership and folder/project path-status routing samples disappear. src/renderer/src/store/slices/repos-catalog-reconciliation.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Audit1337: src/renderer/src/components/sidebar/project-admission/dialog/add-repo-browse-authority.test.ts removed. Removes paired-host browse versus native picker callback flags and SSH no-browse predicate samples. src/renderer/src/components/sidebar/project-admission/dialog/AddRepoDialog.default-checkout.test.ts removed. Removes explicit local/runtime versus missing owner selector examples. No equivalent replacement coverage is claimed. Audit1352: focused Linux unit selections validated on source head b638e07d395b76af3ba6b03761a1a0fe7e5e026e. Historical statements above retain their original scope. Intentional test losses are recorded in knownGaps; these runs claim no physical-provider, p95, rendered E2E or cross-platform validation. Audit1360: focused Linux unit selections validated on source head 415c9cffc2d10024131ec4b6721767a22195de6d. Historical statements above retain their original scope. Intentional test losses are recorded in knownGaps; these runs claim no physical-provider, p95, rendered E2E or cross-platform validation. Audit1391: src/renderer/src/lib/worktree-runtime-owner.test.ts reduced. Lose explicit repeated-lookup work/read budget and standalone initial owner lookup alarms. Retained production resolver proves changed ownership is visible, using synthetic catalogs rather than server publication. No equivalent replacement coverage is claimed.", + "coverageNotes": "Audit3362 retires the whole settings suite, including dirty-draft focus, background-host keepalive, protocol/catalog compatibility, stale/failure and refresh examples. The compound unit selector and test-file entry narrow; all prior owner-routing retirements/history remain. Four unrelated selected-runtime macOS E2E receipts remain verbatim and do not validate the changed unit selector. No equivalent replacement or fresh runtime/provider/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit3349 retires the explicit runtime-owner, explicit SSH-owner and missing-owner-after-catalog-change examples from worktrees-fetch-owner-routing. Of those four named assertions, only the missing-owner-after-provider-reconnect assertion remains; the command and test-file selector survive. Those three alarms are intentionally lost without equivalent replacement. Four unrelated physical selected-runtime macOS E2E receipts remain verbatim; the frozen static closure does not select changed tests through their literal roots. No fresh runtime, provider, historical-import, mobile, mixed-version or cross-platform validation is claimed. Audit3326 adopts reconciled source audit3324 and intentionally retires these low-value examples and their regression alarms: drops older same-host group and folder responses that finish last — Copies group and folder fixtures plus four deferred responses to re-test the same generic catalog generation fence in two wrappers. Retires stale same-host response rejection at these API copies.; drops pre-reconnect group and folder responses without pruning the new catalog — Directly replaces pairing/catalog fixtures then resolves scripted old group/folder replies; repeats identity-fence contract in two catalog wrappers without real reconnect. Retires pre-reconnect catalog pruning refusal example.. Retained tests do not replace these alarms. Dated unrelated evidence remains scoped to its original execution; no historical source/import-closure equivalence, fresh execution, real network/provider/SSH, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit2371 reduces all-host-folder-workspace-catalogs.test.ts by removing the repeated offline compatibility-probe budget and its incidental local-fallback/restored-owner samples, and catalog-settlement-notifications.test.ts by removing the four-route ten-equal-refresh notification/reference matrix. Those probe, quietness, identity and fallback alarms are intentionally lost. Remaining stale-response and revision-fencing examples do not supply equivalent replacement coverage. No fresh execution or red/green evidence validates the reduced sources; the four unrelated physical selected-runtime E2E receipts retain their original commands and scope. Historical prior account (preserved verbatim): Audit2360 removes src/renderer/src/hooks/useIpcEvents-terminal-create-surfacing.test.ts and its exclusive fake-effect harness. Lose local default-runtime persistence across navigation; focused/background terminal request/create/reveal and no-focus recovery; startup cwd/config/agent/view-mode forwarding; explicit runtime-session routing; remote/ambiguous/missing owner refusal; history focus; existing PTY reuse/title preservation; pending tab PTY/layout/identity adoption; split tree, focus, identity and telemetry samples. No equivalent replacement claimed. Changed selectors have no fresh execution or red/green credit. Unrelated retained receipt objects keep their original narrow scope. Historical prior account (preserved verbatim): Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/store/project-groups/nested-repository-operations.test.ts: routes local nested scan progress by scanId and unsubscribes after completion. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Historical prior account (preserved verbatim): Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1488 deletes NonGitFolderDialog tests. The hand-assembled scan/import pipelines, supplied host and folder outcomes, registration callback receipts and static host confirmation alarms are retired. No equivalent replacement coverage or fresh routing validation is claimed. Historical receipts and assertions describe their original sources only. Audit1487 deletes AddProjectFromFolderDialog and project-added-default-checkout tests and reduces AddRepoStartSteps to custom ArrowDown navigation. Mocked admission/activation and static host-control assertions are retired. No equivalent replacement coverage or fresh routing validation is claimed. Historical receipts and assertions below describe their original sources only. Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Audit1417 intentionally reduces src/renderer/src/store/slices/repos-stale-fetch.spec.ts: Loses startup catalog admission/reconnect preservation and settlement failure gating alarms. No equivalent replacement coverage or fresh result is claimed. Historical coverage account: Audit1391 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Audits1342 and1337 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Audit1320 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): This audit removes browser generic Active Server settings isolation and unknown-choice examples; their direct preference and rejection alarms are lost. Other routing evidence is not an equivalent replacement. Historical commands and results remain historical. Platform-neutral deterministic tests separate the durable Active Server preference from per-client connection, selected-workspace, browser-session, Add Project, and execution-host routing. The composed regression models Local desktop -> connect/navigate Windows 2 -> reveal a local terminal -> restart. Multi-client browser host overrides, multi-server profile caches, generic settings IPC rejection, local and remote workspace ownership, Add Project eligibility/owner capture/stale-result fencing, host-qualified group/folder/worktree identity, and restart reset of transient routing are covered. A visible macOS Orca desktop server plus separate paired Electron and web clients prove selected-runtime Add Project operations and disabled creation when the only listed host is blocked or unavailable; headless-server parity also passed. Live Linux, Windows, WSL, and SSH Add Project journeys remain uncollected. The static wrapper-rendering suite was removed during the low-value-test audit; its supplied-prop host-browser and control-visibility output assertions are no longer checked by that suite. This removal supplies no new runtime-routing evidence. The fake-React Clone hook unit suite was also retired: its captured-owner and same-ID sibling assertions no longer supply unit evidence. Historical run commands and counts remain historical; this retirement adds no runtime-routing, cross-platform, or mobile evidence. The test-value audit narrowed resolved-worktree-execution-host.test.ts to cache reuse and invalidation. Its direct hydrated-worktree, missing-folder, restored-owner, host-stamp and empty-runtime selection alarms are lost. Other routing and recovery suites do not establish equivalent selector coverage; historical run commands and results remain historical. The test-value audit narrowed worktree-runtime-owner.test.ts to deterministic owner-lookup work bounds with correct worktree/folder results and changed-collection invalidation. Its separate host/default/folder/mirror inventory alarms are lost; these retained in-memory checks establish no actual host delivery, restart or equivalent replacement coverage. Historical run commands and results remain historical. web-runtime-session.test.ts no longer supplies the terminal/browser/staged-browser explicit-host collision assertions formerly referenced here. Those direct routing alarms are lost; the remaining selector and live routing evidence does not establish equivalent replacement coverage. The test-value audit removes the direct host/provider/project-setup selector tables. selectors.test.ts retains only floating-tab/unread scan-cost checks, which supply no current Active Server routing evidence. Its separate missing-runtime/no-local-fallback and owner-choice alarms are lost; other gate evidence is not an equivalent replacement. Historical executed commands and results remain historical. browser.test.ts no longer supplies the host/profile projection examples. Current routing commands and references name the retained deferred host-list/import completion tests in browser-session-host-selection.test.ts instead. Its actual source supports stale-completion fencing; it does not establish the formerly listed multi-client selection or restart-reset claims. Other evidence is not an equivalent replacement; historical executed commands/counts/results remain historical. The test-value audit deletes repos-paired-runtime-add.test.ts. Its supplied-result assertion that an explicitly selected paired host receives repo.add with the selected path, folder kind and 15000ms timeout while native repos.add and pickFolder remain unused is intentionally lost. Other gate evidence is not an equivalent replacement. Historical executed commands, counts and results remain unchanged. The test-value audit narrows repos-selected-owner-routing.test.ts to an overlapping selected-runtime import/local refresh, reversed same-host folder replies, and group/folder replies crossing an actual pairing revision. Its separate same-ID host-partition, desktop-only pruning, sequential explicit-runtime preservation, and SSH scan/cancel forwarding alarms are intentionally lost. The stale-response case overwrites its group result before the final assertion, so it supplies only a folder stale-response alarm. The catalog-reconciliation caller also retires the refresh-identity and runtime-visibility-default registrars: their immediate reference/field/count, filter/dismissal, readoption-inventory, timestamp and settings/capability-copy/retention alarms are lost. No equivalent replacement or new live host, restart, platform or mobile evidence is claimed; historical executed commands, counts and results remain unchanged. The test-value audit removes the reversed-order direct worktree lookup example from selected-host-active-workspace-identity.test.ts. Its explicit-runtime path lookup with reversed same-ID catalog rows is intentionally lost; that example did not activate a workspace. After the subsequent audit, current assertions in this suite name only the retained local-first worktree activation; the selected-runtime folder/group host-echo example was removed. They are not equivalent replacements for the reversed-order lookup alarm. Historical executed commands, counts and results remain unchanged; no new live host, restart, platform or mobile evidence is claimed. The test-value audit narrows renderer store settings.test.ts by removing immediate authoritative-settings/response rebasing, checked-failure forwarding, best-effort logging, mobile-address/provider normalization, successful catalog-start, hand-seeded partial-status coverage and ghost-status filtering examples. Those direct response, normalization, error and catalog-projection alarms are intentionally lost. The runtime focus-switch resource/draft preservation, unreachable/incompatible refusal and held catalog coalescing/retry/staleness cases remain; they are not equivalent replacements for the removed alarms. Historical executed commands, counts and results remain unchanged; no new live host, restart, platform or mobile evidence is claimed. The test-value audit narrows worktrees-fetch-owner-routing.test.ts by removing default-local transport selection, ownerless runtime stamping, isolated force-local routing, and mocked mobile-denial/toast examples. Those direct routing, field and presentation alarms are lost. Retained concurrency and authority-fencing cases do not establish equivalent replacement coverage or live host, platform, restart or mobile evidence. Historical commands, counts and results remain unchanged. The test-value audit removes the separate paired-web host-switch resource-preservation example from renderer store settings.test.ts. Its explicit web-mode terminal/browser no-close and retained PTY/remote-browser-handle alarms are intentionally lost. The surviving desktop host-merge, resource/draft preservation, refusal and catalog retry/coalescing/staleness cases are not equivalent replacement coverage. Historical executed commands, counts and results remain unchanged; no new live host, restart, platform or mobile evidence is claimed. The test-value audit removes the selected-runtime folder/group activation example from selected-host-active-workspace-identity.test.ts. That large same-ID fixture only asserted that the explicit host argument was stored and read back; it did not check the chosen folder path, group or delivered operation. Its narrow non-rejection/host-echo alarm is intentionally lost. Only the local-first worktree case that independently checks the returned runtime path remains in this suite. Historical executed commands, counts and results remain unchanged; no equivalent replacement or new live-host evidence is claimed. The continued test-value audit narrows worktrees-fetch-owner-routing.test.ts by retiring the simple explicit-local duplicate-repo request and runtime-only host-stamping examples. Those exact request-option and supplied-row alarms are intentionally lost. The retained force-local sibling-preservation and project-setup stamping cases use different inputs and are not equivalent replacements. Historical commands, counts and results remain unchanged; no live-host, restart, platform or mobile evidence is added. The test-value audit removes the browser-settings host-option fallback helper suite. Its direct selected/default/empty-option preference alarms are lost; no browser session, host delivery or persistence was exercised there. Remaining routing evidence is not an equivalent replacement. Historical commands, counts and results remain historical. The test-value audit deletes paired-web-add-project-unavailable-host.spec.ts. Its injected blocked/unavailable-host disabled-action and no-local-option presentation alarms are intentionally lost. The snapshot sequence and null transport do not prove actual version negotiation or operation rejection. Other routing evidence is not an equivalent replacement; no new runtime, platform or mobile evidence is claimed. The two retired historical receipts and assertion reference are archived below with their original fields and results. Audit1320: src/renderer/src/components/settings/runtime-environments/catalog/RuntimeEnvironmentsPane.test.ts removed. Transport-up/runtime-down, failed-probe ready/reconnect/handshake and stale compatibility label/button state inventories lose alarms. No equivalent replacement coverage is claimed. Audit1342: src/renderer/src/components/sidebar/worktree-list/listing/host-filtering.test.ts removed. Runtime/SSH/default row ownership and folder/project path-status routing samples disappear. src/renderer/src/store/slices/repos-catalog-reconciliation.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Audit1337: src/renderer/src/components/sidebar/project-admission/dialog/add-repo-browse-authority.test.ts removed. Removes paired-host browse versus native picker callback flags and SSH no-browse predicate samples. src/renderer/src/components/sidebar/project-admission/dialog/AddRepoDialog.default-checkout.test.ts removed. Removes explicit local/runtime versus missing owner selector examples. No equivalent replacement coverage is claimed. Audit1352: focused Linux unit selections validated on source head b638e07d395b76af3ba6b03761a1a0fe7e5e026e. Historical statements above retain their original scope. Intentional test losses are recorded in knownGaps; these runs claim no physical-provider, p95, rendered E2E or cross-platform validation. Audit1360: focused Linux unit selections validated on source head 415c9cffc2d10024131ec4b6721767a22195de6d. Historical statements above retain their original scope. Intentional test losses are recorded in knownGaps; these runs claim no physical-provider, p95, rendered E2E or cross-platform validation. Audit1391: src/renderer/src/lib/worktree-runtime-owner.test.ts reduced. Lose explicit repeated-lookup work/read budget and standalone initial owner lookup alarms. Retained production resolver proves changed ownership is visible, using synthetic catalogs rather than server publication. No equivalent replacement coverage is claimed.", "motivatingLinks": [ "https://github.com/stablyai/orca/pull/9687", "https://linear.app/stably/issue/STA-4024/p1-paired-web-add-project-enables-unavailable-host-fallback-after-pr" ], "invariant": "Only an explicit user change in Settings > Remote Orca Servers > Advanced > Active Server may mutate activeRuntimeEnvironmentId. Connecting, pairing, disconnecting, selecting or revealing a workspace or terminal, browser/mobile handoff, remote navigation, and reconnect must use transient or target-owner routing and must never rewrite the durable preference. Every Add Project selected host must satisfy canSelectAddRepoHost; paired web has no local filesystem fallback, so no valid host means Browse, Clone, and Create remain disabled. Every operation stays on the host selected when it began, even if preference or catalog state changes. Generic settings mutation cannot bypass the dedicated preference IPC.", - "oracle": "Audit2371 reduces all-host-folder-workspace-catalogs.test.ts by removing the repeated offline compatibility-probe budget and its incidental local-fallback/restored-owner samples, and catalog-settlement-notifications.test.ts by removing the four-route ten-equal-refresh notification/reference matrix. Those probe, quietness, identity and fallback alarms are intentionally lost. Remaining stale-response and revision-fencing examples do not supply equivalent replacement coverage. No fresh execution or red/green evidence validates the reduced sources; the four unrelated physical selected-runtime E2E receipts retain their original commands and scope. Historical prior account (preserved verbatim): Audit2360 removes src/renderer/src/hooks/useIpcEvents-terminal-create-surfacing.test.ts and its exclusive fake-effect harness. Lose local default-runtime persistence across navigation; focused/background terminal request/create/reveal and no-focus recovery; startup cwd/config/agent/view-mode forwarding; explicit runtime-session routing; remote/ambiguous/missing owner refusal; history focus; existing PTY reuse/title preservation; pending tab PTY/layout/identity adoption; split tree, focus, identity and telemetry samples. No equivalent replacement claimed. Changed selectors have no fresh execution or red/green credit. Unrelated retained receipt objects keep their original narrow scope. Historical prior account (preserved verbatim): Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/store/project-groups/nested-repository-operations.test.ts: routes local nested scan progress by scanId and unsubscribes after completion. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Historical prior account (preserved verbatim): Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Historical pre-audit oracle account for changed sources: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Start with Active Server=Local desktop, connect and navigate Windows 2, then reveal a local terminal and assert it succeeds while the persisted preference remains local before and after restart. Repeat transient routing and selected-runtime Add Project operations with exact-ID host decoys and completion reordering. Separately pair the real web client to an isolated headed host, then make its sole still-listed runtime compatibility-blocked and unavailable. Require a null authoritative selection, a disabled host option, and disabled Browse, Clone, and Create actions with no local fallback. Repeat against headless serve. Run the byte-identical selector/action contract on latest main, candidate, and candidate with the eligibility seam disabled.", + "oracle": "Audit3362 retires the whole settings suite, including dirty-draft focus, background-host keepalive, protocol/catalog compatibility, stale/failure and refresh examples. The compound unit selector and test-file entry narrow; all prior owner-routing retirements/history remain. Four unrelated selected-runtime macOS E2E receipts remain verbatim and do not validate the changed unit selector. No equivalent replacement or fresh runtime/provider/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit3349 retires the explicit runtime-owner, explicit SSH-owner and missing-owner-after-catalog-change examples from worktrees-fetch-owner-routing. Of those four named assertions, only the missing-owner-after-provider-reconnect assertion remains; the command and test-file selector survive. Those three alarms are intentionally lost without equivalent replacement. Four unrelated physical selected-runtime macOS E2E receipts remain verbatim; the frozen static closure does not select changed tests through their literal roots. No fresh runtime, provider, historical-import, mobile, mixed-version or cross-platform validation is claimed. Audit3326 adopts reconciled source audit3324 and intentionally retires these low-value examples and their regression alarms: drops older same-host group and folder responses that finish last — Copies group and folder fixtures plus four deferred responses to re-test the same generic catalog generation fence in two wrappers. Retires stale same-host response rejection at these API copies.; drops pre-reconnect group and folder responses without pruning the new catalog — Directly replaces pairing/catalog fixtures then resolves scripted old group/folder replies; repeats identity-fence contract in two catalog wrappers without real reconnect. Retires pre-reconnect catalog pruning refusal example.. Retained tests do not replace these alarms. Dated unrelated evidence remains scoped to its original execution; no historical source/import-closure equivalence, fresh execution, real network/provider/SSH, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit2371 reduces all-host-folder-workspace-catalogs.test.ts by removing the repeated offline compatibility-probe budget and its incidental local-fallback/restored-owner samples, and catalog-settlement-notifications.test.ts by removing the four-route ten-equal-refresh notification/reference matrix. Those probe, quietness, identity and fallback alarms are intentionally lost. Remaining stale-response and revision-fencing examples do not supply equivalent replacement coverage. No fresh execution or red/green evidence validates the reduced sources; the four unrelated physical selected-runtime E2E receipts retain their original commands and scope. Historical prior account (preserved verbatim): Audit2360 removes src/renderer/src/hooks/useIpcEvents-terminal-create-surfacing.test.ts and its exclusive fake-effect harness. Lose local default-runtime persistence across navigation; focused/background terminal request/create/reveal and no-focus recovery; startup cwd/config/agent/view-mode forwarding; explicit runtime-session routing; remote/ambiguous/missing owner refusal; history focus; existing PTY reuse/title preservation; pending tab PTY/layout/identity adoption; split tree, focus, identity and telemetry samples. No equivalent replacement claimed. Changed selectors have no fresh execution or red/green credit. Unrelated retained receipt objects keep their original narrow scope. Historical prior account (preserved verbatim): Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/store/project-groups/nested-repository-operations.test.ts: routes local nested scan progress by scanId and unsubscribes after completion. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Historical prior account (preserved verbatim): Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Historical pre-audit oracle account for changed sources: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Start with Active Server=Local desktop, connect and navigate Windows 2, then reveal a local terminal and assert it succeeds while the persisted preference remains local before and after restart. Repeat transient routing and selected-runtime Add Project operations with exact-ID host decoys and completion reordering. Separately pair the real web client to an isolated headed host, then make its sole still-listed runtime compatibility-blocked and unavailable. Require a null authoritative selection, a disabled host option, and disabled Browse, Clone, and Create actions with no local fallback. Repeat against headless serve. Run the byte-identical selector/action contract on latest main, candidate, and candidate with the eligibility seam disabled.", "commands": [ - "pnpm exec vitest run --config config/vitest.config.ts src/main/ipc/runtime-environments/runtime-environments-pairing.test.ts src/renderer/src/store/slices/settings/settings.test.ts src/renderer/src/store/slices/browser/hosts/browser-session-host-selection.test.ts src/renderer/src/web/web-preload-api-runtime-environment.test.ts --maxWorkers=1", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/resolved-worktree-execution-host.test.ts src/renderer/src/store/repos/ssh-repo-readoption-drafts.test.ts src/renderer/src/store/folder-workspaces/folder-workspace-readoption-drafts.test.ts src/renderer/src/store/repos/repo-catalog-readoption-drafts.test.ts src/renderer/src/store/folder-workspaces/all-host-folder-workspace-catalogs.test.ts src/renderer/src/store/host-catalog/catalog-settlement-notifications.test.ts src/renderer/src/store/repos/repos-stale-fetch.test.ts src/renderer/src/store/folder-workspaces/folder-workspace-routing.test.ts src/renderer/src/store/repos/repos-selected-owner-routing.test.ts src/renderer/src/store/slices/worktrees/session/selected-host-active-workspace-identity.test.ts src/renderer/src/store/slices/worktrees/listing/worktrees-fetch-owner-routing.test.ts --maxWorkers=1", + "pnpm exec vitest run --config config/vitest.config.ts src/main/ipc/runtime-environments/runtime-environments-pairing.test.ts src/renderer/src/store/slices/browser/hosts/browser-session-host-selection.test.ts src/renderer/src/web/web-preload-api-runtime-environment.test.ts --maxWorkers=1", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/repos/ssh-repo-readoption-drafts.test.ts src/renderer/src/store/folder-workspaces/folder-workspace-readoption-drafts.test.ts src/renderer/src/store/repos/repo-catalog-readoption-drafts.test.ts src/renderer/src/store/folder-workspaces/all-host-folder-workspace-catalogs.test.ts src/renderer/src/store/host-catalog/catalog-settlement-notifications.test.ts src/renderer/src/store/repos/repos-stale-fetch.test.ts src/renderer/src/store/folder-workspaces/folder-workspace-routing.test.ts src/renderer/src/store/repos/repos-selected-owner-routing.test.ts src/renderer/src/store/slices/worktrees/session/selected-host-active-workspace-identity.test.ts src/renderer/src/store/slices/worktrees/listing/worktrees-fetch-owner-routing.test.ts --maxWorkers=1", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/sidebar/project-admission/dialog/AddRepoStartSteps.test.tsx --maxWorkers=1", "pnpm run ensure:electron-runtime && npx playwright test tests/e2e/pr11346-selected-runtime-add.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1 --reporter=line", "pnpm run ensure:electron-runtime && npx playwright test tests/e2e/pr11346-selected-runtime-add.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1 --reporter=line" ], "testFiles": [ "src/main/ipc/runtime-environments/runtime-environments-pairing.test.ts", - "src/renderer/src/store/slices/settings/settings.test.ts", "src/renderer/src/store/slices/browser/hosts/browser-session-host-selection.test.ts", - "src/renderer/src/web/web-preload-api-runtime-environment.test.ts", "src/renderer/src/components/sidebar/project-admission/dialog/AddRepoStartSteps.test.tsx", - "src/renderer/src/lib/resolved-worktree-execution-host.test.ts", "src/renderer/src/store/repos/ssh-repo-readoption-drafts.test.ts", "src/renderer/src/store/folder-workspaces/folder-workspace-readoption-drafts.test.ts", "src/renderer/src/store/repos/repo-catalog-readoption-drafts.test.ts", @@ -7660,19 +7460,12 @@ { "file": "src/renderer/src/store/repos/repos-selected-owner-routing.test.ts", "assertions": [ - "keeps a selected-runtime import refresh across an overlapping local refresh", - "drops reversed same-host folder responses without replacing the newer folder catalog", - "rejects pre-reconnect group and folder responses after the runtime pairing revision changes" + "keeps a selected-runtime import refresh across an overlapping local refresh" ] }, { "file": "src/renderer/src/store/slices/worktrees/listing/worktrees-fetch-owner-routing.test.ts", - "assertions": [ - "honors an explicit runtime owner before the repo catalog is hydrated", - "honors an explicit SSH owner before the repo catalog is hydrated", - "rejects a missing-owner SSH result after the repo catalog changes", - "rejects a missing-owner SSH result after the provider reconnects" - ] + "assertions": ["rejects a missing-owner SSH result after the provider reconnects"] }, { "file": "src/renderer/src/store/slices/worktrees/session/selected-host-active-workspace-identity.test.ts", @@ -7801,7 +7594,14 @@ "Audit1488 deletes NonGitFolderDialog tests. The hand-assembled scan/import pipelines, supplied host and folder outcomes, registration callback receipts and static host confirmation alarms are retired. No equivalent replacement coverage or fresh routing validation is claimed. Historical receipts and assertions describe their original sources only.", "Audit1488 historical assertion inventory; not current validated assertions: []", "Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/store/project-groups/nested-repository-operations.test.ts: routes local nested scan progress by scanId and unsubscribes after completion. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed.", - "Audit2371 reduces all-host-folder-workspace-catalogs.test.ts by removing the repeated offline compatibility-probe budget and its incidental local-fallback/restored-owner samples, and catalog-settlement-notifications.test.ts by removing the four-route ten-equal-refresh notification/reference matrix. Those probe, quietness, identity and fallback alarms are intentionally lost. Remaining stale-response and revision-fencing examples do not supply equivalent replacement coverage. No fresh execution or red/green evidence validates the reduced sources; the four unrelated physical selected-runtime E2E receipts retain their original commands and scope." + "Audit2371 reduces all-host-folder-workspace-catalogs.test.ts by removing the repeated offline compatibility-probe budget and its incidental local-fallback/restored-owner samples, and catalog-settlement-notifications.test.ts by removing the four-route ten-equal-refresh notification/reference matrix. Those probe, quietness, identity and fallback alarms are intentionally lost. Remaining stale-response and revision-fencing examples do not supply equivalent replacement coverage. No fresh execution or red/green evidence validates the reduced sources; the four unrelated physical selected-runtime E2E receipts retain their original commands and scope.", + "Module-layout wave2 intentionally retires complete prohibited owning registrations in src/renderer/src/lib/resolved-worktree-execution-host.test.ts. Lost alarms: Both explicit and legacy workspace owners resolve to env-a initially. Replacing the repo catalog refreshes legacy ownership to env-b. A conflicting local repo row makes ownership ambiguous and returns null. Repeated unrelated updates perform zero id reads, an internal work-budget alarm removed. No equivalent replacement coverage or reduced-selector pass is claimed.", + "Audit3326 adopts reconciled source audit3324 and intentionally retires these low-value examples and their regression alarms: drops older same-host group and folder responses that finish last — Copies group and folder fixtures plus four deferred responses to re-test the same generic catalog generation fence in two wrappers. Retires stale same-host response rejection at these API copies.; drops pre-reconnect group and folder responses without pruning the new catalog — Directly replaces pairing/catalog fixtures then resolves scripted old group/folder replies; repeats identity-fence contract in two catalog wrappers without real reconnect. Retires pre-reconnect catalog pruning refusal example.. Retained tests do not replace these alarms. Dated unrelated evidence remains scoped to its original execution; no historical source/import-closure equivalence, fresh execution, real network/provider/SSH, rendered UI, mobile, mixed-version or cross-platform validation is claimed.", + "Audit3349 retires the explicit runtime-owner, explicit SSH-owner and missing-owner-after-catalog-change examples from worktrees-fetch-owner-routing. Of those four named assertions, only the missing-owner-after-provider-reconnect assertion remains; the command and test-file selector survive. Those three alarms are intentionally lost without equivalent replacement. Four unrelated physical selected-runtime macOS E2E receipts remain verbatim; the frozen static closure does not select changed tests through their literal roots. No fresh runtime, provider, historical-import, mobile, mixed-version or cross-platform validation is claimed.", + "Audit3349 historical original assertionRefs object, preserved verbatim; retired source claims are not active evidence or replacement coverage:\n{\n \"file\": \"src/renderer/src/store/slices/worktrees/listing/worktrees-fetch-owner-routing.test.ts\",\n \"assertions\": [\n \"honors an explicit runtime owner before the repo catalog is hydrated\",\n \"honors an explicit SSH owner before the repo catalog is hydrated\",\n \"rejects a missing-owner SSH result after the repo catalog changes\",\n \"rejects a missing-owner SSH result after the provider reconnects\"\n ]\n }", + "Audit3362 retires the whole settings suite, including dirty-draft focus, background-host keepalive, protocol/catalog compatibility, stale/failure and refresh examples. The compound unit selector and test-file entry narrow; all prior owner-routing retirements/history remain. Four unrelated selected-runtime macOS E2E receipts remain verbatim and do not validate the changed unit selector. No equivalent replacement or fresh runtime/provider/UI/mobile/mixed-version/cross-platform evidence is claimed.", + "Audit3362 historical original commands object, preserved verbatim; retired source claims are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/main/ipc/runtime-environments/runtime-environments-pairing.test.ts src/renderer/src/store/slices/settings/settings.test.ts src/renderer/src/store/slices/browser/hosts/browser-session-host-selection.test.ts src/renderer/src/web/web-preload-api-runtime-environment.test.ts --maxWorkers=1\"", + "Audit3362 historical original testFiles object, preserved verbatim; retired source claims are not active evidence or replacement coverage:\n\"src/renderer/src/store/slices/settings/settings.test.ts\"" ], "demotionRule": "Demote or block release if any non-Advanced path mutates Active Server, if local reveal or Add Project depends on the durable default instead of captured workspace/host ownership, if an Add Project operation reaches a different host after it begins, or if transient host state survives restart." }, @@ -8006,7 +7806,7 @@ "id": "terminal-scroll.intent-preservation", "title": "Scrollbar drag intent survives tab and visibility resume", "maturity": "experimental", - "protection": "partial", + "protection": "none", "owner": "terminal-rendering", "layer": "renderer-unit", "surfaces": [ @@ -8018,36 +7818,16 @@ ], "platforms": ["macos", "linux", "windows"], "providers": ["local", "daemon", "ssh", "wsl", "remote-runtime"], - "coveredPlatforms": ["macos"], + "coveredPlatforms": [], "coveredProviders": [], "coverageNotes": "Audit2236: retain only old-terminal disposal refusing to overwrite its keyed successor, and mouse-report classification preserving wheel intent through rebuild. Both use synthetic terminal state. Remove delayed wheel sampling, pinned-growth remount, stale settle, generic rebuild suppression, wheel direction matrix, cleared-buffer durable pin and cancelled rebuild examples. No direct scrollbar/native scroll coverage or equivalent replacement is claimed. Historical dated receipt and budgets remain verbatim and do not validate these reduced source bytes. Historical prior account (preserved verbatim): The audit removes all direct scrollbar pointer-classification, dragged-viewport restoration and terminal-body exclusion examples. Retained wheel/rebuild and keyed-owner fixtures exercise related scroll-intent behavior with synthetic terminal state; they do not provide equivalent scrollbar coverage. The recorded macOS run is historical and is not a rerun of the reduced suite. Live daemon, SSH, WSL, remote-runtime, Linux and Windows scrollbar validation remains unproved.", "motivatingLinks": ["STA-1341"], "invariant": "A user-driven xterm scrollbar thumb or track scroll updates the live terminal scroll intent before tab, visibility, or layout resume enforces intent, so resume preserves the latest dragged viewport instead of an older pinned line.", "oracle": "Audit2236: retain only old-terminal disposal refusing to overwrite its keyed successor, and mouse-report classification preserving wheel intent through rebuild. Both use synthetic terminal state. Remove delayed wheel sampling, pinned-growth remount, stale settle, generic rebuild suppression, wheel direction matrix, cleared-buffer durable pin and cancelled rebuild examples. No direct scrollbar/native scroll coverage or equivalent replacement is claimed. Historical dated receipt and budgets remain verbatim and do not validate these reduced source bytes. Historical prior account (preserved verbatim): No retained unit test directly exercises scrollbar thumb/track targeting or a dragged viewport. The retained deterministic slice checks delayed wheel viewport sampling, keyed disposal/remount ownership, and wheel intent through rebuild completion or cancellation; these checks do not establish scrollbar-drag preservation.", - "commands": [ - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/pane-manager/terminal-scroll-intent.test.ts" - ], - "testFiles": ["src/renderer/src/lib/pane-manager/terminal-scroll-intent.test.ts"], - "assertionRefs": [ - { - "file": "src/renderer/src/lib/pane-manager/terminal-scroll-intent.test.ts", - "assertions": [ - "does not let an old terminal disposal overwrite its keyed successor", - "keeps rebuild wheel intent when xterm classifies the same event as mouse input" - ] - } - ], - "evidenceRuns": [ - { - "date": "2026-07-05", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/pane-manager/terminal-scroll-intent.test.ts", - "result": "passed", - "durationSeconds": 0.3, - "summary": "1 test file(s) passed, 17 tests passed in this worktree. Audit965 removes the direct scrollbar examples; this command/result remains historical and does not validate the reduced suite or equivalent scrollbar coverage." - } - ], + "commands": [], + "testFiles": [], + "assertionRefs": [], + "evidenceRuns": [], "runtimeBudget": { "p95Seconds": 10, "scope": "focused renderer unit test" @@ -8070,6 +7850,10 @@ "Attach red/green evidence for stale intent restoring the wrong viewport." ], "knownGaps": [ + "NEXT65 current scope qualification: The NEXT65 knownGaps entries below govern the changed selectors and qualify any broader coverage implication in this gate’s unchanged oracle/coverageNotes narratives. Those narratives and preserved dated evidenceRuns retain their historical text and original exact execution scopes only; no fresh execution, transferred pass or equivalent replacement coverage is claimed. Upstream case removals remain upstream; original NEXT65 proposal descriptions grant no duplicate retirement credit.", + "NEXT65 terminal-owner layout and whole-case policy: src/renderer/src/lib/pane-manager/terminal-scroll-intent.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence.", + "NEXT65 historical original active selector fields (verbatim JSON values; not current coverage):\ncommands: [\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/pane-manager/terminal-scroll-intent.test.ts\"\n ]\ntestFiles: [\"src/renderer/src/lib/pane-manager/terminal-scroll-intent.test.ts\"]\nassertionRefs: [\n {\n \"file\": \"src/renderer/src/lib/pane-manager/terminal-scroll-intent.test.ts\",\n \"assertions\": [\n \"does not let an old terminal disposal overwrite its keyed successor\",\n \"keeps rebuild wheel intent when xterm classifies the same event as mouse input\"\n ]\n }\n ]\ncoveredPlatforms: [\"macos\"]\ncoveredProviders: []", + "NEXT65 historical original evidenceRuns object (verbatim; no current-selector pass credit):\n{\n \"date\": \"2026-07-05\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/pane-manager/terminal-scroll-intent.test.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 0.3,\n \"summary\": \"1 test file(s) passed, 17 tests passed in this worktree. Audit965 removes the direct scrollbar examples; this command/result remains historical and does not validate the reduced suite or equivalent scrollbar coverage.\"\n }", "Audit2236: retain only old-terminal disposal refusing to overwrite its keyed successor, and mouse-report classification preserving wheel intent through rebuild. Both use synthetic terminal state. Remove delayed wheel sampling, pinned-growth remount, stale settle, generic rebuild suppression, wheel direction matrix, cleared-buffer durable pin and cancelled rebuild examples. No direct scrollbar/native scroll coverage or equivalent replacement is claimed. Historical dated receipt and budgets remain verbatim and do not validate these reduced source bytes.", "The manifest command covers narrower deterministic wheel/rebuild/keyed-owner behavior; it does not exercise scrollbar dragging or its DOM target contract.", "Live daemon, SSH, WSL, remote-runtime, Linux, and Windows validation is not covered by this gate.", @@ -8082,7 +7866,7 @@ "id": "terminal-scroll.streaming-refocus-intent", "title": "Streaming refocus preserves follow-output viewport intent", "maturity": "experimental", - "protection": "partial", + "protection": "none", "owner": "terminal-rendering", "layer": "renderer-unit-and-electron-e2e", "surfaces": [ @@ -8094,43 +7878,19 @@ ], "platforms": ["macos", "linux", "windows"], "providers": ["local", "daemon", "ssh", "wsl", "remote-runtime"], - "coveredPlatforms": ["macos"], - "coveredProviders": ["local", "daemon"], - "coverageNotes": "Unit coverage proves provider-independent ordering for any PaneManager. Live Electron coverage exercises a local PTY through the daemon on macOS; SSH, WSL, remote-runtime, Linux, and Windows remain unproved for this exact race. Audit1299 removes tests/e2e/terminal-streaming-refocus-viewport.spec.ts. Private-state/work-budget/assembled-fixture alarms are intentionally lost; retained suites are not equivalent replacement coverage. No new runtime/platform evidence is claimed.", + "coveredPlatforms": [], + "coveredProviders": [], + "coverageNotes": "NEXT46 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence. Historical prior account (preserved verbatim): Unit coverage proves provider-independent ordering for any PaneManager. Live Electron coverage exercises a local PTY through the daemon on macOS; SSH, WSL, remote-runtime, Linux, and Windows remain unproved for this exact race. Audit1299 removes tests/e2e/terminal-streaming-refocus-viewport.spec.ts. Private-state/work-budget/assembled-fixture alarms are intentionally lost; retained suites are not equivalent replacement coverage. No new runtime/platform evidence is claimed.", "motivatingLinks": [ "https://github.com/stablyai/orca/issues/11753", "https://github.com/stablyai/orca/pull/11915" ], "invariant": "When output is queued during a focus or visibility transition, Orca records the pre-flush viewport intent before xterm parses backlog writes, so a follow-output terminal stays at the bottom and a pinned terminal keeps its prior position.", "oracle": "Unit tests require exactly one intent sync before each queued-output flush. The Electron test injects a transient top-of-buffer xterm wobble during refocus and requires every presented scrollbar frame, including the final rendered output, to remain at the bottom.", - "commands": [ - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts", - "pnpm exec electron-vite build --mode e2e" - ], - "testFiles": [ - "src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts" - ], - "assertionRefs": [ - { - "file": "src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts", - "assertions": [ - "window-wake recovery synchronizes viewport intent exactly once before flushing queued output", - "heavy visibility resume synchronizes intent exactly once before flushing queued output" - ] - } - ], - "evidenceRuns": [ - { - "date": "2026-08-01", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/terminal-visibility-resume.test.ts", - "result": "passed", - "durationSeconds": 0.096, - "summary": "14 tests passed, including exact sync count and pre-flush ordering for wake and heavy visibility resume.", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts" - } - ], + "commands": [], + "testFiles": [], + "assertionRefs": [], + "evidenceRuns": [], "runtimeBudget": { "p95Seconds": 30, "scope": "focused renderer unit test or one Electron E2E iteration" @@ -8157,7 +7917,10 @@ "Live Linux, Windows, SSH, WSL, and remote-runtime execution is not covered for this exact race.", "The Electron gate proves follow-output behavior; adjacent scroll-intent coverage protects pinned viewport behavior.", "Audit1299 removes tests/e2e/terminal-streaming-refocus-viewport.spec.ts. Private-state/work-budget/assembled-fixture alarms are intentionally lost; retained suites are not equivalent replacement coverage. No new runtime/platform evidence is claimed.", - "Archived retired-suite historical receipt (JSON, original fields/results unchanged): {\"date\":\"2026-08-01\",\"runner\":\"local\",\"platform\":\"macos\",\"command\":\"SKIP_BUILD=1 pnpm exec playwright test tests/e2e/terminal-streaming-refocus-viewport.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1 --repeat-each=5\",\"result\":\"passed\",\"durationSeconds\":35.2,\"summary\":\"Five consecutive Electron iterations passed after replacing fixed-time readiness and stale tab capture with deterministic viewport and pane-identity oracles.\"}" + "Archived retired-suite historical receipt (JSON, original fields/results unchanged): {\"date\":\"2026-08-01\",\"runner\":\"local\",\"platform\":\"macos\",\"command\":\"SKIP_BUILD=1 pnpm exec playwright test tests/e2e/terminal-streaming-refocus-viewport.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1 --repeat-each=5\",\"result\":\"passed\",\"durationSeconds\":35.2,\"summary\":\"Five consecutive Electron iterations passed after replacing fixed-time readiness and stale tab capture with deterministic viewport and pane-identity oracles.\"}", + "NEXT46 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence.", + "NEXT46 historical original active selector fields (verbatim JSON values; not current coverage):\ncommands: [\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts\",\n \"pnpm exec electron-vite build --mode e2e\"\n ]\ntestFiles: [\n \"src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts\",\n \"assertions\": [\n \"window-wake recovery synchronizes viewport intent exactly once before flushing queued output\",\n \"heavy visibility resume synchronizes intent exactly once before flushing queued output\"\n ]\n }\n ]\ncoveredPlatforms: [\"macos\"]\ncoveredProviders: [\"local\", \"daemon\"]", + "NEXT46 historical original evidenceRuns object (verbatim; no current-selector pass credit):\n{\n \"date\": \"2026-08-01\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/terminal-visibility-resume.test.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 0.096,\n \"summary\": \"14 tests passed, including exact sync count and pre-flush ordering for wake and heavy visibility resume.\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts\"\n }" ], "demotionRule": "Demote or quarantine if the Electron oracle flakes without a product bug or harness bug filed to terminal-rendering." }, @@ -8528,15 +8291,15 @@ ], "platforms": ["macos", "linux", "windows"], "providers": ["paired-runtime", "ssh"], - "coveredPlatforms": ["macos", "linux"], + "coveredPlatforms": ["macos"], "coveredProviders": [], - "coverageNotes": "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. The direct side-effect-facts selector retains six cases: replay exclusion, live sequence handling, stale disposer ownership, one handoff drain, drain-before-snapshot, and stale replacement-snapshot refusal. Successful current-entry snapshot application is not witnessed by the retained snapshot case. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2162: Reduced inventory-authority source intentionally loses the examples recorded in knownGaps; historical execution is not validation of changed bytes. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2003: Remove SSH/absent-inventory attach refusal, later-subscriber retry, no-view adoption/takeback, provider-tail/unknown-read projections, failed-keystroke retry and simpler loss reattach examples. Keep the existing-subscriber inventory-ready retry alias only at its retained callback, plus retained held-input cancellation/replacement and overlapping attach/loss fences. The inventory driver also loses the whole empty-worktree-publication registration and folder-host/unverifiable scalar examples. Retire the entire dated10-case attach receipt; retain16 independent receipts only in their original scopes. No retained-memory or real-daemon measurement follows from supplied provider inventories. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, physical provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1991: Remove initial-snapshot sequence-domain, limited-tail/truncation and unknown-output-sequence aliases whose callbacks are removed. The source retains partial-chunk replay and requested-snapshot retry/admission at supplied snapshot/data seams, not equivalent replacement or measured retained-memory proof. Preserve the existing stream/pending-wait capacity aliases only to their retained owning multiplex callbacks with supplied PTY resolutions. Removing the sibling-PTY heartbeat dedup work-count sample does not establish a new decorative fanout budget; the unrelated-PTY cancellation fence survives. Preserve17 unrelated dated receipts. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, physical provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1983: Remove the reasonless-close selector and narrow census aliases to actual retained runtime and injected-inventory callbacks. The removed synthetic census-dedup and isolated pre-boundary timing cases receive no replacement credit; preserve17 unrelated dated receipts. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1939 (sources1934/1935): Delete the synthetic watcher-synchronization and partial-reconciliation suites. Retire all affected host-fact, capability-owner, activation-residue and retention-cap aliases because the remaining callbacks do not establish those full claims. Keep exact local hook/timer, byte-stream side effects, exit/disposal, scroll-intent cleanup and deterministic local rank/TTL progression callbacks within their mocked-host scope. No physical paired-host retention, resource budget or equivalent replacement evidence is assigned. The generic broad test command remains a runnable discovery command, never a dated execution receipt. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Delete the complete hook-agent-status projection suite and its two behavioral assertion aliases. Supplied stored hook/title/resume/staleness/rename/question/generation/PTY-retirement/snapshot-version projections are intentionally lost. The separate osc-status-scan gate mentions this source only in existing historical notes and receives no mutation. No measured hidden-output retention, CPU/RSS or resource budget result is claimed by the deleted source or this audit. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Module ownership cleanup retires the modeled cold-park private watcher/render/work-count suites under the current test policy. Their assertions are no longer active evidence. Retained lifecycle tests and headed/headless journeys do not establish equivalent coverage for those removed harness alarms. Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1634 removes low-value IPC, filesystem and runtime projections, argument inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained cancellation, ownership, authorization, filesystem and SQLite boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1627 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Audit1417 intentionally deletes src/renderer/src/components/terminal-pane/pty-connection-hidden-tui-snapshot-replay.spec.ts: Loses rich hidden snapshot sequence replay/grid resize and forced repaint after hidden snapshot alarms, including live-trigger deduplication. deletes src/renderer/src/components/terminal-pane/terminal-cold-park-verdict-loop.test.tsx: Loses modeled React oscillation alarm; real pane/watchers are not exercised. deletes src/renderer/src/runtime/remote-runtime-terminal-parse-backpressure.test.ts: Loses delayed credit until parsing, malformed frame/unknown stream handling, discarded transformed output recovery and failed ACK rearm alarms. No equivalent replacement coverage or fresh result is claimed. Historical coverage account: Audit1412 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): This audit removes the browser response-after-manual-disconnect example. Its distinct in-flight response fencing alarm is lost; retained queued-call disconnect tests are not an equivalent replacement. Historical commands and results remain historical. Deterministic headed macOS runs launch an isolated Orca desktop server and a separate paired web client. A byte-identical headless run uses an isolated `orca serve` host. Both create six real paired host PTYs with bounded high-output scrollback, prove sustained output while all six client xterms are warm-mounted but hidden causes zero renderer scheduler work, then drive 180 timed real-PTY spinner frames through a second production `session.tabs.subscribeAll` transport and the real Zustand store. Each worktree must publish and apply only its exact initial-working and final-idle titles. Both topologies ordinary-park five xterms without enabling the lossy retention budget, assert bounded cells/heap/timer lag, then restore the bounded authoritative tail exactly once on the original PTY including output produced while parked and continued input/output. The headed oracle additionally keeps every remote target workspace and terminal unmounted in the host renderer before and after client recovery. Production-parity React contracts reproduce and remove the independent cold-park watcher/title feedback loop, including memo-cache discard, StrictMode cleanup replay, detached split-PTY replacement, and the zero-park fast path. A deterministic cross-boundary contract drives 24 real PTY trackers in distinct worktrees through 2,880 decorative spinner and bare-native redraw chunks and counts host publications, serialized bytes, renderer apply calls, and store mutations while preserving exact per-PTY raw chunks and per-worktree semantic transitions. Fake-clock continuation beyond the 30-minute stale boundary requires one deduplicated refresh per worktree every 15 minutes, globally spaced by at least 50 ms, with every mirrored working status still fresh. Exact-identical Pi plus rotating normalized Pi/Grok frames renew coarse working/permission state; rich prompt/tool/question fields retain their original 30-minute lease, and `stateStartedAt`/acknowledgement identity remain stable across title/hook source swaps. A separate headed desktop-client journey relaunches the host main process while retaining the daemon and a daemon-backgrounded PTY, then requires first-observation foreground sync and continued input/output on the same PTY. Unit coverage keeps layout versions out of snapshot output high-waters when a restored snapshot has no output sequence and retries an existing subscriber only after authoritative provider inventory proves the retained PTY exists. Separate headed/headless ACK-starvation tests recover one stalled stream without replacing its PTY. A headed output-drop oracle proves a successful snapshot probe cannot certify a stale live stream when the authoritative PTY sequence advanced beyond the client high-water. Unit coverage requires an unsequenced client to establish a first-probe baseline, remain attached at the same sequence, and recover only after a later probe advances. A capability-disabled run proves legacy hosts retain the prior lossy limit/TTL fallback. Unit tests cover exact-owner capability routing, raw-stream release, singleton side-effect facts with timed handoff cleanup, 64 simultaneous synthetic-title sources with zero decorative client events after convergence, per-client late-subscribe recovery, semantic bell/title transitions, local animation-frame preservation, legacy no-output-pause delivery gating with exact snapshot restore, provider-authoritative snapshots, 128 active streams plus retry after a 129th-stream capacity rejection, capacity-pressure backoff, full split-leaf remint reconciliation, truncation, and manual-disconnect queue fencing. Linux, Windows, live SSH, and production-scale paired hosts remain gaps. The audit removed the E2E parking override/debug-handle suite. Override exposure guards, delay/retention independence, TTL filtering and debug-handle forwarding alarms are lost. Retained real parking journeys do not establish equivalent test-harness configuration coverage. The test-value audit removes separate responsive-stream, intervening-control-frame and capacity-error classification examples. Retained multiplexer checks use fake clocks and captured transport callbacks; their per-stream isolation, deadline and probe-baseline assertions do not prove an actual host restart or equivalent replacement coverage. Historical run commands and results remain historical. The test-value audit removes the standalone retained/live metadata projection and additive-preference negative example from runtime-client-events.test.ts. Its remaining case checks partial-authority event admission through a captured callback; it does not establish full-pair projection, actual peer delivery or equivalent replacement coverage. Historical commands and results remain historical. The isolated accepted-handle-events observer suite is removed. Its runtime/worktree/pane membership, once-only delivery and listener-release ledger alarms are lost. Live hidden-retention evidence does not establish equivalent observer coverage. Audit1292: The entire host-session mirror empty-inventory settle suite is removed. Live-unpublished versus genuinely-empty hydration, same-ID revision response/in-flight fencing and cleared-tracking pending-probe invalidation alarms are lost. The singleton store and inventories were mocked; no real host census or resume delivery or equivalent replacement coverage is claimed. Audit1302: src/main/runtime/session-tabs-inventory-publication.test.ts: Keep actual runtime public inventory authority across renderer epochs/resync, fallback, aborts and invalid graph publishers. Remove copied nonempty publication, private scan counters/collector and known-host replacement, fake refresh that performs the restoration itself, environment capability flag, and private resume-store characterization whose fixture supplies reservation/rollback ordering. Lose isolated refresh/churn/receiver/capability and copied-payload wiring alarms; no equivalent replacement. Reduced selectors require fresh validation; prior full-suite receipts do not validate removed or changed coverage. No equivalent replacement or physical-provider claim. Audit1312 removes low-value imported specs from aggregate test drivers; old whole-driver execution receipts are archived. Retained registrations are unchanged. No equivalent replacement coverage is claimed. Audit1318: src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts: Retain real local encrypted WebSocket regressions for pre-ready socket replacement preserving a request, close-before-ready logical subscription cleanup, unrelated RPC surviving another deadline, and pending setup abort leaving a sibling pending. Host server is synthetic and uses production crypto; kept scenarios also retain internal diagnostics/memory assertions unchanged. Remove happy routing, authority-envelope, unknown-ID/log, cleanup enum, binary, keepalive/liveness and production-budget/private socket inventories; intentionally lose those alarms, no physical host authorization, independent crypto or remote provider claim. Reduced selectors need fresh validation; historical full-suite receipts do not validate the changed coverage. No equivalent replacement or physical-provider claim. Audit1346 removes the entire private-state-injected session-tabs rich-status boundary suite. Its stale task/question, neutral-title preservation, owner-change and provider-generation alarms are intentionally lost. Retained real terminal journeys do not establish equivalent replacement coverage. The prior mixed 42-contract execution receipt is historical and must not validate the reduced current selector; fresh validation remains required. Audit1352: focused Linux unit selections validated on source head b638e07d395b76af3ba6b03761a1a0fe7e5e026e. Historical statements above retain their original scope. Intentional test losses are recorded in knownGaps; these runs claim no physical-provider, p95, rendered E2E or cross-platform validation. Audit1360: focused Linux unit selections validated on source head 415c9cffc2d10024131ec4b6721767a22195de6d. Historical statements above retain their original scope. Intentional test losses are recorded in knownGaps; these runs claim no physical-provider, p95, rendered E2E or cross-platform validation. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1391: src/renderer/src/components/terminal-pane/pty-connection-remote-pause-drop-notice.spec.ts reduced. Lose repeated quiet switches avoiding snapshots and legacy host without drop-report capability requesting a snapshot. Retained imported registrar uses fake transport/xterm writes, exercising real gap/restore lifecycle rather than actual terminal rendering. No equivalent replacement coverage is claimed. The existing primary-selector receipt and its claims remain scoped to their unchanged sources; the broad optional command has no new execution result. Audit1396: src/renderer/src/components/terminal-pane/terminal-parked-watcher-reconciliation.test.ts reduced. Retire standalone reconcile set output and positive untouchedFreshSpawn/workspaceOwner copying alarms; no native watcher execution claim. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result. Audit1402: src/renderer/src/components/terminal-pane/pty-connection-park-reveal-model-snapshot.spec.ts reduced. Loses basic paired serialize/initial replay forwarding check; hidden alt-frame grid/precedence policy remains. No real terminal renderer claim. No equivalent replacement coverage is claimed. The existing primary-selector receipt and its claims remain scoped to their unchanged sources; the broad optional command has no new execution result. Audit1412: src/main/runtime/mobile-session-tabs-agent-status-heartbeat.test.ts reduced. Loses FIFO fairness/spacing, semantic bypass/cancellation, delayed-boundary scheduling and teardown timer-cleanup alarms. Retained fixed emission cases do not replace those outcomes. No equivalent replacement coverage is claimed.", + "coverageNotes": "Audit3342 removes three supplied activation/inventory fallback and same-handle retry examples; their fallback/retry alarms are intentionally lost without equivalent replacement. The exact mounted-HUB pending old-stream-end versus replacement-snapshot registration and its assertion remain. Unrelated dated macOS receipts retain only their original scope; no fresh runtime, provider, performance, mobile, mixed-version or cross-platform validation is claimed. NEXT46 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts, src/renderer/src/runtime/hosted-terminals/streams/remote-runtime-terminal-stall-recovery.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence. Historical prior account (preserved verbatim): Audit3326 adopts reconciled source audit3324 and intentionally retires these low-value examples and their regression alarms: restarts only the stream whose renderer delivery credit never settles — An unreturned renderer delivery credit stalls only its stream, leaving healthy sibling/shared transport alive. Fake-clock deadline plus real multiplexer unsubscribe isolates recovery ownership.; probes then restarts a stream when an entered command receives no frames — Entered command produces no output; actual multiplexer must probe then close only its stalled stream after probe timeout. Distinct response liveness from parser credit.; establishes a probe baseline before recovering an unsequenced stream — 142-line manual five-probe baseline/regression sequence derives request IDs from encoded mock traffic and checks repeated no-close/close choreography. Oversized algorithm/state-machine example; no actual renderer/host command or recovery delivery. Retires unsequenced/unchanged/regressed baseline classification alarms.. Retained tests do not replace these alarms. Dated unrelated evidence remains scoped to its original execution; no historical source/import-closure equivalence, fresh execution, real network/provider/SSH, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit 3318 reduces remote-runtime-pty-transport-unpublished-host-graph.test.ts, retiring its direct published-empty-graph omission-to-pane-exit alarm. The unchanged bounded unpublished-frame/pushed-recovery and stale-handle park/manual-retry cases are narrower, not equivalent replacements. Both complete three-case Linux receipts dated 2026-11-04 are archived as historical, including source heads; they do not validate this reduced selector. Remaining fourteen active receipts are macOS only. No fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed. Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed. Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed. Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical. Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims. Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands. Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. The direct side-effect-facts selector retains six cases: replay exclusion, live sequence handling, stale disposer ownership, one handoff drain, drain-before-snapshot, and stale replacement-snapshot refusal. Successful current-entry snapshot application is not witnessed by the retained snapshot case. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2162: Reduced inventory-authority source intentionally loses the examples recorded in knownGaps; historical execution is not validation of changed bytes. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2003: Remove SSH/absent-inventory attach refusal, later-subscriber retry, no-view adoption/takeback, provider-tail/unknown-read projections, failed-keystroke retry and simpler loss reattach examples. Keep the existing-subscriber inventory-ready retry alias only at its retained callback, plus retained held-input cancellation/replacement and overlapping attach/loss fences. The inventory driver also loses the whole empty-worktree-publication registration and folder-host/unverifiable scalar examples. Retire the entire dated10-case attach receipt; retain16 independent receipts only in their original scopes. No retained-memory or real-daemon measurement follows from supplied provider inventories. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, physical provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1991: Remove initial-snapshot sequence-domain, limited-tail/truncation and unknown-output-sequence aliases whose callbacks are removed. The source retains partial-chunk replay and requested-snapshot retry/admission at supplied snapshot/data seams, not equivalent replacement or measured retained-memory proof. Preserve the existing stream/pending-wait capacity aliases only to their retained owning multiplex callbacks with supplied PTY resolutions. Removing the sibling-PTY heartbeat dedup work-count sample does not establish a new decorative fanout budget; the unrelated-PTY cancellation fence survives. Preserve17 unrelated dated receipts. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, physical provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1983: Remove the reasonless-close selector and narrow census aliases to actual retained runtime and injected-inventory callbacks. The removed synthetic census-dedup and isolated pre-boundary timing cases receive no replacement credit; preserve17 unrelated dated receipts. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1939 (sources1934/1935): Delete the synthetic watcher-synchronization and partial-reconciliation suites. Retire all affected host-fact, capability-owner, activation-residue and retention-cap aliases because the remaining callbacks do not establish those full claims. Keep exact local hook/timer, byte-stream side effects, exit/disposal, scroll-intent cleanup and deterministic local rank/TTL progression callbacks within their mocked-host scope. No physical paired-host retention, resource budget or equivalent replacement evidence is assigned. The generic broad test command remains a runnable discovery command, never a dated execution receipt. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Delete the complete hook-agent-status projection suite and its two behavioral assertion aliases. Supplied stored hook/title/resume/staleness/rename/question/generation/PTY-retirement/snapshot-version projections are intentionally lost. The separate osc-status-scan gate mentions this source only in existing historical notes and receives no mutation. No measured hidden-output retention, CPU/RSS or resource budget result is claimed by the deleted source or this audit. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Module ownership cleanup retires the modeled cold-park private watcher/render/work-count suites under the current test policy. Their assertions are no longer active evidence. Retained lifecycle tests and headed/headless journeys do not establish equivalent coverage for those removed harness alarms. Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1634 removes low-value IPC, filesystem and runtime projections, argument inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained cancellation, ownership, authorization, filesystem and SQLite boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1627 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Audit1417 intentionally deletes src/renderer/src/components/terminal-pane/pty-connection-hidden-tui-snapshot-replay.spec.ts: Loses rich hidden snapshot sequence replay/grid resize and forced repaint after hidden snapshot alarms, including live-trigger deduplication. deletes src/renderer/src/components/terminal-pane/terminal-cold-park-verdict-loop.test.tsx: Loses modeled React oscillation alarm; real pane/watchers are not exercised. deletes src/renderer/src/runtime/remote-runtime-terminal-parse-backpressure.test.ts: Loses delayed credit until parsing, malformed frame/unknown stream handling, discarded transformed output recovery and failed ACK rearm alarms. No equivalent replacement coverage or fresh result is claimed. Historical coverage account: Audit1412 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): This audit removes the browser response-after-manual-disconnect example. Its distinct in-flight response fencing alarm is lost; retained queued-call disconnect tests are not an equivalent replacement. Historical commands and results remain historical. Deterministic headed macOS runs launch an isolated Orca desktop server and a separate paired web client. A byte-identical headless run uses an isolated `orca serve` host. Both create six real paired host PTYs with bounded high-output scrollback, prove sustained output while all six client xterms are warm-mounted but hidden causes zero renderer scheduler work, then drive 180 timed real-PTY spinner frames through a second production `session.tabs.subscribeAll` transport and the real Zustand store. Each worktree must publish and apply only its exact initial-working and final-idle titles. Both topologies ordinary-park five xterms without enabling the lossy retention budget, assert bounded cells/heap/timer lag, then restore the bounded authoritative tail exactly once on the original PTY including output produced while parked and continued input/output. The headed oracle additionally keeps every remote target workspace and terminal unmounted in the host renderer before and after client recovery. Production-parity React contracts reproduce and remove the independent cold-park watcher/title feedback loop, including memo-cache discard, StrictMode cleanup replay, detached split-PTY replacement, and the zero-park fast path. A deterministic cross-boundary contract drives 24 real PTY trackers in distinct worktrees through 2,880 decorative spinner and bare-native redraw chunks and counts host publications, serialized bytes, renderer apply calls, and store mutations while preserving exact per-PTY raw chunks and per-worktree semantic transitions. Fake-clock continuation beyond the 30-minute stale boundary requires one deduplicated refresh per worktree every 15 minutes, globally spaced by at least 50 ms, with every mirrored working status still fresh. Exact-identical Pi plus rotating normalized Pi/Grok frames renew coarse working/permission state; rich prompt/tool/question fields retain their original 30-minute lease, and `stateStartedAt`/acknowledgement identity remain stable across title/hook source swaps. A separate headed desktop-client journey relaunches the host main process while retaining the daemon and a daemon-backgrounded PTY, then requires first-observation foreground sync and continued input/output on the same PTY. Unit coverage keeps layout versions out of snapshot output high-waters when a restored snapshot has no output sequence and retries an existing subscriber only after authoritative provider inventory proves the retained PTY exists. Separate headed/headless ACK-starvation tests recover one stalled stream without replacing its PTY. A headed output-drop oracle proves a successful snapshot probe cannot certify a stale live stream when the authoritative PTY sequence advanced beyond the client high-water. Unit coverage requires an unsequenced client to establish a first-probe baseline, remain attached at the same sequence, and recover only after a later probe advances. A capability-disabled run proves legacy hosts retain the prior lossy limit/TTL fallback. Unit tests cover exact-owner capability routing, raw-stream release, singleton side-effect facts with timed handoff cleanup, 64 simultaneous synthetic-title sources with zero decorative client events after convergence, per-client late-subscribe recovery, semantic bell/title transitions, local animation-frame preservation, legacy no-output-pause delivery gating with exact snapshot restore, provider-authoritative snapshots, 128 active streams plus retry after a 129th-stream capacity rejection, capacity-pressure backoff, full split-leaf remint reconciliation, truncation, and manual-disconnect queue fencing. Linux, Windows, live SSH, and production-scale paired hosts remain gaps. The audit removed the E2E parking override/debug-handle suite. Override exposure guards, delay/retention independence, TTL filtering and debug-handle forwarding alarms are lost. Retained real parking journeys do not establish equivalent test-harness configuration coverage. The test-value audit removes separate responsive-stream, intervening-control-frame and capacity-error classification examples. Retained multiplexer checks use fake clocks and captured transport callbacks; their per-stream isolation, deadline and probe-baseline assertions do not prove an actual host restart or equivalent replacement coverage. Historical run commands and results remain historical. The test-value audit removes the standalone retained/live metadata projection and additive-preference negative example from runtime-client-events.test.ts. Its remaining case checks partial-authority event admission through a captured callback; it does not establish full-pair projection, actual peer delivery or equivalent replacement coverage. Historical commands and results remain historical. The isolated accepted-handle-events observer suite is removed. Its runtime/worktree/pane membership, once-only delivery and listener-release ledger alarms are lost. Live hidden-retention evidence does not establish equivalent observer coverage. Audit1292: The entire host-session mirror empty-inventory settle suite is removed. Live-unpublished versus genuinely-empty hydration, same-ID revision response/in-flight fencing and cleared-tracking pending-probe invalidation alarms are lost. The singleton store and inventories were mocked; no real host census or resume delivery or equivalent replacement coverage is claimed. Audit1302: src/main/runtime/session-tabs-inventory-publication.test.ts: Keep actual runtime public inventory authority across renderer epochs/resync, fallback, aborts and invalid graph publishers. Remove copied nonempty publication, private scan counters/collector and known-host replacement, fake refresh that performs the restoration itself, environment capability flag, and private resume-store characterization whose fixture supplies reservation/rollback ordering. Lose isolated refresh/churn/receiver/capability and copied-payload wiring alarms; no equivalent replacement. Reduced selectors require fresh validation; prior full-suite receipts do not validate removed or changed coverage. No equivalent replacement or physical-provider claim. Audit1312 removes low-value imported specs from aggregate test drivers; old whole-driver execution receipts are archived. Retained registrations are unchanged. No equivalent replacement coverage is claimed. Audit1318: src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts: Retain real local encrypted WebSocket regressions for pre-ready socket replacement preserving a request, close-before-ready logical subscription cleanup, unrelated RPC surviving another deadline, and pending setup abort leaving a sibling pending. Host server is synthetic and uses production crypto; kept scenarios also retain internal diagnostics/memory assertions unchanged. Remove happy routing, authority-envelope, unknown-ID/log, cleanup enum, binary, keepalive/liveness and production-budget/private socket inventories; intentionally lose those alarms, no physical host authorization, independent crypto or remote provider claim. Reduced selectors need fresh validation; historical full-suite receipts do not validate the changed coverage. No equivalent replacement or physical-provider claim. Audit1346 removes the entire private-state-injected session-tabs rich-status boundary suite. Its stale task/question, neutral-title preservation, owner-change and provider-generation alarms are intentionally lost. Retained real terminal journeys do not establish equivalent replacement coverage. The prior mixed 42-contract execution receipt is historical and must not validate the reduced current selector; fresh validation remains required. Audit1352: focused Linux unit selections validated on source head b638e07d395b76af3ba6b03761a1a0fe7e5e026e. Historical statements above retain their original scope. Intentional test losses are recorded in knownGaps; these runs claim no physical-provider, p95, rendered E2E or cross-platform validation. Audit1360: focused Linux unit selections validated on source head 415c9cffc2d10024131ec4b6721767a22195de6d. Historical statements above retain their original scope. Intentional test losses are recorded in knownGaps; these runs claim no physical-provider, p95, rendered E2E or cross-platform validation. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1391: src/renderer/src/components/terminal-pane/pty-connection-remote-pause-drop-notice.spec.ts reduced. Lose repeated quiet switches avoiding snapshots and legacy host without drop-report capability requesting a snapshot. Retained imported registrar uses fake transport/xterm writes, exercising real gap/restore lifecycle rather than actual terminal rendering. No equivalent replacement coverage is claimed. The existing primary-selector receipt and its claims remain scoped to their unchanged sources; the broad optional command has no new execution result. Audit1396: src/renderer/src/components/terminal-pane/terminal-parked-watcher-reconciliation.test.ts reduced. Retire standalone reconcile set output and positive untouchedFreshSpawn/workspaceOwner copying alarms; no native watcher execution claim. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result. Audit1402: src/renderer/src/components/terminal-pane/pty-connection-park-reveal-model-snapshot.spec.ts reduced. Loses basic paired serialize/initial replay forwarding check; hidden alt-frame grid/precedence policy remains. No real terminal renderer claim. No equivalent replacement coverage is claimed. The existing primary-selector receipt and its claims remain scoped to their unchanged sources; the broad optional command has no new execution result. Audit1412: src/main/runtime/mobile-session-tabs-agent-status-heartbeat.test.ts reduced. Loses FIFO fairness/spacing, semantic bypass/cancellation, delayed-boundary scheduling and teardown timer-cleanup alarms. Retained fixed emission cases do not replace those outcomes. No equivalent replacement coverage is claimed.", "motivatingLinks": [ "https://github.com/stablyai/orca/issues/8652", "https://github.com/stablyai/orca/pull/10625" ], "invariant": "A host advertising terminal.paired-parking.v1 keeps the PTY and bounded authoritative history alive while an ordinary hidden-view park destroys the client xterm and releases its raw per-PTY stream. Reveal must restore up to the requested 5,000 rows, parked-time side effects/output, the same PTY identity, and continued input/output. Parked watcher synchronization compares parking semantics rather than fresh object identity, owns setup and cleanup across StrictMode replay, reconciles real PTY/layout changes, and performs no terminal-state scan when nothing is parked. After a host main-process relaunch, unknown local delivery-sync state must not be treated as proof that a surviving daemon PTY is already foregrounded. An empty headed session-tab inventory is authoritative only after the current renderer graph generation publishes a complete inventory and every execution host answers the PTY census; unpublished, resync-pending, transport-failed, and partially scoped inventories remain unverifiable, while genuinely authoritative empty and non-empty inventories settle and a scope-less legacy empty keeps its pre-authority best-effort settle so outdated hosts retain agent auto-resume. The unpublished-empty regression must keep the resume dispatch parked with exactly one daemon process/writer; restoring unconditional empty hydration must release one dispatch and create two live writers. If subscription precedes provider readiness, authoritative inventory must reconsider that existing subscriber without spawning, resizing, or changing reconnect state. A snapshot without an output high-water must keep it unknown rather than borrowing a layout version that can suppress newer live output. Hosts without the capability must gate hidden raw output before xterm scheduling and repaint from the authoritative snapshot on reveal while retaining the existing limit/TTL force-parking fallback. After the first semantic title state, decorative spinner frequency must add zero paired client-event frames and zero full session-tabs work between status-freshness leases regardless of hidden worktree count. Continuous working or permission evidence may refresh each affected worktree once per 15 minutes through one globally spaced FIFO so current and legacy viewers do not decay before 30 minutes; sibling PTYs share that worktree refresh, while local title animation, raw output, and semantic title, status, bell, completion, and query facts remain intact. A paired terminal stream whose delivery credits stop progressing must replace only that stream; command silence first probes authoritative state and replaces the stream if the probe times out or proves the PTY advanced beyond the client's delivered output sequence. When no comparable delivery high-water exists, the first sequenced probe establishes a baseline and only later advancement proves staleness. A same-sequence snapshot remains valid proof of a responsive silent command. A successful status probe may replace a pre-ready shared-control socket without rejecting or duplicating calls already waiting for that transport. Manual disconnect must retain pairing while preventing queued or passive calls and subscriptions from recreating transport until explicit Connect. A paired pane reconnecting to a relaunched host that has not yet published its window graph (an unpublished frame, bare or client-projected) must stay in recovery rather than retire, and the host's first published snapshot carrying the surface must reattach it; a published frame lacking the surface still retires it. The placeholder is only ever sent before the host's graph first publishes; afterwards a worktree with no tabs gets a real empty answer, pushed once to any client that asked during startup, so a paired client opening a never-opened host worktree still gets its first terminal.", - "oracle": "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. The direct side-effect-facts selector retains six cases: replay exclusion, live sequence handling, stale disposer ownership, one handoff drain, drain-before-snapshot, and stale replacement-snapshot refusal. Successful current-entry snapshot application is not witnessed by the retained snapshot case. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2003: Remove SSH/absent-inventory attach refusal, later-subscriber retry, no-view adoption/takeback, provider-tail/unknown-read projections, failed-keystroke retry and simpler loss reattach examples. Keep the existing-subscriber inventory-ready retry alias only at its retained callback, plus retained held-input cancellation/replacement and overlapping attach/loss fences. The inventory driver also loses the whole empty-worktree-publication registration and folder-host/unverifiable scalar examples. Retire the entire dated10-case attach receipt; retain16 independent receipts only in their original scopes. No retained-memory or real-daemon measurement follows from supplied provider inventories. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, physical provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1991: Remove initial-snapshot sequence-domain, limited-tail/truncation and unknown-output-sequence aliases whose callbacks are removed. The source retains partial-chunk replay and requested-snapshot retry/admission at supplied snapshot/data seams, not equivalent replacement or measured retained-memory proof. Preserve the existing stream/pending-wait capacity aliases only to their retained owning multiplex callbacks with supplied PTY resolutions. Removing the sibling-PTY heartbeat dedup work-count sample does not establish a new decorative fanout budget; the unrelated-PTY cancellation fence survives. Preserve17 unrelated dated receipts. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, physical provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1983: Remove the reasonless-close selector and narrow census aliases to actual retained runtime and injected-inventory callbacks. The removed synthetic census-dedup and isolated pre-boundary timing cases receive no replacement credit; preserve17 unrelated dated receipts. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1939 (sources1934/1935): Delete the synthetic watcher-synchronization and partial-reconciliation suites. Retire all affected host-fact, capability-owner, activation-residue and retention-cap aliases because the remaining callbacks do not establish those full claims. Keep exact local hook/timer, byte-stream side effects, exit/disposal, scroll-intent cleanup and deterministic local rank/TTL progression callbacks within their mocked-host scope. No physical paired-host retention, resource budget or equivalent replacement evidence is assigned. The generic broad test command remains a runnable discovery command, never a dated execution receipt. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Delete the complete hook-agent-status projection suite and its two behavioral assertion aliases. Supplied stored hook/title/resume/staleness/rename/question/generation/PTY-retirement/snapshot-version projections are intentionally lost. The separate osc-status-scan gate mentions this source only in existing historical notes and receives no mutation. No measured hidden-output retention, CPU/RSS or resource budget result is claimed by the deleted source or this audit. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Historical pre-audit oracle account for changed sources: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Run one byte-identical six-terminal oracle against an isolated headed desktop host and an isolated headless `orca serve` host. Stage at least 1,000,000 xterm cells, hide all six warm managers, emit an initial working title followed by 30 timed real-PTY spinner frames and a final idle title per worktree, and observe a second real session-tabs subscription plus the production renderer store. Require exactly two transport envelopes and two title mutations per worktree, no decorative title crossing either boundary, and positive decoded-envelope bytes. Enable ordinary parking with the lossy retention budget disabled, require exactly one mounted manager and five parked tabs, at most 45% retained cells, no more than 16 MiB heap growth, and under 500 ms timer drift. In headed mode, require the host renderer to remain on its original workspace with zero target terminal managers mounted throughout client park, reveal, and live I/O. While a tab is parked, require authoritative terminal.read to observe new PTY output; reveal it and require the original PTY, a marker within the requested 5,000-row history, the parked marker, and post-reveal input/output. Drive 24 real PTY title trackers in distinct worktrees through 40 decorative spinner frames each, then 40 spinner frames alternating with Cursor's bare native identity redraw, using fake clocks. Require all 2,880 raw chunks exactly and zero host session-tabs publications, serialized bytes, renderer apply calls, and renderer store mutations. Continue decorative evidence beyond 30 minutes, require exactly one refresh per worktree per 15-minute lease through a FIFO spaced by at least 50 ms, and require all 24 viewer statuses to remain working and fresh; then require one exact semantic idle transition and one visible-output chunk per PTY. Require ordinary and interior-Braille title changes to publish. Drive 64 host PTYs through ten 80 ms synthetic title frames, require zero paired client events after the first frame per PTY while all 640 local frames remain observable, attach a late client and require one current frame per PTY, then require semantic bell and idle transitions on both clients. Reconstruct a legacy subscribed stream with no outputPause capability, hide a chatty pane, require no hidden xterm writes, reveal it, and require one authoritative snapshot plus continued live output. Drop and acknowledge output only for one original paired-client stream, prove the fixture process consumed input while the host model advanced and the client stayed stale, then require the command snapshot probe to replace that stream, repaint exact fixture output, preserve authoritative PTY identity and target-tab cardinality, and resume live I/O. For a client without a delivered sequence, require the first numeric probe to establish a baseline without replacement, a same-sequence probe to remain attached, and a later advanced probe to replace only that stream. Withhold the first encrypted shared-control ready frame, start one RPC, trigger a status-probe refresh, and require two connections, one host delivery, successful response, and zero retained request bytes. Admit 128 active streams, reject the 129th as retryable, release one stream, then require the retry to attach and publish a snapshot without multiplying retained subscribers. Disable terminal.paired-parking.v1 and require the same oracle to fail before parking, while the legacy limit-one fallback separately passes. Also preserve truncated first paint, ACK-starved same-PTY recovery, responsive silent-command snapshot probes, dead-stream probe timeout recovery, and queued manual-disconnect fencing.", + "oracle": "Audit3342 removes three supplied activation/inventory fallback and same-handle retry examples; their fallback/retry alarms are intentionally lost without equivalent replacement. The exact mounted-HUB pending old-stream-end versus replacement-snapshot registration and its assertion remain. Unrelated dated macOS receipts retain only their original scope; no fresh runtime, provider, performance, mobile, mixed-version or cross-platform validation is claimed. Audit3326 adopts reconciled source audit3324 and intentionally retires these low-value examples and their regression alarms: restarts only the stream whose renderer delivery credit never settles — An unreturned renderer delivery credit stalls only its stream, leaving healthy sibling/shared transport alive. Fake-clock deadline plus real multiplexer unsubscribe isolates recovery ownership.; probes then restarts a stream when an entered command receives no frames — Entered command produces no output; actual multiplexer must probe then close only its stalled stream after probe timeout. Distinct response liveness from parser credit.; establishes a probe baseline before recovering an unsequenced stream — 142-line manual five-probe baseline/regression sequence derives request IDs from encoded mock traffic and checks repeated no-close/close choreography. Oversized algorithm/state-machine example; no actual renderer/host command or recovery delivery. Retires unsequenced/unchanged/regressed baseline classification alarms.. Retained tests do not replace these alarms. Dated unrelated evidence remains scoped to its original execution; no historical source/import-closure equivalence, fresh execution, real network/provider/SSH, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit 3318 reduces remote-runtime-pty-transport-unpublished-host-graph.test.ts, retiring its direct published-empty-graph omission-to-pane-exit alarm. The unchanged bounded unpublished-frame/pushed-recovery and stale-handle park/manual-retry cases are narrower, not equivalent replacements. Both complete three-case Linux receipts dated 2026-11-04 are archived as historical, including source heads; they do not validate this reduced selector. Remaining fourteen active receipts are macOS only. No fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed. Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed. Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed. Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical. Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims. Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands. Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. The direct side-effect-facts selector retains six cases: replay exclusion, live sequence handling, stale disposer ownership, one handoff drain, drain-before-snapshot, and stale replacement-snapshot refusal. Successful current-entry snapshot application is not witnessed by the retained snapshot case. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2003: Remove SSH/absent-inventory attach refusal, later-subscriber retry, no-view adoption/takeback, provider-tail/unknown-read projections, failed-keystroke retry and simpler loss reattach examples. Keep the existing-subscriber inventory-ready retry alias only at its retained callback, plus retained held-input cancellation/replacement and overlapping attach/loss fences. The inventory driver also loses the whole empty-worktree-publication registration and folder-host/unverifiable scalar examples. Retire the entire dated10-case attach receipt; retain16 independent receipts only in their original scopes. No retained-memory or real-daemon measurement follows from supplied provider inventories. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, physical provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1991: Remove initial-snapshot sequence-domain, limited-tail/truncation and unknown-output-sequence aliases whose callbacks are removed. The source retains partial-chunk replay and requested-snapshot retry/admission at supplied snapshot/data seams, not equivalent replacement or measured retained-memory proof. Preserve the existing stream/pending-wait capacity aliases only to their retained owning multiplex callbacks with supplied PTY resolutions. Removing the sibling-PTY heartbeat dedup work-count sample does not establish a new decorative fanout budget; the unrelated-PTY cancellation fence survives. Preserve17 unrelated dated receipts. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, physical provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1983: Remove the reasonless-close selector and narrow census aliases to actual retained runtime and injected-inventory callbacks. The removed synthetic census-dedup and isolated pre-boundary timing cases receive no replacement credit; preserve17 unrelated dated receipts. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1939 (sources1934/1935): Delete the synthetic watcher-synchronization and partial-reconciliation suites. Retire all affected host-fact, capability-owner, activation-residue and retention-cap aliases because the remaining callbacks do not establish those full claims. Keep exact local hook/timer, byte-stream side effects, exit/disposal, scroll-intent cleanup and deterministic local rank/TTL progression callbacks within their mocked-host scope. No physical paired-host retention, resource budget or equivalent replacement evidence is assigned. The generic broad test command remains a runnable discovery command, never a dated execution receipt. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Delete the complete hook-agent-status projection suite and its two behavioral assertion aliases. Supplied stored hook/title/resume/staleness/rename/question/generation/PTY-retirement/snapshot-version projections are intentionally lost. The separate osc-status-scan gate mentions this source only in existing historical notes and receives no mutation. No measured hidden-output retention, CPU/RSS or resource budget result is claimed by the deleted source or this audit. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Historical pre-audit oracle account for changed sources: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Run one byte-identical six-terminal oracle against an isolated headed desktop host and an isolated headless `orca serve` host. Stage at least 1,000,000 xterm cells, hide all six warm managers, emit an initial working title followed by 30 timed real-PTY spinner frames and a final idle title per worktree, and observe a second real session-tabs subscription plus the production renderer store. Require exactly two transport envelopes and two title mutations per worktree, no decorative title crossing either boundary, and positive decoded-envelope bytes. Enable ordinary parking with the lossy retention budget disabled, require exactly one mounted manager and five parked tabs, at most 45% retained cells, no more than 16 MiB heap growth, and under 500 ms timer drift. In headed mode, require the host renderer to remain on its original workspace with zero target terminal managers mounted throughout client park, reveal, and live I/O. While a tab is parked, require authoritative terminal.read to observe new PTY output; reveal it and require the original PTY, a marker within the requested 5,000-row history, the parked marker, and post-reveal input/output. Drive 24 real PTY title trackers in distinct worktrees through 40 decorative spinner frames each, then 40 spinner frames alternating with Cursor's bare native identity redraw, using fake clocks. Require all 2,880 raw chunks exactly and zero host session-tabs publications, serialized bytes, renderer apply calls, and renderer store mutations. Continue decorative evidence beyond 30 minutes, require exactly one refresh per worktree per 15-minute lease through a FIFO spaced by at least 50 ms, and require all 24 viewer statuses to remain working and fresh; then require one exact semantic idle transition and one visible-output chunk per PTY. Require ordinary and interior-Braille title changes to publish. Drive 64 host PTYs through ten 80 ms synthetic title frames, require zero paired client events after the first frame per PTY while all 640 local frames remain observable, attach a late client and require one current frame per PTY, then require semantic bell and idle transitions on both clients. Reconstruct a legacy subscribed stream with no outputPause capability, hide a chatty pane, require no hidden xterm writes, reveal it, and require one authoritative snapshot plus continued live output. Drop and acknowledge output only for one original paired-client stream, prove the fixture process consumed input while the host model advanced and the client stayed stale, then require the command snapshot probe to replace that stream, repaint exact fixture output, preserve authoritative PTY identity and target-tab cardinality, and resume live I/O. For a client without a delivered sequence, require the first numeric probe to establish a baseline without replacement, a same-sequence probe to remain attached, and a later advanced probe to replace only that stream. Withhold the first encrypted shared-control ready frame, start one RPC, trigger a status-probe refresh, and require two connections, one host delivery, successful response, and zero retained request bytes. Admit 128 active streams, reject the 129th as retryable, release one stream, then require the retry to attach and publish a snapshot without multiplying retained subscribers. Disable terminal.paired-parking.v1 and require the same oracle to fail before parking, while the legacy limit-one fallback separately passes. Also preserve truncated first paint, ACK-starved same-PTY recovery, responsive silent-command snapshot probes, dead-stream probe timeout recovery, and queued manual-disconnect fencing.", "commands": [ "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-unpublished-host-graph.test.ts", "ORCA_BACKGROUND_LAUNCH=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-host-quit-reconnect-input.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1", @@ -8544,11 +8307,10 @@ "ORCA_BACKGROUND_LAUNCH=1 pnpm exec playwright test tests/e2e/paired-client-first-terminal-unopened-host-worktree.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1", "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/session-lifecycle/publication/mobile-session-tabs-agent-status-heartbeat.test.ts tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts --maxWorkers=1", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/parking/lifecycle/use-terminal-tab-cold-parking.test.ts --maxWorkers=1", - "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/construction/orca-runtime.test.ts src/main/runtime/rpc/terminal-multiplex-initial-snapshot-buffering.test.ts src/main/runtime/rpc/terminal-multiplex-snapshot-serialization.test.ts src/main/runtime/rpc/terminal-multiplex-pty-wait-capacity.test.ts src/main/runtime/rpc/terminal-subscribe-buffer.test.ts src/renderer/src/components/terminal-pane/parking/output-watchers/parked-terminal-byte-watcher.test.ts src/renderer/src/components/terminal-pane/pty-transport/output/terminal-side-effect-facts-handler.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-activation-inventory-fallback.test.ts src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-view-parking.test.ts src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-worktree-retention.test.ts src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-tab-watchers.test.ts src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-reconciliation.test.ts src/renderer/src/runtime/hosted-terminals/streams/remote-runtime-terminal-stall-recovery.test.ts src/renderer/src/runtime/rpc/subscriptions/runtime-client-events.test.ts src/renderer/src/web/web-preload-api-runtime-environment.test.ts src/main/ipc/runtime-environments/runtime-environments-pairing.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/construction/orca-runtime.test.ts src/main/runtime/rpc/terminal-multiplex-initial-snapshot-buffering.test.ts src/main/runtime/rpc/terminal-multiplex-snapshot-serialization.test.ts src/main/runtime/rpc/terminal-multiplex-pty-wait-capacity.test.ts src/main/runtime/rpc/terminal-subscribe-buffer.test.ts src/renderer/src/components/terminal-pane/pty-transport/output/terminal-side-effect-facts-handler.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-activation-inventory-fallback.test.ts src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-view-parking.test.ts src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-worktree-retention.test.ts src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-tab-watchers.test.ts src/renderer/src/runtime/rpc/subscriptions/runtime-client-events.test.ts src/renderer/src/web/web-preload-api-runtime-environment.test.ts src/main/ipc/runtime-environments/runtime-environments-pairing.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/terminal/adoption/terminal-subscriber-driven-daemon-attach.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/session-tabs/runtime-inventory-publication-authority.test.ts src/main/runtime/rpc/methods/session-tabs/session-tabs-inventory-census-race.test.ts src/main/daemon/terminal-host/testing/terminal-host-agent-session.test.ts tests/e2e/session-tabs-empty-inventory-daemon-oracle.unit.test.ts --maxWorkers=1", "pnpm exec vitest run --config config/vitest.config.ts src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts", "SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-host-restart-background-sync.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1", "ORCA_E2E_FORWARD_APP_LOGS=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-host-restart-background-sync.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1 --repeat-each=10 --max-failures=1", "ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-truncated-tail-first-paint.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1", @@ -8578,15 +8340,12 @@ "src/main/runtime/rpc/methods/session-tabs/session-tabs-inventory-census-race.test.ts", "src/main/daemon/terminal-host/testing/terminal-host-agent-session.test.ts", "tests/e2e/session-tabs-empty-inventory-daemon-oracle.unit.test.ts", - "src/renderer/src/components/terminal-pane/parking/output-watchers/parked-terminal-byte-watcher.test.ts", "src/renderer/src/components/terminal-pane/pty-transport/output/terminal-side-effect-facts-handler.test.ts", "src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts", "src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts", "src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-worktree-retention.test.ts", "src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-view-parking.test.ts", "src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-tab-watchers.test.ts", - "src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-reconciliation.test.ts", - "src/renderer/src/runtime/hosted-terminals/streams/remote-runtime-terminal-stall-recovery.test.ts", "src/renderer/src/runtime/rpc/subscriptions/runtime-client-events.test.ts", "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-activation-inventory-fallback.test.ts", "src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts", @@ -8724,15 +8483,6 @@ "keeps a mounted HUB mirror alive when the old stream ends before the replacement snapshot" ] }, - { - "file": "src/renderer/src/runtime/hosted-terminals/streams/remote-runtime-terminal-stall-recovery.test.ts", - "assertions": [ - "restarts only the stream whose renderer delivery credit never settles", - "keeps the oldest pending delivery deadline anchored while later frames settle", - "probes then restarts a stream when an entered command receives no frames", - "establishes a first-probe baseline and fences regressed snapshots before recovering an unsequenced stream" - ] - }, { "file": "src/renderer/src/web/web-preload-api-runtime-environment.test.ts", "assertions": [ @@ -8882,26 +8632,6 @@ "durationSeconds": 17.5, "summary": "The headed six-PTY oracle kept all warm-mounted hidden streams at zero renderer scheduler enqueues/drains under sustained output and under 500 ms timer lag, then restored the authoritative flood tail and parked/live markers exactly once.", "currentCommand": "ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-retention-memory.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1" - }, - { - "date": "2026-11-04", - "runner": "local", - "platform": "linux", - "result": "passed", - "command": "ORCA_BACKGROUND_LAUNCH=1 pnpm --config.verifyDepsBeforeRun=false test src/renderer/src/components/terminal-pane/remote-runtime-pty-transport-unpublished-host-graph.test.ts --maxWorkers=2", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-unpublished-host-graph.test.ts", - "durationSeconds": 3.87, - "summary": "Test Files 1 passed (1); Tests 3 passed (3). Focused Linux unit execution; no physical-provider, p95 or cross-platform claim. Source head b638e07d395b76af3ba6b03761a1a0fe7e5e026e." - }, - { - "date": "2026-11-04", - "runner": "local", - "platform": "linux", - "result": "passed", - "command": "ORCA_BACKGROUND_LAUNCH=1 pnpm --config.verifyDepsBeforeRun=false test src/renderer/src/components/terminal-pane/remote-runtime-pty-transport-unpublished-host-graph.test.ts --maxWorkers=2", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-unpublished-host-graph.test.ts", - "durationSeconds": 3.79, - "summary": "Test Files 1 passed (1); Tests 3 passed (3). Focused Linux unit execution; no physical-provider, p95 or cross-platform claim. Source head 415c9cffc2d10024131ec4b6721767a22195de6d." } ], "runtimeBudget": { @@ -8928,6 +8658,9 @@ "Keep the budget-off control, exact manager count, final bounded-tail flood marker, parked-time output, and post-reveal PTY input in both topology runs." ], "knownGaps": [ + "NEXT65 current scope qualification: The NEXT65 knownGaps entries below govern the changed selectors and qualify any broader coverage implication in this gate’s unchanged oracle/coverageNotes narratives. Those narratives and preserved dated evidenceRuns retain their historical text and original exact execution scopes only; no fresh execution, transferred pass or equivalent replacement coverage is claimed. Upstream case removals remain upstream; original NEXT65 proposal descriptions grant no duplicate retirement credit.", + "NEXT65 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-reconciliation.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence.", + "NEXT65 historical original active selector fields (verbatim JSON values; not current coverage):\ncommands: [\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-unpublished-host-graph.test.ts\",\n \"ORCA_BACKGROUND_LAUNCH=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-host-quit-reconnect-input.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/terminal/query/runtime-terminal-inventory-contracts.test.ts\",\n \"ORCA_BACKGROUND_LAUNCH=1 pnpm exec playwright test tests/e2e/paired-client-first-terminal-unopened-host-worktree.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/session-lifecycle/publication/mobile-session-tabs-agent-status-heartbeat.test.ts tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts --maxWorkers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/parking/lifecycle/use-terminal-tab-cold-parking.test.ts --maxWorkers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/construction/orca-runtime.test.ts src/main/runtime/rpc/terminal-multiplex-initial-snapshot-buffering.test.ts src/main/runtime/rpc/terminal-multiplex-snapshot-serialization.test.ts src/main/runtime/rpc/terminal-multiplex-pty-wait-capacity.test.ts src/main/runtime/rpc/terminal-subscribe-buffer.test.ts src/renderer/src/components/terminal-pane/pty-transport/output/terminal-side-effect-facts-handler.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-activation-inventory-fallback.test.ts src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-view-parking.test.ts src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-worktree-retention.test.ts src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-tab-watchers.test.ts src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-reconciliation.test.ts src/renderer/src/runtime/rpc/subscriptions/runtime-client-events.test.ts src/renderer/src/web/web-preload-api-runtime-environment.test.ts src/main/ipc/runtime-environments/runtime-environments-pairing.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/terminal/adoption/terminal-subscriber-driven-daemon-attach.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/session-tabs/runtime-inventory-publication-authority.test.ts src/main/runtime/rpc/methods/session-tabs/session-tabs-inventory-census-race.test.ts src/main/daemon/terminal-host/testing/terminal-host-agent-session.test.ts tests/e2e/session-tabs-empty-inventory-daemon-oracle.unit.test.ts --maxWorkers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts\",\n \"SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-host-restart-background-sync.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\",\n \"ORCA_E2E_FORWARD_APP_LOGS=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-host-restart-background-sync.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1 --repeat-each=10 --max-failures=1\",\n \"ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-truncated-tail-first-paint.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-lossy-initial-snapshot.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 ORCA_E2E_DISABLE_PAIRED_TERMINAL_PARKING=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-truncated-tail-first-paint.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-stall-recovery.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-probe-gap-recovery.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/headless-paired-remote-terminal-stall-recovery.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-retention-memory.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-retention-memory.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/headless-paired-remote-terminal-retention-memory.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\",\n \"SKIP_BUILD=1 pnpm exec playwright test tests/e2e/terminal-parked-memory.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\"\n ]\ntestFiles: [\n \"src/main/runtime/session-lifecycle/publication/mobile-session-tabs-agent-status-heartbeat.test.ts\",\n \"tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts\",\n \"src/renderer/src/components/terminal-pane/parking/lifecycle/use-terminal-tab-cold-parking.test.ts\",\n \"src/main/runtime/construction/orca-runtime.test.ts\",\n \"src/renderer/src/web/web-preload-api-runtime-environment.test.ts\",\n \"src/main/ipc/runtime-environments/runtime-environments-pairing.test.ts\",\n \"src/main/runtime/rpc/terminal-multiplex-initial-snapshot-buffering.test.ts\",\n \"src/main/runtime/rpc/terminal-multiplex-snapshot-serialization.test.ts\",\n \"src/main/runtime/rpc/terminal-multiplex-pty-wait-capacity.test.ts\",\n \"src/main/runtime/rpc/terminal-subscribe-buffer.test.ts\",\n \"src/main/runtime/terminal/adoption/terminal-subscriber-driven-daemon-attach.test.ts\",\n \"src/main/runtime/session-tabs/runtime-inventory-publication-authority.test.ts\",\n \"src/main/runtime/rpc/methods/session-tabs/session-tabs-inventory-census-race.test.ts\",\n \"src/main/daemon/terminal-host/testing/terminal-host-agent-session.test.ts\",\n \"tests/e2e/session-tabs-empty-inventory-daemon-oracle.unit.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/output/terminal-side-effect-facts-handler.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts\",\n \"src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-worktree-retention.test.ts\",\n \"src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-view-parking.test.ts\",\n \"src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-tab-watchers.test.ts\",\n \"src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-reconciliation.test.ts\",\n \"src/renderer/src/runtime/rpc/subscriptions/runtime-client-events.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-activation-inventory-fallback.test.ts\",\n \"src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts\",\n \"tests/e2e/paired-remote-terminal-lossy-initial-snapshot.spec.ts\",\n \"tests/e2e/paired-remote-terminal-truncated-tail-first-paint.spec.ts\",\n \"tests/e2e/paired-remote-terminal-stall-recovery.spec.ts\",\n \"tests/e2e/paired-remote-terminal-probe-gap-recovery.spec.ts\",\n \"tests/e2e/headless-paired-remote-terminal-stall-recovery.spec.ts\",\n \"tests/e2e/paired-remote-terminal-retention-memory.spec.ts\",\n \"tests/e2e/headless-paired-remote-terminal-retention-memory.spec.ts\",\n \"tests/e2e/terminal-parked-memory.spec.ts\",\n \"tests/e2e/paired-remote-terminal-host-restart-background-sync.spec.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-unpublished-host-graph.test.ts\",\n \"tests/e2e/paired-remote-terminal-host-quit-reconnect-input.spec.ts\",\n \"src/main/runtime/terminal/query/runtime-terminal-inventory-contracts.test.ts\",\n \"tests/e2e/paired-client-first-terminal-unopened-host-worktree.spec.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts\",\n \"assertions\": [\n \"2,880 decorative spinner and bare-native real-PTY OSC chunks publish zero session-tabs snapshots or serialized bytes after semantic convergence\",\n \"the viewer performs zero snapshot applies and zero store mutations during decorative activity\",\n \"after 30 minutes, one globally spaced refresh per worktree keeps every mirrored working status fresh\",\n \"exact Pi and rotating normalized Pi/Grok frames renew explicit and fallback status without changing stateStartedAt or acknowledgement semantics\",\n \"matching title evidence renews retained OSC hook status without resetting stateStartedAt, then drops unverifiable prompt metadata after the hook row expires\",\n \"renderer-authored rich status keeps its original lease, then renews only coarse title-confirmed state and provider identity\",\n \"ordinary-shell title transitions replace working stateStartedAt with the completion transition time\",\n \"decorative heartbeats remain blocked until unknown foreground ownership resolves, then resume at the bounded interval\",\n \"tracked terminal state reset clears delayed foreground ownership markers\",\n \"raw chunks, semantic idle transitions, and visible output remain exact\"\n ]\n },\n {\n \"file\": \"src/main/runtime/terminal/adoption/terminal-subscriber-driven-daemon-attach.test.ts\",\n \"assertions\": [\"retries an existing subscriber when provider inventory becomes ready\"]\n },\n {\n \"file\": \"src/main/runtime/rpc/methods/session-tabs/session-tabs-inventory-census-race.test.ts\",\n \"assertions\": [\n \"creation and removal at the census release edge are subsumed once, and a delayed pre-boundary change is not replayed\",\n \"post-boundary creation and removal replay after the initial snapshot in sequence order\",\n \"create/remove/recreate transitions are preserved without collapse\",\n \"a post-boundary projected-state change is delivered without a new snapshot revision\",\n \"an older coalesced callback cannot overwrite a newer immediate change\",\n \"initialization churn publishes only the latest projected state and repeated structural overflow fails after bounded recollection\",\n \"disconnect aborts the census and removes the real runtime listener\"\n ]\n },\n {\n \"file\": \"tests/e2e/session-tabs-empty-inventory-daemon-oracle.unit.test.ts\",\n \"assertions\": [\n \"unpublished empty inventory keeps resume dispatch at zero with the original daemon session, process id, and writer as the sole live writer\",\n \"an authoritative empty inventory settles the mirror and releases exactly one resume dispatch with zero liveness probes\",\n \"re-enabling unconditional empty hydration makes the identical oracle red with one resume dispatch, two session ids, two process ids, and two writer calls\"\n ]\n },\n {\n \"file\": \"tests/e2e/paired-remote-terminal-host-restart-background-sync.spec.ts\",\n \"assertions\": [\n \"preserves daemon PID and target PTY identity across the paired host relaunch\",\n \"foregrounds the daemon-backgrounded target on its first post-relaunch remote observation\",\n \"delivers target and post-relaunch control terminal input and live output\"\n ]\n },\n {\n \"file\": \"tests/e2e/paired-remote-terminal-probe-gap-recovery.spec.ts\",\n \"assertions\": [\"replaces a stale paired stream when the PTY snapshot advanced\"]\n },\n {\n \"file\": \"tests/e2e/paired-remote-terminal-stall-recovery.spec.ts\",\n \"assertions\": [\n \"restarts one ACK-starved paired terminal stream without replacing its PTY\"\n ]\n },\n {\n \"file\": \"tests/e2e/headless-paired-remote-terminal-stall-recovery.spec.ts\",\n \"assertions\": [\"recovers an ACK-starved stream from an isolated headless Orca host\"]\n },\n {\n \"file\": \"tests/e2e/paired-remote-terminal-lossy-initial-snapshot.spec.ts\",\n \"assertions\": [\n \"a nonempty lossy initial snapshot paints exactly once on a paired client\",\n \"the authoritative host cursor advances and live output resumes exactly once\"\n ]\n },\n {\n \"file\": \"tests/e2e/paired-remote-terminal-truncated-tail-first-paint.spec.ts\",\n \"assertions\": [\n \"paints a paired remote terminal when only its retained text tail overflowed\",\n \"legacy paired hosts retain the lossy hidden-manager budget fallback\"\n ]\n },\n {\n \"file\": \"tests/e2e/paired-remote-terminal-retention-memory.spec.ts\",\n \"assertions\": [\n \"ordinary-parks paired terminals and restores authoritative host scrollback\",\n \"warm-mounted hidden paired streams schedule zero renderer output work under sustained host output\",\n \"six hidden real PTYs publish and apply only exact working and idle title transitions across paired transport\",\n \"client recovery completes while every target terminal remains unmounted in the host renderer\"\n ]\n },\n {\n \"file\": \"tests/e2e/headless-paired-remote-terminal-retention-memory.spec.ts\",\n \"assertions\": [\n \"ordinary-parks paired terminals against an isolated headless Orca host\",\n \"cold-activates only visible paired terminals against an isolated headless host\",\n \"the headless host bounds real-PTY decorative title transport and production store application\",\n \"the headless host shares the zero-hidden-renderer-work and exact-restoration contract\"\n ]\n },\n {\n \"file\": \"tests/e2e/terminal-parked-memory.spec.ts\",\n \"assertions\": [\n \"releases un-parkable hidden worktree buffers only once the retention budget engages\"\n ]\n },\n {\n \"file\": \"src/main/runtime/rpc/terminal-multiplex-pty-wait-capacity.test.ts\",\n \"assertions\": [\n \"admits 128 active streams, rejects the 129th, and reuses released capacity\",\n \"reserves PTY wait capacity independently from active streams\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"assertions\": [\n \"pauses capable paired output while hidden and restores exactly on reveal\",\n \"locally gates hidden paired output when a legacy host cannot pause it\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-activation-inventory-fallback.test.ts\",\n \"assertions\": [\n \"keeps a mounted HUB mirror alive when the old stream ends before the replacement snapshot\"\n ]\n },\n {\n \"file\": \"src/renderer/src/web/web-preload-api-runtime-environment.test.ts\",\n \"assertions\": [\n \"keeps pairing while manual disconnect fences passive reconnects\",\n \"returns a disconnect envelope when a queued active runtime call disconnects\",\n \"returns a disconnect envelope when a queued selected environment call disconnects\"\n ]\n }\n ]", "Audit3061 retires the park-model supplied snapshot suite and nominal mode, cursor, focus, geometry and remote resume metadata variants. Their distinct alarms are intentionally lost; six retained mode/remote cases preserve selected tail-order, authority and parse-readiness boundaries without equivalent replacement. Existing selectors and dated evidence retain their original scope. The ordinary paired-scroll-back alias was already absent before this batch and is removed as stale metadata, separately from the newly retired floating-pane example.", "Audit3053 reduces hidden-replay coverage by retiring nominal overlap, resize, cursor metadata and standalone stalled-restore variants. Timeout, overflow, identity/generation fences and retained live-output coordination remain; the removed alarms are intentionally lost without equivalent replacement. Existing commands, assertion references and dated evidence retain their original scope.", "Audit2145 accepts removal of canned runtime metadata/guard/forwarding, fake in-memory persistence, private work-count and wrapper-duplication tests from the construction/orca-runtime.test.ts aggregate, plus the two automation run-context guards from runtime-workspace-launch-contracts.test.ts. Retained race, framing, physical completion and ownership callbacks remain byte-identical. Existing commands remain valid selectors; historical receipts stay unchanged and provide no fresh validation or replacement coverage for the reduced suites.", @@ -9023,7 +8756,21 @@ "Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed.", "Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed.", "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired.", - "Terminal/runtime defining-owner cleanup retires complete parking timer, lifecycle, mocked close/disposal and render/flip/mount work-count cases under repository test policy. The retained watcher source has only two literal-oracle coverage decisions; the retained cold-parking hook source has only the layout-PTY exemption invalidation case. Lost alarms include cooldown/measure/pin wakeups, split exit/close attribution and cancellation, watcher disposal/restart, flood timer rearm, worktree verdict damping, and destroyed-transport cold restore. No equivalent replacement coverage or execution pass for the reduced cases is claimed; prior dated receipts retain their original scope." + "Terminal/runtime defining-owner cleanup retires complete parking timer, lifecycle, mocked close/disposal and render/flip/mount work-count cases under repository test policy. The retained watcher source has only two literal-oracle coverage decisions; the retained cold-parking hook source has only the layout-PTY exemption invalidation case. Lost alarms include cooldown/measure/pin wakeups, split exit/close attribution and cancellation, watcher disposal/restart, flood timer rearm, worktree verdict damping, and destroyed-transport cold restore. No equivalent replacement coverage or execution pass for the reduced cases is claimed; prior dated receipts retain their original scope.", + "Module-layout wave3 intentionally retires complete prohibited owning registrations in src/renderer/src/components/terminal-pane/parking/output-watchers/parked-terminal-byte-watcher.test.ts. Lost alarms: Loss of the OSC title forwarding/order alarm for both pane and tab titles. Loss of the bare Cursor Agent title versus synthetic spinner title/deduplication alarm. Loss of the unread BEL attribution and delayed OS bell notification alarm. Loss of the OSC-terminator BEL exclusion alarm across chunk boundaries. Loss of the working-to-idle prompt-cache and completion-notification alarm. Loss of the same-burst completion-over-bell coalescing alarm. Loss of the resumed-working cancellation of pending completion and cache timer alarm. Loss of the cross-chunk GitHub pull-request discovery and workspace/pane attribution alarm. Loss of the Command Code return-to-done callback wiring alarm; real composer delivery was not established. Loss of the already-in-flight Command Code scrape/return alarm. Loss of the park-time working seed to idle completion alarm. Loss of the no-unobserved-transition completion alarm. Loss of the shutdown cancellation and final-flush attention-suppression alarm. Loss of the sidecar unregistration and pending-bell cancellation alarm. Loss of the same-PTY previous-watcher disposal alarm. Loss of the cold snapshot title restoration without replayed attention alarm. Loss of the stale-derived idle fact state-clear/no-completion alarm. Loss of the fact-consumer disposal and written title-slot clearing alarm. No equivalent replacement coverage or reduced-selector pass is claimed.", + "Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands.", + "Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims.", + "Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical.", + "Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed.", + "Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed.", + "Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed.", + "Audit 3318 reduces remote-runtime-pty-transport-unpublished-host-graph.test.ts, retiring its direct published-empty-graph omission-to-pane-exit alarm. The unchanged bounded unpublished-frame/pushed-recovery and stale-handle park/manual-retry cases are narrower, not equivalent replacements. Both complete three-case Linux receipts dated 2026-11-04 are archived as historical, including source heads; they do not validate this reduced selector. Remaining fourteen active receipts are macOS only. No fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed.", + "Audit 3318 retires this complete dated three-case Linux unit receipt because remote-runtime-pty-transport-unpublished-host-graph.test.ts was reduced. Original command/currentCommand/result/date/duration/source head/count remain historical and do not validate the reduced selector. Original receipt verbatim:\n{\n \"date\": \"2026-11-04\",\n \"runner\": \"local\",\n \"platform\": \"linux\",\n \"result\": \"passed\",\n \"command\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm --config.verifyDepsBeforeRun=false test src/renderer/src/components/terminal-pane/remote-runtime-pty-transport-unpublished-host-graph.test.ts --maxWorkers=2\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-unpublished-host-graph.test.ts\",\n \"durationSeconds\": 3.87,\n \"summary\": \"Test Files 1 passed (1); Tests 3 passed (3). Focused Linux unit execution; no physical-provider, p95 or cross-platform claim. Source head b638e07d395b76af3ba6b03761a1a0fe7e5e026e.\"\n }", + "Audit 3318 retires this complete dated three-case Linux unit receipt because remote-runtime-pty-transport-unpublished-host-graph.test.ts was reduced. Original command/currentCommand/result/date/duration/source head/count remain historical and do not validate the reduced selector. Original receipt verbatim:\n{\n \"date\": \"2026-11-04\",\n \"runner\": \"local\",\n \"platform\": \"linux\",\n \"result\": \"passed\",\n \"command\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm --config.verifyDepsBeforeRun=false test src/renderer/src/components/terminal-pane/remote-runtime-pty-transport-unpublished-host-graph.test.ts --maxWorkers=2\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-unpublished-host-graph.test.ts\",\n \"durationSeconds\": 3.79,\n \"summary\": \"Test Files 1 passed (1); Tests 3 passed (3). Focused Linux unit execution; no physical-provider, p95 or cross-platform claim. Source head 415c9cffc2d10024131ec4b6721767a22195de6d.\"\n }", + "Audit3326 adopts reconciled source audit3324 and intentionally retires these low-value examples and their regression alarms: restarts only the stream whose renderer delivery credit never settles — An unreturned renderer delivery credit stalls only its stream, leaving healthy sibling/shared transport alive. Fake-clock deadline plus real multiplexer unsubscribe isolates recovery ownership.; probes then restarts a stream when an entered command receives no frames — Entered command produces no output; actual multiplexer must probe then close only its stalled stream after probe timeout. Distinct response liveness from parser credit.; establishes a probe baseline before recovering an unsequenced stream — 142-line manual five-probe baseline/regression sequence derives request IDs from encoded mock traffic and checks repeated no-close/close choreography. Oversized algorithm/state-machine example; no actual renderer/host command or recovery delivery. Retires unsequenced/unchanged/regressed baseline classification alarms.. Retained tests do not replace these alarms. Dated unrelated evidence remains scoped to its original execution; no historical source/import-closure equivalence, fresh execution, real network/provider/SSH, rendered UI, mobile, mixed-version or cross-platform validation is claimed.", + "NEXT46 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts, src/renderer/src/runtime/hosted-terminals/streams/remote-runtime-terminal-stall-recovery.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence.", + "NEXT46 historical original active selector fields (verbatim JSON values; not current coverage):\ncommands: [\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-unpublished-host-graph.test.ts\",\n \"ORCA_BACKGROUND_LAUNCH=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-host-quit-reconnect-input.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/terminal/query/runtime-terminal-inventory-contracts.test.ts\",\n \"ORCA_BACKGROUND_LAUNCH=1 pnpm exec playwright test tests/e2e/paired-client-first-terminal-unopened-host-worktree.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/session-lifecycle/publication/mobile-session-tabs-agent-status-heartbeat.test.ts tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts --maxWorkers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/parking/lifecycle/use-terminal-tab-cold-parking.test.ts --maxWorkers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/construction/orca-runtime.test.ts src/main/runtime/rpc/terminal-multiplex-initial-snapshot-buffering.test.ts src/main/runtime/rpc/terminal-multiplex-snapshot-serialization.test.ts src/main/runtime/rpc/terminal-multiplex-pty-wait-capacity.test.ts src/main/runtime/rpc/terminal-subscribe-buffer.test.ts src/renderer/src/components/terminal-pane/pty-transport/output/terminal-side-effect-facts-handler.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-activation-inventory-fallback.test.ts src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-view-parking.test.ts src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-worktree-retention.test.ts src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-tab-watchers.test.ts src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-reconciliation.test.ts src/renderer/src/runtime/hosted-terminals/streams/remote-runtime-terminal-stall-recovery.test.ts src/renderer/src/runtime/rpc/subscriptions/runtime-client-events.test.ts src/renderer/src/web/web-preload-api-runtime-environment.test.ts src/main/ipc/runtime-environments/runtime-environments-pairing.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/terminal/adoption/terminal-subscriber-driven-daemon-attach.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/session-tabs/runtime-inventory-publication-authority.test.ts src/main/runtime/rpc/methods/session-tabs/session-tabs-inventory-census-race.test.ts src/main/daemon/terminal-host/testing/terminal-host-agent-session.test.ts tests/e2e/session-tabs-empty-inventory-daemon-oracle.unit.test.ts --maxWorkers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts\",\n \"SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-host-restart-background-sync.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\",\n \"ORCA_E2E_FORWARD_APP_LOGS=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-host-restart-background-sync.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1 --repeat-each=10 --max-failures=1\",\n \"ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-truncated-tail-first-paint.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-lossy-initial-snapshot.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 ORCA_E2E_DISABLE_PAIRED_TERMINAL_PARKING=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-truncated-tail-first-paint.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-stall-recovery.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-probe-gap-recovery.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/headless-paired-remote-terminal-stall-recovery.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-retention-memory.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-retention-memory.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"ORCA_E2E_WEB_CLIENT=1 SKIP_BUILD=1 pnpm exec playwright test tests/e2e/headless-paired-remote-terminal-retention-memory.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\",\n \"SKIP_BUILD=1 pnpm exec playwright test tests/e2e/terminal-parked-memory.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\"\n ]\ntestFiles: [\n \"src/main/runtime/session-lifecycle/publication/mobile-session-tabs-agent-status-heartbeat.test.ts\",\n \"tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts\",\n \"src/renderer/src/components/terminal-pane/parking/lifecycle/use-terminal-tab-cold-parking.test.ts\",\n \"src/main/runtime/construction/orca-runtime.test.ts\",\n \"src/renderer/src/web/web-preload-api-runtime-environment.test.ts\",\n \"src/main/ipc/runtime-environments/runtime-environments-pairing.test.ts\",\n \"src/main/runtime/rpc/terminal-multiplex-initial-snapshot-buffering.test.ts\",\n \"src/main/runtime/rpc/terminal-multiplex-snapshot-serialization.test.ts\",\n \"src/main/runtime/rpc/terminal-multiplex-pty-wait-capacity.test.ts\",\n \"src/main/runtime/rpc/terminal-subscribe-buffer.test.ts\",\n \"src/main/runtime/terminal/adoption/terminal-subscriber-driven-daemon-attach.test.ts\",\n \"src/main/runtime/session-tabs/runtime-inventory-publication-authority.test.ts\",\n \"src/main/runtime/rpc/methods/session-tabs/session-tabs-inventory-census-race.test.ts\",\n \"src/main/daemon/terminal-host/testing/terminal-host-agent-session.test.ts\",\n \"tests/e2e/session-tabs-empty-inventory-daemon-oracle.unit.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/output/terminal-side-effect-facts-handler.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-visibility-and-exit.test.ts\",\n \"src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-worktree-retention.test.ts\",\n \"src/renderer/src/components/terminal-pane/parking/retention/terminal-hidden-view-parking.test.ts\",\n \"src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-tab-watchers.test.ts\",\n \"src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-reconciliation.test.ts\",\n \"src/renderer/src/runtime/hosted-terminals/streams/remote-runtime-terminal-stall-recovery.test.ts\",\n \"src/renderer/src/runtime/rpc/subscriptions/runtime-client-events.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-activation-inventory-fallback.test.ts\",\n \"src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts\",\n \"tests/e2e/paired-remote-terminal-lossy-initial-snapshot.spec.ts\",\n \"tests/e2e/paired-remote-terminal-truncated-tail-first-paint.spec.ts\",\n \"tests/e2e/paired-remote-terminal-stall-recovery.spec.ts\",\n \"tests/e2e/paired-remote-terminal-probe-gap-recovery.spec.ts\",\n \"tests/e2e/headless-paired-remote-terminal-stall-recovery.spec.ts\",\n \"tests/e2e/paired-remote-terminal-retention-memory.spec.ts\",\n \"tests/e2e/headless-paired-remote-terminal-retention-memory.spec.ts\",\n \"tests/e2e/terminal-parked-memory.spec.ts\",\n \"tests/e2e/paired-remote-terminal-host-restart-background-sync.spec.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-unpublished-host-graph.test.ts\",\n \"tests/e2e/paired-remote-terminal-host-quit-reconnect-input.spec.ts\",\n \"src/main/runtime/terminal/query/runtime-terminal-inventory-contracts.test.ts\",\n \"tests/e2e/paired-client-first-terminal-unopened-host-worktree.spec.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts\",\n \"assertions\": [\n \"2,880 decorative spinner and bare-native real-PTY OSC chunks publish zero session-tabs snapshots or serialized bytes after semantic convergence\",\n \"the viewer performs zero snapshot applies and zero store mutations during decorative activity\",\n \"after 30 minutes, one globally spaced refresh per worktree keeps every mirrored working status fresh\",\n \"exact Pi and rotating normalized Pi/Grok frames renew explicit and fallback status without changing stateStartedAt or acknowledgement semantics\",\n \"matching title evidence renews retained OSC hook status without resetting stateStartedAt, then drops unverifiable prompt metadata after the hook row expires\",\n \"renderer-authored rich status keeps its original lease, then renews only coarse title-confirmed state and provider identity\",\n \"ordinary-shell title transitions replace working stateStartedAt with the completion transition time\",\n \"decorative heartbeats remain blocked until unknown foreground ownership resolves, then resume at the bounded interval\",\n \"tracked terminal state reset clears delayed foreground ownership markers\",\n \"raw chunks, semantic idle transitions, and visible output remain exact\"\n ]\n },\n {\n \"file\": \"src/main/runtime/terminal/adoption/terminal-subscriber-driven-daemon-attach.test.ts\",\n \"assertions\": [\"retries an existing subscriber when provider inventory becomes ready\"]\n },\n {\n \"file\": \"src/main/runtime/rpc/methods/session-tabs/session-tabs-inventory-census-race.test.ts\",\n \"assertions\": [\n \"creation and removal at the census release edge are subsumed once, and a delayed pre-boundary change is not replayed\",\n \"post-boundary creation and removal replay after the initial snapshot in sequence order\",\n \"create/remove/recreate transitions are preserved without collapse\",\n \"a post-boundary projected-state change is delivered without a new snapshot revision\",\n \"an older coalesced callback cannot overwrite a newer immediate change\",\n \"initialization churn publishes only the latest projected state and repeated structural overflow fails after bounded recollection\",\n \"disconnect aborts the census and removes the real runtime listener\"\n ]\n },\n {\n \"file\": \"tests/e2e/session-tabs-empty-inventory-daemon-oracle.unit.test.ts\",\n \"assertions\": [\n \"unpublished empty inventory keeps resume dispatch at zero with the original daemon session, process id, and writer as the sole live writer\",\n \"an authoritative empty inventory settles the mirror and releases exactly one resume dispatch with zero liveness probes\",\n \"re-enabling unconditional empty hydration makes the identical oracle red with one resume dispatch, two session ids, two process ids, and two writer calls\"\n ]\n },\n {\n \"file\": \"tests/e2e/paired-remote-terminal-host-restart-background-sync.spec.ts\",\n \"assertions\": [\n \"preserves daemon PID and target PTY identity across the paired host relaunch\",\n \"foregrounds the daemon-backgrounded target on its first post-relaunch remote observation\",\n \"delivers target and post-relaunch control terminal input and live output\"\n ]\n },\n {\n \"file\": \"tests/e2e/paired-remote-terminal-probe-gap-recovery.spec.ts\",\n \"assertions\": [\"replaces a stale paired stream when the PTY snapshot advanced\"]\n },\n {\n \"file\": \"tests/e2e/paired-remote-terminal-stall-recovery.spec.ts\",\n \"assertions\": [\n \"restarts one ACK-starved paired terminal stream without replacing its PTY\"\n ]\n },\n {\n \"file\": \"tests/e2e/headless-paired-remote-terminal-stall-recovery.spec.ts\",\n \"assertions\": [\"recovers an ACK-starved stream from an isolated headless Orca host\"]\n },\n {\n \"file\": \"tests/e2e/paired-remote-terminal-lossy-initial-snapshot.spec.ts\",\n \"assertions\": [\n \"a nonempty lossy initial snapshot paints exactly once on a paired client\",\n \"the authoritative host cursor advances and live output resumes exactly once\"\n ]\n },\n {\n \"file\": \"tests/e2e/paired-remote-terminal-truncated-tail-first-paint.spec.ts\",\n \"assertions\": [\n \"paints a paired remote terminal when only its retained text tail overflowed\",\n \"legacy paired hosts retain the lossy hidden-manager budget fallback\"\n ]\n },\n {\n \"file\": \"tests/e2e/paired-remote-terminal-retention-memory.spec.ts\",\n \"assertions\": [\n \"ordinary-parks paired terminals and restores authoritative host scrollback\",\n \"warm-mounted hidden paired streams schedule zero renderer output work under sustained host output\",\n \"six hidden real PTYs publish and apply only exact working and idle title transitions across paired transport\",\n \"client recovery completes while every target terminal remains unmounted in the host renderer\"\n ]\n },\n {\n \"file\": \"tests/e2e/headless-paired-remote-terminal-retention-memory.spec.ts\",\n \"assertions\": [\n \"ordinary-parks paired terminals against an isolated headless Orca host\",\n \"cold-activates only visible paired terminals against an isolated headless host\",\n \"the headless host bounds real-PTY decorative title transport and production store application\",\n \"the headless host shares the zero-hidden-renderer-work and exact-restoration contract\"\n ]\n },\n {\n \"file\": \"tests/e2e/terminal-parked-memory.spec.ts\",\n \"assertions\": [\n \"releases un-parkable hidden worktree buffers only once the retention budget engages\"\n ]\n },\n {\n \"file\": \"src/main/runtime/rpc/terminal-multiplex-pty-wait-capacity.test.ts\",\n \"assertions\": [\n \"admits 128 active streams, rejects the 129th, and reuses released capacity\",\n \"reserves PTY wait capacity independently from active streams\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"assertions\": [\n \"pauses capable paired output while hidden and restores exactly on reveal\",\n \"locally gates hidden paired output when a legacy host cannot pause it\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-activation-inventory-fallback.test.ts\",\n \"assertions\": [\n \"keeps a mounted HUB mirror alive when the old stream ends before the replacement snapshot\"\n ]\n },\n {\n \"file\": \"src/renderer/src/runtime/hosted-terminals/streams/remote-runtime-terminal-stall-recovery.test.ts\",\n \"assertions\": [\n \"keeps the oldest pending delivery deadline anchored while later frames settle\"\n ]\n },\n {\n \"file\": \"src/renderer/src/web/web-preload-api-runtime-environment.test.ts\",\n \"assertions\": [\n \"keeps pairing while manual disconnect fences passive reconnects\",\n \"returns a disconnect envelope when a queued active runtime call disconnects\",\n \"returns a disconnect envelope when a queued selected environment call disconnects\"\n ]\n }\n ]", + "Audit3342 removes three supplied activation/inventory fallback and same-handle retry examples; their fallback/retry alarms are intentionally lost without equivalent replacement. The exact mounted-HUB pending old-stream-end versus replacement-snapshot registration and its assertion remain. Unrelated dated macOS receipts retain only their original scope; no fresh runtime, provider, performance, mobile, mixed-version or cross-platform validation is claimed." ], "demotionRule": "Keep experimental or demote to protection none if decorative title frequency changes paired client-event or session-tabs publication volume after convergence, a semantic fact is dropped, paired first paint is blank, passive work reconnects after manual disconnect, a capable hidden paired manager survives ordinary parking, a legacy hidden pane schedules raw xterm output or bypasses its fallback, reveal loses requested bounded history or live PTY identity, retained buffer cells do not fall, or either headed/headless scenario flakes." }, @@ -9102,7 +8849,7 @@ "id": "terminal-observability.lifecycle-breadcrumbs", "title": "Terminal lifecycle anomalies enter crash diagnostics as compact breadcrumbs", "maturity": "experimental", - "protection": "partial", + "protection": "none", "owner": "terminal-runtime", "layer": "renderer-observability", "surfaces": [ @@ -9115,38 +8862,19 @@ ], "platforms": ["macos", "linux", "windows"], "providers": ["local", "daemon", "ssh", "wsl", "remote-runtime"], - "coveredPlatforms": ["macos"], + "coveredPlatforms": [], "coveredProviders": [], - "coverageNotes": "Retained renderer unit cases exercise guard release after a silent stalled parse and hardcoded breadcrumb event/pane identity with a fake terminal and mocked recorder. The identity-rich hashing/redaction registration was retired whole. No hashed tab/worktree/leaf identity, path-redaction, diagnostics-bundle export, live provider or packaged runtime coverage is claimed.", + "coverageNotes": "NEXT46 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence. Historical prior account (preserved verbatim): Retained renderer unit cases exercise guard release after a silent stalled parse and hardcoded breadcrumb event/pane identity with a fake terminal and mocked recorder. The identity-rich hashing/redaction registration was retired whole. No hashed tab/worktree/leaf identity, path-redaction, diagnostics-bundle export, live provider or packaged runtime coverage is claimed.", "motivatingLinks": [ "https://github.com/stablyai/orca/pull/6800", "https://github.com/stablyai/orca/issues/6773" ], "invariant": "Terminal lifecycle anomalies around reattach, restore, replay wedges, provider ownership, stale liveness, and fallback routing must leave compact, deduped, privacy-safe breadcrumbs in crash diagnostics so future reports can be attributed from evidence. Replay anomalies must distinguish pane managers and PTYs without recording path-bearing worktree or session identities.", "oracle": "Simulate replay and probe completions that never arrive, advance fake timers through both quiet windows, and require the real replay guard to transition from engaged to released while the mocked recorder receives terminal_replay_guard_wedged_release with paneId 1. This does not establish correlation hashing, path redaction or diagnostics-bundle export.", - "commands": [ - "ORCA_BACKGROUND_LAUNCH=1 pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts --maxWorkers=2" - ], - "testFiles": ["src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts"], - "assertionRefs": [ - { - "file": "src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts", - "assertions": [ - "releases after the probe itself never parses (wedged pipeline) and reports it" - ] - } - ], - "evidenceRuns": [ - { - "date": "2026-11-10", - "runner": "local", - "platform": "macos", - "result": "passed", - "command": "ORCA_BACKGROUND_LAUNCH=1 pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts --maxWorkers=2", - "durationSeconds": 1.52, - "summary": "Retained replay-guard suite passed 19 cases on the module-layout wave1 candidate. The named breadcrumb case preserves real replay guard release and the hardcoded wedged event/pane1 with a fake terminal and mocked recorder. No identity-hash/redaction, live provider, diagnostics-bundle, fresh red/green, performance or CI-soak claim." - } - ], + "commands": [], + "testFiles": [], + "assertionRefs": [], + "evidenceRuns": [], "runtimeBudget": { "p95Seconds": 10, "scope": "renderer observability unit test" @@ -9175,7 +8903,10 @@ "Current coverage does not assert forbidden transitions across live Electron/provider flows.", "Module-layout wave1 intentionally retires complete prohibited owning registrations in src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts. Lost alarms: a wedged release hands the terminal to pane recovery; a healthy parse completion never notifies pane recovery; HOLDS the guard while a slow replay is still parsing — a probe is queued, never a blind release; records correlatable replay identity without exposing worktree or PTY paths; holds past the probe deadline while sibling completions prove the parser alive; settles guards on a disposed xterm without certifying a wedge. No equivalent replacement coverage or pass for a reduced selector is claimed. All unrelated selectors and historical receipts retain their original scope.", "Module-layout wave1 retires this complete historical receipt because its explicit current selector was reduced. It does not validate the reduced suite. Original receipt verbatim:\n{\n \"date\": \"2026-07-29\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/replay-guard.test.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 0.201,\n \"summary\": \"The focused file passed 29 tests; replay anomaly breadcrumbs preserved event classification while adding hashed tab/worktree/leaf correlation and a path-redacted PTY identity.\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts\"\n }", - "Module-layout wave1 historical richer-oracle metadata before identity-registration retirement, retained verbatim without current validation credit: {\"coverageNotes\":\"Renderer unit coverage proves replay-guard lost-completion and certified-wedge events carry correlatable tab, worktree, durable leaf, pane, and redacted PTY identity without exposing path-bearing values. Full provider lifecycle attribution and diagnostics-bundle artifact proof remain gaps.\",\"oracle\":\"Drop a replay write completion while allowing its FIFO probe to parse, then require the lost-completion breadcrumb to include pane ID, stable hashes for tab/worktree/leaf identity, and a path-redacted PTY ID. Existing wedge tests require both lost-completion and certified-dead paths to record their distinct event names. Full pane transition traces and diagnostics-bundle artifact proof remain follow-ups.\",\"redGreenEvidence\":{\"status\":\"partial\",\"evidence\":\"Tests fail if replay anomalies stop recording their event name, omit pane/terminal correlation, or expose the fixture's path-bearing worktree and PTY prefixes. Needs diagnostics-bundle artifact proof and full transition-trace evidence before promotion.\"}}" + "Module-layout wave1 historical richer-oracle metadata before identity-registration retirement, retained verbatim without current validation credit: {\"coverageNotes\":\"Renderer unit coverage proves replay-guard lost-completion and certified-wedge events carry correlatable tab, worktree, durable leaf, pane, and redacted PTY identity without exposing path-bearing values. Full provider lifecycle attribution and diagnostics-bundle artifact proof remain gaps.\",\"oracle\":\"Drop a replay write completion while allowing its FIFO probe to parse, then require the lost-completion breadcrumb to include pane ID, stable hashes for tab/worktree/leaf identity, and a path-redacted PTY ID. Existing wedge tests require both lost-completion and certified-dead paths to record their distinct event names. Full pane transition traces and diagnostics-bundle artifact proof remain follow-ups.\",\"redGreenEvidence\":{\"status\":\"partial\",\"evidence\":\"Tests fail if replay anomalies stop recording their event name, omit pane/terminal correlation, or expose the fixture's path-bearing worktree and PTY prefixes. Needs diagnostics-bundle artifact proof and full transition-trace evidence before promotion.\"}}", + "NEXT46 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence.", + "NEXT46 historical original active selector fields (verbatim JSON values; not current coverage):\ncommands: [\n \"ORCA_BACKGROUND_LAUNCH=1 pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts --maxWorkers=2\"\n ]\ntestFiles: [\"src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts\"]\nassertionRefs: [\n {\n \"file\": \"src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts\",\n \"assertions\": [\n \"releases after the probe itself never parses (wedged pipeline) and reports it\"\n ]\n }\n ]\ncoveredPlatforms: [\"macos\"]\ncoveredProviders: []", + "NEXT46 historical original evidenceRuns object (verbatim; no current-selector pass credit):\n{\n \"date\": \"2026-11-10\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"result\": \"passed\",\n \"command\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts --maxWorkers=2\",\n \"durationSeconds\": 1.52,\n \"summary\": \"Retained replay-guard suite passed 19 cases on the module-layout wave1 candidate. The named breadcrumb case preserves real replay guard release and the hardcoded wedged event/pane1 with a fake terminal and mocked recorder. No identity-hash/redaction, live provider, diagnostics-bundle, fresh red/green, performance or CI-soak claim.\"\n }" ], "demotionRule": "Cannot promote if diagnostics are console-only, unbounded, or missing from support artifacts." }, @@ -9202,7 +8933,7 @@ "providers": ["local", "daemon", "ssh", "remote-runtime"], "coveredPlatforms": ["macos"], "coveredProviders": [], - "coverageNotes": "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Module layout SSH policy: Retire the multiplexer private-clock saturation registration, the writer saturation transition-count registration and the changed-source dated writer/backpressure receipt. Retained byte delivery, lane order, fairness, settlement and cancellation cases are unvalidated by that historical receipt. No equivalent replacement, new execution, measured performance, live SSH/WSL or cross-platform proof is claimed. The unchanged WSL protocol receipt retains only its original command scope. Historical prior account (preserved verbatim): Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2070 (sources2068/2069): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime.test.ts: ordinary registration cleanup removes only await import('./orca-runtime-tests/hooks-and-hosted-review.spec'). src/main/ssh/ssh-multiplexer-transport-writer.test.ts: reports saturated epochs and their drain boundary exactly once. src/main/runtime/orca-runtime-tests/worktree-removal-archive-hook-gate.spec.ts: removes and records the waiver when the failure is explicitly overridden; removes without an override record when the hook succeeds; removes when the hook is configured but not requested; removes when no archive hook is configured; holds a desktop removal in the same repo until this one is accepted; joins a desktop removal of the same worktree accepted while this one waited. src/main/runtime/orca-runtime-tests/worktree-ps-agent-row-dismissal.spec.ts: drops the row as soon as the user dismisses it, without waiting for the PTY to exit; tells paired clients to republish on the transition and on the dismissal; rejoins a row through its %s handle after pane ownership clears. src/main/runtime/orca-runtime-tests/hooks-and-hosted-review.spec.ts: reports an error when the SSH filesystem provider is unavailable; reports an SSH orca.yaml as an error without reading any filesystem; reports ok for a local repo hook check; reads SSH issue commands as absent and drops writes without touching any filesystem; allows host integration slug helpers for SSH repos through provider-aware GitHub clients; routes runtime GitHub repo identity helpers through the selected WSL project runtime; routes runtime GitHub issue and work-item actions through the selected WSL project runtime; pins explicit origin preference on runtime open-by-number work item lookups; forwards check-details cancellation without local Git overrides. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. The historical receipt/currentCommand selecting src/main/ssh/ssh-multiplexer-transport-writer.test.ts remains historical and is not a passing result for the reduced current command. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Delete the complete tail-wait memo suite: its sole current authored callback checks supplied fromTail/blocked field values. Retire all three broader memoization/equivalence/eviction assertion aliases; they are not backed by retained source callbacks. No scan-work budget, sustained output, physical terminal or resource measurement is assigned to this removed test. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1674 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1634 removes low-value IPC, filesystem and runtime projections, argument inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained cancellation, ownership, authorization, filesystem and SQLite boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Local macOS evidence covers main-process pending-output and projection-admission caps, saturated-tail wait detection, direct-SSH source retention/accounting, always-on V1 negotiation with legacy peer fallback, exact provider-generation pause ownership, renderer exit/data ordering, decoder input bounds, bounded reconnect scheduling, and WSL stdio transport settlement through deterministic unit contracts. A joined main/runtime oracle exercises renderer-sourced headed semantics and headless-model snapshot semantics without launching a live paired server. Separately, a macOS-hosted Docker OpenSSH run exercises only the deployed Linux relay and direct SSH provider with an exact 256 KiB source-credit plateau, concurrent PTY typing, fixed-size filesystem frames, Git churn, and owner-lease reconnect. Neither deterministic topology labels nor Docker SSH constitute live headed desktop, headless orca serve, or physical WSL evidence; local/daemon, prior-version daemons, Windows named pipes/ConPTY, folder workspaces, and mixed-version clients also remain uncovered. Audit1312 removes low-value imported specs from aggregate test drivers; old whole-driver execution receipts are archived. Retained registrations are unchanged. No equivalent replacement coverage is claimed. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result.", + "coverageNotes": "Audit3375 composes root-adopted3370/independent3371 and3373/independent3374: intentionally retires79 authored registrations/84 expanded cases, including39 whole suites, without equivalent replacement. Lost alarms include federation field/parser inventories; Claude rejected-key precedence, credential clone redaction, managed-versus-user hook preservation and CLI defaults; setting/status/activity projections, mocked SSH/notification/reveal/Linear refusal, fake-clock reconnect and noise; image-fold artifact visibility, paste eligibility, setup trust, scripted ACP error-to-journal publication and ligature cache tuple aliasing; plus supplied folder-runner uniqueness, mobile host-overlay/credential/update/preference races, status/markup/title/keyed-row projections, subscriber cleanup, cancellation/close/refusal/link-issue and mirror suppression alarms. Retained3373 merger contiguity, dual-clock overdue-resume exactly-once, rejected-paste IPC sink and annotation schema roundtrip remain bounded. Retained actual HTTP/OSC status composition, destructive sibling-filesystem isolation, external contrast invariant and fixture CSS pixel intervention remain narrower. Original reviewed87authored/92expanded become9/9; current OpenCode suite adds two preserved upstream cases and the synthetic-title suite gained one Cursor policy mock-call case, independently reviewed for removal in root3378; current90/95 become11/11. That Cursor suppression/ready-frame regression alarm is intentionally lost; it does not observe native title ownership or tab flicker. For3370 only the peer was independently blind, with author exposure explicit;3373/3374 both blind pins were verified. This broad root unit command selects the reduced root unit suite; UNIT_INCLUDE excludes mobile tests, which require the existing mobile runner; retained Playwright component-pixel spec uses its separate existing headless fixture runner and is not validated by the broad unit command. No fresh execution, actual agent/shell/provider, OS material/focus, historical import equivalence, mobile, mixed-version or cross-platform evidence is claimed. All dated receipts retain their original scope. Audit3368 composes root-adopted3363/3364 and3367/3369: intentionally retires181 authored registrations/196 expanded cases, including28 whole suites, without equivalent replacement. Lost alarms include hibernation attention/liveness/backoff/sequential teardown and inventory, host launch compatibility/legacy/Kimi/resource cleanup, terminal recovery parser/pause/quarantine/remount, window-visibility omission-fence lifetime, launch-option rendered Start, sleeping-resume saved recipe/WSL quoting/cancellation, plus removed project/window/input variants. Additional tiny-suite losses include sentence/label/field/default inventories, credential omission, Windows argument/environment mapping, URI decoding, diagnostics, provider classification and fake-clock callback/parser examples. Retained ten registrations/twelve expanded cases include two literal Unicode Mn/Cf zero-width range guards in the actual character-range algorithm and protect narrower delayed editor bytes/destructive ownership, mounted hidden collision repair, ten transport epochs, duplicate-command refusal, caller timeout typing, executor unknown-opener refusal and failed-chunk user bytes. This broad unit command selects the reduced suite; no fresh runtime, real provider/network/PTY, filesystem restart, native UI, historical import equivalence, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3362 composes root-adopted3358/independent3360: intentionally retires129 authored registrations/140 expanded cases, including four whole suites, without equivalent replacement. Lost alarms include supplied orphan-adoption retry/malformed inventory/cancellation; fake-terminal replay parser/wedge/disposal callbacks; all-host catalog metadata and Windows preferences; host keepalive/protocol/stale/settings failures; and removed exact-stop/suppression, source save lifetime, diff-note queue, rename/editor close, input flood/chunk refusal/limits, purge and creation examples. Retained18 registrations/21 expanded cases protect narrower ownership, generation, dirty-state, queue convergence, encoding and attachment-lease outcomes. No replacement or keeper quota claim. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY/xterm parser, disk restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3359 composes root-adopted source3355/independent3356: intentionally retires130 authored registrations/139 expanded cases, including eight whole suites, without equivalent replacement. Lost alarms include strict create naming/capability/legacy payloads; supplied transport host replacement, deadline reattach, create-handoff and split activation; agent-session fork/clipboard/platform flags; shutdown cleared-scrollback/unmounted bindings; simulator host-collision/selection/shutdown; and removed editor, catalog, mutation, launch and status examples. Retained12 adverse-ordering/state-consequence cases are narrower and do not replace all removed alarms. Two queue absences receive zero removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY, filesystem restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3349 composes adopted batches3343,3345 and refreshed3354: intentionally retires234 authored registrations/294 expanded cases, including13 whole suites, without equivalent replacement. Lost alarms include supplied terminal reconnect/replacement/typeahead/mirror/result and snapshot examples; synthetic render-desync persistence/recovery; worktree listing/owner/catalog/lineage/removal and activation/creation examples; host-scoped PR and task-record projections; editor diff/status/comment and UI send-target examples; automation observation/wake, supplied sleep/deadline clock and native-chat completion/notification/relaunch samples; held-tab layout and cleanup/progress guard examples. Retained adverse-ordering and wire-boundary cases are narrower and do not replace all removed alarms. The already-upstream visibility-resume deletion receives zero new removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH, native process/power/GPU, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3342 composes adopted source batches3333/3334,3336/3337 and3340/3341: intentionally retires180 authored registrations/263 expanded cases, including seven whole suites, without equivalent replacement. Lost alarms include corrupt editor hydration; mobile editor/diff publication and privacy projections; stale-resubscribe routing; model-picker projection/refetch/retry/fallback; editor check-details and frame property inventories; latched-pane cleanup/quiescence; client create replay identity/options/compatibility; and removed owner, async routing, terminal and layout examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts keep their original scope. Audit3335 composes adopted source unions3327/3328 and3330/3332: intentionally retires100 authored registrations/123 expanded cases, including ten whole suites, without equivalent replacement. Lost alarms include seeded host persistence/contention and stale-host cleanup; browser snapshot assembly; mocked wake/DPR callbacks and frame budgets; preflight projections; palette authority/cache suppression, URL intent and saved-title cross-repo collisions; metadata coverage/set patch and dropdown assembly; and removed terminal, worktree, review-refresh and owner-routing examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI/GPU/focus, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain only their original scope. Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed. Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed. Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed. Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical. Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims. Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands. Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Module layout SSH policy: Retire the multiplexer private-clock saturation registration, the writer saturation transition-count registration and the changed-source dated writer/backpressure receipt. Retained byte delivery, lane order, fairness, settlement and cancellation cases are unvalidated by that historical receipt. No equivalent replacement, new execution, measured performance, live SSH/WSL or cross-platform proof is claimed. The unchanged WSL protocol receipt retains only its original command scope. Historical prior account (preserved verbatim): Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2070 (sources2068/2069): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime.test.ts: ordinary registration cleanup removes only await import('./orca-runtime-tests/hooks-and-hosted-review.spec'). src/main/ssh/ssh-multiplexer-transport-writer.test.ts: reports saturated epochs and their drain boundary exactly once. src/main/runtime/orca-runtime-tests/worktree-removal-archive-hook-gate.spec.ts: removes and records the waiver when the failure is explicitly overridden; removes without an override record when the hook succeeds; removes when the hook is configured but not requested; removes when no archive hook is configured; holds a desktop removal in the same repo until this one is accepted; joins a desktop removal of the same worktree accepted while this one waited. src/main/runtime/orca-runtime-tests/worktree-ps-agent-row-dismissal.spec.ts: drops the row as soon as the user dismisses it, without waiting for the PTY to exit; tells paired clients to republish on the transition and on the dismissal; rejoins a row through its %s handle after pane ownership clears. src/main/runtime/orca-runtime-tests/hooks-and-hosted-review.spec.ts: reports an error when the SSH filesystem provider is unavailable; reports an SSH orca.yaml as an error without reading any filesystem; reports ok for a local repo hook check; reads SSH issue commands as absent and drops writes without touching any filesystem; allows host integration slug helpers for SSH repos through provider-aware GitHub clients; routes runtime GitHub repo identity helpers through the selected WSL project runtime; routes runtime GitHub issue and work-item actions through the selected WSL project runtime; pins explicit origin preference on runtime open-by-number work item lookups; forwards check-details cancellation without local Git overrides. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. The historical receipt/currentCommand selecting src/main/ssh/ssh-multiplexer-transport-writer.test.ts remains historical and is not a passing result for the reduced current command. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Delete the complete tail-wait memo suite: its sole current authored callback checks supplied fromTail/blocked field values. Retire all three broader memoization/equivalence/eviction assertion aliases; they are not backed by retained source callbacks. No scan-work budget, sustained output, physical terminal or resource measurement is assigned to this removed test. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1674 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1634 removes low-value IPC, filesystem and runtime projections, argument inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained cancellation, ownership, authorization, filesystem and SQLite boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Local macOS evidence covers main-process pending-output and projection-admission caps, saturated-tail wait detection, direct-SSH source retention/accounting, always-on V1 negotiation with legacy peer fallback, exact provider-generation pause ownership, renderer exit/data ordering, decoder input bounds, bounded reconnect scheduling, and WSL stdio transport settlement through deterministic unit contracts. A joined main/runtime oracle exercises renderer-sourced headed semantics and headless-model snapshot semantics without launching a live paired server. Separately, a macOS-hosted Docker OpenSSH run exercises only the deployed Linux relay and direct SSH provider with an exact 256 KiB source-credit plateau, concurrent PTY typing, fixed-size filesystem frames, Git churn, and owner-lease reconnect. Neither deterministic topology labels nor Docker SSH constitute live headed desktop, headless orca serve, or physical WSL evidence; local/daemon, prior-version daemons, Windows named pipes/ConPTY, folder workspaces, and mixed-version clients also remain uncovered. Audit1312 removes low-value imported specs from aggregate test drivers; old whole-driver execution receipts are archived. Retained registrations are unchanged. No equivalent replacement coverage is claimed. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result.", "motivatingLinks": [ "https://github.com/stablyai/orca/pull/6836", "https://github.com/stablyai/orca/pull/6858", @@ -9210,7 +8941,7 @@ "https://github.com/stablyai/orca/pull/7054" ], "invariant": "High-volume terminal output must stay bounded across daemon socket writes, SSH relay writer/decoder/source retention/reconnect, main model and projection admission, runtime metadata, detectors, and tail checks, main-to-renderer in-flight bytes, renderer scheduler queues, and hidden-output restore without starving focused input. Every new SSH session offers V1 and every same-build relay supports it; legacy delivery is reachable only when capability negotiation proves the peer cannot use V1. Negotiated SSH spans remain exact and contiguous through activation, exit, cancellation, recovery, desktop projection, and required remote replacement; provisional activation data cannot project, reconnect may release it only into the exact attempt's private recovery quarantine after contract validation, and exit seals that quarantine against later same-token frames until ordered admission or exact cancellation proof. Reconnect checkpoint capture freezes exact provider-generation/PTy admission, cancels queued old work, and waits for the running raw completion before exposing its accepted checkpoint; timeout or failure detaches only that PTy's old model, makes the checkpoint unavailable, and releases the bounded fence without closing the shared provider, while the same failure outside an active exact migration remains generation-fatal and overlapping reconnects preserve any earlier outstanding fence. Pending renderer projection IDs are capped and compacted across split remainders, exit preparation owns its renderer fence through finalization, exit-time cancellation transfers published projections before proof commit, generation close fences late proof while draining exact projection waiters, closed-generation identity compacts without weakening stale rejection, canceled source-delivery retirement retains at most one ordered token per PTY, and pause/resume targets only the exact provider generation. Additional subscribers cannot stall the owner, while the required legacy primary retains backpressure.", - "oracle": "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Module layout SSH policy: Retire the multiplexer private-clock saturation registration, the writer saturation transition-count registration and the changed-source dated writer/backpressure receipt. Retained byte delivery, lane order, fairness, settlement and cancellation cases are unvalidated by that historical receipt. No equivalent replacement, new execution, measured performance, live SSH/WSL or cross-platform proof is claimed. The unchanged WSL protocol receipt retains only its original command scope. Historical prior account (preserved verbatim): Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2070 (sources2068/2069): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime.test.ts: ordinary registration cleanup removes only await import('./orca-runtime-tests/hooks-and-hosted-review.spec'). src/main/ssh/ssh-multiplexer-transport-writer.test.ts: reports saturated epochs and their drain boundary exactly once. src/main/runtime/orca-runtime-tests/worktree-removal-archive-hook-gate.spec.ts: removes and records the waiver when the failure is explicitly overridden; removes without an override record when the hook succeeds; removes when the hook is configured but not requested; removes when no archive hook is configured; holds a desktop removal in the same repo until this one is accepted; joins a desktop removal of the same worktree accepted while this one waited. src/main/runtime/orca-runtime-tests/worktree-ps-agent-row-dismissal.spec.ts: drops the row as soon as the user dismisses it, without waiting for the PTY to exit; tells paired clients to republish on the transition and on the dismissal; rejoins a row through its %s handle after pane ownership clears. src/main/runtime/orca-runtime-tests/hooks-and-hosted-review.spec.ts: reports an error when the SSH filesystem provider is unavailable; reports an SSH orca.yaml as an error without reading any filesystem; reports ok for a local repo hook check; reads SSH issue commands as absent and drops writes without touching any filesystem; allows host integration slug helpers for SSH repos through provider-aware GitHub clients; routes runtime GitHub repo identity helpers through the selected WSL project runtime; routes runtime GitHub issue and work-item actions through the selected WSL project runtime; pins explicit origin preference on runtime open-by-number work item lookups; forwards check-details cancellation without local Git overrides. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. The historical receipt/currentCommand selecting src/main/ssh/ssh-multiplexer-transport-writer.test.ts remains historical and is not a passing result for the reduced current command. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Delete the complete tail-wait memo suite: its sole current authored callback checks supplied fromTail/blocked field values. Retire all three broader memoization/equivalence/eviction assertion aliases; they are not backed by retained source callbacks. No scan-work budget, sustained output, physical terminal or resource measurement is assigned to this removed test. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1674 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: The current executable slice injects main-process renderer backlog pressure, then asserts ordinary terminal-wait detection without a joined-tail allocation and with full prompt-family continuity, per-PTY and total pending-output caps, a 1,024-ID projection cap with split-remainder compaction, preserved sequenced-tail metadata, active-pending protection ahead of background trimming, exact provider-generation pause ownership, renderer exit/data ordering, and ACK-gated in-flight bounds. The negotiation seam proves every initial connection and reconnect offers V1, the same-build relay advertises V1 without launch flags, old clients remain token-free, and method-not-found peers fall back without installing source ACK publication. The joined source-intake/multiplex oracle blocks renderer or headless serialization, admits one snapshot-covered span and one trailing span, requires replacement reservation only after the authoritative sequence is known, advances upstream ACK eligibility exactly to the covered boundary after SnapshotEnd, and delivers then ACKs the trailing span through the ordinary live path without cancellation. Source-range ledger and multiplex seams additionally require cumulative byte ACK 40 then 100 for one 100-byte frame to release exact byte credit without early source settlement, admit a contiguous higher-generation recovered token while the prior token remains unsettled, and reject stale stream or source generations without releasing in-flight byte credit. Replacement reservation rolls back every earlier span on a later failure, commit requires the exact frozen transfer states, and an authoritatively reclaimed covered span rejects commit without local trim authority while rollback removes the reservation idempotently. The exit-deadline oracle publishes a source-backed desktop projection, advances a fake clock to cancellation, and requires one projection transfer, proof commit, preparation, and final exit with no provider close, retained obligation, duplicate finalization, or process-lifetime cancellation tombstone; a second controlled proof remains pending across generation close and must never publish final exit, while both paths release the renderer preparation lease exactly once. The model-migration oracle accepts span A, blocks span B's raw emulator completion, begins disconnect migration, and proves no checkpoint or reconnect attach can remain at A; releasing B advances the exact checkpoint to B and projects B once. Its fake-clock arm reaches the 10-second deadline, requires checkpoint-unavailable, one exact model reset, zero retained admission charge and timers, and no effect from late raw settlement. Its two-PTY failure arm rejects one running raw callback under an active exact migration and requires one checkpoint-unavailable result, one model reset, zero provider closes, retained sibling checkpoint and transport liveness, zero charges and timers, and an unaffected other generation; a non-migrating sibling oracle still requires generation close. The intake additionally closes 2,048 sequential provider generations into one exact range, rejects stale events across that range, and preserves an out-of-order live gap until its own close. Direct-SSH contracts additionally prove activation-response settlement before the first source frame, claim-gated projection under same-decoder-turn response/data delivery, exact early-ACK reservation through send settlement or same-token retry, recovery completion visible before lease-held frames transfers those frames only into the private quarantine and admits no output until exact checkpoint-to-recoveryEnd coverage, invalid-checkpoint restore retention through response settlement followed by fresh-token retry and one live source frame, isolated saturated-subscriber eviction with healthy owner liveness, preserved legacy-primary backpressure, one-write ownership across write(false)/drain, control selection ahead of queued ordinary PTY input with FIFO lanes and bounded fairness, liveness rebasing, failed-exit retention through late ACK or exact recovery, response-settlement cancellation authority, token-scoped exit cancellation, exact checkpoint-to-recoveryEnd continuity, stale-owner one-shot retry, no physical PTY teardown on recovery failure, exact provider-generation closure and once-only cleanup when recovery cancellation publication or proof rejects, 16 MiB-plus-1 MiB decoder caps, charged per-PTY/session retention budgets, and eight-wide isolated reattach. The live Electron perf oracle adds hidden-output floods, renderer scheduler queue depth, dropped-output-zero normal scenarios, and active key latency budgets before promotion.", + "oracle": "Audit3375 composes root-adopted3370/independent3371 and3373/independent3374: intentionally retires79 authored registrations/84 expanded cases, including39 whole suites, without equivalent replacement. Lost alarms include federation field/parser inventories; Claude rejected-key precedence, credential clone redaction, managed-versus-user hook preservation and CLI defaults; setting/status/activity projections, mocked SSH/notification/reveal/Linear refusal, fake-clock reconnect and noise; image-fold artifact visibility, paste eligibility, setup trust, scripted ACP error-to-journal publication and ligature cache tuple aliasing; plus supplied folder-runner uniqueness, mobile host-overlay/credential/update/preference races, status/markup/title/keyed-row projections, subscriber cleanup, cancellation/close/refusal/link-issue and mirror suppression alarms. Retained3373 merger contiguity, dual-clock overdue-resume exactly-once, rejected-paste IPC sink and annotation schema roundtrip remain bounded. Retained actual HTTP/OSC status composition, destructive sibling-filesystem isolation, external contrast invariant and fixture CSS pixel intervention remain narrower. Original reviewed87authored/92expanded become9/9; current OpenCode suite adds two preserved upstream cases and the synthetic-title suite gained one Cursor policy mock-call case, independently reviewed for removal in root3378; current90/95 become11/11. That Cursor suppression/ready-frame regression alarm is intentionally lost; it does not observe native title ownership or tab flicker. For3370 only the peer was independently blind, with author exposure explicit;3373/3374 both blind pins were verified. This broad root unit command selects the reduced root unit suite; UNIT_INCLUDE excludes mobile tests, which require the existing mobile runner; retained Playwright component-pixel spec uses its separate existing headless fixture runner and is not validated by the broad unit command. No fresh execution, actual agent/shell/provider, OS material/focus, historical import equivalence, mobile, mixed-version or cross-platform evidence is claimed. All dated receipts retain their original scope. Audit3368 composes root-adopted3363/3364 and3367/3369: intentionally retires181 authored registrations/196 expanded cases, including28 whole suites, without equivalent replacement. Lost alarms include hibernation attention/liveness/backoff/sequential teardown and inventory, host launch compatibility/legacy/Kimi/resource cleanup, terminal recovery parser/pause/quarantine/remount, window-visibility omission-fence lifetime, launch-option rendered Start, sleeping-resume saved recipe/WSL quoting/cancellation, plus removed project/window/input variants. Additional tiny-suite losses include sentence/label/field/default inventories, credential omission, Windows argument/environment mapping, URI decoding, diagnostics, provider classification and fake-clock callback/parser examples. Retained ten registrations/twelve expanded cases include two literal Unicode Mn/Cf zero-width range guards in the actual character-range algorithm and protect narrower delayed editor bytes/destructive ownership, mounted hidden collision repair, ten transport epochs, duplicate-command refusal, caller timeout typing, executor unknown-opener refusal and failed-chunk user bytes. This broad unit command selects the reduced suite; no fresh runtime, real provider/network/PTY, filesystem restart, native UI, historical import equivalence, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3362 composes root-adopted3358/independent3360: intentionally retires129 authored registrations/140 expanded cases, including four whole suites, without equivalent replacement. Lost alarms include supplied orphan-adoption retry/malformed inventory/cancellation; fake-terminal replay parser/wedge/disposal callbacks; all-host catalog metadata and Windows preferences; host keepalive/protocol/stale/settings failures; and removed exact-stop/suppression, source save lifetime, diff-note queue, rename/editor close, input flood/chunk refusal/limits, purge and creation examples. Retained18 registrations/21 expanded cases protect narrower ownership, generation, dirty-state, queue convergence, encoding and attachment-lease outcomes. No replacement or keeper quota claim. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY/xterm parser, disk restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3359 composes root-adopted source3355/independent3356: intentionally retires130 authored registrations/139 expanded cases, including eight whole suites, without equivalent replacement. Lost alarms include strict create naming/capability/legacy payloads; supplied transport host replacement, deadline reattach, create-handoff and split activation; agent-session fork/clipboard/platform flags; shutdown cleared-scrollback/unmounted bindings; simulator host-collision/selection/shutdown; and removed editor, catalog, mutation, launch and status examples. Retained12 adverse-ordering/state-consequence cases are narrower and do not replace all removed alarms. Two queue absences receive zero removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY, filesystem restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3349 composes adopted batches3343,3345 and refreshed3354: intentionally retires234 authored registrations/294 expanded cases, including13 whole suites, without equivalent replacement. Lost alarms include supplied terminal reconnect/replacement/typeahead/mirror/result and snapshot examples; synthetic render-desync persistence/recovery; worktree listing/owner/catalog/lineage/removal and activation/creation examples; host-scoped PR and task-record projections; editor diff/status/comment and UI send-target examples; automation observation/wake, supplied sleep/deadline clock and native-chat completion/notification/relaunch samples; held-tab layout and cleanup/progress guard examples. Retained adverse-ordering and wire-boundary cases are narrower and do not replace all removed alarms. The already-upstream visibility-resume deletion receives zero new removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH, native process/power/GPU, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3342 composes adopted source batches3333/3334,3336/3337 and3340/3341: intentionally retires180 authored registrations/263 expanded cases, including seven whole suites, without equivalent replacement. Lost alarms include corrupt editor hydration; mobile editor/diff publication and privacy projections; stale-resubscribe routing; model-picker projection/refetch/retry/fallback; editor check-details and frame property inventories; latched-pane cleanup/quiescence; client create replay identity/options/compatibility; and removed owner, async routing, terminal and layout examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts keep their original scope. Audit3335 composes adopted source unions3327/3328 and3330/3332: intentionally retires100 authored registrations/123 expanded cases, including ten whole suites, without equivalent replacement. Lost alarms include seeded host persistence/contention and stale-host cleanup; browser snapshot assembly; mocked wake/DPR callbacks and frame budgets; preflight projections; palette authority/cache suppression, URL intent and saved-title cross-repo collisions; metadata coverage/set patch and dropdown assembly; and removed terminal, worktree, review-refresh and owner-routing examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI/GPU/focus, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain only their original scope. Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed. Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed. Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed. Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical. Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims. Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands. Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Module layout SSH policy: Retire the multiplexer private-clock saturation registration, the writer saturation transition-count registration and the changed-source dated writer/backpressure receipt. Retained byte delivery, lane order, fairness, settlement and cancellation cases are unvalidated by that historical receipt. No equivalent replacement, new execution, measured performance, live SSH/WSL or cross-platform proof is claimed. The unchanged WSL protocol receipt retains only its original command scope. Historical prior account (preserved verbatim): Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2070 (sources2068/2069): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime.test.ts: ordinary registration cleanup removes only await import('./orca-runtime-tests/hooks-and-hosted-review.spec'). src/main/ssh/ssh-multiplexer-transport-writer.test.ts: reports saturated epochs and their drain boundary exactly once. src/main/runtime/orca-runtime-tests/worktree-removal-archive-hook-gate.spec.ts: removes and records the waiver when the failure is explicitly overridden; removes without an override record when the hook succeeds; removes when the hook is configured but not requested; removes when no archive hook is configured; holds a desktop removal in the same repo until this one is accepted; joins a desktop removal of the same worktree accepted while this one waited. src/main/runtime/orca-runtime-tests/worktree-ps-agent-row-dismissal.spec.ts: drops the row as soon as the user dismisses it, without waiting for the PTY to exit; tells paired clients to republish on the transition and on the dismissal; rejoins a row through its %s handle after pane ownership clears. src/main/runtime/orca-runtime-tests/hooks-and-hosted-review.spec.ts: reports an error when the SSH filesystem provider is unavailable; reports an SSH orca.yaml as an error without reading any filesystem; reports ok for a local repo hook check; reads SSH issue commands as absent and drops writes without touching any filesystem; allows host integration slug helpers for SSH repos through provider-aware GitHub clients; routes runtime GitHub repo identity helpers through the selected WSL project runtime; routes runtime GitHub issue and work-item actions through the selected WSL project runtime; pins explicit origin preference on runtime open-by-number work item lookups; forwards check-details cancellation without local Git overrides. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. The historical receipt/currentCommand selecting src/main/ssh/ssh-multiplexer-transport-writer.test.ts remains historical and is not a passing result for the reduced current command. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Delete the complete tail-wait memo suite: its sole current authored callback checks supplied fromTail/blocked field values. Retire all three broader memoization/equivalence/eviction assertion aliases; they are not backed by retained source callbacks. No scan-work budget, sustained output, physical terminal or resource measurement is assigned to this removed test. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1674 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: The current executable slice injects main-process renderer backlog pressure, then asserts ordinary terminal-wait detection without a joined-tail allocation and with full prompt-family continuity, per-PTY and total pending-output caps, a 1,024-ID projection cap with split-remainder compaction, preserved sequenced-tail metadata, active-pending protection ahead of background trimming, exact provider-generation pause ownership, renderer exit/data ordering, and ACK-gated in-flight bounds. The negotiation seam proves every initial connection and reconnect offers V1, the same-build relay advertises V1 without launch flags, old clients remain token-free, and method-not-found peers fall back without installing source ACK publication. The joined source-intake/multiplex oracle blocks renderer or headless serialization, admits one snapshot-covered span and one trailing span, requires replacement reservation only after the authoritative sequence is known, advances upstream ACK eligibility exactly to the covered boundary after SnapshotEnd, and delivers then ACKs the trailing span through the ordinary live path without cancellation. Source-range ledger and multiplex seams additionally require cumulative byte ACK 40 then 100 for one 100-byte frame to release exact byte credit without early source settlement, admit a contiguous higher-generation recovered token while the prior token remains unsettled, and reject stale stream or source generations without releasing in-flight byte credit. Replacement reservation rolls back every earlier span on a later failure, commit requires the exact frozen transfer states, and an authoritatively reclaimed covered span rejects commit without local trim authority while rollback removes the reservation idempotently. The exit-deadline oracle publishes a source-backed desktop projection, advances a fake clock to cancellation, and requires one projection transfer, proof commit, preparation, and final exit with no provider close, retained obligation, duplicate finalization, or process-lifetime cancellation tombstone; a second controlled proof remains pending across generation close and must never publish final exit, while both paths release the renderer preparation lease exactly once. The model-migration oracle accepts span A, blocks span B's raw emulator completion, begins disconnect migration, and proves no checkpoint or reconnect attach can remain at A; releasing B advances the exact checkpoint to B and projects B once. Its fake-clock arm reaches the 10-second deadline, requires checkpoint-unavailable, one exact model reset, zero retained admission charge and timers, and no effect from late raw settlement. Its two-PTY failure arm rejects one running raw callback under an active exact migration and requires one checkpoint-unavailable result, one model reset, zero provider closes, retained sibling checkpoint and transport liveness, zero charges and timers, and an unaffected other generation; a non-migrating sibling oracle still requires generation close. The intake additionally closes 2,048 sequential provider generations into one exact range, rejects stale events across that range, and preserves an out-of-order live gap until its own close. Direct-SSH contracts additionally prove activation-response settlement before the first source frame, claim-gated projection under same-decoder-turn response/data delivery, exact early-ACK reservation through send settlement or same-token retry, recovery completion visible before lease-held frames transfers those frames only into the private quarantine and admits no output until exact checkpoint-to-recoveryEnd coverage, invalid-checkpoint restore retention through response settlement followed by fresh-token retry and one live source frame, isolated saturated-subscriber eviction with healthy owner liveness, preserved legacy-primary backpressure, one-write ownership across write(false)/drain, control selection ahead of queued ordinary PTY input with FIFO lanes and bounded fairness, liveness rebasing, failed-exit retention through late ACK or exact recovery, response-settlement cancellation authority, token-scoped exit cancellation, exact checkpoint-to-recoveryEnd continuity, stale-owner one-shot retry, no physical PTY teardown on recovery failure, exact provider-generation closure and once-only cleanup when recovery cancellation publication or proof rejects, 16 MiB-plus-1 MiB decoder caps, charged per-PTY/session retention budgets, and eight-wide isolated reattach. The live Electron perf oracle adds hidden-output floods, renderer scheduler queue depth, dropped-output-zero normal scenarios, and active key latency budgets before promotion.", "commands": [ "pnpm exec vitest run --config config/vitest.config.ts", "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/construction/orca-runtime.test.ts", @@ -9309,6 +9040,7 @@ "Keep stress variants non-blocking until stable runtime history exists." ], "knownGaps": [ + "Launch direct-owner cleanup current scope: This gate’s unfiltered unit command now selects a suite reduced by 82 whole registrations / 159 potential table examples in 10 whole test Programs, including 8 registrations / 15 examples from five once-registered create-message factory closures. Lost alarms include frozen first-message/options and legacy-host fallback; distinct actions and redelivery; uncertain/refused/reloaded input custody, Retry and late proof; rich prompt/attachment upload Stop/close and handback; ordinary draft/editor/IME/StrictMode lifetime and accepted topology; provisional fallback tab placement/group/pin/order and rich worktree handoff. Four whole consent/resume-identity cases remain in two Programs; they do not replace these alarms. This entry governs current reduced-unit scope and qualifies any broader implication of unchanged oracle/coverageNotes history. Entire dated evidenceRuns, original commands/currentCommand values, counts/results and existing history retain their original scopes only; no fresh execution, transferred pass, replacement equivalence or prior upstream-removal credit is claimed.", "Audit2145 accepts removal of canned runtime metadata/guard/forwarding, fake in-memory persistence, private work-count and wrapper-duplication tests from the construction/orca-runtime.test.ts aggregate, plus the two automation run-context guards from runtime-workspace-launch-contracts.test.ts. Retained race, framing, physical completion and ownership callbacks remain byte-identical. Existing commands remain valid selectors; historical receipts stay unchanged and provide no fresh validation or replacement coverage for the reduced suites.", "Audit2133 current-parent preparation (988 authored removals; independently reviewed2099/2107/2115/2116 decisions; upstream clear-buffer and recovery-image regressions retained): Intentionally retire these low-value alarms without replacement: src/main/runtime/construction/orca-runtime.test.ts: remove only literal registration import/call pairs await import('../orca-runtime-tests/worktree-setup-and-startup.spec'), await import('../orca-runtime-tests/gitlab-and-pr-bases.spec'); no additional authored credit. src/main/ssh/ssh-channel-multiplexer.test.ts: sends a JSON-RPC request and resolves on response; assigns unique request IDs; sends notifications without expecting a response; dispatches incoming notifications to handler; sends one keepalive frame per cadence tick; drives keepalive sends AND dead-link detection from a single interval; resolves false immediately on a disposed mux; throws on request after dispose; reports isDisposed correctly; clears registered handlers on dispose; does not retain handlers registered after dispose. src/main/persistence/worktree-sort-order-write.test.ts: re-ranks every writable row when a blocked row sits in the requested order. src/main/runtime/orca-runtime-tests/targeting-and-resilience.spec.ts: routes tab switch and capture start by explicit page id; accepts focus on tab switch without altering bridge args (focus is main-side concern); keeps terminal cwd resolution fail-soft when the provider is unavailable. src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-04.spec.ts: drops the bounded scan cache when orphan-cleanup removal completes; clears optimistic reconcile tokens when a CLI worktree removal succeeds; emits drift without mutating when the fetched base fast-forwards created HEAD; emits base_changed without mutation when the fetched base rewrote history; skips stale-token reconciles without mutating or emitting stale status; emits unknown without mutation when fetch fails or the base ref is missing. src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-03.spec.ts: routes runtime preserved-branch force-delete through the selected WSL project runtime; replies to a waiting client with the error of a delete that fails after acceptance; treats forced runtime deletion of an already-missing unregistered worktree as cleanup; treats normal runtime deletion of an already-missing unregistered worktree as cleanup. src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-02.spec.ts: warns that a missing-repo removal only forgot the workspace; restores runtime watchers when CLI worktree deletion fails after teardown; does not re-spend the drain budget on a removal after a wedged install was abandoned; routes runtime worktree removal through the selected WSL project runtime; force-deletes a branch that was preserved by runtime worktree removal. src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases-part-02.spec.ts: records GitLab pasted-project recents only after successful runtime lookup; threads explicit origin preference through runtime WSL PR base resolution; resolves local GitLab fork MR bases from the target project MR head ref; captures the fork MR head from a dedicated ref, not the shared FETCH_HEAD; keeps the durable MR head when the head fetch fails but the local ref resolves; routes runtime GitLab fork MR base git calls through the selected WSL project runtime. src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases.spec.ts: passes SSH connection ids through GitLab task operations; routes runtime GitLab issue, MR, work-item, and todo actions through the selected WSL project runtime; routes runtime GitLab MR details, review-management, job, and pasted URL actions through the selected WSL project runtime; normalizes runtime GitLab issue list arguments like the desktop IPC path. src/main/runtime/orca-runtime-tests/worktree-setup-and-startup-part-03.spec.ts: does not warn when setup is explicitly skipped for CLI-created worktrees; puts the agent a create starts in the first default tab, as the window does; keeps the 8s main-runtime startup readiness budget for agents without an override; gives OpenCode the 20s main-runtime startup readiness budget; launches explicit startup agents with prompts for CLI-created worktrees. src/main/runtime/orca-runtime-tests/worktree-setup-and-startup.spec.ts: returns a setup launch payload for CLI-created worktrees when hooks are explicitly enabled; does not hand the window a setup main never tried to start; passes the selected Windows setup shell into runtime runner generation; follows normal setup policy for CLI-created worktrees without activating them; uses returned WSL setup shell metadata when runtime spawns setup; uses the shell-aware setup runner for windowless creates without a startup command; reports the in-process setup hook as running when nothing can launch the runner. src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-02.spec.ts: coalesces two clients sleeping the same host worktree; stops exactly the expected live PTYs for a worktree; explains a refused workspace close instead of throwing the raw refusal enum. src/main/runtime/orca-runtime-tests/mobile-summaries-part-03.spec.ts: marks the desktop-active worktree as isActive; includes SSH-backed worktrees in the mobile worktree summary; caches repeated malformed path misses before normalizing them again. src/main/runtime/orca-runtime-tests/mobile-summaries-part-02.spec.ts: keeps title-only foreground work ahead of monitoring in another pane; keeps a local hook row while a connected PTY still backs its pane; keeps an OSC row via its connected PTY after the pane binding is cleared. src/main/runtime/orca-runtime-tests/mobile-summaries.spec.ts: resolves files through a source-visible linked-checkout worktree; marks saved session tabs with live PTYs as host sidebar activity; attributes live legacy PTYs from saved layout bindings when their panes are hidden; marks saved browser tabs as host sidebar activity like desktop; falls back to the path-keyed GitHub cache entry; includes folder workspaces in compact worktree summaries for mobile; attaches inline agent rows from the latest OSC 9999 status; projects monitoring over a title-derived working status. src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-03.spec.ts: pushes to an idle pane when the only live waiter filters out the message type; resolves a registered waiter without PTY-injecting when the leaf is already idle; keeps already-idle status after tui-idle wait for immediate message delivery; resolves message waiters when notifyMessageArrived is called; does not resolve type-filtered message waiters for unrelated message types; removes message waiter abort listeners after message arrival; resolves message waiters on timeout when no message arrives. src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-02.spec.ts: delivers pending mail via notifyMessageArrived when the recipient is already idle; does not keep retrying when every pending row was already pointed; repoints pending rows restored with a live-idle coordinator. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-13.spec.ts: rolls back a half-created terminal whose surface never publishes. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-12.spec.ts: rejects startup prompts for agents that require post-ready stdin; uses portable Unix quoting for mobile agent launch commands in WSL project runtimes; keeps PowerShell quoting for mobile agent launch commands in Windows host runtimes; uses cmd.exe quoting for mobile agent launch commands in local Windows host runtimes; publishes headless mobile session agent identity with synthesized PTY status; rejects disabled mobile session agent launches before spawning; validates mobile terminal insertion anchors before resolving agent launch commands. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-11.spec.ts: coalesces a reconnect close burst onto one authoritative PTY inventory; keeps an explicit user close destructive while the PTY is live; builds mobile session agent launch commands on the runtime host; injects mobile quick-command prompts into the host-built agent startup command. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-10.spec.ts: closes persisted headless terminal parents before any prior list call; tears down a serve-owned headless tab on close while a renderer is attached so it cannot resurrect; defers a renderer-published pending tab to the renderer instead of tearing it down; returns a delegated close outcome with no selection tombstone when the renderer owns the outcome; tears down a runtime pending shell the renderer never adopted on close. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-08.spec.ts: materializes a plain shell when the pending tab has no launch agent; hydrates legacy persisted terminal tabs without layout entries; reads and indexes the full agent-status snapshot once per mobile projection; kills persisted SSH PTYs when closing hydrated headless tabs before pane metadata is restored; materializes hydrated pending headless terminals with the persisted session identity. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-07.spec.ts: hydrates a persisted SSH-owned pane before an attached renderer publishes its graph. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-05.spec.ts: publishes the desktop's tab name over the live agent title, and the live title without one; uses fresh neutral PTY titles over stale mobile snapshot and OSC titles; operates PTY-backed mobile session terminals without a renderer graph; reuses pane close for live PTYs that do not own a renderer tab; lists PTY-backed mobile session terminals without a renderer graph; shows and resolves active PTY-backed mobile session terminals without a renderer graph. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-04.spec.ts: creates mobile session terminals for folder workspaces in a headless runtime server; spawns fresh headless SSH mobile session terminals instead of reattaching synthetic local ids; hydrates headless mobile session terminals from the host workspace session; keeps live headless mobile session terminals when a desktop renderer publishes without them; publishes laptop-created remote runtime split terminals to phone session tabs. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-02.spec.ts: does not report headless wake degradation without sleeping records; does not wake slept agents for non-mobile session-only activation; does not rewrite unread metadata when a mobile activation finds the worktree already read; returns unread:false from worktree.ps after a mobile activation clears the flag; materializes pending mobile session terminals without focusing desktop clients; closes browser mobile session tabs when addressed by browser workspace id. src/main/runtime/orca-runtime-tests/mobile-session-tabs.spec.ts: resolves mobile terminal surfaces by exact split leaf; closes the matching mobile terminal UUID leaf without closing the whole tab; closes the whole mobile terminal tab when addressed by parent tab id; activates the active split leaf when addressed by parent tab id; clears unread metadata on mobile worktree activation without focusing desktop clients; wakes slept agents on the host renderer when a phone activates a worktree. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-05.spec.ts: publishes the hook provider session on a headless mobile tab so native chat can address the transcript; recovers the agent type from the hook row when the pane was launched without an agent hint; reads one agent-status snapshot per projection, not one per terminal tab; waits for unknown-launch foreground owner before publishing Pi-compatible mobile status; keeps Pi-compatible mobile session status as Pi for an unknown-launch foreground pi PTY; keeps renderer-vetted mobile agent status for custom-titled terminals. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-04.spec.ts: publishes terminal surface agent status for paired web clients; preserves authoritative OMP identity for Pi-compatible remote terminal snapshots; normalizes a remote OMP title without republishing omitted launch identity; skips the foreground-process probe when the PTY launch agent is already known; probes the foreground process only on a status transition for unknown launch agents; passes the client signal and the slept-worktree refusal to the spawn. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-03.spec.ts: does not use stale runtime-created PTY status when a neutral PTY title exists; recognizes runtime-created Codex PTY handles from the ready prompt; recognizes runtime-created Antigravity PTY handles from the ready prompt; recognizes live leaf Antigravity terminals from the ready prompt; recognizes a later Antigravity header with a prompt but no model line; keeps mobile terminal surfaces visible while their leaf handle is pending. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-02.spec.ts: lets Claude agents management titles clear stale runtime-created title status; does not recognize live Claude agents panes from a Claude foreground process; does not let stale tab-level agent titles override current neutral pane titles; lists live terminals with fresh pane titles over stale tab titles; lets adopted neutral pane titles use non-shell foreground fallback; lets adopted neutral pane titles retry wrapper foregrounds until recognized; authorizes settled CLI prompts only after positive %s foreground identity; does not recognize arbitrary foreground TUIs as running agents; lets live neutral pane titles retry wrapper foregrounds until recognized; lets current Claude agents PTY titles override stale runtime-created OSC titles; does not let stale Claude agents OSC titles suppress current PTY title activity. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status.spec.ts: keeps preallocated terminal handles valid across renderer reloads; preserves runtime-created PTY process identity after graph unavailable; keeps prompt bindings fenced across runtime restarts without provider incarnation; recognizes runtime-created PTY handles with agent launch titles; does not treat a bare Cursor Agent native title as a running agent session; uses stale runtime-created PTY status when there is no title or foreground evidence. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-07.spec.ts: keeps orphaned list and show writability aligned with the send gate. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-04.spec.ts: cancels a coalesced SSH worker recovery retry when its provider disconnects. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-03.spec.ts: retries renderer reveal before clearing an adopted legacy worker sleeping record. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-02.spec.ts: recovers exported ORCA_TERMINAL_HANDLE from discovered live PTY sessions. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-12.spec.ts: applies ANSI erase-from-start line controls in retained previews; applies ANSI stripping for private or intermediate CSI line controls; applies ANSI stripping for unsupported erase-line modes; reveals an agent terminal under the pane the caller reserved; keeps a fresh %s pane host-owned when a desktop window is available; keeps desktop publication %s separate from the reserved host spawn; mints its own pane when the reserved leaf is malformed, and reports the one it used; starts an agent terminal with the model the caller picked; starts an agent terminal without a model flag when no pick was made; attributes a startup-agent launch named %s as %s; attributes a fresh agent session the host builds as unknown; leaves a bare agent command the user typed out of launch attribution. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-11.spec.ts: trims oversized terminal output bursts without per-line array shifts; builds terminal previews without mapping the full retained tail; keeps recent PTY replay output capped without needing previous data for large chunks; applies terminal redraw controls before retaining previews; applies ANSI terminal redraw controls before retaining previews; retains multi-line ANSI footer redraws instead of appending old frames; keeps the cursor column when erasing full lines in multi-line redraws; applies ANSI split redraw controls without leaking raw params. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-10.spec.ts: returns renderer visible screen lines through terminal.read RPC JSON result; separates composer drafts from provider-owned terminal screens. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-09.spec.ts: reports an in-flight PTY focus as not navigated when its notifier disappears; reports graph-leaf focus as not navigated without a host notifier; grounds the provider mode tracker before a later chunk, in the emulator order; grounds an in-flight provider snapshot capture so it cannot publish the pre-reset screen; waits for terminal exit and resolves with the exit status; keeps terminal read payloads bounded while retained output remains pageable; trims terminal read preview character budget without per-line array shifts. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-08.spec.ts: submits a silent Claude composer once after the bounded render fallback; chunks large terminal.send text before provider writes; yields chunked terminal input through immediates between writes; yields while validating accepted large terminal.send text before provider writes; reveals a background terminal session when focusing its handle; replays captured launch config when focusing a background agent session; reveals background terminal sessions with the freshest PTY title; renames background terminal handles without requiring a visible tab; keeps a background terminal handle stable while reveal adoption is racing. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-07.spec.ts: resolves tui-idle when a stale Codex prompt is followed by Antigravity readiness; returns an agent-neutral blocked wait result for update prompts; returns an agent-neutral blocked wait result for workspace trust prompts; returns an agent-neutral blocked wait result for cwd selection prompts; returns a blocked wait result for Codex model migration prompts; returns a blocked wait result for Codex startup hook review prompts; returns an agent-neutral blocked wait result for generic interactive prompts; splits text and enter writes for background terminal handles; types the lead line for %s: %s; submits through the agent-specific PTY timing policy for %s. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-06.spec.ts: waits for exit on background terminal handles; keeps retained PTY transcript memory when controller refresh fails; resolves tui-idle from an Antigravity ready prompt preview; resolves Antigravity ready prompts with newline-heavy pasted tails without splitting; resolves live-leaf tui-idle from an Antigravity ready prompt preview. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-03.spec.ts: spawns the available Qoder command for a captured same-session resume: %s; does not use the local Windows shell setting for remote Windows bare agent creates; matches canonical bare agent commands when a command override is configured; keeps non-bare agent command terminal creates unchanged; keeps disabled bare agent command terminal creates unchanged; injects runtime hook receiver env into terminal sessions; creates background terminal sessions for a $label; creates background terminal sessions for a $label; enables Claude Agent Teams only for direct Claude launches when configured in-process; reveals Claude Agent Teams launches with the rewritten launch config; preserves Claude Agent Teams for sequenced Claude launches. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness.spec.ts: creates visible terminal sessions without asking the renderer to focus a tab; asks the pty controller for the requested shell instead of a startup command; knows the agent a flagged launch command names before any process read; retires a flagged command pane identity when the command exits; retires only receipted restored PTY authority on command completion and exit; forgets synthetic handles when disconnected PTY records are pruned. src/main/runtime/orca-runtime-tests/headless-snapshots.spec.ts: returns OSC titles from headless main terminal snapshots; adopts renderer-seeded titles into headless main terminal snapshots; returns cwd metadata from seeded headless main terminal snapshots; adopts OSC7 host metadata from seeded headless terminal scrollback; falls back to the renderer snapshot for hidden-output recovery without headless state; keeps an empty headless snapshot authoritative for hidden-output recovery; advances the absolute output sequence across a daemon stream gap; emits explicit OSC 9999 agent status from runtime PTY data. src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-02.spec.ts: falls back to the provider snapshot for a restored PTY with no mounted renderer; falls back to the available mirror when authoritative provider history is unavailable; keeps an empty renderer snapshot when the provider has no retained content; keeps restored provider history authoritative after later live output; uses provider alternate-screen state while a partial model is unsafe; prefers the tracked title over the headless emulator lastTitle; keeps the cursor-agent literal in record-fallback snapshots only without a tracker title; touches mobile snapshots once for decorative spinner ticks, again on idle. src/main/runtime/orca-runtime-tests/local-worktree-creation-part-02.spec.ts: creates a same-repo PR branch override from a resolved head SHA and matching push target; skips broad remote fetch for an existing full-SHA PR base; creates a selected Bitbucket PR branch override from a matching remote branch; suffixes an existing PR when a matching push target lacks selected PR metadata; suffixes a matching push target branch when selected PR metadata has no PR number; suffixes a matching push target branch when the existing PR is different; suffixes a selected PR remote conflict when the PR lookup fails; checks out an unused runtime PR branch only when it is at the resolved head SHA; suffixes only the runtime worktree path when an exact PR branch checkout path exists. src/main/runtime/orca-runtime-tests/local-worktree-creation.spec.ts: returns runtime local base update suggestions from addWorktree; creates a runtime local worktree from a usable persisted local branch base; does not create a runtime local worktree when the refresh fails and no local base ref exists; creates a branchNameOverride worktree from the selected matching remote base ref. src/main/runtime/integrations/skill/orca-runtime-skill-recovery.test.ts: continues skill management after startup recovery fails. src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-detached-routing.spec.ts: uses bounded ownership lookup for direct arrivals while the agent cannot take input; wakes a bound Run waiter when same-Run direct mail arrives; keeps an unowned detached-recipient message in its direct mailbox; uses primary-key lookups for bounded routing updates. src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-delivery.test.ts: remove only literal registration import/call pairs import './orchestration-mailbox-pointer-cli-command.spec'; no additional authored credit. src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-pointer-cli-command.spec.ts: renders the %s CLI command in a mailbox pointer. src/main/runtime/rpc/methods/terminal/terminal-multiplex-link-estimate.test.ts: sizes a slow high-latency link near twice its bandwidth-delay product; never paces a LAN, even when its client parses slowly; never paces a fast link; returns to legacy windows when the path RTT jumps. src/main/runtime/rpc/methods/terminal/terminal-snapshot-scrollback-rows.test.ts: steps down the row ladder when history is over the byte budget; tries the larger first row count, then the usual ladder within the same byte budget. src/main/runtime/rpc/server/pairing/network/windows-default-route-interfaces.test.ts: returns unknown when route inspection fails or emits malformed data; does not inspect routes outside Windows. src/main/runtime/rpc/server/pairing/pairing-offer-owner-cli.test.ts: is refused to a paired %s client; reports a failed widening instead of advertising an unreachable address. src/main/runtime/rpc/terminal-multiplex-end-verdict.test.ts: reports exited only when the owning runtime completes the exit waiter; reports unverifiable when the runtime cannot observe the exit waiter; reports unverifiable when a disconnected PTY resolves with unknown liveness. src/main/runtime/session-graph/headless-runtime-graph.spec.ts: lets a session tab inventory settle on a host no renderer publishes for. src/main/runtime/session-graph/runtime-graph-standing-contracts.test.ts: remove only literal registration import/call pairs import { registerHeadlessRuntimeGraphTests } from './headless-runtime-graph.spec', registerHeadlessRuntimeGraphTests(); no additional authored credit. src/main/runtime/session-tabs/structured-conversation-tab-title.test.ts: bumps the stored snapshot version only when the title changes. src/main/runtime/session-tabs/terminal-close-observed-exit.test.ts: keeps the healthy aggregate verification and delayed physical exit behavior; uses a stamped exit for the incarnation that was actually being closed. src/main/runtime/terminal/identity/terminal-identity-probe.test.ts: answers live for a structured worker without touching the PTY graph; answers live for a PTY handle the runtime still holds; runs the full leaf check for a handle with no live PTY; answers not-live for a stale handle; propagates \"could not look\" rather than reporting it as a dead handle. src/main/runtime/terminal/layout/paired-desktop-server-writes-layout-owner.test.ts: names the tab in main’s layout through terminal.rename; takes a window-style layout.apply close as already stopped, so the terminal runs on. src/main/runtime/terminal/lifecycle/pty-lifecycle-generation-retention.test.ts: retains no lifecycle generation after a spawn/exit cycle. src/main/runtime/terminal/lifecycle/run-terminal-user-open.test.ts: reads a freshly spawned terminal as used once a user opens its tab, not on a probe; keeps the open mark on the process a user open starts. src/main/runtime/terminal/surface/terminal-surface-replies-window.test.ts: from a desktop window that mounts both panes; from a server with no window. src/main/runtime/terminal/surface/workspace-layout-projection.test.ts: carries views for a partition that holds none yet. src/main/runtime/terminal/view/terminal-subscribe-exit-waiter-leak.test.ts: releases a signalled exit-waiter when the signal aborts. src/main/runtime/terminal/wait/orca-runtime-exact-worker-provider-session.test.ts: selects a local hook status for a local pane. src/main/runtime/terminal/wait/prime-agent-screen-readiness-transcripts.test.ts: keeps the footer and the bare caret on screen mid-turn; %s: the screen alone reads ready during %s. src/main/runtime/workspaces/startup/runtime-worktree-agent-startup.test.ts: uses per-launch arguments and preserves launch telemetry; attributes a startup agent whose caller named no surface as unknown; launches %s bare for an absent or blank prompt; attributes a %s draft launch named %s as %s; merges an automation's extras over the host defaults; threads worktree-create extras into the startup build; returns an enabled requested agent without detecting; returns the default when nothing was requested; detects instead of using the default when the requested agent is disabled; starts no agent when the default is blank; detects an enabled agent on this host when nothing usable was named; starts no agent when detection finds none. src/main/runtime/workspaces/startup/runtime-worktree-startup-readiness.test.ts: pastes and submits through composer readiness, never typing raw input; types the follow-up on WSL or SSH-to-Windows once the agent is in front, as before; cleans up the deadline when the composer was already captured; a draft that is not submitted is pasted on the box cursor, as before; takes the box after the grace when the row never comes, whatever repaints; takes the box at the deadline when the grace would outlast the budget; lets a dialog on screen veto a grace; refuses the deadline inside a pending grace while a shell is in front; takes the box at the deadline inside a pending grace with the agent in front; takes the box at the deadline after a refused grace once the agent is in front. src/main/skills/skill-install-transaction.test.ts: installs, previews unchanged bytes, and updates a clean receipt-owned skill; preserves the old version after a %s filesystem failure. src/main/speech/model-manager-download-resume.test.ts: requests the remaining bytes when a clean range response ends before the file total; bounds a server that advances by pathologically tiny segments forever. src/main/ssh/config/ssh-config-parser.test.ts: parses a basic host block; parses multiple host blocks; skips wildcard-only Host entries; skips Host entries with only pattern characters; parses IdentityFile with ~ expansion; parses Windows-style IdentityFile with ~ expansion; parses quoted scalar values like OpenSSH; parses equals-form scalar directives; parses IdentityAgent with ~ expansion; parses IdentitiesOnly; parses GSSAPIAuthentication; keeps the first GSSAPIAuthentication value like OpenSSH; parses ProxyCommand, ProxyUseFdpass, and ProxyJump; ignores comments and blank lines; handles case-insensitive keywords; stops current block on Match directive; returns empty array for empty input; creates one parsed host per concrete alias on a multi-pattern Host line; applies identity agent settings to every concrete alias on a multi-pattern Host line; defaults port to 22 for invalid port values; converts hosts to SshTarget objects; uses host alias as hostname when HostName is missing; skips hosts that are already imported; defaults username to empty string when not specified; carries through identityFile, identityAgent, identitiesOnly, proxyCommand, and jumpHost; carries through gssapiAuthentication; imports duplicate aliases only once and keeps the first concrete host; maps hosts for the picker and flags aliases already in Orca; de-dupes aliases and defaults missing fields; parses hostname, user, port from ssh -G output; collects multiple identity files; parses forwardagent yes; defaults port to 22 when missing; returns empty hostname when missing; returns undefined user when missing; handles empty output; skips lines without spaces; parses proxycommand and filters \"none\"; parses proxyusefdpass yes; parses proxyjump and filters \"none\"; handles ~ expansion in identity file paths; handles Windows-style ~ expansion in identity file paths; parses identityagent with ~ expansion; preserves identityagent none so auth can disable agent fallback; parses identitiesonly yes; parses gssapiauthentication; parses controlmaster options and filters controlpath none. src/main/ssh/config/ssh-known-hosts-source.test.ts: splits the space-separated list ssh -G prints on one line; expands ~ in a reported path; keeps a double-quoted path containing spaces whole; falls back to the default files when ssh -G reported nothing; drops an explicit none without falling back to the defaults; splits both known_hosts lists on one line each; reads StrictHostKeyChecking, including accept-new; reads HostKeyAlias and prefers it for the lookup; reads the non-default port; reports that the lookup came from an alias, so the port is not appended; reports no alias when the dialed host is used; unions the entries of every file; skips a path that is a directory; returns nothing when no file can be read; reports nothing unreadable when every file parses; does not count an empty file as unreadable; prefers HostKeyAlias over the resolved hostname; uses the dialed host, because a resolved hostname can just echo the label; still prefers an explicit HostKeyAlias over the dialed host; falls back to the dialed host when nothing was resolved; is rejoined when the split fragments resolve to nothing; leaves a single unresolvable path alone rather than inventing one; expands the __PROGRAMDATA__ token rather than passing it through as a path; does not rewrite a path that merely BEGINS with the token characters; keeps a drive-letter path with mixed separators intact; splits a spaced Windows home into the fragments the rejoin has to put back. src/main/ssh/config/ssh-known-hosts.test.ts: reads the algorithm from the blob rather than trusting the line; rejects %s; refuses a malformed blob: %s; uses the bare host on the default port; tries the bracketed form first and falls back to bare off-port; matches an exact line; matches case-insensitively; reports a changed key of the same type; reports unknown for %s; matches any host in a comma list; matches the bracketed form on its port; does not apply a bracketed entry to the default port; falls back to a bare line when off-port; never reports a change from the fallback pass; matches a bare literal on the default port; matches a bracketed literal on its port; reports a change for a literal; handles %s; still reports a change for a different key on a revoked host; skips a line carrying an unrecognised marker; does not report a change when only another key type is on file; matches within the same type; accepts CRLF terminators; skips blanks, comments and surrounding whitespace; accepts a hit regardless of which file holds it (%s); never brackets the alias, whatever the port; still brackets an ordinary host on a non-default port; matches a bare alias entry on a non-default port; still accepts the unmodified key field; accepts a hashed entry whose salt is a full SHA1 digest; still accepts the unmutated ssh-keygen -H vector; falls back to the bare host line on a non-default port, as ssh did; refuses a key type it has not seen for a host it knows, as ssh did. src/main/ssh/connection/ssh-connect-config.test.ts: returns undefined when no default keys exist; returns the first existing key file; probes regular and FIDO2 keys in stable default order; keeps a regular default ahead of a malformed FIDO2 default; uses target host/port/username; falls back to resolved config when target fields are empty; keeps imported endpoint fields as the fallback when ssh -G is unavailable; sets readyTimeout to CONNECT_TIMEOUT_MS; sets keepaliveInterval to 15s; enables keyboard-interactive auth so MFA challenges can be answered; uses agent auth when no explicit key and SSH_AUTH_SOCK is set; enables agent forwarding when OpenSSH config requests it and an agent is available; does not enable agent forwarding without a usable agent; resolves IdentityAgent SSH_AUTH_SOCK from the environment; uses the Windows OpenSSH agent pipe when no environment socket is available on Windows; wraps agent auth with IdentityFile filtering when IdentitiesOnly is enabled; applies a manual target IdentitiesOnly setting when ssh -G reports it off; includes unencrypted target.identityFile auth when an agent is available; defers encrypted target.identityFile auth when an agent is available; uses keyFile auth when target.identityFile is set and no agent is available; includes unencrypted resolved identityFile auth when an agent is available; defers a default-path resolved identityFile to the no-agent retry; offers the keyboard-interactive challenge when the agent defers no key; provides fallback key when no agent is available; can force private key inclusion for the post-agent fallback path; falls back to resolved proxyCommand; returns structured jump-host config for target.jumpHost; returns structured jump-host config for resolved proxyJump; returns undefined when no proxy is configured. src/main/ssh/connection/ssh-connection-auth-fallback.test.ts: resolves OpenSSH config using configHost when present; tries ssh-agent before reading an explicit private key; falls back to direct private key auth when agent auth fails; falls back to direct private key auth after too many agent authentication failures; answers bounded keyboard-interactive challenges such as Duo 2FA. src/main/ssh/connection/ssh-connection-store.test.ts: lists picker suppression aliases without consulting re-adoption tombstones; getTarget delegates to store; addTarget generates an id and persists; saves the CLI control switch as given, with no consent stamp; addTarget stamps source as manual by default; addTarget preserves an explicitly provided source; inserts a new config host stamped as ssh-config; asks the parser for all hosts — reconciliation happens in the store; updates an existing config-sourced target when the port changed; refreshes gssapiAuthentication on sync; never overwrites a manual target that owns the alias; does not rewrite an unchanged config-sourced target; returns empty array when nothing changed; tombstones a deleted config-sourced host so re-import skips it; suppresses a deleted manual target from config discovery; re-adding a deleted host reclaims its alias so sync stops suppressing it; editing a target reclaims its alias from the deleted set; records a tombstone when removing any user-facing target; re-adopts orphaned repos when the same host is re-added. src/main/ssh/connection/ssh-connection.test.ts: transitions to connected on successful connect; captures the negotiated SSH server key fingerprint; allows concurrent exec commands for ssh2 transport; removes startup listeners after ssh2 connect succeeds; scopes lifecycle events and pending handshake timers to one mock client; enables TCP_NODELAY on the new ssh2 client after a reconnect cycle; transitions through connecting → connected states; reports error state on connection failure; disconnect cleans up and sets state to disconnected; getTarget returns a copy of the target; getState returns a copy of the state; throws when connecting a disposed connection. src/main/ssh/orcad-migration-stuck-host-profiles.test.ts: never leaves a running terminal behind; is offered only when leaving saved state behind would clear the refusal. src/main/ssh/orcad-runtime-maintenance.test.ts: keeps a connect from retrying a build an explicit Update also failed; offers Force when Update was refused by policy; forwards anew after an activation, since the new slot may bind another port; passes a refusal through and leaves the server linked; forwards anew once a serving slot is restored, which may have bound another port. src/main/ssh/port-forwarding/ssh-port-forward.test.ts: reports the port the OS bound when an ssh2 forward asks for port 0; adds an ssh2 port forward and returns entry; adds a system SSH port forward when no ssh2 client is available; reports the port a system SSH forward resolved when asked for port 0; passes resolved OpenSSH config to system SSH port forwards; disposes a system SSH tunnel when removing the forward; lists forwards filtered by connectionId; removes a forward by id; awaits forward close when removing a forward for user actions; returns null when removing nonexistent forward; removes all forwards for a connection; dispose removes all forwards; stores label in the entry; preserves the existing id when updating a forward succeeds. src/main/ssh/system-transport/system-ssh-forward-process.test.ts: spawns exactly the argv the orphan matcher is given, LogLevel=INFO included; runs port forwards unmultiplexed even when ssh_config disables muxing; preserves manual target port and identity options in the forwarded ssh command; does not spawn ssh when the requested local forward port is already in use; spawns ssh after the requested local forward port preflight succeeds; resolves startup after the grace period when ssh keeps running; sends SIGTERM then SIGKILL when the process does not exit; does not resolve stop until the process exits. src/main/ssh/system-transport/system-ssh-loopback-route.test.ts: dials the held forward ahead of the alias so OpenSSH keeps these over ssh_config; drops a manual target's own port and proxies, which would fight the route; never routes a forward, whose argv must stay stable for orphan recovery; %s → %s; opens the forward over the real proxy, then proves a login over the route; lands the forward on the sshd and known_hosts name the direct route resolved; holds the forward with server-alive probes; never lets the background forward or probe ask for credentials; starts no forward when admission refuses the route; stops the forward when sshd refuses logins over it; stops the whole forward process tree on Windows, once; reports a forward that already exited before anyone listened for it. src/main/startup/browser-process-user-agent-ordering.test.ts: explains admission refusal before a desktop launch exits; explains an orcad holding the profile instead of exiting silently; does not acquire profile admission for a duplicate launch; executes after the dev app name and before later preflight work; exits and releases admission after pending profile move recovery fails; keeps Linux background startup failures console-only and immediate; keeps Linux serve startup failures console-only and immediate. src/main/startup/quit/quit-path-durable-write-blocking.test.ts: store.flushAsync() issues no synchronous fs syscalls; store.flushAsync() also moves the active-view and github-cache sidecars off the thread; stats.flushAsync() issues no synchronous fs syscalls; Grok session cleanup issues no synchronous fs syscalls; stats.flushAsync() closes out live agents before it returns, not when its write lands; a stalled mount leaves the event loop live instead of parking it; store.flushAsync() is one idempotent final barrier; store.flushAsync() resolves instead of throwing when the profile mount rejects writes. src/main/stats/agent-session-transition-recorder.test.ts: counts a hook-only agent that never writes an agent-shaped terminal title; never opens a session from a replayed or disk-restored working status; still closes a live session when the terminating status arrives as a replay; counts one session per turn across repeated working/done cycles; closes an open session when its pane is torn down; bounds the mirror and closes what it evicts; stops the session when the main agent settles and only a watch loop holds the row working; keeps the session open while a subagent outlives the main agent, and closes it when the child settles; dates the stop by the evidence when a shell outlives the last subagent; opens a new session dated by the observation when the main agent resumes after monitoring; never dates a reopen before the close a fact-less OSC repaint caused; dates the first live row after a restored one by the evidence, not the restored clock; treats an unchanged answer as a snapshot, never a transition; opens only on a live working edge; closes only a session it opened. src/main/text-generation/commit-message-text-generation-model-discovery.test.ts: returns static catalog models without spawning for static agents; discovers dynamic models through the agent CLI; discovers dynamic models through the configured agent command override; falls back to static models when dynamic discovery returns no parseable models; falls back to the first discovered non-Pi model when its static default is unavailable. src/main/text-generation/pull-request-context.test.ts: does not fetch unrelated fork remotes before generating PR context; bounds exact remote-ref probe concurrency for a large remote list; reports no branch change because PR context preparation is read-only; keeps a remote-qualified base when the selected base includes the remote. src/main/text-generation/source-control-local-process.test.ts: asks the supervisor to stop and leaves its group to it; signals nothing once the supervisor has exited; stops an agent that ignores its stdin end through its supervisor. src/main/updater/linux-package/linux-package-update-recovery.test.ts: retains the downloaded package with the digest from the event metadata; requires a string downloaded path; accepts an uppercase extension; requires a non-empty string version; matches an absolute file URL by basename; accepts duplicate entries that agree on the digest; refuses an entry with a missing or non-string digest; refuses a digest that is not base64 at all; refuses a malformed percent-encoded URL; refuses a missing or non-array file list; tolerates a non-object event; replaces the retained artifact with a newer download; keeps the retained artifact when a new download has no usable digest; keeps the retained artifact when an unrelated download event arrives; clears the retained artifact; preserves the artifact across a recheck of the same version; clears the artifact when another version takes over; preserves the artifact for an unknown or empty version; is a no-op without a retained artifact; returns the built command and package file name for a verified package; reports missing without a retained artifact; propagates a package-manager discovery failure; rejects a well-formed digest that belongs to another file; never hashes a package that a malformed digest failed to arm; rejects a path outside the cache root; rejects the cache root itself; rejects a package in the updater directory itself; rejects a pending directory that is a symlink out of the cache; performs one hash pass for concurrent requests; revalidates once the in-flight pass settles; does not reuse an in-flight pass for a different artifact; starts a fresh proof when the same package is captured again; returns the verified package path; returns missing without a retained artifact. src/main/updater/releases/updater-prerelease-feed-readiness.test.ts: accepts a GitHub %s asset redirect as ready; reports a GitHub asset request error as unavailable; reports not-ready with a verified last-good tag when the newest assets are unavailable; does not classify a non-positive tag limit as feed unavailability; reproduces the v1.4.142 publishing incident as not-ready; reports transport failures as unavailable instead of not-ready; treats an explicit asset 404 as not-ready when another asset is unavailable; accepts absolute manifest asset URLs without rewriting them to release asset paths; returns not-ready with an older ready update as last-good while newest is publishing. src/main/updater/releases/updater-release-builds.test.ts: lists hourly builds from the dedicated repo, newest first; lists daily builds from the dedicated repo, newest first; separates stable from rc in the shared main repo; skips drafts and unparseable tags; keeps a composed release title and drops one that repeats the tag; hides builds that published no artifact for this platform; returns an empty list when no build has this platform artifact; keeps mac builds visible on macOS regardless of the Windows leg; resolves the platform installer download url; leaves the installer url null when the release published no installer; tolerates a release whose assets are missing or malformed; sends the local gh token as a bearer header when one is available; sends no authorization header when gh has no token; retries unauthenticated once when GitHub rejects the token; does not retry a 401 that was already unauthenticated; falls back to the per-IP bucket when the token is rate limited and tells the gh breaker; reports a secondary limit carrying retry-after without retrying or tripping the breaker; records a primary limit in the token scope %s; keeps %s authenticated when only %s is blocked; skips the token while its scope %s is blocked; surfaces a rate limit with its reset time and a sign-in hint when unauthenticated; omits the sign-in hint when the rate-limited request was authenticated; treats 429 as a rate limit; reports a 403 without rate-limit headers as a plain HTTP error; reports a missing hourly repo distinctly; is null when GitHub sent no reset; prefers retry-after over the primary reset epoch; falls back to the primary reset epoch when there is no retry-after; reads retry-after as seconds; reads retry-after as an HTTP date; pins an hourly tag at the hourly repo download path; pins a daily tag at the daily repo download path; pins a stable tag at the main repo download path; rejects a tag that is not a version. src/main/updater/updater.build-channel-selection.test.ts: uses the display label in the unsupported-platform %s pinned-build error; still pins %s from an unsigned Windows dev build; restores ordinary release checks after local build selection fails; opts into the RC channel when checkForUpdatesFromMenu is called with includePrerelease; pins the generic feed to a perf-tagged prerelease when requested; surfaces no-update feedback when no newer perf-tagged prerelease exists; keeps prerelease publishing-window misses on the generic retry path; leaves the feed URL alone for a normal user-initiated check. src/main/updater/updater.check-preflight.test.ts: ignores a stale update-not-available event after a new check starts preflight; deduplicates repeated manual checks while the immediate checking status is active. src/main/updater/updater.prerelease-fallback.test.ts: retries a prerelease check once against the previous feed tag when the manifest is missing; surfaces a promise-only prerelease fallback failure after the primary error event. src/main/updater/updater.publishing-window-feed.test.ts: repins the generic feed to the newest RC tag for a prerelease user; repins the generic feed to a newer stable tag for a prerelease user; pins a stable fallback when Atom has no newer prerelease; uses last-good concrete feed when a user-initiated check lands during publishing; can offer an older fully published update while the newest release is publishing; keeps background publishing-window fallback on the short retry cadence. src/main/updater/updater.quit-and-install.test.ts: surfaces an accepted retry before electron-updater emits download progress; defers quitAndInstall and runs its launcher within the launch PATH scope; runs pre-quit cleanup before local PTY cleanup during update install; keeps optional pre-quit cleanup fail-and-continue behavior by default; ignores duplicate quitAndInstall requests while the shared delay is pending; arms the forced-exit watchdog once the install commits; disarms the forced-exit watchdog when sync install error recovery keeps the app open. src/main/window/createMainWindow-markdown-editor-focus.test.ts: ignores traffic light sync IPC on non-macOS; still intercepts Cmd+Shift+B and Cmd+Alt+B when the markdown editor is focused; coerces non-boolean setMarkdownEditorFocused payloads to false; opens a table-aware context menu synchronously without a renderer query; builds the plain edit menu for the one right-click the renderer marks as plain text. src/main/window/createMainWindow-renderer-crash-recovery.test.ts: notifies the caller when the renderer process is gone; passes the renderer webContents id through crash recording and recovery callbacks; forwards expected renderer teardowns so the recorder can diagnose suppression; reloads the app shell after an unexpected renderer process loss; does not reload after renderer loss when recovery is disabled; stops auto-reloading after a rapid renderer crash loop trips the breaker. src/main/window/dashboard-popout-window.test.ts: updates the title after language initialization and unsubscribes when closed; lets its preload expose saved WSL hosts in serve-only, and passes nothing otherwise; creates a native-frame window with the shared preload and no webview surface; shows the window on ready-to-show; loads the prod file entry; loads the dev server URL when in dev; focuses the existing window instead of creating a second one; trusts only the live popout webContents; restores a minimized window when re-requested; restores valid persisted bounds; discards off-screen persisted bounds and falls back to defaults; persists bounds on resize after the debounce, guarding near-minimum sizes; keeps saving bounds after a vetoed quit and freezes them only on an allowed quit; closeDashboardPopout closes an open window; applies the persisted app zoom level on dom-ready; follows app zoom changes while open and unsubscribes on close; zoomDashboardPopoutIfFocused steps the popout zoom only while focused; handles the zoom-in chord via before-input-event and ignores other keys; handles mouse-wheel zoom requests outside before-input-event; respects zoom keybinding overrides for keyboard and mouse-wheel paths. src/main/window/dropped-path-preparation.test.ts: opens and stores each unique source once as drop size grows tenfold; passes ordinary paths without copying for %s; preserves ordinary successes and copied successes when another file fails; serializes copy requests from different owners; reports all lost paths without a shared reason when their failures differ. src/main/window/main-window-updater-deferred-setup.test.ts: releases all 64 completed fallback handles without repeating initialization; keeps setup after ready-to-show and releases its fallback afterward; preserves the 15-second fallback when first paint never arrives; preserves destroyed-window guard reads before and at the fallback deadline; keeps the exact %s error and releases its completed fallback; keeps the exact fallback %s error without retrying initialization; preserves pending manual setup after failed ready registration; keeps setup options, live store reads, nudge writes and required quit flush. src/main/worker-threads/worker-thread-request-queue.test.ts: posts one request at a time and in the order it was dispatched; fires a posted call at its own deadline; stops respawning and fails the rest of the queue once deaths hit the cap; clears the death count when a fresh burst starts from full idle. src/main/workspace-hooks/hooks-setup-runner-script.test.ts: builds Windows runners for newline-heavy scripts without line-array splitting; builds POSIX runners without regex-wide CRLF normalization; writes POSIX setup runners for shebang-declared scripts on native Windows paths; keeps batch setup scripts on cmd.exe when the terminal is Git Bash; hands a Git Bash pane a launch command MSYS cannot rewrite for a cmd runner; replays interpreter flags declared on the shebang line; preserves cmd.exe setup runner semantics for configured cmd users; keeps POSIX runner behavior on POSIX platforms; waits when either local or project policy requires completed setup; marks setup-runner terminals for the always-on credential guard; maps git-bash to POSIX setup launch metadata on Windows; falls back to the cmd runner when the git-bash setting has no installed Git Bash; keeps the cmd runner for a non-Git bash such as Cygwin; keeps the cmd runner for a bare bash whose flavor cannot be resolved; uses the POSIX runner for a bare bash that resolves to Git Bash; uses the POSIX runner for an extension-less Git Bash path; preserves the existing cmd runner for PowerShell terminals; preserves cmd setup compatibility when a Windows-host project has a WSL shell setting; classifies an installed explicit Git Bash executable as a POSIX runner; falls back to the cmd runner when the explicit Git Bash path no longer exists. src/main/workspaces/catalog/repo-git-remote-identity-enrichment.test.ts: schedules remote identity enrichment without blocking the caller; probes a drive project whose runtime is WSL %s; sweeps a local repo: %s; probes an SSH row that carries only executionHostId on its own host; keeps same-path rows on two different SSH hosts from sharing one backoff; coalesces concurrent probes for the same repo location; caches no-identity probes briefly so list calls do not retry every time; does not rewrite the no-remote marker on a later retry; resolves a settled no-remote repo once it gains a remote; does not re-probe a resolved identity before the refresh window elapses; re-probes a resolved identity after the refresh window elapses; bounds re-probes per sweep so a large repo list drains gradually; forgets a removed repo location so its deadline cannot outlive the repo; keeps a surviving repo backoff when a sibling repo is removed; probes again when the same location is re-added after its probe was retired; coalesces concurrent sweeps instead of running one pass per list call. src/main/workspaces/creation/preparation/worktree-create-preparation.test.ts: preserves create priority through claim probes on %s; starts the checkout only once the async workspace root resolves; still deduplicates when both callers await the same pending root lookup; namespaces native Windows preparation directories for long paths; deduplicates preparation for the same repo, base, runtime, and workspace root; does not spend a divergence walk when the base matches exactly; claims when the two sides spell the same ref differently; evicts a repo's own stale preparation before another repo's; still discards armed checkouts when the project runtime needs repair; routes preparation and finalization through the selected WSL runtime; retries stale cleanup after a transient listing failure; does not discard a detached worktree with caller-controlled preparation metadata; does not re-arm after an isolated create; re-arms a preparation once creates arrive in a burst; holds the re-arm checkout until the create runs the deferred thunk; starts one explicit prefetch after the create completes; does not re-arm when finalization failed; reports a pending create while a stale-cleanup scan is running. src/main/workspaces/removal/local-worktree-removal-recovery.test.ts: recovers Git for Windows partial filesystem deletion failures; finishes a clean non-force deletion after Git leaves a Windows directory behind; recovers localized Windows failures after Git already removed the registration; does not recover unrelated localized failures while Git still owns the row; finishes a macOS deletion Git deregistered before failing with Directory not empty; leaves an orphaned checkout to the orphan cleanup instead of deleting it; prunes and strictly verifies on the selected WSL host without deleting files or branches. src/main/workspaces/removal/worktree-removal-safety.test.ts: rejects deleting a worktree that contains another registered worktree; rejects POSIX home directories even when host homedir has a different path shape; refuses a home the host reported even when no path rule recognises it; refuses the Windows host's home directory from a POSIX client; refuses the Windows host's home directory even when the host reported nothing. src/main/wsl/discovery/distro-catalog.test.ts: retries asynchronous discovery after a transient wsl.exe failure; retries synchronous discovery after a transient wsl.exe failure; retries asynchronous discovery after wsl.exe reports no distros yet; retries synchronous discovery after wsl.exe reports no distros yet; bounds the wsl.exe spawn rate while no distros are installed; bounds the asynchronous spawn rate while no distros are installed; still caches a non-empty distro list for the process lifetime; re-probes a docker-desktop-only machine once a user distro can appear; backs off while the list keeps coming back empty; backs off after repeated distro-list failures; caps the empty-list backoff at five minutes; keeps reporting an empty result after it goes stale; keeps reporting a known distro list indefinitely; bounds cached homes while retaining the most recently used distros; still lists distros, and an excluded distro home probe fails like any other probe; gives the async home probe time for a cold boot instead of killing it at 5 s; retries availability after a probe timeout instead of latching false; bounds the probe rate while the failure window is open; caches a successful probe for the process lifetime; names an explicit spawn directory, so no deleted cwd can read as ENOENT; shares one wsl.exe spawn between concurrent probes; keeps reporting the last observed answer after it goes stale; holds a definitive failure far longer than a timeout when %s; backs off after repeated probe failures; re-probes a seeded retryable failure once its window lapses; re-probes availability once a distro list succeeds after %s; does not drop an availability failure for an empty distro list; keeps reporting unavailable off Windows without probing. src/main/wsl/discovery/wsl-distro-holder.test.ts: runs a busybox-safe loop through --exec and names the distro; spawns a detached-style holder, records it, and waits for the distro to run; a holder exiting with code 1 notes its distro may have stopped (E9); rejects a pid whose command line is not our holder for that distro; cleans up stale and corrupt records; keeps a holder and its record when release cannot verify it; reports unverifiable when the command line is unreadable even with a matching pid; release kills a verified holder and removes its record; release never kills a pid that is no longer our holder; reports a spawned holder exit so liveness can re-check. src/main/wsl/filesystem/wsl-guest-drive-mountinfo.test.ts: skips 9p shares that are not drvfs, and malformed lines. src/main/wsl/orcad/wsl-orcad-deploy-app-update.test.ts: plans the update on the census the running orcad reports, not an unknown one; forwards force to the update planner; does not serve the incumbent past a refusal that is not a wait; does not re-activate the build this host rolled back from; labels the launch with the build the adoption found serving, not the stale record; defers while another run holds the host fence; lets an explicit force deploy past both skips; names a newer host refusal apart from a rolled-back one, so only Force is offered; updates an older host as before, without asking to adopt it; never asks the incumbent when it already runs this build. src/renderer/src/components/agent/agent-launch-picker-acquisition.test.ts: keeps a completed listing usable when the host rejects the wait parameter. src/renderer/src/components/feature-tips/feature-tip-telemetry.test.ts: delivers to chat-default users in all targeting while holding out not-switched users. src/renderer/src/components/native-chat/composer/pickers/use-native-chat-side-chat-command.test.ts: completes the row on a pick, even when the command is already typed; ignores a pick of the row while side chats are unavailable. src/renderer/src/components/native-chat/media/images/native-chat-image-copy.test.ts: explains a too-large refusal that arrives through the IPC error prefix. src/renderer/src/components/native-chat/messages/actions/native-chat-fork-launch.test.ts: keeps the question with the caller and says once that it never went; tells the user to check the side chat when delivery is unconfirmed; reports a delivered question as sent, silently. src/renderer/src/components/native-chat/messages/actions/native-chat-side-chat-fork-point.test.ts: decides each of %i tool-only turns once per layout, and nothing without a listener. src/renderer/src/components/native-chat/messages/actions/use-native-chat-fork.test.tsx: places a side chat whose question was %s: %o. src/renderer/src/components/terminal-pane/provider-notices/agent-presence/agent-terminal-presence.test.ts: calls back once for %s; stops watching once unsubscribed. src/renderer/src/components/terminal-pane/pty-connection/emulation/pty-connection-mode2031-raw-subscription.spec.ts: records a mode 2031 subscribe from the raw chunk boundary without answering. src/renderer/src/components/terminal-pane/pty-connection/input/pty-connection-deferred-input-forwarding.spec.ts: routes terminal input through deferPtyInput so the host can withhold it; forwards terminal input directly when the host supplies no deferPtyInput. src/renderer/src/components/terminal-pane/pty-connection/notifications/pty-connection-terminal-bell-attention.spec.ts: forwards onBell to pane attention and notification policy; hands the bell to the attention module with its pane even when pane attention is off. src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-dropped-output-snapshot-healing.spec.ts: repaints from the main-owned snapshot when main drops pending output at the cap. src/renderer/src/components/terminal-pane/pty-connection/output/pty-connection-fresh-native-follow-reset.spec.ts: retries a fresh-spawn native follow reset when renderer dimensions return. src/renderer/src/components/terminal-pane/pty-connection/spawn/unbound-pane-spawn-recovery.test.ts: requests a tab remount for an unbound spawn; leaves recovery to a remote transport that armed its own retry; requests a remount when the transport reports no recovery of its own; settles the spawn as failed before requesting a remount; prefers the restored leaf id when reporting the anomaly; falls back to the pane leaf id when no restored leaf exists. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-foreground-agent.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionDeferredInputForwardingTests } from '../input/pty-connection-deferred-input-forwarding.spec', registerPtyConnectionDeferredInputForwardingTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts: structural support changed only; no new authored removal credit. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionFreshNativeFollowResetTests } from '../output/pty-connection-fresh-native-follow-reset.spec', registerPtyConnectionFreshNativeFollowResetTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionTerminalBellAttentionTests } from '../notifications/pty-connection-terminal-bell-attention.spec', registerPtyConnectionTerminalBellAttentionTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-delivery-interest.test.ts: registers interest on the first sidecar and releases on the last unsubscribe; releases sidecar interest only once for repeated unsubscribes; does not let an eager pre-mount buffer defeat hidden delivery gating; keeps eager buffers outside delivery interest when the PTY exits before mount; lets a sidecar exclusively own interest while an eager buffer overlaps. src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-push-reattach.test.ts: blackholed delivery reproduces the wedge: no handler dispatch, no ACK ever. src/renderer/src/components/terminal-pane/pty-transport/ipc/ipc-pty-opencode-model.test.ts: sends preferences to the execution host and attaches only to its returned PTY; preserves one operation ID across a lost reply and reconnect; preserves ordinary raw startup and captured-session attachment. src/renderer/src/components/terminal-pane/pty-transport/output/pty-side-effect-pending-census.test.ts: sums registered gauges and drops disposed ones; ignores a repeated dispose instead of dropping another gauge; stops tracking new gauges past the cap so a missed dispose cannot grow it; tracks a live output processor queue through enqueue, drain, and dispose; excludes cleared consumed entries from retention after a bounded drain. src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-prebind-discard-notice.test.ts: says nothing once the pane is closed. src/renderer/src/components/terminal-pane/render-health/terminal-webgl-atlas-recovery.test.ts: refreshes after each scheduled atlas reset; falls back to a timeout when animation frames are unavailable; continues recovery when a manager throws after scheduling. src/renderer/src/components/terminal-pane/snapshots/pty-buffer-serializer.test.ts: tracks a remounted quiet title source even when the stale owner unregisters later; preserves the renderer-parsed output sequence in the response; preserves a pending escape tail for snapshot replay; routes a host's Reset Terminal request to the pane that owns the PTY. src/renderer/src/components/terminal-pane/snapshots/saved-terminal-output-replay.test.ts: marks panes with restored scrollback for fresh-shell viewport blanking. src/renderer/src/components/terminal-pane/viewport/split-right-white-screen.test.ts: recovers a 0x0 spawn whose container is briefly unmeasurable then settles. src/renderer/src/components/terminal-pane/viewport/visibility/stale-document-visibility.test.ts: removes global listeners when the last pane unregisters. src/renderer/src/components/ui/security-surface-theme-contrast.test.tsx: keeps trust text readable on a host-owned dialog surface; applies the hostile surface to ordinary dialogs, so the case above is exercised. src/renderer/src/components/use-terminal-parking-pass.test.tsx: does not queue a render when a pass produces the same parking sets; keeps parking transitions working under StrictMode. src/renderer/src/hooks/client-workspace-view-report.test.ts: reports an away user’s screen with no presence, and renews as soon as input returns; retries a failed send, empty or not, no sooner than a refresh. src/renderer/src/hooks/ipc-events/terminal-request-ipc-bridge-placement.test.ts: is new work in a workspace with no live terminal: its first bind moves it up in Recent. src/renderer/src/hooks/use-bundled-skill-install.test.tsx: ignores a repeated click while the install runs; retries the last requested skills on this host. src/renderer/src/hooks/useGitHubSlugMetadata.assignee-reuse.test.tsx: adds seeds to a successful empty list but not to loading or failed results; retains seed projection after expiry and fetches fresh metadata for a new reader. src/renderer/src/hooks/useSettingsNavigationMetadata.language-switch.test.tsx: retranslates the settings nav labels when the UI language changes live. src/renderer/src/lib/codex-stale-pane-account-identity.test.ts: keeps the prompt when the roster read fails and every label collapses. src/renderer/src/lib/image-blob-png.test.ts: downscales a pasted image above the pixel cap; releases its temporary URL on a decode error; releases its temporary URL when PNG encoding fails or exceeds the byte cap. src/renderer/src/lib/react-commit-cascade-store-write-samples.test.ts: names callers above the frame the write came from; restores Error.stackTraceLimit when the capture throws; stops collecting after the sample cap when captureStackTrace is unavailable; caps reported changed keys from a single wide write. src/renderer/src/lib/work-items/linear/linear-issue-context-snapshot.test.ts: applies the rendered text hard cap last and reserves the final overflow marker. src/renderer/src/runtime/rpc/targets/use-worktree-runtime-target.test.ts: keeps the runtime target identity stable across unrelated store writes. src/renderer/src/runtime/source-control/git/runtime-git-branch-client.test.ts: keeps creation available on old hosts and explains the missing operation; preserves landed warnings and direct collision recovery data; propagates remote discovery failure instead of a false empty page. src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-key-reuse.test.ts: reuses unchanged worktree tab projections when one worktree title changes; bumps only the changed worktree version when a sibling stays byte-identical. src/renderer/src/store/repos/repos-catalog-request-coordination.test.ts: shares safe-auto fork sync cooldown attempts across store instances. src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-batch.test.ts: collapses a 193-workspace hydration to one store write; leaves the store byte-identical to the per-workspace path; re-reconciling the batched result is a no-op, as it is for the per-workspace path. src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-fixture.ts: dedicated zero-case helper retirement; no authored test credit. src/renderer/src/store/slices/worktrees/metadata/update-worktrees-meta.test.ts: persists each batch metadata update to its workspace owner. src/renderer/src/store/slices/worktrees/metadata/worktree-meta-rename.test.ts: dismisses a rename error on its capable remote owner; clears pending first-agent rename when the title is updated. src/renderer/src/store/terminals/store-sleep-shutdown-order.test.ts: orders capture, guards, handlers, main's stop, commit, cleanup, and exit settlement. src/renderer/src/store/terminals/terminal-first-tab-publication.test.ts: publishes the first terminal and root tab group atomically; publishes the first terminal and root tab group atomically, then marks it starting in main. src/renderer/src/store/terminals/workspace-terminal-reconnect-hydration.test.ts: restores daemon terminal wake hints before declaring the session ready. src/renderer/src/web/web-runtime-connection-auth-framing.test.ts: keeps legacy framing for sockets that cannot absorb a refused attempt. src/shared/terminal/appearance/terminal-font-weight-windows-regular.test.ts: moves the old Windows default to Regular once and queues the notice; keeps custom weights and fresh profiles without a notice; leaves macOS and Linux profiles untouched. tests/e2e/claude-agent-row-view.unit.test.ts: updates a mounted compact workflow description through the subscribed production parent; bounds upstream active-SSH visits for $population records, fallback=$fallback; derives %s destinations without requiring type or a workflow child ID; terminates a $path parent $status with no third request or intermediate toast; does not recover a first child %s. tests/e2e/cross-version-wire/agent-permission-legacy-spawn.unit.test.ts: keeps exact legacy ordering when structured creation cannot express afterTabId; can create a terminal without selecting the target worktree; preserves the legacy fresh-agent path when host authority is unavailable. tests/e2e/paired-instant-browser-tab.spec.ts: shows a paired browser tab before its create RPC resolves, then keeps it as one tab; adopts a paired browser tab without rebuilding its chrome. tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts: bounds host publication and renderer application across remote worktrees; globally caps decorative freshness while every working status stays fresh. tests/e2e/session-tabs/mobile-session-active-performance.unit.test.ts: bounds saved-order publication selection at N and 10N without rematerializing navigation; bounds admitted placement reconciliation during supported reads at N and 10N; bounds selection input visits at 50 and 500 rows, including unavailable-target projection; keeps publication scoped to a changed worktree and shared by listeners at N and 10N; bounds preserved-chat merge and runtime-owned hydration at N and 10N (legacy=%s); bounds actual native retirement and shared delivery work at N and 10N. tests/e2e/session-tabs/mobile-session-active-publication.unit.test.ts: does not substitute a preserved row for an unavailable explicit legacy selection; resolves main-layout group selection %s (omitted group=%s). tests/e2e/structured-agent-session-launch-admission.unit.test.ts: opens a direct caller's terminal with the caller's own CLI arguments on a decline; opens the chat on the server that admitted it; opens only the terminal when this machine declines, without a notice; opens a new agent tab's terminal with the typed prompt when the caller names none; opens the chat, not a terminal, when this machine cannot resolve a new workspace yet; keeps its terminal fallback, as before. tests/e2e/structured-attention-prompt-relay.unit.test.ts: settles once per relayed prompt, not on every later status update. tests/e2e/structured-attention-read-retirement.unit.test.ts: Mark read on a chat never opened withdraws the prompt alert it surfaced; Mark read on a chat hidden since an earlier view covers the newer prompt it surfaced; reads a newly accepted visible prompt without sending an RPC for text-only updates. tests/e2e/structured-chat-tab-lifetime-cost.unit.test.ts: counts real raw stores, unrelated window publications and captured cleanup at %i chats; counts complete supplied-member sweep and separate final retirement at S=%i N=%i. tests/e2e/structured-session-workspace-authority.unit.test.ts: bounds actual target reveal across %i repo roots and metadata aliases. tests/e2e/terminal-agent-pane-launch.unit.test.ts: starts the host's planned command once, at the pane's size, and says it started; plans a pane whose prompt the window submits without the startup update prompt; preserves caller shell-ready delivery only for a connection-scoped adapter ($connectionId); starts no shell on plan failure (original failure: $returnLaunchFailure); cannot confirm a start whose provider answer was lost. tests/e2e/terminal-parked-memory.spec.ts: releases renderer terminal memory when hidden tabs park. tests/e2e/terminal-shortcuts.spec.ts: @headful Codex-like background output stays visible without disabling WebGL in auto mode; Shift with Russian layout text reaches the PTY as Cyrillic under kitty keyboard reporting. tests/e2e/terminal-split-activation-latency.spec.ts: records attributed CWD, spawn, bind, fixture-ready, input, and echo phases. tests/e2e/terminal-split-activation-latency-phases.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-main-probe.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-artifact.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-report.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-tab-switch-visual-restore.spec.ts: restores skipped hidden Grok output on light tab resume. tests/e2e/web-runtime-session-terminal-host-authority.unit.test.ts: delivers independent %s effort through the real prepared web callback; keeps same-ID local and runtime worktrees on the selected runtime owner; creates paired web agents through host authority so activation is mirrored; delivers generated continuation context after host-authoritative creation; seeds the chat composer for a draft that rode in on the launch command. Current changed source bytes, wrapper registrations and reduced selectors have no fresh execution or red/green credit. Unrelated surviving receipt objects keep their original narrow scope; current literal graph reachability does not establish historical import closure or equivalent replacement coverage. Current conservative command/import graph reaches src/main/persistence/worktree-sort-order-write.test.ts, src/main/runtime/construction/orca-runtime.test.ts, src/main/runtime/orca-runtime-tests/targeting-and-resilience.spec.ts, src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-04.spec.ts, src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-03.spec.ts, src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-02.spec.ts, src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases-part-02.spec.ts, src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases.spec.ts, src/main/runtime/orca-runtime-tests/worktree-setup-and-startup-part-03.spec.ts, src/main/runtime/orca-runtime-tests/worktree-setup-and-startup.spec.ts, src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-summaries-part-03.spec.ts, src/main/runtime/orca-runtime-tests/mobile-summaries-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-summaries.spec.ts, src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-03.spec.ts, src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-13.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-12.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-11.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-10.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-08.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-07.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-05.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-04.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-05.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-04.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-03.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-02.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-07.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-04.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-03.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-02.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-12.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-11.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-10.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-09.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-08.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-07.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-06.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-03.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness.spec.ts, src/main/runtime/orca-runtime-tests/headless-snapshots.spec.ts, src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-02.spec.ts, src/main/runtime/orca-runtime-tests/local-worktree-creation-part-02.spec.ts, src/main/runtime/orca-runtime-tests/local-worktree-creation.spec.ts, src/main/runtime/integrations/skill/orca-runtime-skill-recovery.test.ts, src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-detached-routing.spec.ts, src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-delivery.test.ts, src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-pointer-cli-command.spec.ts, src/main/runtime/rpc/methods/terminal/terminal-multiplex-link-estimate.test.ts, src/main/runtime/rpc/methods/terminal/terminal-snapshot-scrollback-rows.test.ts, src/main/runtime/rpc/server/pairing/network/windows-default-route-interfaces.test.ts, src/main/runtime/rpc/server/pairing/pairing-offer-owner-cli.test.ts, src/main/runtime/rpc/terminal-multiplex-end-verdict.test.ts, src/main/runtime/session-graph/headless-runtime-graph.spec.ts, src/main/runtime/session-graph/runtime-graph-standing-contracts.test.ts, src/main/runtime/session-tabs/structured-conversation-tab-title.test.ts, src/main/runtime/session-tabs/terminal-close-observed-exit.test.ts, src/main/runtime/terminal/identity/terminal-identity-probe.test.ts, src/main/runtime/terminal/layout/paired-desktop-server-writes-layout-owner.test.ts, src/main/runtime/terminal/lifecycle/pty-lifecycle-generation-retention.test.ts, src/main/runtime/terminal/lifecycle/run-terminal-user-open.test.ts, src/main/runtime/terminal/surface/terminal-surface-replies-window.test.ts, src/main/runtime/terminal/surface/workspace-layout-projection.test.ts, src/main/runtime/terminal/view/terminal-subscribe-exit-waiter-leak.test.ts, src/main/runtime/terminal/wait/orca-runtime-exact-worker-provider-session.test.ts, src/main/runtime/terminal/wait/prime-agent-screen-readiness-transcripts.test.ts, src/main/runtime/workspaces/startup/runtime-worktree-agent-startup.test.ts, src/main/runtime/workspaces/startup/runtime-worktree-startup-readiness.test.ts, src/main/skills/skill-install-transaction.test.ts, src/main/speech/model-manager-download-resume.test.ts, src/main/ssh/config/ssh-config-parser.test.ts, src/main/ssh/config/ssh-known-hosts-source.test.ts, src/main/ssh/config/ssh-known-hosts.test.ts, src/main/ssh/connection/ssh-connect-config.test.ts, src/main/ssh/connection/ssh-connection-auth-fallback.test.ts, src/main/ssh/connection/ssh-connection-store.test.ts, src/main/ssh/connection/ssh-connection.test.ts, src/main/ssh/orcad-migration-stuck-host-profiles.test.ts, src/main/ssh/orcad-runtime-maintenance.test.ts, src/main/ssh/port-forwarding/ssh-port-forward.test.ts, src/main/ssh/ssh-channel-multiplexer.test.ts, src/main/ssh/system-transport/system-ssh-forward-process.test.ts, src/main/ssh/system-transport/system-ssh-loopback-route.test.ts, src/main/startup/browser-process-user-agent-ordering.test.ts, src/main/startup/quit/quit-path-durable-write-blocking.test.ts, src/main/stats/agent-session-transition-recorder.test.ts, src/main/text-generation/commit-message-text-generation-model-discovery.test.ts, src/main/text-generation/pull-request-context.test.ts, src/main/text-generation/source-control-local-process.test.ts, src/main/updater/linux-package/linux-package-update-recovery.test.ts, src/main/updater/releases/updater-prerelease-feed-readiness.test.ts, src/main/updater/releases/updater-release-builds.test.ts, src/main/updater/updater.build-channel-selection.test.ts, src/main/updater/updater.check-preflight.test.ts, src/main/updater/updater.prerelease-fallback.test.ts, src/main/updater/updater.publishing-window-feed.test.ts, src/main/updater/updater.quit-and-install.test.ts, src/main/window/createMainWindow-markdown-editor-focus.test.ts, src/main/window/createMainWindow-renderer-crash-recovery.test.ts, src/main/window/dashboard-popout-window.test.ts, src/main/window/dropped-path-preparation.test.ts, src/main/window/main-window-updater-deferred-setup.test.ts, src/main/worker-threads/worker-thread-request-queue.test.ts, src/main/workspace-hooks/hooks-setup-runner-script.test.ts, src/main/workspaces/catalog/repo-git-remote-identity-enrichment.test.ts, src/main/workspaces/creation/preparation/worktree-create-preparation.test.ts, src/main/workspaces/removal/local-worktree-removal-recovery.test.ts, src/main/workspaces/removal/worktree-removal-safety.test.ts, src/main/wsl/discovery/distro-catalog.test.ts, src/main/wsl/discovery/wsl-distro-holder.test.ts, src/main/wsl/filesystem/wsl-guest-drive-mountinfo.test.ts, src/main/wsl/orcad/wsl-orcad-deploy-app-update.test.ts, src/renderer/src/components/agent/agent-launch-picker-acquisition.test.ts, src/renderer/src/components/feature-tips/feature-tip-telemetry.test.ts, src/renderer/src/components/native-chat/composer/pickers/use-native-chat-side-chat-command.test.ts, src/renderer/src/components/native-chat/media/images/native-chat-image-copy.test.ts, src/renderer/src/components/native-chat/messages/actions/native-chat-fork-launch.test.ts, src/renderer/src/components/native-chat/messages/actions/native-chat-side-chat-fork-point.test.ts, src/renderer/src/components/native-chat/messages/actions/use-native-chat-fork.test.tsx, src/renderer/src/components/terminal-pane/provider-notices/agent-presence/agent-terminal-presence.test.ts, src/renderer/src/components/terminal-pane/pty-connection/emulation/pty-connection-mode2031-raw-subscription.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/input/pty-connection-deferred-input-forwarding.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/notifications/pty-connection-terminal-bell-attention.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-dropped-output-snapshot-healing.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/output/pty-connection-fresh-native-follow-reset.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/spawn/unbound-pane-spawn-recovery.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-foreground-agent.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts, src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-delivery-interest.test.ts, src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-push-reattach.test.ts, src/renderer/src/components/terminal-pane/pty-transport/ipc/ipc-pty-opencode-model.test.ts, src/renderer/src/components/terminal-pane/pty-transport/output/pty-side-effect-pending-census.test.ts, src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-prebind-discard-notice.test.ts, src/renderer/src/components/terminal-pane/render-health/terminal-webgl-atlas-recovery.test.ts, src/renderer/src/components/terminal-pane/snapshots/pty-buffer-serializer.test.ts, src/renderer/src/components/terminal-pane/snapshots/saved-terminal-output-replay.test.ts, src/renderer/src/components/terminal-pane/viewport/split-right-white-screen.test.ts, src/renderer/src/components/terminal-pane/viewport/visibility/stale-document-visibility.test.ts, src/renderer/src/components/ui/security-surface-theme-contrast.test.tsx, src/renderer/src/components/use-terminal-parking-pass.test.tsx, src/renderer/src/hooks/client-workspace-view-report.test.ts, src/renderer/src/hooks/ipc-events/terminal-request-ipc-bridge-placement.test.ts, src/renderer/src/hooks/use-bundled-skill-install.test.tsx, src/renderer/src/hooks/useGitHubSlugMetadata.assignee-reuse.test.tsx, src/renderer/src/hooks/useSettingsNavigationMetadata.language-switch.test.tsx, src/renderer/src/lib/codex-stale-pane-account-identity.test.ts, src/renderer/src/lib/image-blob-png.test.ts, src/renderer/src/lib/react-commit-cascade-store-write-samples.test.ts, src/renderer/src/lib/work-items/linear/linear-issue-context-snapshot.test.ts, src/renderer/src/runtime/rpc/targets/use-worktree-runtime-target.test.ts, src/renderer/src/runtime/source-control/git/runtime-git-branch-client.test.ts, src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-key-reuse.test.ts, src/renderer/src/store/repos/repos-catalog-request-coordination.test.ts, src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-batch.test.ts, src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-fixture.ts, src/renderer/src/store/slices/worktrees/metadata/update-worktrees-meta.test.ts, src/renderer/src/store/slices/worktrees/metadata/worktree-meta-rename.test.ts, src/renderer/src/store/terminals/store-sleep-shutdown-order.test.ts, src/renderer/src/store/terminals/terminal-first-tab-publication.test.ts, src/renderer/src/store/terminals/workspace-terminal-reconnect-hydration.test.ts, src/renderer/src/web/web-runtime-connection-auth-framing.test.ts, src/shared/terminal/appearance/terminal-font-weight-windows-regular.test.ts, tests/e2e/claude-agent-row-view.unit.test.ts, tests/e2e/cross-version-wire/agent-permission-legacy-spawn.unit.test.ts, tests/e2e/paired-instant-browser-tab.spec.ts, tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts, tests/e2e/session-tabs/mobile-session-active-performance.unit.test.ts, tests/e2e/session-tabs/mobile-session-active-publication.unit.test.ts, tests/e2e/structured-agent-session-launch-admission.unit.test.ts, tests/e2e/structured-attention-prompt-relay.unit.test.ts, tests/e2e/structured-attention-read-retirement.unit.test.ts, tests/e2e/structured-chat-tab-lifetime-cost.unit.test.ts, tests/e2e/structured-session-workspace-authority.unit.test.ts, tests/e2e/terminal-agent-pane-launch.unit.test.ts, tests/e2e/terminal-parked-memory.spec.ts, tests/e2e/terminal-shortcuts.spec.ts, tests/e2e/terminal-split-activation-latency.spec.ts, tests/e2e/terminal-split-activation-latency-phases.ts, tests/e2e/terminal-split-activation-latency-main-probe.ts, tests/e2e/terminal-split-activation-latency-artifact.ts, tests/e2e/terminal-split-activation-latency-report.ts, tests/e2e/terminal-tab-switch-visual-restore.spec.ts, tests/e2e/web-runtime-session-terminal-host-authority.unit.test.ts. Unresolved local/computed edges remain explicit debt.", "Audit2095 current-parent preparation2126 (approved2092/2093 removals; source refresh2109/independent2112): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-03.spec.ts: rejects exact terminal stop for multiple expected PTYs before stopping anything; omits stale renderer leaves when fresh PTY liveness is required; omits unbound renderer placeholders when fresh PTY liveness is required; captures the event method before the nested sleep receipt changes it; returns the close receipt without requiring a PTY stop; uses the same stop result as an empty explicit stop. src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-04.spec.ts: builds a compact worktree summary from persisted and live runtime state; reads the linked-PR state from the renderer repoId-keyed GitHub cache; carries persisted worktree host ownership in mobile summaries; emits only instance- and boundary-validated lineage parents in mobile summaries; resolves WSL platforms only for repos represented in mobile summaries; omits worktrees hidden by the host visibility policy from mobile summaries; applies linked-checkout source visibility to mobile summaries. src/main/runtime/orca-runtime-tests/hooks-and-hosted-review-part-02.spec.ts: routes runtime GitHub PR details and actions through the selected WSL project runtime; passes SSH connection context through hosted review creation flows; routes local WSL project hosted review flows through runtime git options; treats SSH worktree drift as unknown without local git probes. src/main/runtime/orca-runtime-tests/terminal-listing.spec.ts: emits one mobile session terminal tab per live PTY even if two tabs resolve to it; resolves projected split authority from the parent layout PTY binding; keeps explicit-id terminal lists from resolving all worktrees; keeps explicit-id cold-cache terminal lists from classifying unrelated same-repo worktrees; keeps unknown bare terminal-list ids on the no-scan exact-id path; matches explicit-id cwd PTYs for folder workspace instance IDs; routes PTY output through the PTY leaf index in large terminal graphs. src/main/runtime/orca-runtime-tests/window-authority.spec.ts: claims the first window as authoritative and ignores later windows; transfers authority from the headless sentinel to the first real window; relays terminal browser launches only while headless owns the graph; marks live headless PTYs for renderer reattach before desktop promotion; reports the activation gate state while no desktop window is available; bumps the epoch and enters reloading when the authoritative window reloads; can mark the graph ready for the authoritative window; drops back to unavailable and clears authority when the window disappears; hands the graph back to headless when a promoted serve window closes (#27292); keeps a crashed promoted serve renderer on its own window while the window is open; stays unavailable during initial loads before a graph is published. src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-routing-races.spec.ts: stops paged routing when the check is cancelled; keeps an unfiltered redrive unrestricted when reservations merge; keeps an unfiltered parked delivery unrestricted when reservations merge; uses a bounded indexed pane lookup for reminted Dispatch identity. src/main/runtime/workspaces/removal/worktree-teardown-unstopped-pty.test.ts: removes the reported wedged automation workspace without --force; clears PTY state once a failed stop is proven to have exited; names only the PTYs that are actually live, not every failed stop; warns with the specific sweep failure, not the generic deadline; still fails closed on a sweep-level failure without force. src/main/skills/bundled-skill-install/layouts.test.ts: links into a project only where its agent folder already exists; reads a pending cloud transaction as busy and a cloud receipt as another skill. src/main/skills/skill-upload-session-service.test.ts: joins concurrent disposal callers through exact cleanup completion. src/main/source-control/hosted-review-creation.test.ts: creates the pull request after fresh main-process validation passes; routes local WSL git and GitHub review creation through the selected runtime; creates a pull request on a GitHub Enterprise Server remote (#8312); creates a GitLab merge request after fresh main-process validation passes; creates an Azure DevOps pull request after fresh main-process validation passes; creates a Gitea pull request after fresh main-process validation passes. src/main/source-control/hosted-review-execution-host-routing.test.ts: reads a GitHub review on the SSH host a row names only in executionHostId; reads a GitLab review on the executionHostId host when connectionId names a different one; does not dial this client for a runtime row whose nested target shares a local name; keeps a runtime row with no nested target on this process (self-addressed stamp); keeps a legacy connectionId-only SSH row on its target; does not share a cached answer between two rows at one path on different hosts; creates a Bitbucket review locally for a runtime row rather than dialing its nested target; reports creation eligibility from the executionHostId-only SSH host; resolves the GitHub slug for a repo listing on the row it is asked about; refuses to dial a runtime host from this process; answers with the SSH target for both spellings and local otherwise; reads a runtime stamp on a row in this store as self-addressing, not a second machine. src/main/source-control/hosted-review-inflight-invalidation.test.ts: keeps other hosts, paths and their pending promises isolated. src/main/speech/model-manager.test.ts: requires pinned, internally consistent metadata for every model file; verifies downloaded model file hashes before installation; rejects non-HTTPS model downloads; marks OpenAI transcription models ready only when an API key is configured. src/main/ssh/connection/ssh-connection-sftp-namespace.test.ts: writes to the SFTP namespace path discovered on the same session; uploads the bundle into the SFTP namespace directory; issues no discovery requests when the caller supplies no mapping; ignores a mapping on a Windows host; never resolves on the system-SSH transport; leaves writeBuffer and openFileUploadSession on the shell path; keeps the shell path when discovery is inconclusive; preserves a session-limit channel-open error unchanged. src/main/ssh/connection/ssh-connection-system-transport.test.ts: uses system SSH transport when ProxyUseFdpass is resolved by OpenSSH; allows concurrent exec commands for system SSH with an Orca ControlMaster socket; keeps concurrent exec commands disabled for system SSH without a reusable socket; uses system SSH transport for ProxyCommand targets before ssh2 auth; keeps the original ssh2 reachability error when the system SSH probe fails; reports the system SSH failure when ssh2 cannot negotiate with the host; uses system transport for target or resolved OpenSSH proxy directives; allows an environment override for e2e coverage; ignores stale imported proxy fields when fresh OpenSSH config has no proxy. src/main/ssh/orcad-migration-catalog-client.test.ts: keeps each server project’s execution host, so a nested SSH row is never read as local; reads the server’s folder workspaces and the groups that place them on a host; sends and validates the %s operation; validates an abort result without letting it erase committed state; validates a committed receipt against the requested manifest; rejects malformed stage timestamps and abort envelopes; fails closed for method absence, malformed identity, and invalid pairing; refuses a destination without the capability before sending any migration request; reads method-not-found as the same refusal, not as a lost answer. src/main/ssh/runtime-ssh-access.test.ts: persists intent then claim before connecting and publishes redacted authenticated access; names the saved dependency when dependent state blocks an SSH access link; handles lost link responses without connecting or verifying again; invalidates old transport only after authenticated access is published; rejects changed request tuple after a completed link; rejects provisioning and missing durable generations without connecting; treats a lost successful unlink response as an idempotent no-op; hashes connection identity, not display state or owner; strictly validates ports and request IDs. src/main/startup/cli-launch-redirect.test.ts: detects a launch that received the unpacked CLI entrypoint; ignores normal desktop launches; ignores the entrypoint when it is only the executable itself (argv[0]); applies on Linux too; strips injected Chromium switches before node-mode CLI arguments; keeps user flags after the command and malformed boolean assignments; does not treat a later positional entrypoint path as the launcher; redirects a direct binary launch with no AppImage env at all; strips Chromium switches node mode would reject; preserves desktop-shaped switches after the command; leaves direct serve in-process but redirects its help; treats help as a CLI launch even without a command; treats %s as a CLI launch even without a command; does not treat a value of %s as a CLI early-exit flag; does not treat a serve option value as a help request; does not reinterpret help after the argument terminator; leaves a plain desktop launch alone; skips flag values when looking for the command positional; preserves a project selector in %j; does not apply the command form on macOS or Windows; never redirects an unpackaged build; runs the in-package CLI in Electron node mode with sanitized env; refuses to redirect twice so a dropped ELECTRON_RUN_AS_NODE cannot loop; reports a missing CLI entrypoint instead of booting the desktop app; execs a direct serve into the CLI so it keeps its pid and honours profile and supervise; keeps ORCA_USER_DATA_PATH for a direct serve without --user-data-dir; serves in-process when this runtime cannot exec or the exec fails; never execs the --serve child the CLI itself spawns, or serve on other platforms; surfaces a spawn failure as a non-zero exit; re-execs a direct --serve onto X11 when Electron resolved Wayland; leaves $name alone. src/main/startup/main-process-runtime-launch-activation.test.ts: marks startup settled for the launch record only after the window has loaded and settled; loads SSH targets on a windowless serve before paired clients can connect (#25886); pins the serve listener to loopback only for orcad browser sidecars (sidecar=$sidecar, #31895); saves Codex auth before a headless serve update restart, like the desktop does. src/main/startup/run-electron-vite-dev.test.ts: forwards dev instance identity to electron-vite; prepares userData orca and orca-dev wrappers for dev terminals; consumes the stable-name flag before forwarding args to electron-vite. src/main/updater/releases/updater-prerelease-feed.test.ts: returns the newest stable tag when the user is on an RC and a newer stable exists; returns the newest RC tag when no stable is newer than the current RC; can exclude prerelease tags for stable-channel checks; probes the %s %s platform manifest; returns null for stable-channel checks when only prereleases are newer; returns null when nothing in the feed is newer than the current version; ignores entries with unparseable tags; returns null when the fetch is not ok; returns null when the fetch throws; picks semver-newest across a mixed-order feed; ignores perf-tagged prereleases for regular RC checks; reports no RC update when only perf-tagged prereleases are newer; picks the semver-newest perf-tagged prerelease; matches only literal rc.N.perf prerelease tags for perf checks; reports no perf update instead of falling back to stable or RC tags; returns a bounded fallback candidate after the newest newer tag; returns null when the only newer tag has a manifest but its asset still 404s; requires a known old timestamp for a stable-fallback tag. src/main/updater/updater-events.test.ts: hands the whole downloaded event to artifact capture; publishes manual-install recovery after a %s download; publishes the normal downloaded state for AppImage builds; blocks downloaded-state handling when the packaged marker is unusable; passes the actual updater error into the install-failure handler; keeps manual-install recovery when a later check finds only the installed release; drops the artifact when another version takes over the cycle; ignores a downloaded event for an older target; accepts a matching event when the pending cache target was cleared; drops the artifact when progress reports a different pending version. src/main/updater/updater-linux-package-recovery-actions.test.ts: rejects both actions while no package-install recovery is active; validates the retained package on every invocation; restores recovery after a recheck resolves without a terminal event; restores recovery after a recheck fails; restores recovery when a pinned check resolves to the current version; restores recovery when resolving a pinned check fails; clears recovery for both actions once the package is gone; resolves %s as a result and keeps the card usable instead of rejecting; keeps recovery available after a transient read failure. src/main/updater/updater.check-settlement.test.ts: leaves a dismissed release update on the release source; surfaces net::ERR_FAILED to user-initiated checks with a friendly message; shows checking immediately for a user-initiated check while feed pinning is pending; keeps background checks event-driven before checking-for-update fires. src/main/usage/usage-provider-store-lifecycle.test.ts: persists identities for a whole first scan with one write; skips disabled and fresh matching states; invalidates prior sources on fingerprint changes and reuses them for forced scans. src/main/window/createMainWindow-close-confirmation.test.ts: clears the quit latch when the renderer prevents unload; does not notify the crash recorder when renderer teardown follows a confirmed window close; allows close when Electron reports a crashed webContents; requests confirmation for a hung-but-alive renderer instead of bypassing. src/main/workspaces/catalog/worktree-identity-persistence.test.ts: stores independent metadata for colliding locators on two hosts; projects canonical-only metadata for exactly one host; keeps canonical metadata current for legacy writers on a known owner; removes only the selected legacy-owner metadata when locators collide; keeps the canonical identity stable when the locator changes; leaves other hosts at the old locator when one host renames its folder. src/main/wsl/filesystem/wsl-drive-unc-conversion-startup.test.ts: leaves a journaled conversion untouched with the gate closed, %s. src/main/wsl/orcad/wsl-orcad-deploy.test.ts: holds the distro before it deploys and launches, and reports what C5 dials; passes its connect-state read (%s) on as hints; applies the SSH census and downgrade admission to the first deploy; refuses a WSL 1 distro before holding it or touching its files; tells an unregistered distro how to find the installed ones, before holding anything; surfaces an unsupported libc as the SSH host refusal does; starts an already-active slot the distro stop ended, instead of reporting it ready; deploys over an adopted unrecorded orcad under the SSH terminal gate, never a fresh launch; reports the adopted instance once the same version is serving; returns a deferral rather than launching over live terminals; hands a failed first deploy to the fresh-install cleanup before reporting it. src/main/zcode/zcode-v2-plan-credentials.test.ts: prefers migrated credentials over a stale legacy account; keeps legacy support when no personal v2 file exists; honors the upstream personal config override independently of the credential directory; does not borrow credentials from another execution host; preserves the protected Orca key priority even if v2 is corrupt; rejects upstream-invalid selection %j without legacy fallback; accepts a valid optional reasoning level; rejects upstream-invalid rule containers %j without legacy fallback; accepts a valid selected-provider empty personal rule and smart model rule; cannot establish selected credentials from %s rules; leaves encrypted CLI files unchanged across repeated account reads. tests/e2e/automation-terminal-launch.unit.test.ts: launches explicit Chat for %s through the common entry and keeps its actual fallback; does not apply stored Terminal extras to Chat; forwards only complete Chat-consumed values, with no Terminal startup base; refuses an expired admission without minting another launch identity; records the actual chat identity and delegates new workspace setup and provenance. tests/e2e/github-project-provider-columns.unit.test.ts: renders %s through one bounded items request on a named cloud host; preserves zero and complete counters: %j; preserves populated and legacy rows through shared sorting, grouping and cells. tests/e2e/structured-agent-session-launch-continuation.unit.test.ts: carries renderer lifetime through host intent to the real %s provider builders. tests/e2e/terminal-account-restart.unit.test.ts: replaces a tombstoned owner while its persisted pane binding has not yet been cleared; paired restart retains the old owner (host authority: %s). tests/e2e/terminal-hidden-view-parking.spec.ts: does not park excluded tabs; reproduces a static frame byte-for-byte across 25 park/reveal cycles. tests/e2e/terminal-long-table-scroll-restore.spec.ts: reproduces long markdown table artifacts after workspace switch and scroll; keeps narrow wrapped signer markdown table coherent after restore and scroll; keeps real emoji markdown table right edge clean after restore and scroll. tests/e2e/terminal-long-table-fixtures.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-paste-ownership.spec.ts: Windows multiline keyboard paste normalizes terminal newlines with one PTY owner; right-click paste sends clipboard text to the focused terminal exactly once. tests/e2e/terminal-raw-emoji-table-scroll-restore.spec.ts: uses WebGL by default for ordinary terminal output when available @terminal-rendering-golden. tests/e2e/terminal-windows-shell-paste-ownership.spec.ts: cmd.exe default terminal keyboard paste preserves exact content with one PTY owner; Git Bash default terminal keyboard paste preserves POSIX-shaped content with one PTY owner; WSL terminal keyboard paste preserves Linux shell content with one PTY owner. tests/e2e/workspace-board-lane-virtualization.spec.ts: mounts a window of cards for a large lane and keeps lane indexes; renders later lane indexes after the lane scrolls. Current changed source bytes, wrapper registrations and reduced selectors have no fresh execution or red/green credit. Unrelated surviving receipt objects keep their original narrow scope; current literal graph reachability does not establish historical import closure or equivalent replacement coverage. Current conservative command/import graph reaches src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-03.spec.ts, src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-04.spec.ts, src/main/runtime/orca-runtime-tests/hooks-and-hosted-review-part-02.spec.ts, src/main/runtime/orca-runtime-tests/terminal-listing.spec.ts, src/main/runtime/orca-runtime-tests/window-authority.spec.ts, src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-routing-races.spec.ts, src/main/runtime/workspaces/removal/worktree-teardown-unstopped-pty.test.ts, src/main/skills/bundled-skill-install/layouts.test.ts, src/main/skills/skill-upload-session-service.test.ts, src/main/source-control/hosted-review-creation.test.ts, src/main/source-control/hosted-review-execution-host-routing.test.ts, src/main/source-control/hosted-review-inflight-invalidation.test.ts, src/main/speech/model-manager.test.ts, src/main/ssh/connection/ssh-connection-sftp-namespace.test.ts, src/main/ssh/connection/ssh-connection-system-transport.test.ts, src/main/ssh/orcad-migration-catalog-client.test.ts, src/main/ssh/runtime-ssh-access.test.ts, src/main/startup/cli-launch-redirect.test.ts, src/main/startup/main-process-runtime-launch-activation.test.ts, src/main/startup/run-electron-vite-dev.test.ts, src/main/updater/releases/updater-prerelease-feed.test.ts, src/main/updater/updater-events.test.ts, src/main/updater/updater-linux-package-recovery-actions.test.ts, src/main/updater/updater.check-settlement.test.ts, src/main/usage/usage-provider-store-lifecycle.test.ts, src/main/window/createMainWindow-close-confirmation.test.ts, src/main/workspaces/catalog/worktree-identity-persistence.test.ts, src/main/wsl/filesystem/wsl-drive-unc-conversion-startup.test.ts, src/main/wsl/orcad/wsl-orcad-deploy.test.ts, src/main/zcode/zcode-v2-plan-credentials.test.ts, tests/e2e/automation-terminal-launch.unit.test.ts, tests/e2e/github-project-provider-columns.unit.test.ts, tests/e2e/structured-agent-session-launch-continuation.unit.test.ts, tests/e2e/terminal-account-restart.unit.test.ts, tests/e2e/terminal-hidden-view-parking.spec.ts, tests/e2e/terminal-long-table-scroll-restore.spec.ts, tests/e2e/terminal-long-table-fixtures.ts, tests/e2e/terminal-paste-ownership.spec.ts, tests/e2e/terminal-raw-emoji-table-scroll-restore.spec.ts, tests/e2e/terminal-windows-shell-paste-ownership.spec.ts, tests/e2e/workspace-board-lane-virtualization.spec.ts. Unresolved local/computed edges remain explicit debt.", @@ -9368,7 +9100,21 @@ "Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed.", "Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed.", "Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed.", - "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired." + "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired.", + "Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands.", + "Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims.", + "Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical.", + "Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed.", + "Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed.", + "Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed.", + "Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed.", + "Audit3335 composes adopted source unions3327/3328 and3330/3332: intentionally retires100 authored registrations/123 expanded cases, including ten whole suites, without equivalent replacement. Lost alarms include seeded host persistence/contention and stale-host cleanup; browser snapshot assembly; mocked wake/DPR callbacks and frame budgets; preflight projections; palette authority/cache suppression, URL intent and saved-title cross-repo collisions; metadata coverage/set patch and dropdown assembly; and removed terminal, worktree, review-refresh and owner-routing examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI/GPU/focus, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain only their original scope.", + "Audit3342 composes adopted source batches3333/3334,3336/3337 and3340/3341: intentionally retires180 authored registrations/263 expanded cases, including seven whole suites, without equivalent replacement. Lost alarms include corrupt editor hydration; mobile editor/diff publication and privacy projections; stale-resubscribe routing; model-picker projection/refetch/retry/fallback; editor check-details and frame property inventories; latched-pane cleanup/quiescence; client create replay identity/options/compatibility; and removed owner, async routing, terminal and layout examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts keep their original scope.", + "Audit3349 composes adopted batches3343,3345 and refreshed3354: intentionally retires234 authored registrations/294 expanded cases, including13 whole suites, without equivalent replacement. Lost alarms include supplied terminal reconnect/replacement/typeahead/mirror/result and snapshot examples; synthetic render-desync persistence/recovery; worktree listing/owner/catalog/lineage/removal and activation/creation examples; host-scoped PR and task-record projections; editor diff/status/comment and UI send-target examples; automation observation/wake, supplied sleep/deadline clock and native-chat completion/notification/relaunch samples; held-tab layout and cleanup/progress guard examples. Retained adverse-ordering and wire-boundary cases are narrower and do not replace all removed alarms. The already-upstream visibility-resume deletion receives zero new removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH, native process/power/GPU, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3359 composes root-adopted source3355/independent3356: intentionally retires130 authored registrations/139 expanded cases, including eight whole suites, without equivalent replacement. Lost alarms include strict create naming/capability/legacy payloads; supplied transport host replacement, deadline reattach, create-handoff and split activation; agent-session fork/clipboard/platform flags; shutdown cleared-scrollback/unmounted bindings; simulator host-collision/selection/shutdown; and removed editor, catalog, mutation, launch and status examples. Retained12 adverse-ordering/state-consequence cases are narrower and do not replace all removed alarms. Two queue absences receive zero removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY, filesystem restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3362 composes root-adopted3358/independent3360: intentionally retires129 authored registrations/140 expanded cases, including four whole suites, without equivalent replacement. Lost alarms include supplied orphan-adoption retry/malformed inventory/cancellation; fake-terminal replay parser/wedge/disposal callbacks; all-host catalog metadata and Windows preferences; host keepalive/protocol/stale/settings failures; and removed exact-stop/suppression, source save lifetime, diff-note queue, rename/editor close, input flood/chunk refusal/limits, purge and creation examples. Retained18 registrations/21 expanded cases protect narrower ownership, generation, dirty-state, queue convergence, encoding and attachment-lease outcomes. No replacement or keeper quota claim. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY/xterm parser, disk restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3368 composes root-adopted3363/3364 and3367/3369: intentionally retires181 authored registrations/196 expanded cases, including28 whole suites, without equivalent replacement. Lost alarms include hibernation attention/liveness/backoff/sequential teardown and inventory, host launch compatibility/legacy/Kimi/resource cleanup, terminal recovery parser/pause/quarantine/remount, window-visibility omission-fence lifetime, launch-option rendered Start, sleeping-resume saved recipe/WSL quoting/cancellation, plus removed project/window/input variants. Additional tiny-suite losses include sentence/label/field/default inventories, credential omission, Windows argument/environment mapping, URI decoding, diagnostics, provider classification and fake-clock callback/parser examples. Retained ten registrations/twelve expanded cases include two literal Unicode Mn/Cf zero-width range guards in the actual character-range algorithm and protect narrower delayed editor bytes/destructive ownership, mounted hidden collision repair, ten transport epochs, duplicate-command refusal, caller timeout typing, executor unknown-opener refusal and failed-chunk user bytes. This broad unit command selects the reduced suite; no fresh runtime, real provider/network/PTY, filesystem restart, native UI, historical import equivalence, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3375 composes root-adopted3370/independent3371 and3373/independent3374: intentionally retires79 authored registrations/84 expanded cases, including39 whole suites, without equivalent replacement. Lost alarms include federation field/parser inventories; Claude rejected-key precedence, credential clone redaction, managed-versus-user hook preservation and CLI defaults; setting/status/activity projections, mocked SSH/notification/reveal/Linear refusal, fake-clock reconnect and noise; image-fold artifact visibility, paste eligibility, setup trust, scripted ACP error-to-journal publication and ligature cache tuple aliasing; plus supplied folder-runner uniqueness, mobile host-overlay/credential/update/preference races, status/markup/title/keyed-row projections, subscriber cleanup, cancellation/close/refusal/link-issue and mirror suppression alarms. Retained3373 merger contiguity, dual-clock overdue-resume exactly-once, rejected-paste IPC sink and annotation schema roundtrip remain bounded. Retained actual HTTP/OSC status composition, destructive sibling-filesystem isolation, external contrast invariant and fixture CSS pixel intervention remain narrower. Original reviewed87authored/92expanded become9/9; current OpenCode suite adds two preserved upstream cases and the synthetic-title suite gained one Cursor policy mock-call case, independently reviewed for removal in root3378; current90/95 become11/11. That Cursor suppression/ready-frame regression alarm is intentionally lost; it does not observe native title ownership or tab flicker. For3370 only the peer was independently blind, with author exposure explicit;3373/3374 both blind pins were verified. This broad root unit command selects the reduced root unit suite; UNIT_INCLUDE excludes mobile tests, which require the existing mobile runner; retained Playwright component-pixel spec uses its separate existing headless fixture runner and is not validated by the broad unit command. No fresh execution, actual agent/shell/provider, OS material/focus, historical import equivalence, mobile, mixed-version or cross-platform evidence is claimed. All dated receipts retain their original scope." ], "demotionRule": "Cannot promote without metric artifacts and bounded-byte assertions." }, @@ -9602,9 +9348,9 @@ ], "platforms": ["macos", "linux", "windows"], "providers": ["ssh", "remote-runtime", "wsl"], - "coveredPlatforms": ["macos"], + "coveredPlatforms": ["linux"], "coveredProviders": ["ssh", "remote-runtime"], - "coverageNotes": "Audit3096: remove the deleted reconnect-banner selector and its two UI aliases. The reduced recovery-state selector retains only the deadline cancelling pending backoff and explicit retry owning a new epoch alias; healthy-replacement stale-schedule and independent caller-cutoff cancellation aliases retire. Other retained state cases cover reentrant retry, owner settlement and same-epoch parked revival, without replacing those removed alarms. Prior admission-selector retirement, archived July 28 receipt, unrelated selectors/claims/receipts and old gaps remain unchanged; no fresh execution is claimed. Audit3086: retire the destroyed fresh-session fallback settlement/non-destructive reattach alias and its direct selector; retain the detach/attach selector and assertion unchanged. The retained admission cases cover adopt-before-data and explicitly buffered-death admission without a new spawn, without replacing fallback retirement. July 28 evidence was already archived by audit3077; no duplicate retirement or new execution is claimed. Audit2709 removes src/renderer/src/runtime/web-session-tabs-sync/inventory/remote-runtime-session-tabs-inflight.test.ts: intentionally retire waiting out an older inventory and sharing a fresh post-operation request among concurrent callers. No equivalent replacement or fresh execution is claimed. Dated receipts remain historical evidence for their unchanged selectors only; they do not validate the reduced commands or full current gate. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/ssh/connection/ssh-connection-manager.test.ts: tears a failed startup down quietly, so its error is not replaced by a disconnect; marks a dial that never reached the host, so setup reports SSH’s reason; removes the registration when bulk teardown fails; leaves a connection whose own reconnect is asking the user alone; clears the pool entry when the closed connection is still the registered one; still reuses a connection that is already up; dials a user's connection test. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2052 (sources2049/2050/2051): Remove complete low-value restored-pane-title and pane-visibility-identity suites and their current selectors. Their supplied snapshot/title and nullable identity-comparison alarms are intentionally lost without replacement. Unrelated dated evidenceRuns remain unchanged and do not validate the reduced commands. No fresh gate execution, actual PTY/provider, rendered, remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1983: Delete the terminal-create idempotency forwarding suite and its prospective selector. Preserve2 unrelated receipts without claiming the lost forwarding alarm was replaced. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Delete complete transport-unmount and queued-initial-CWD helper suites: despite lifecycle-shaped fixtures, the unmount owner returns a Boolean PTY-id predicate, while CWD cases check nullish field selection and callback counts. Lose their detach/destroy/teardown and one-shot-CWD supplied examples. Partial queued-pane-startup loses three identical/empty/nonowner identity examples, retaining four exact one-shot/replacement ownership callbacks. No assertion object maps to these three sources, so unrelated alias objects remain byte-exact. Preserve the current81ed prior removal of pane-split-startup; stale bd948 source metadata snapshots are not replayed. No actual process/PTY startup, transport shutdown, live SSH or rendered recovery is proven by this metadata change. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1925 (sources1922/1923): Delete the sole supplied public-SSH-state spread/sanitized-error projection and its provider-authority-pair alias. Also delete the complete tiny one-shot split-startup wrapper suite: callback-visible temporary field/reset, sequential payload and thrown-sentinel reset alarms disappear. No SSH provider epoch handoff, connection, process startup or actual terminal split was performed by either deleted suite. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1903 removes whole mocked detach, supplied geometry and/or close-request suites selected by this gate. Their pending-CWD/PTY-binding argument/order, fabricated hit-test and close bookkeeping alarms are intentionally lost without replacement. Valid remaining selectors/assertions and unchanged-selector execution receipts retain their original scope. Reduced unit selections have no fresh broad gate, real PTY/provider, rendered focus, or measured-budget validation. Historical prior account (preserved verbatim): Audit1645 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1342 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Audit1301 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Deterministic renderer coverage proves retained native and runtime SSH payloads are admitted through production routes only with valid complete authority, stale cleanup cannot unregister a replacement runtime terminal, direct SSH Git and folder panes keep their PTY bindings through disconnect and reconnect, one authority chain stops after two automatic attempts even when each timeout exceeds the rolling window, rejected acknowledgements mutate no store maps, and one shared exact attempt admits every concurrent split-pane spawn and reattach while preserving the first PTY as the tab fallback. A later sibling failure rotates the tab once, stale callbacks from the prior attempt mutate no state, split remount activity suppression is counted per leaf, primary PTY exit promotes a bound survivor or preserves an empty continuation gap for a late sibling, and primary, non-primary, or null-PTY detach preserves exact authority on both resulting tabs. Intentional pane disposal cancels its settlement timer without breaking StrictMode remount timeout ownership. A mounted remote-runtime terminal survives repeated transport partitions without changing PTY identity. A real encrypted-WebSocket oracle proves a successful reachability probe can replace a pre-ready shared-control socket without rejecting or duplicating the waiting RPC. Direct SSH coordinator tests cover immediate terminal finalization, hydration correction, damping, bounded retry, and telemetry non-interference. Client/server heartbeat tests cover timer suspension, socket generations fence stale callbacks, cold restored-terminal attachment retries, cached pixels remain unhealthy until authoritative replay, automatic retries stop after one minute, manual reconnect preserves the PTY, and pane closure releases recovery UI state. Current-transport recovery clears every error that transport surfaced without clearing or displaying a sibling pane's errors, while transport suppression, pane retention, and the rendered surface are independently bounded. Current macOS Electron journeys against an ephemeral Linux Docker SSH target cover exact-authority repo/worktree hydration, live terminal recovery after disconnect/reconnect, and eager six-terminal remount after renderer reload. A Windows remote-runtime smoke covers reachability and PTY round-trip. Multi-target live fanout, paired-close, WSL, and patched live partition journeys remain gaps. The test-value audit narrowed resolved-worktree-execution-host.test.ts to cache reuse and invalidation. Its direct hydrated-worktree, missing-folder, restored-owner, host-stamp and empty-runtime selection alarms are lost. Other routing and recovery suites do not establish equivalent selector coverage; historical run commands and results remain historical. The test-value audit removes standalone unwritten/released renderer-authority and cross-scope request-count examples. The retained synthetic mirror/store/sidebar and pending-inventory checks do not establish real PTY byte ownership, SSH reconnection or equivalent replacement coverage; historical commands and results remain historical. The test-value audit removes direct join/label ledgers, immediate failure and negative-only stale/removal/partial-authority examples, plus the standalone retained/live event projection. Retained synthetic store/hydration compositions do not establish real SSH continuity, remote authority delivery or equivalent replacement alarms. Historical commands and results remain historical. The renderer scheduling fixture retains in-flight coalescing only. Its immediate publication and negative stale-SSH-cleanup call ledgers were removed; the retained SSH recovery evidence does not replace those alarms. The accepted-handle-events observer suite is removed, including its scoped listener and settlement-release assertions. These observer alarms are lost; retained SSH/transport journeys are not equivalent replacement coverage. The test-value audit removed repeated remote-handle rotation inventories and snapshot-first pending-restart migration examples from terminal-pty-identity-replacement.test.ts, plus direct foreground metadata setter, confirmation, evidence-enum, and prefix/worktree cleanup examples. Those rotation, pending-restart, snapshot-first migration, and foreground scalar-update alarms are lost. The retained replacement case observes pane and tab identities in one subscriber publication; it does not establish equivalent migration, process-evidence, or input-routing coverage. Historical commands and results remain historical. The test-value audit narrows terminals-hydration.test.ts to a real reconnect batch with one measured store publication and hydration-seeded history consumed by a subsequent visit/Back check. Direct split-layout, runtime/folder/floating restoration, dead-leaf focus, cold/known-absent SSH deferral, title, default-tab marker, navigation initialization, and hydrationSucceeded scalar examples are removed; those specific alarms are lost. No actual target-removal transition, live SSH connection, session writer, or persisted restart is exercised by the retained cases. The old target-scoped/snapshot assertion references are retired because the current file does not contain those oracles. Other suites and historical runs do not establish equivalent replacement coverage. Audit1299 removes tests/e2e/terminal-cold-activation-deferral.spec.ts. Private-state/work-budget/assembled-fixture alarms are intentionally lost; retained suites are not equivalent replacement coverage. No new runtime/platform evidence is claimed. Audit1301: src/renderer/src/runtime/remote-runtime-session-tabs-inflight.test.ts reduced. Direct dedupe eviction/count and equal receipt-position sample loses authored alarm. No equivalent replacement coverage is claimed. Audit1318: src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts: Retain real local encrypted WebSocket regressions for pre-ready socket replacement preserving a request, close-before-ready logical subscription cleanup, unrelated RPC surviving another deadline, and pending setup abort leaving a sibling pending. Host server is synthetic and uses production crypto; kept scenarios also retain internal diagnostics/memory assertions unchanged. Remove happy routing, authority-envelope, unknown-ID/log, cleanup enum, binary, keepalive/liveness and production-budget/private socket inventories; intentionally lose those alarms, no physical host authorization, independent crypto or remote provider claim. Reduced selectors need fresh validation; historical full-suite receipts do not validate the changed coverage. No equivalent replacement or physical-provider claim. Audit1342: src/renderer/src/hooks/ipc-events/direct-ssh-connect-reply-routing.test.ts removed. Initial and event-triggered partial-authority hydration fixture alarms disappear. src/renderer/src/components/terminal-pane/terminal-error-accumulation.test.ts removed. Multiline dedup/storm bounds, resource classification/collision, scoped clear/reconnect strip and1000-pane map count alarms disappear. No equivalent replacement coverage is claimed. Audit1396: src/renderer/src/components/terminal-pane/pty-connection-pending-spawn.spec.ts reduced. Lose standalone debug-state retention/log silence alarm. React StrictMode is not mounted; bindings manually simulate remount over mocked transport. No equivalent replacement coverage is claimed. The existing primary-selector receipt and its claims remain scoped to their unchanged sources; the broad optional command has no new execution result. Audit1400: src/main/ipc/ssh/ssh.test.ts reduced. Lose trivial missing target and mocked publication inventory. Preexisting unresolved ../ssh/ssh-port-scanner mock is recorded, not fixed. src/renderer/src/runtime/sync-runtime-graph-scheduling.test.ts removed. Removes whole coalescing call-count suite; no newest-state delivery or replacement claim. src/renderer/src/store/slices/terminal-pty-identity-replacement.test.ts reduced. Removes three no-op/work-count registrations; retains externally observed ownership consistency. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result. Audit1412: src/main/ssh/ssh-provider-authority.test.ts removed. Loses real AbortController revocation/target isolation/reentrancy outcomes, recreated-target generation-floor/session rollover behavior, stale mutation refusal and settled-registration cleanup alarms. These useful alarms are deliberately lost; no equivalent cancellation coverage is claimed. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result. Audit1743 removes the standalone line-height clamp/default and pane cwd fallback helper tests (5 authored cases). These trivial-helper alarms are intentionally lost, with no equivalent replacement. Only current commands/testFiles lose the deleted selectors; historical receipts and evidenceRuns remain unchanged and do not validate the reduced commands.", + "coverageNotes": "Audit3368 narrows stream-reconnect coverage to the actual ten synthetic transport epochs retaining one PTY identity, accepting and holding detached input for exactly-once later delivery, current decoded output and per-epoch subscription release. Prior rejection wording was inaccurate. Phase/backoff/cutoff/manual reconnect and parser/OSC/pause/retained-image/fatal/latch/claim/early-close alarms are intentionally lost without equivalent replacement. The Linux multi-pane reconnect receipt remains verbatim with its original scope; no fresh live SSH/provider/PTY/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit3359 retires whole host-surface-replacement and create-handoff suites, removing their compound unit command tokens, test-file entries and assertion references. Fake polling/deadline/subscription, supplied stale-handle ownership, close and replacement examples are intentionally lost without equivalent replacement. The unrelated Linux paired multi-pane reconnect receipt stays verbatim with its original scope. No fresh SSH/provider/network/PTY recovery, historical-import, mobile, mixed-version or cross-platform validation is claimed. Audit3342 retires the complete client create-outcome identity/options/recovery suite and the malformed-or-contradictory repo-owner response matrix. Client replay identity, options, no-downgrade, quiescence/budget/manual retry, authoritative probe-error and malformed-owner refusal alarms are intentionally lost without equivalent replacement. Remaining repo-owner late catalog and old-host re-adoption boundaries do not replace them. The unrelated Linux paired-reconnect receipt stays verbatim with its original scope. Surviving selectors are unexecuted here; no fresh SSH/provider/process-deduplication, mobile, mixed-version or cross-platform validation is claimed. Audit3329 execution amendment: the reduced one-suite reconnect selector passed on Linux (1 case). Original source-review statements about no fresh execution describe the earlier static review; this new receipt validates only this one local deterministic unit case, not the complete gate or physical/runtime/rendered/provider/platform parity. Historical seven-case macOS and two-case Linux receipts remain archived verbatim. Audit3326 adopts reconciled source audit3324 and intentionally retires these low-value examples and their regression alarms: keeps a sidebar row for every still-live pane after a long sleep — Whole suite: 279 lines manually replay renderer ownership registry/status writes, snapshot patch/set, six-pane fixture inventory, and sidebar selectors/builders; expected pane IDs are production-computed. Does not run sleep/wake/transport or actual sidebar entry. Retires reconnect row-preservation assembly alarm.; still retires the regular TUI surface after an explicit terminal exit — Ordinary explicit-exit callback/map cleanup is repeated in the stale/new stream lifecycle case below. Retires separate regular-TUI baseline; keeper is not equivalent process/UI proof.; asks the HUB to recover an expired SSH pane and rebinds the host identity — Expired SSH owner error must ask the owning HUB to recover, then adopt fixed replacement handle, resubscribe and report rebind; actual transport dispatch and handle state prevent wrong-client recovery.; does not recover a pane whose relay reply was an identity mismatch — Identity mismatch means a different live PTY, so actual transport must surface refusal without recover/create, keeping original identity. Prevents destructive duplicate agent recovery.; fails closed when an older HUB cannot recover an expired SSH pane — Old HUB method_not_found is scripted mock refusal/error echo with no actual skewed host; repeats generic recovery failure propagation. Retires old-host recovery fallback refusal example.; names a held recovery's stopped WSL distro in readable copy, not the raw hold code — Pins exact WSL stopped-distro error prose after mock code; translation/copy assertion with no actual held recovery behavior. Retires readable-copy alarm.. Retained tests do not replace these alarms. Dated unrelated evidence remains scoped to its original execution; no historical source/import-closure equivalence, fresh execution, real network/provider/SSH, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit 3318 reduces runtime-environment-ssh-state.test.ts, intentionally losing metadata membership-pruning/new-target-only-read and other-environment/local-bucket isolation alarms. Preserve generation/failed-full-refresh assertion and unknown-target authoritative-list reread; these narrower cases are not equivalent replacements. The unchanged active two-case Linux reconnect materialization/sidebar receipt and covered platform retain their exact scope and do not validate the reduced SSH state selector. Preserve unrelated SSH assertions, selectors and archived history. No fresh SSH discovery, provider/PTY/network, rendered, mobile, mixed-version, cross-platform or full-gate execution is claimed. Audit3315 execution amendment: the reduced two-suite reconnect selector passed on Linux (2 cases). Original source-review statements about no fresh execution describe the earlier static review; this new receipt validates only these two local deterministic unit cases, not the complete gate or physical/runtime/rendered/provider/platform parity. Historical seven-case macOS receipt remains archived verbatim. Audit 3312 retires the ordinary six-pane distinct-live-handle reconnect/resubscription alarm from paired-reconnect-multi-pane-materialization.test.ts. The unchanged parked-pane activation/rematerialization case remains narrower and is not an equivalent replacement. The complete prior seven-contract macOS receipt is archived as historical evidence; it does not validate the reduced selector. No fresh socket, PTY, sleep/wake, provider, platform, mobile, mixed-version or rendered execution is claimed. Audit3096: remove the deleted reconnect-banner selector and its two UI aliases. The reduced recovery-state selector retains only the deadline cancelling pending backoff and explicit retry owning a new epoch alias; healthy-replacement stale-schedule and independent caller-cutoff cancellation aliases retire. Other retained state cases cover reentrant retry, owner settlement and same-epoch parked revival, without replacing those removed alarms. Prior admission-selector retirement, archived July 28 receipt, unrelated selectors/claims/receipts and old gaps remain unchanged; no fresh execution is claimed. Audit3086: retire the destroyed fresh-session fallback settlement/non-destructive reattach alias and its direct selector; retain the detach/attach selector and assertion unchanged. The retained admission cases cover adopt-before-data and explicitly buffered-death admission without a new spawn, without replacing fallback retirement. July 28 evidence was already archived by audit3077; no duplicate retirement or new execution is claimed. Audit2709 removes src/renderer/src/runtime/web-session-tabs-sync/inventory/remote-runtime-session-tabs-inflight.test.ts: intentionally retire waiting out an older inventory and sharing a fresh post-operation request among concurrent callers. No equivalent replacement or fresh execution is claimed. Dated receipts remain historical evidence for their unchanged selectors only; they do not validate the reduced commands or full current gate. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/ssh/connection/ssh-connection-manager.test.ts: tears a failed startup down quietly, so its error is not replaced by a disconnect; marks a dial that never reached the host, so setup reports SSH’s reason; removes the registration when bulk teardown fails; leaves a connection whose own reconnect is asking the user alone; clears the pool entry when the closed connection is still the registered one; still reuses a connection that is already up; dials a user's connection test. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2052 (sources2049/2050/2051): Remove complete low-value restored-pane-title and pane-visibility-identity suites and their current selectors. Their supplied snapshot/title and nullable identity-comparison alarms are intentionally lost without replacement. Unrelated dated evidenceRuns remain unchanged and do not validate the reduced commands. No fresh gate execution, actual PTY/provider, rendered, remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1983: Delete the terminal-create idempotency forwarding suite and its prospective selector. Preserve2 unrelated receipts without claiming the lost forwarding alarm was replaced. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Delete complete transport-unmount and queued-initial-CWD helper suites: despite lifecycle-shaped fixtures, the unmount owner returns a Boolean PTY-id predicate, while CWD cases check nullish field selection and callback counts. Lose their detach/destroy/teardown and one-shot-CWD supplied examples. Partial queued-pane-startup loses three identical/empty/nonowner identity examples, retaining four exact one-shot/replacement ownership callbacks. No assertion object maps to these three sources, so unrelated alias objects remain byte-exact. Preserve the current81ed prior removal of pane-split-startup; stale bd948 source metadata snapshots are not replayed. No actual process/PTY startup, transport shutdown, live SSH or rendered recovery is proven by this metadata change. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1925 (sources1922/1923): Delete the sole supplied public-SSH-state spread/sanitized-error projection and its provider-authority-pair alias. Also delete the complete tiny one-shot split-startup wrapper suite: callback-visible temporary field/reset, sequential payload and thrown-sentinel reset alarms disappear. No SSH provider epoch handoff, connection, process startup or actual terminal split was performed by either deleted suite. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1903 removes whole mocked detach, supplied geometry and/or close-request suites selected by this gate. Their pending-CWD/PTY-binding argument/order, fabricated hit-test and close bookkeeping alarms are intentionally lost without replacement. Valid remaining selectors/assertions and unchanged-selector execution receipts retain their original scope. Reduced unit selections have no fresh broad gate, real PTY/provider, rendered focus, or measured-budget validation. Historical prior account (preserved verbatim): Audit1645 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1342 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Audit1301 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Deterministic renderer coverage proves retained native and runtime SSH payloads are admitted through production routes only with valid complete authority, stale cleanup cannot unregister a replacement runtime terminal, direct SSH Git and folder panes keep their PTY bindings through disconnect and reconnect, one authority chain stops after two automatic attempts even when each timeout exceeds the rolling window, rejected acknowledgements mutate no store maps, and one shared exact attempt admits every concurrent split-pane spawn and reattach while preserving the first PTY as the tab fallback. A later sibling failure rotates the tab once, stale callbacks from the prior attempt mutate no state, split remount activity suppression is counted per leaf, primary PTY exit promotes a bound survivor or preserves an empty continuation gap for a late sibling, and primary, non-primary, or null-PTY detach preserves exact authority on both resulting tabs. Intentional pane disposal cancels its settlement timer without breaking StrictMode remount timeout ownership. A mounted remote-runtime terminal survives repeated transport partitions without changing PTY identity. A real encrypted-WebSocket oracle proves a successful reachability probe can replace a pre-ready shared-control socket without rejecting or duplicating the waiting RPC. Direct SSH coordinator tests cover immediate terminal finalization, hydration correction, damping, bounded retry, and telemetry non-interference. Client/server heartbeat tests cover timer suspension, socket generations fence stale callbacks, cold restored-terminal attachment retries, cached pixels remain unhealthy until authoritative replay, automatic retries stop after one minute, manual reconnect preserves the PTY, and pane closure releases recovery UI state. Current-transport recovery clears every error that transport surfaced without clearing or displaying a sibling pane's errors, while transport suppression, pane retention, and the rendered surface are independently bounded. Current macOS Electron journeys against an ephemeral Linux Docker SSH target cover exact-authority repo/worktree hydration, live terminal recovery after disconnect/reconnect, and eager six-terminal remount after renderer reload. A Windows remote-runtime smoke covers reachability and PTY round-trip. Multi-target live fanout, paired-close, WSL, and patched live partition journeys remain gaps. The test-value audit narrowed resolved-worktree-execution-host.test.ts to cache reuse and invalidation. Its direct hydrated-worktree, missing-folder, restored-owner, host-stamp and empty-runtime selection alarms are lost. Other routing and recovery suites do not establish equivalent selector coverage; historical run commands and results remain historical. The test-value audit removes standalone unwritten/released renderer-authority and cross-scope request-count examples. The retained synthetic mirror/store/sidebar and pending-inventory checks do not establish real PTY byte ownership, SSH reconnection or equivalent replacement coverage; historical commands and results remain historical. The test-value audit removes direct join/label ledgers, immediate failure and negative-only stale/removal/partial-authority examples, plus the standalone retained/live event projection. Retained synthetic store/hydration compositions do not establish real SSH continuity, remote authority delivery or equivalent replacement alarms. Historical commands and results remain historical. The renderer scheduling fixture retains in-flight coalescing only. Its immediate publication and negative stale-SSH-cleanup call ledgers were removed; the retained SSH recovery evidence does not replace those alarms. The accepted-handle-events observer suite is removed, including its scoped listener and settlement-release assertions. These observer alarms are lost; retained SSH/transport journeys are not equivalent replacement coverage. The test-value audit removed repeated remote-handle rotation inventories and snapshot-first pending-restart migration examples from terminal-pty-identity-replacement.test.ts, plus direct foreground metadata setter, confirmation, evidence-enum, and prefix/worktree cleanup examples. Those rotation, pending-restart, snapshot-first migration, and foreground scalar-update alarms are lost. The retained replacement case observes pane and tab identities in one subscriber publication; it does not establish equivalent migration, process-evidence, or input-routing coverage. Historical commands and results remain historical. The test-value audit narrows terminals-hydration.test.ts to a real reconnect batch with one measured store publication and hydration-seeded history consumed by a subsequent visit/Back check. Direct split-layout, runtime/folder/floating restoration, dead-leaf focus, cold/known-absent SSH deferral, title, default-tab marker, navigation initialization, and hydrationSucceeded scalar examples are removed; those specific alarms are lost. No actual target-removal transition, live SSH connection, session writer, or persisted restart is exercised by the retained cases. The old target-scoped/snapshot assertion references are retired because the current file does not contain those oracles. Other suites and historical runs do not establish equivalent replacement coverage. Audit1299 removes tests/e2e/terminal-cold-activation-deferral.spec.ts. Private-state/work-budget/assembled-fixture alarms are intentionally lost; retained suites are not equivalent replacement coverage. No new runtime/platform evidence is claimed. Audit1301: src/renderer/src/runtime/remote-runtime-session-tabs-inflight.test.ts reduced. Direct dedupe eviction/count and equal receipt-position sample loses authored alarm. No equivalent replacement coverage is claimed. Audit1318: src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts: Retain real local encrypted WebSocket regressions for pre-ready socket replacement preserving a request, close-before-ready logical subscription cleanup, unrelated RPC surviving another deadline, and pending setup abort leaving a sibling pending. Host server is synthetic and uses production crypto; kept scenarios also retain internal diagnostics/memory assertions unchanged. Remove happy routing, authority-envelope, unknown-ID/log, cleanup enum, binary, keepalive/liveness and production-budget/private socket inventories; intentionally lose those alarms, no physical host authorization, independent crypto or remote provider claim. Reduced selectors need fresh validation; historical full-suite receipts do not validate the changed coverage. No equivalent replacement or physical-provider claim. Audit1342: src/renderer/src/hooks/ipc-events/direct-ssh-connect-reply-routing.test.ts removed. Initial and event-triggered partial-authority hydration fixture alarms disappear. src/renderer/src/components/terminal-pane/terminal-error-accumulation.test.ts removed. Multiline dedup/storm bounds, resource classification/collision, scoped clear/reconnect strip and1000-pane map count alarms disappear. No equivalent replacement coverage is claimed. Audit1396: src/renderer/src/components/terminal-pane/pty-connection-pending-spawn.spec.ts reduced. Lose standalone debug-state retention/log silence alarm. React StrictMode is not mounted; bindings manually simulate remount over mocked transport. No equivalent replacement coverage is claimed. The existing primary-selector receipt and its claims remain scoped to their unchanged sources; the broad optional command has no new execution result. Audit1400: src/main/ipc/ssh/ssh.test.ts reduced. Lose trivial missing target and mocked publication inventory. Preexisting unresolved ../ssh/ssh-port-scanner mock is recorded, not fixed. src/renderer/src/runtime/sync-runtime-graph-scheduling.test.ts removed. Removes whole coalescing call-count suite; no newest-state delivery or replacement claim. src/renderer/src/store/slices/terminal-pty-identity-replacement.test.ts reduced. Removes three no-op/work-count registrations; retains externally observed ownership consistency. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result. Audit1412: src/main/ssh/ssh-provider-authority.test.ts removed. Loses real AbortController revocation/target isolation/reentrancy outcomes, recreated-target generation-floor/session rollover behavior, stale mutation refusal and settled-registration cleanup alarms. These useful alarms are deliberately lost; no equivalent cancellation coverage is claimed. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result. Audit1743 removes the standalone line-height clamp/default and pane cwd fallback helper tests (5 authored cases). These trivial-helper alarms are intentionally lost, with no equivalent replacement. Only current commands/testFiles lose the deleted selectors; historical receipts and evidenceRuns remain unchanged and do not validate the reduced commands.", "motivatingLinks": [ "https://linear.app/stably/issue/STA-3107", "https://github.com/stablyai/orca/pull/12664", @@ -9619,12 +9365,12 @@ "https://github.com/stablyai/orca/issues/12902" ], "invariant": "SSH, WSL, and remote-runtime restore paths must treat provider listing failures and unknown liveness as unknown, not dead, while still avoiding duplicate spawn and clearing expired relay leases exactly once. Direct SSH disconnect, reconnect, and wake must keep PTY bindings and relay identity, and target snapshot hydration/reconnect cannot reset sibling SSH, local, WSL, or runtime-owned state. Every restored remote terminal must preserve its provider PTY identity, including the authoritative incarnation returned by a successful session-ID reattach. After a recoverable partition the same authenticated runtime must reattach the same PTY, reject detached input, apply the latest viewport, and report healthy only after authoritative replay. A successful one-shot reachability probe may replace a pre-ready shared-control socket, but waiting RPCs must continue onto the replacement under their original deadline without duplicate host delivery or retained request bytes. Automatic PTY recovery stops after one bounded minute without a fatal terminal error; a manual reconnect starts a newly fenced epoch against the same PTY, and closed panes retain no recovery UI state. Successful current-transport recovery must clear every stale error surfaced for that pane without clearing or displaying a sibling pane's error; a later genuine failure must remain visible. Each transport retains at most eight suppressed messages, each pane retains at most eight distinct messages, and the rendered surface retains at most 24 lines and 4,000 characters. One capability-gated terminal-create mutation must produce at most one host PTY across an unknown response outcome, remain manually retryable after cutoff, and never let a stale completion replace a newer pane lifecycle. Reconnect must alternate exact activation with authoritative inventory so neither a stale activation response nor an activation failure can strand or retire a pane, and activating a parked surface whose persisted binding was already retired must respawn it rather than report a changed owner after signalling its exit.", - "oracle": "Audit3096: remove the deleted reconnect-banner selector and its two UI aliases. The reduced recovery-state selector retains only the deadline cancelling pending backoff and explicit retry owning a new epoch alias; healthy-replacement stale-schedule and independent caller-cutoff cancellation aliases retire. Other retained state cases cover reentrant retry, owner settlement and same-epoch parked revival, without replacing those removed alarms. Prior admission-selector retirement, archived July 28 receipt, unrelated selectors/claims/receipts and old gaps remain unchanged; no fresh execution is claimed. Audit3086: retire the destroyed fresh-session fallback settlement/non-destructive reattach alias and its direct selector; retain the detach/attach selector and assertion unchanged. The retained admission cases cover adopt-before-data and explicitly buffered-death admission without a new spawn, without replacing fallback retirement. July 28 evidence was already archived by audit3077; no duplicate retirement or new execution is claimed. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/ssh/connection/ssh-connection-manager.test.ts: tears a failed startup down quietly, so its error is not replaced by a disconnect; marks a dial that never reached the host, so setup reports SSH’s reason; removes the registration when bulk teardown fails; leaves a connection whose own reconnect is asking the user alone; clears the pool entry when the closed connection is still the registered one; still reuses a connection that is already up; dials a user's connection test. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2052 (sources2049/2050/2051): Remove complete low-value restored-pane-title and pane-visibility-identity suites and their current selectors. Their supplied snapshot/title and nullable identity-comparison alarms are intentionally lost without replacement. Unrelated dated evidenceRuns remain unchanged and do not validate the reduced commands. No fresh gate execution, actual PTY/provider, rendered, remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1983: Delete the terminal-create idempotency forwarding suite and its prospective selector. Preserve2 unrelated receipts without claiming the lost forwarding alarm was replaced. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Delete complete transport-unmount and queued-initial-CWD helper suites: despite lifecycle-shaped fixtures, the unmount owner returns a Boolean PTY-id predicate, while CWD cases check nullish field selection and callback counts. Lose their detach/destroy/teardown and one-shot-CWD supplied examples. Partial queued-pane-startup loses three identical/empty/nonowner identity examples, retaining four exact one-shot/replacement ownership callbacks. No assertion object maps to these three sources, so unrelated alias objects remain byte-exact. Preserve the current81ed prior removal of pane-split-startup; stale bd948 source metadata snapshots are not replayed. No actual process/PTY startup, transport shutdown, live SSH or rendered recovery is proven by this metadata change. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1925 (sources1922/1923): Delete the sole supplied public-SSH-state spread/sanitized-error projection and its provider-authority-pair alias. Also delete the complete tiny one-shot split-startup wrapper suite: callback-visible temporary field/reset, sequential payload and thrown-sentinel reset alarms disappear. No SSH provider epoch handoff, connection, process startup or actual terminal split was performed by either deleted suite. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1903 removes whole mocked detach, supplied geometry and/or close-request suites selected by this gate. Their pending-CWD/PTY-binding argument/order, fabricated hit-test and close bookkeeping alarms are intentionally lost without replacement. Valid remaining selectors/assertions and unchanged-selector execution receipts retain their original scope. Reduced unit selections have no fresh broad gate, real PTY/provider, rendered focus, or measured-budget validation. Historical prior account (preserved verbatim): Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Deterministic tests cover bounded stale-handle replacement, suspended heartbeat clocks, cold and established subscription failure, ten partition/recovery cycles, automatic-recovery cutoff, manual reconnect, and direct SSH binding retention. They assert SSH state changes leave PTY bindings in place, relay identity survives, and another target/local/WSL/runtime panes remain byte-identical through target snapshot hydration and reconnect. Both remount callbacks consume split-count activity suppression, intentional dispose emits no failure/timeout, and a same-attempt StrictMode remount still owns one timeout. Hydration clears an untrusted PTY hint without clearing its current pending owner, healthy current-authority bindings suppress correction, hydration finalizes once, and reconnect emits no paired close lifecycle. A provider-level session-ID reattach returns an incarnation, then a legacy exit without an incarnation must resolve to that returned identity rather than minting a fallback identity. The shared-control oracle withholds the first encrypted ready frame, starts one RPC, triggers the successful-probe refresh, then requires exactly two client connections, one host request, a successful response, zero pending calls, and zero retained request bytes. Tests also assert one unsubscribe per remote-runtime epoch, observable recovery phases, stable PTY identity, resumed snapshot/output/input, no healthy state before replay, no retry or input after cutoff, a new manual epoch against the same PTY, quiet recovery UI with an explicit Reconnect action, pane-close state cleanup, one stable create mutation id, old-runtime no-retry behavior, cross-process PTY adoption, and bounded in-flight coordination. A focused recovery oracle surfaces two distinct failures through one transport, completes authoritative replay, and requires both matching clear callbacks; pane-state tests require only the active pane's error to render, matching-pane recovery to preserve sibling and unrelated errors, dismissal to re-admit later failures, and distinct storms to retain only the newest eight messages within 24 lines and 4,000 characters. The retained store replacement assertion observes one atomic pane/tab subscriber publication; repeated rotations and snapshot-first pending-restart migration no longer have their direct store examples.", + "oracle": "Audit3368 narrows stream-reconnect coverage to the actual ten synthetic transport epochs retaining one PTY identity, accepting and holding detached input for exactly-once later delivery, current decoded output and per-epoch subscription release. Prior rejection wording was inaccurate. Phase/backoff/cutoff/manual reconnect and parser/OSC/pause/retained-image/fatal/latch/claim/early-close alarms are intentionally lost without equivalent replacement. The Linux multi-pane reconnect receipt remains verbatim with its original scope; no fresh live SSH/provider/PTY/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit3359 retires whole host-surface-replacement and create-handoff suites, removing their compound unit command tokens, test-file entries and assertion references. Fake polling/deadline/subscription, supplied stale-handle ownership, close and replacement examples are intentionally lost without equivalent replacement. The unrelated Linux paired multi-pane reconnect receipt stays verbatim with its original scope. No fresh SSH/provider/network/PTY recovery, historical-import, mobile, mixed-version or cross-platform validation is claimed. Audit3342 retires the complete client create-outcome identity/options/recovery suite and the malformed-or-contradictory repo-owner response matrix. Client replay identity, options, no-downgrade, quiescence/budget/manual retry, authoritative probe-error and malformed-owner refusal alarms are intentionally lost without equivalent replacement. Remaining repo-owner late catalog and old-host re-adoption boundaries do not replace them. The unrelated Linux paired-reconnect receipt stays verbatim with its original scope. Surviving selectors are unexecuted here; no fresh SSH/provider/process-deduplication, mobile, mixed-version or cross-platform validation is claimed. Audit3326 adopts reconciled source audit3324 and intentionally retires these low-value examples and their regression alarms: keeps a sidebar row for every still-live pane after a long sleep — Whole suite: 279 lines manually replay renderer ownership registry/status writes, snapshot patch/set, six-pane fixture inventory, and sidebar selectors/builders; expected pane IDs are production-computed. Does not run sleep/wake/transport or actual sidebar entry. Retires reconnect row-preservation assembly alarm.; still retires the regular TUI surface after an explicit terminal exit — Ordinary explicit-exit callback/map cleanup is repeated in the stale/new stream lifecycle case below. Retires separate regular-TUI baseline; keeper is not equivalent process/UI proof.; asks the HUB to recover an expired SSH pane and rebinds the host identity — Expired SSH owner error must ask the owning HUB to recover, then adopt fixed replacement handle, resubscribe and report rebind; actual transport dispatch and handle state prevent wrong-client recovery.; does not recover a pane whose relay reply was an identity mismatch — Identity mismatch means a different live PTY, so actual transport must surface refusal without recover/create, keeping original identity. Prevents destructive duplicate agent recovery.; fails closed when an older HUB cannot recover an expired SSH pane — Old HUB method_not_found is scripted mock refusal/error echo with no actual skewed host; repeats generic recovery failure propagation. Retires old-host recovery fallback refusal example.; names a held recovery's stopped WSL distro in readable copy, not the raw hold code — Pins exact WSL stopped-distro error prose after mock code; translation/copy assertion with no actual held recovery behavior. Retires readable-copy alarm.. Retained tests do not replace these alarms. Dated unrelated evidence remains scoped to its original execution; no historical source/import-closure equivalence, fresh execution, real network/provider/SSH, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit 3318 reduces runtime-environment-ssh-state.test.ts, intentionally losing metadata membership-pruning/new-target-only-read and other-environment/local-bucket isolation alarms. Preserve generation/failed-full-refresh assertion and unknown-target authoritative-list reread; these narrower cases are not equivalent replacements. The unchanged active two-case Linux reconnect materialization/sidebar receipt and covered platform retain their exact scope and do not validate the reduced SSH state selector. Preserve unrelated SSH assertions, selectors and archived history. No fresh SSH discovery, provider/PTY/network, rendered, mobile, mixed-version, cross-platform or full-gate execution is claimed. Audit 3312 retires the ordinary six-pane distinct-live-handle reconnect/resubscription alarm from paired-reconnect-multi-pane-materialization.test.ts. The unchanged parked-pane activation/rematerialization case remains narrower and is not an equivalent replacement. The complete prior seven-contract macOS receipt is archived as historical evidence; it does not validate the reduced selector. No fresh socket, PTY, sleep/wake, provider, platform, mobile, mixed-version or rendered execution is claimed. Audit3096: remove the deleted reconnect-banner selector and its two UI aliases. The reduced recovery-state selector retains only the deadline cancelling pending backoff and explicit retry owning a new epoch alias; healthy-replacement stale-schedule and independent caller-cutoff cancellation aliases retire. Other retained state cases cover reentrant retry, owner settlement and same-epoch parked revival, without replacing those removed alarms. Prior admission-selector retirement, archived July 28 receipt, unrelated selectors/claims/receipts and old gaps remain unchanged; no fresh execution is claimed. Audit3086: retire the destroyed fresh-session fallback settlement/non-destructive reattach alias and its direct selector; retain the detach/attach selector and assertion unchanged. The retained admission cases cover adopt-before-data and explicitly buffered-death admission without a new spawn, without replacing fallback retirement. July 28 evidence was already archived by audit3077; no duplicate retirement or new execution is claimed. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/ssh/connection/ssh-connection-manager.test.ts: tears a failed startup down quietly, so its error is not replaced by a disconnect; marks a dial that never reached the host, so setup reports SSH’s reason; removes the registration when bulk teardown fails; leaves a connection whose own reconnect is asking the user alone; clears the pool entry when the closed connection is still the registered one; still reuses a connection that is already up; dials a user's connection test. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2052 (sources2049/2050/2051): Remove complete low-value restored-pane-title and pane-visibility-identity suites and their current selectors. Their supplied snapshot/title and nullable identity-comparison alarms are intentionally lost without replacement. Unrelated dated evidenceRuns remain unchanged and do not validate the reduced commands. No fresh gate execution, actual PTY/provider, rendered, remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1983: Delete the terminal-create idempotency forwarding suite and its prospective selector. Preserve2 unrelated receipts without claiming the lost forwarding alarm was replaced. Changed-source prior results do not validate reduced-source bytes. No fresh execution, equivalent replacement, red/green, measured budget, soak, provider/PTY, rendered, live remote/mobile or cross-platform result is claimed. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Delete complete transport-unmount and queued-initial-CWD helper suites: despite lifecycle-shaped fixtures, the unmount owner returns a Boolean PTY-id predicate, while CWD cases check nullish field selection and callback counts. Lose their detach/destroy/teardown and one-shot-CWD supplied examples. Partial queued-pane-startup loses three identical/empty/nonowner identity examples, retaining four exact one-shot/replacement ownership callbacks. No assertion object maps to these three sources, so unrelated alias objects remain byte-exact. Preserve the current81ed prior removal of pane-split-startup; stale bd948 source metadata snapshots are not replayed. No actual process/PTY startup, transport shutdown, live SSH or rendered recovery is proven by this metadata change. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1925 (sources1922/1923): Delete the sole supplied public-SSH-state spread/sanitized-error projection and its provider-authority-pair alias. Also delete the complete tiny one-shot split-startup wrapper suite: callback-visible temporary field/reset, sequential payload and thrown-sentinel reset alarms disappear. No SSH provider epoch handoff, connection, process startup or actual terminal split was performed by either deleted suite. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1903 removes whole mocked detach, supplied geometry and/or close-request suites selected by this gate. Their pending-CWD/PTY-binding argument/order, fabricated hit-test and close bookkeeping alarms are intentionally lost without replacement. Valid remaining selectors/assertions and unchanged-selector execution receipts retain their original scope. Reduced unit selections have no fresh broad gate, real PTY/provider, rendered focus, or measured-budget validation. Historical prior account (preserved verbatim): Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Deterministic tests cover bounded stale-handle replacement, suspended heartbeat clocks, cold and established subscription failure, ten partition/recovery cycles, automatic-recovery cutoff, manual reconnect, and direct SSH binding retention. They assert SSH state changes leave PTY bindings in place, relay identity survives, and another target/local/WSL/runtime panes remain byte-identical through target snapshot hydration and reconnect. Both remount callbacks consume split-count activity suppression, intentional dispose emits no failure/timeout, and a same-attempt StrictMode remount still owns one timeout. Hydration clears an untrusted PTY hint without clearing its current pending owner, healthy current-authority bindings suppress correction, hydration finalizes once, and reconnect emits no paired close lifecycle. A provider-level session-ID reattach returns an incarnation, then a legacy exit without an incarnation must resolve to that returned identity rather than minting a fallback identity. The shared-control oracle withholds the first encrypted ready frame, starts one RPC, triggers the successful-probe refresh, then requires exactly two client connections, one host request, a successful response, zero pending calls, and zero retained request bytes. Tests also assert one unsubscribe per remote-runtime epoch, observable recovery phases, stable PTY identity, resumed snapshot/output/input, no healthy state before replay, no retry or input after cutoff, a new manual epoch against the same PTY, quiet recovery UI with an explicit Reconnect action, pane-close state cleanup, one stable create mutation id, old-runtime no-retry behavior, cross-process PTY adoption, and bounded in-flight coordination. A focused recovery oracle surfaces two distinct failures through one transport, completes authoritative replay, and requires both matching clear callbacks; pane-state tests require only the active pane's error to render, matching-pane recovery to preserve sibling and unrelated errors, dismissal to re-admit later failures, and distinct storms to retain only the newest eight messages within 24 lines and 4,000 characters. The retained store replacement assertion observes one atomic pane/tab subscriber publication; repeated rotations and snapshot-first pending-restart migration no longer have their direct store examples.", "commands": [ - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts src/renderer/src/runtime/web-session-tabs-sync/agent-status/paired-reconnect-sidebar-agent-count.test.ts --reporter=dot", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/resolved-worktree-execution-host.test.ts src/renderer/src/components/terminal/background-terminal-worktree-mount.test.ts src/renderer/src/components/terminal-pane/mounting/queued-pane-startup.test.ts src/renderer/src/components/terminal-pane/parking/one-shot-park-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts src/renderer/src/store/terminals/terminal-pty-identity-replacement.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts --reporter=dot", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal/background-terminal-worktree-mount.test.ts src/renderer/src/components/terminal-pane/mounting/queued-pane-startup.test.ts src/renderer/src/components/terminal-pane/parking/one-shot-park-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts src/renderer/src/store/terminals/terminal-pty-identity-replacement.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/ipc/pty-transport-detach-attach-handoff.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-expired-pane-recovery.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-outcome-recovery.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/recovery/remote-runtime-pty-recovery-state.test.ts src/shared/remote-runtime/remote-runtime-socket-liveness.test.ts src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts src/shared/remote-runtime/control/remote-runtime-shared-control-socket-generation.test.ts src/shared/remote-runtime/remote-runtime-client-error-classification.test.ts src/main/runtime/rpc/remote-runtime-server-heartbeat.test.ts src/main/runtime/terminal/launch/orca-runtime-terminal-create-idempotency.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-expired-pane-recovery.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/recovery/remote-runtime-pty-recovery-state.test.ts src/shared/remote-runtime/remote-runtime-socket-liveness.test.ts src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts src/shared/remote-runtime/control/remote-runtime-shared-control-socket-generation.test.ts src/shared/remote-runtime/remote-runtime-client-error-classification.test.ts src/main/runtime/rpc/remote-runtime-server-heartbeat.test.ts src/main/runtime/terminal/launch/orca-runtime-terminal-create-idempotency.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/ui/workspace-navigation-history-hydration.test.ts src/renderer/src/store/repos/repos-ssh-host-reconciliation.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts --reporter=dot", "pnpm exec vitest run --config config/vitest.config.ts src/main/ipc/ssh/ssh.test.ts src/main/ipc/worktrees-ssh-repo-owner-resolution.test.ts src/main/ssh/connection/ssh-connection-manager.test.ts src/main/ssh/connection/ssh-connection.test.ts src/preload/ssh-authority-forwarding.test.ts src/renderer/src/runtime/rpc/subscriptions/runtime-client-events.test.ts src/renderer/src/runtime/hosts/ssh/runtime-environment-ssh-state.test.ts src/shared/ssh-retained-payload-admission.test.ts --reporter=dot", "pnpm exec electron-vite build --mode e2e", @@ -9633,18 +9379,13 @@ ], "testFiles": [ "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts", - "src/renderer/src/runtime/web-session-tabs-sync/agent-status/paired-reconnect-sidebar-agent-count.test.ts", - "src/renderer/src/lib/resolved-worktree-execution-host.test.ts", "src/renderer/src/components/terminal/background-terminal-worktree-mount.test.ts", "src/renderer/src/components/terminal-pane/mounting/queued-pane-startup.test.ts", "src/renderer/src/components/terminal-pane/parking/one-shot-park-replay.test.ts", "src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts", "src/renderer/src/components/terminal-pane/pty-transport/ipc/pty-transport-detach-attach-handoff.test.ts", - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts", "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts", "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-expired-pane-recovery.test.ts", - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-outcome-recovery.test.ts", - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts", "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/recovery/remote-runtime-pty-recovery-state.test.ts", "src/renderer/src/store/terminals/terminal-pty-identity-replacement.test.ts", "src/shared/remote-runtime/remote-runtime-socket-liveness.test.ts", @@ -9669,44 +9410,13 @@ { "file": "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts", "assertions": [ - "six panes sharing one dropped multiplex connection each resubscribe to a distinct live host handle", "a pane parked while the client slept is authoritatively activated and rematerialized without leaving any pane handle null" ] }, - { - "file": "src/renderer/src/runtime/web-session-tabs-sync/agent-status/paired-reconnect-sidebar-agent-count.test.ts", - "assertions": [ - "after a long sleep every live host PTY and tab retains its client-owned sidebar agent row" - ] - }, - { - "file": "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts", - "assertions": [ - "a stale web-mirror handle polls until a different ready handle is published without resubscribing the stale handle", - "replacement does not emit pane exit or disconnect callbacks and explicit terminal exit still retires the mirror", - "replacement polling and each in-flight request share a 15-second deadline, then accepted snapshots own recovery without input re-arming polling" - ] - }, { "file": "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts", "assertions": [ - "recovery exposes connecting, recovering, backoff, connected, and fatal-offline phases with fenced epochs", - "ten partition cycles retain one PTY identity, reject detached input, and unsubscribe each epoch exactly once", - "automatic retries stop after one minute with no fatal error, no further requests, and no stale input", - "manual reconnect starts a new epoch, resubscribes the same PTY exactly once, and becomes healthy only after its snapshot" - ] - }, - { - "file": "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-outcome-recovery.test.ts", - "assertions": [ - "unknown terminal-create recovery stops all request activity after one minute without a fatal error, clips post-probe RPC timeouts to the remaining budget, then manual retry re-probes capability and reconciles the same mutation", - "an authoritative capability-probe failure replaces the stale connectivity error" - ] - }, - { - "file": "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts", - "assertions": [ - "a stale create completion cannot replace or close a newer attachment, including when two runtimes use the same raw handle" + "ten synthetic partition cycles retain one PTY identity, deliver each held detached input exactly once and release each epoch subscription exactly once; decoded live input/output remains current" ] }, { @@ -9767,15 +9477,8 @@ { "file": "src/renderer/src/runtime/hosts/ssh/runtime-environment-ssh-state.test.ts", "assertions": [ - "membership refresh prunes removed targets and reads only newly joined targets", "held replies from an old generation cannot replace a newer generation; failed full refresh preserves live state behind queued metadata", - "positive environment and local state remain isolated; an unknown target triggers an authoritative list reread" - ] - }, - { - "file": "src/renderer/src/store/repos/repos-ssh-host-reconciliation.test.ts", - "assertions": [ - "a provider result becomes stale when same-ID repo ownership turns malformed or contradictory during the await" + "an unknown target triggers an authoritative list reread" ] }, { @@ -9793,14 +9496,14 @@ ], "evidenceRuns": [ { - "date": "2026-08-23", + "date": "2026-11-11", "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/paired-reconnect-multi-pane-materialization.test.ts src/renderer/src/runtime/paired-reconnect-sidebar-agent-count.test.ts --reporter=dot", + "platform": "linux", + "command": "ORCA_BACKGROUND_LAUNCH=1 pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts --reporter=dot --maxWorkers=2", + "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts --reporter=dot", "result": "passed", - "durationSeconds": 2.54, - "summary": "Seven deterministic STA-3107 contracts passed across six-pane multiplex rematerialization and client-owned sidebar-row retention after sleep/wake.", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts src/renderer/src/runtime/web-session-tabs-sync/agent-status/paired-reconnect-sidebar-agent-count.test.ts --reporter=dot" + "durationSeconds": 1.99, + "summary": "Audit3329 focused candidate run: 1 suite / 1 deterministic unit case passed for parked-pane reconnect materialization. currentCommand names the same gate selector; executed command adds background launch and two-worker flags. This is local fake-runtime/store evidence only, not the complete gate, authenticated SSH/PTY/network, rendered Electron, provider, sleep/wake, mobile, mixed-version or cross-platform validation. Re-executed after updating onto main 985176b11bbb92175043a8d302581412d703e81c; unchanged finite reviewed source and owner identities." } ], "runtimeBudget": { @@ -9825,6 +9528,9 @@ "Include reconnect/polling artifacts that identify provider, connection id, and lease state." ], "knownGaps": [ + "NEXT65 current scope qualification: The NEXT65 knownGaps entries below govern the changed selectors and qualify any broader coverage implication in this gate’s unchanged oracle/coverageNotes narratives. Those narratives and preserved dated evidenceRuns retain their historical text and original exact execution scopes only; no fresh execution, transferred pass or equivalent replacement coverage is claimed. Upstream case removals remain upstream; original NEXT65 proposal descriptions grant no duplicate retirement credit.", + "NEXT65 active selector scope reduction (including directory-selected whole-file retirements): src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts. Remove complete registrations or registrar files within the selected scope for src/renderer/src/components/terminal-pane/pty-connection/spawn/pty-connection-split-spawn.spec.ts. Intentionally lose these named regression alarms without replacement: clears the mobile-fit pane binding when the pane connection is disposed — Pane dispose clearing the mobile-fit binding and PTY dataset loses this direct example.; continues post-spawn size reconcile after a transient mobile presence lock — Size reconciliation continuing after a transient phone-presence lock loses this direct example.; spawns the delayed primary pane of an issue-command split when its sibling owns the tab PTY fallback — Delayed primary split spawning independently after a sibling acquires tab fallback loses this direct example.; does not reuse a sibling split pane pending spawn after remount — Remounted primary adopting its own pending PTY rather than the sibling spawn loses this direct example.; replays a stable-pane adoption without submitting the resume command — Stable-pane adoption replay preserving replay-before-live ordering and suppressing resume command loses this direct example.; forwards focus and hover reports without claiming a parked mirror (#26469) — Passive focus/hover forwarding without stealing mirror ownership, then intended Ctrl+C/click claiming, loses this direct example.. Surviving parent statements and sibling registrations are preserved, but these reduced parent selectors have no fresh execution or transferred historical pass. Unrelated complete dated receipts retain only their original exact scopes; no equivalent replacement, rendered UI, provider, mobile, or cross-platform coverage is claimed.", + "NEXT65 historical original active parent-selector fields (verbatim native JSON values; not current coverage):\ncommands: [\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts --reporter=dot\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal/background-terminal-worktree-mount.test.ts src/renderer/src/components/terminal-pane/mounting/queued-pane-startup.test.ts src/renderer/src/components/terminal-pane/parking/one-shot-park-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts src/renderer/src/store/terminals/terminal-pty-identity-replacement.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/ipc/pty-transport-detach-attach-handoff.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-expired-pane-recovery.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-outcome-recovery.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/recovery/remote-runtime-pty-recovery-state.test.ts src/shared/remote-runtime/remote-runtime-socket-liveness.test.ts src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts src/shared/remote-runtime/control/remote-runtime-shared-control-socket-generation.test.ts src/shared/remote-runtime/remote-runtime-client-error-classification.test.ts src/main/runtime/rpc/remote-runtime-server-heartbeat.test.ts src/main/runtime/terminal/launch/orca-runtime-terminal-create-idempotency.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/store/slices/ui/workspace-navigation-history-hydration.test.ts src/renderer/src/store/repos/repos-ssh-host-reconciliation.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts --reporter=dot\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/main/ipc/ssh/ssh.test.ts src/main/ipc/worktrees-ssh-repo-owner-resolution.test.ts src/main/ssh/connection/ssh-connection-manager.test.ts src/main/ssh/connection/ssh-connection.test.ts src/preload/ssh-authority-forwarding.test.ts src/renderer/src/runtime/rpc/subscriptions/runtime-client-events.test.ts src/renderer/src/runtime/hosts/ssh/runtime-environment-ssh-state.test.ts src/shared/ssh-retained-payload-admission.test.ts --reporter=dot\",\n \"pnpm exec electron-vite build --mode e2e\",\n \"pnpm run build:web-from-renderer\",\n \"SKIP_BUILD=1 pnpm exec playwright test tests/e2e/paired-remote-terminal-materialization-reconnect.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\"\n ]\ntestFiles: [\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts\",\n \"src/renderer/src/components/terminal/background-terminal-worktree-mount.test.ts\",\n \"src/renderer/src/components/terminal-pane/mounting/queued-pane-startup.test.ts\",\n \"src/renderer/src/components/terminal-pane/parking/one-shot-park-replay.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/ipc/pty-transport-detach-attach-handoff.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-expired-pane-recovery.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-outcome-recovery.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/recovery/remote-runtime-pty-recovery-state.test.ts\",\n \"src/renderer/src/store/terminals/terminal-pty-identity-replacement.test.ts\",\n \"src/shared/remote-runtime/remote-runtime-socket-liveness.test.ts\",\n \"src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts\",\n \"src/shared/remote-runtime/control/remote-runtime-shared-control-socket-generation.test.ts\",\n \"src/shared/remote-runtime/remote-runtime-client-error-classification.test.ts\",\n \"src/main/runtime/rpc/remote-runtime-server-heartbeat.test.ts\",\n \"src/main/runtime/terminal/launch/orca-runtime-terminal-create-idempotency.test.ts\",\n \"tests/e2e/paired-remote-terminal-materialization-reconnect.spec.ts\",\n \"src/renderer/src/store/slices/ui/workspace-navigation-history-hydration.test.ts\",\n \"src/renderer/src/store/repos/repos-ssh-host-reconciliation.test.ts\",\n \"src/main/ipc/ssh/ssh.test.ts\",\n \"src/main/ipc/worktrees-ssh-repo-owner-resolution.test.ts\",\n \"src/main/ssh/connection/ssh-connection-manager.test.ts\",\n \"src/main/ssh/connection/ssh-connection.test.ts\",\n \"src/preload/ssh-authority-forwarding.test.ts\",\n \"src/renderer/src/runtime/rpc/subscriptions/runtime-client-events.test.ts\",\n \"src/renderer/src/runtime/hosts/ssh/runtime-environment-ssh-state.test.ts\",\n \"src/shared/ssh-retained-payload-admission.test.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts\",\n \"assertions\": [\n \"a pane parked while the client slept is authoritatively activated and rematerialized without leaving any pane handle null\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts\",\n \"assertions\": [\n \"a stale web-mirror handle polls until a different ready handle is published without resubscribing the stale handle\",\n \"replacement does not emit pane exit or disconnect callbacks and explicit terminal exit still retires the mirror\",\n \"replacement polling and each in-flight request share a 15-second deadline, then accepted snapshots own recovery without input re-arming polling\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts\",\n \"assertions\": [\n \"recovery exposes connecting, recovering, backoff, connected, and fatal-offline phases with fenced epochs\",\n \"ten partition cycles retain one PTY identity, reject detached input, and unsubscribe each epoch exactly once\",\n \"automatic retries stop after one minute with no fatal error, no further requests, and no stale input\",\n \"manual reconnect starts a new epoch, resubscribes the same PTY exactly once, and becomes healthy only after its snapshot\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-outcome-recovery.test.ts\",\n \"assertions\": [\n \"unknown terminal-create recovery stops all request activity after one minute without a fatal error, clips post-probe RPC timeouts to the remaining budget, then manual retry re-probes capability and reconciles the same mutation\",\n \"an authoritative capability-probe failure replaces the stale connectivity error\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts\",\n \"assertions\": [\n \"a stale create completion cannot replace or close a newer attachment, including when two runtimes use the same raw handle\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/recovery/remote-runtime-pty-recovery-state.test.ts\",\n \"assertions\": [\n \"the automatic-recovery deadline cancels pending backoff and a manual retry owns a new epoch\"\n ]\n },\n {\n \"file\": \"src/shared/remote-runtime/remote-runtime-socket-liveness.test.ts\",\n \"assertions\": [\n \"a suspended client receives a fresh probe deadline after resume and post-resume activity clears it\"\n ]\n },\n {\n \"file\": \"src/main/runtime/terminal/launch/orca-runtime-terminal-create-idempotency.test.ts\",\n \"assertions\": [\n \"one authenticated client/worktree mutation derives a stable server-owned terminal handle\",\n \"an unknown-outcome retry adopts the same provider PTY after runtime-process restart without rerunning startup\",\n \"retry inventory failure, missing same-worktree identity metadata, or ownership mismatch fails closed without spawning\",\n \"in-flight mutation coordination is bounded and releases capacity after settlement\"\n ]\n },\n {\n \"file\": \"src/main/ssh/connection/ssh-connection-manager.test.ts\",\n \"assertions\": [\n \"disconnect invalidates a pending transport attempt immediately so late rejection or resolution cannot remove the replacement\"\n ]\n },\n {\n \"file\": \"src/main/ssh/connection/ssh-connection.test.ts\",\n \"assertions\": [\n \"late ssh2 ready and startup error events after disconnect cannot resurrect or overwrite disconnected state\"\n ]\n },\n {\n \"file\": \"src/preload/ssh-authority-forwarding.test.ts\",\n \"assertions\": [\n \"full authority crosses Electron IPC without loss\",\n \"partial authority becomes unknown for bounded reconciliation and malformed full authority is dropped\",\n \"variable-form host-qualified worktree requests retain fail-closed outcomes in their return type\"\n ]\n },\n {\n \"file\": \"src/shared/ssh-retained-payload-admission.test.ts\",\n \"assertions\": [\n \"retained connection states reject partial or malformed authority\",\n \"only partial compatibility authority can normalize to unknown for bounded direct-SSH reconciliation\",\n \"shared direct SSH authority admission requires bounded identifiers and a non-negative safe generation\"\n ]\n },\n {\n \"file\": \"src/renderer/src/runtime/rpc/subscriptions/runtime-client-events.test.ts\",\n \"assertions\": [\n \"partial runtime authority is rejected through the captured subscription callback before environment state receives it\"\n ]\n },\n {\n \"file\": \"src/renderer/src/runtime/hosts/ssh/runtime-environment-ssh-state.test.ts\",\n \"assertions\": [\n \"held replies from an old generation cannot replace a newer generation; failed full refresh preserves live state behind queued metadata\",\n \"an unknown target triggers an authoritative list reread\"\n ]\n },\n {\n \"file\": \"src/renderer/src/store/repos/repos-ssh-host-reconciliation.test.ts\",\n \"assertions\": [\n \"a provider result becomes stale when same-ID repo ownership turns malformed or contradictory during the await\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts\",\n \"assertions\": [\n \"a StrictMode remount joins the pending spawn instead of starting a second one\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/ipc/pty-transport-detach-attach-handoff.test.ts\",\n \"assertions\": [\n \"abandoning an obsolete reattach drops its data, replay, write-unavailable, and exit handlers without killing the durable PTY\"\n ]\n }\n ]", "Audit3077 reduces the IPC handoff suite while retaining the obsolete-reattach detach observer case and its alias. Removed nominal no-kill and gauge-cleanup alarms have no equivalent replacement.", "Audit3077 retires this complete dated receipt because its selected source was reduced. It does not validate the reduced selector. Original receipt verbatim:\n{\n \"date\": \"2026-07-28\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport-reattach-admission.test.ts src/renderer/src/components/terminal-pane/pty-transport-detach-attach-handoff.test.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 1.48,\n \"summary\": \"All 90 transport tests passed, including pre-publication admission rejection, handler-complete non-destructive detach for obsolete SSH reattach transports, settled retirement of rejected or destroyed fresh fallbacks, and reported shutdown refusal.\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/ipc/pty-transport-reattach-admission.test.ts src/renderer/src/components/terminal-pane/pty-transport/ipc/pty-transport-detach-attach-handoff.test.ts\"\n }", "Audit3069 retires nominal spawn/resume/banner wiring, first-fit and lookup-budget variants, private pending-map checks, the split-CWD disposal suite and startup command/draft baseline variants. Distinct regression alarms are intentionally lost without equivalent replacement; retained ownership, cancellation and recovery cases remain. Existing selectors and dated evidence retain their original scope.", @@ -9878,7 +9584,29 @@ "Audit2709 removes src/renderer/src/runtime/web-session-tabs-sync/inventory/remote-runtime-session-tabs-inflight.test.ts: intentionally retire waiting out an older inventory and sharing a fresh post-operation request among concurrent callers. No equivalent replacement or fresh execution is claimed. Dated receipts remain historical evidence for their unchanged selectors only; they do not validate the reduced commands or full current gate. Original prospective command before removal: pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/resolved-worktree-execution-host.test.ts src/renderer/src/components/terminal/background-terminal-worktree-mount.test.ts src/renderer/src/components/terminal-pane/mounting/queued-pane-startup.test.ts src/renderer/src/components/terminal-pane/parking/one-shot-park-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts src/renderer/src/runtime/web-session-tabs-sync/inventory/remote-runtime-session-tabs-inflight.test.ts src/renderer/src/store/terminals/terminal-pty-identity-replacement.test.ts", "Audit3086: retire the destroyed fresh-session fallback settlement/non-destructive reattach alias and its direct selector; retain the detach/attach selector and assertion unchanged. The retained admission cases cover adopt-before-data and explicitly buffered-death admission without a new spawn, without replacing fallback retirement. July 28 evidence was already archived by audit3077; no duplicate retirement or new execution is claimed.", "Audit3096: remove the deleted reconnect-banner selector and its two UI aliases. The reduced recovery-state selector retains only the deadline cancelling pending backoff and explicit retry owning a new epoch alias; healthy-replacement stale-schedule and independent caller-cutoff cancellation aliases retire. Other retained state cases cover reentrant retry, owner settlement and same-epoch parked revival, without replacing those removed alarms. Prior admission-selector retirement, archived July 28 receipt, unrelated selectors/claims/receipts and old gaps remain unchanged; no fresh execution is claimed.", - "Module-layout wave1 intentionally retires complete prohibited owning registrations in src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-attach-subscription.test.ts. Lost alarms: attaches to an existing remote runtime terminal handle; reports a rejected multiplex write through the pane recovery callback; does not report a rejected write from a superseded multiplex stream; does not report attachment health until the authoritative PTY snapshot arrives; drops its side-effect gauge from the census on %s; recovers when the first restored-terminal subscription attempt is offline; recovers when the runtime closes before a restored subscription becomes ready; surfaces a fatal error during subscription setup exactly once; reports viewer disconnect as an unverifiable remote exit; clears every retained transport error when the current stream becomes healthy. No equivalent replacement coverage or pass for a reduced selector is claimed. All unrelated selectors and historical receipts retain their original scope." + "Module-layout wave1 intentionally retires complete prohibited owning registrations in src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-attach-subscription.test.ts. Lost alarms: attaches to an existing remote runtime terminal handle; reports a rejected multiplex write through the pane recovery callback; does not report a rejected write from a superseded multiplex stream; does not report attachment health until the authoritative PTY snapshot arrives; drops its side-effect gauge from the census on %s; recovers when the first restored-terminal subscription attempt is offline; recovers when the runtime closes before a restored subscription becomes ready; surfaces a fatal error during subscription setup exactly once; reports viewer disconnect as an unverifiable remote exit; clears every retained transport error when the current stream becomes healthy. No equivalent replacement coverage or pass for a reduced selector is claimed. All unrelated selectors and historical receipts retain their original scope.", + "Module-layout wave2 intentionally retires complete prohibited owning registrations in src/renderer/src/lib/resolved-worktree-execution-host.test.ts. Lost alarms: Both explicit and legacy workspace owners resolve to env-a initially. Replacing the repo catalog refreshes legacy ownership to env-b. A conflicting local repo row makes ownership ambiguous and returns null. Repeated unrelated updates perform zero id reads, an internal work-budget alarm removed. No equivalent replacement coverage or reduced-selector pass is claimed.", + "Audit 3312 retires the ordinary six-pane distinct-live-handle reconnect/resubscription alarm from paired-reconnect-multi-pane-materialization.test.ts. The unchanged parked-pane activation/rematerialization case remains narrower and is not an equivalent replacement. The complete prior seven-contract macOS receipt is archived as historical evidence; it does not validate the reduced selector. No fresh socket, PTY, sleep/wake, provider, platform, mobile, mixed-version or rendered execution is claimed.", + "Audit 3312 retires this complete dated seven-contract receipt because paired-reconnect-multi-pane-materialization.test.ts was reduced. Original command, currentCommand, result, counts, date and duration remain historical and do not validate the reduced selector. Original receipt verbatim:\n{\n \"date\": \"2026-08-23\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/paired-reconnect-multi-pane-materialization.test.ts src/renderer/src/runtime/paired-reconnect-sidebar-agent-count.test.ts --reporter=dot\",\n \"result\": \"passed\",\n \"durationSeconds\": 2.54,\n \"summary\": \"Seven deterministic STA-3107 contracts passed across six-pane multiplex rematerialization and client-owned sidebar-row retention after sleep/wake.\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts src/renderer/src/runtime/web-session-tabs-sync/agent-status/paired-reconnect-sidebar-agent-count.test.ts --reporter=dot\"\n }", + "Audit3315 execution amendment: the reduced two-suite reconnect selector passed on Linux (2 cases). Original source-review statements about no fresh execution describe the earlier static review; this new receipt validates only these two local deterministic unit cases, not the complete gate or physical/runtime/rendered/provider/platform parity. Historical seven-case macOS receipt remains archived verbatim.", + "Audit 3318 reduces runtime-environment-ssh-state.test.ts, intentionally losing metadata membership-pruning/new-target-only-read and other-environment/local-bucket isolation alarms. Preserve generation/failed-full-refresh assertion and unknown-target authoritative-list reread; these narrower cases are not equivalent replacements. The unchanged active two-case Linux reconnect materialization/sidebar receipt and covered platform retain their exact scope and do not validate the reduced SSH state selector. Preserve unrelated SSH assertions, selectors and archived history. No fresh SSH discovery, provider/PTY/network, rendered, mobile, mixed-version, cross-platform or full-gate execution is claimed.", + "Audit3326 adopts reconciled source audit3324 and intentionally retires these low-value examples and their regression alarms: keeps a sidebar row for every still-live pane after a long sleep — Whole suite: 279 lines manually replay renderer ownership registry/status writes, snapshot patch/set, six-pane fixture inventory, and sidebar selectors/builders; expected pane IDs are production-computed. Does not run sleep/wake/transport or actual sidebar entry. Retires reconnect row-preservation assembly alarm.; still retires the regular TUI surface after an explicit terminal exit — Ordinary explicit-exit callback/map cleanup is repeated in the stale/new stream lifecycle case below. Retires separate regular-TUI baseline; keeper is not equivalent process/UI proof.; asks the HUB to recover an expired SSH pane and rebinds the host identity — Expired SSH owner error must ask the owning HUB to recover, then adopt fixed replacement handle, resubscribe and report rebind; actual transport dispatch and handle state prevent wrong-client recovery.; does not recover a pane whose relay reply was an identity mismatch — Identity mismatch means a different live PTY, so actual transport must surface refusal without recover/create, keeping original identity. Prevents destructive duplicate agent recovery.; fails closed when an older HUB cannot recover an expired SSH pane — Old HUB method_not_found is scripted mock refusal/error echo with no actual skewed host; repeats generic recovery failure propagation. Retires old-host recovery fallback refusal example.; names a held recovery's stopped WSL distro in readable copy, not the raw hold code — Pins exact WSL stopped-distro error prose after mock code; translation/copy assertion with no actual held recovery behavior. Retires readable-copy alarm.. Retained tests do not replace these alarms. Dated unrelated evidence remains scoped to its original execution; no historical source/import-closure equivalence, fresh execution, real network/provider/SSH, rendered UI, mobile, mixed-version or cross-platform validation is claimed.", + "Audit3326 retires this complete historical compound Linux unit receipt from active evidence because its paired-sidebar selector was removed. A fresh surviving-selector execution is required before restoring current evidence/platform credit. Original receipt verbatim:\n{\n \"date\": \"2026-11-11\",\n \"runner\": \"local\",\n \"platform\": \"linux\",\n \"command\": \"ORCA_BACKGROUND_LAUNCH=1 pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts src/renderer/src/runtime/web-session-tabs-sync/agent-status/paired-reconnect-sidebar-agent-count.test.ts --reporter=dot --maxWorkers=2\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/paired-reconnect-multi-pane-materialization.test.ts src/renderer/src/runtime/web-session-tabs-sync/agent-status/paired-reconnect-sidebar-agent-count.test.ts --reporter=dot\",\n \"result\": \"passed\",\n \"durationSeconds\": 5.65,\n \"summary\": \"Audit3315 focused candidate run: 2 suites / 2 deterministic unit cases passed for parked-pane reconnect materialization and client-owned sidebar retention. currentCommand names the same gate selector; executed command adds background launch and two-worker flags. This is local fake-runtime/store evidence only, not the complete gate, authenticated SSH/PTY/network, rendered Electron, provider, sleep/wake, mobile, mixed-version or cross-platform validation. Re-executed after rebasing onto main 1af64194a46d338777058c06954c2c8ee4a437be (candidate source commit 63adee8174d388466f9276a893972255cee06588).\"\n }", + "Audit3329 execution amendment: the reduced one-suite reconnect selector passed on Linux (1 case). Original source-review statements about no fresh execution describe the earlier static review; this new receipt validates only this one local deterministic unit case, not the complete gate or physical/runtime/rendered/provider/platform parity. Historical seven-case macOS and two-case Linux receipts remain archived verbatim.", + "Audit3342 retires the complete client create-outcome identity/options/recovery suite and the malformed-or-contradictory repo-owner response matrix. Client replay identity, options, no-downgrade, quiescence/budget/manual retry, authoritative probe-error and malformed-owner refusal alarms are intentionally lost without equivalent replacement. Remaining repo-owner late catalog and old-host re-adoption boundaries do not replace them. The unrelated Linux paired-reconnect receipt stays verbatim with its original scope. Surviving selectors are unexecuted here; no fresh SSH/provider/process-deduplication, mobile, mixed-version or cross-platform validation is claimed.", + "Audit3342 historical original commands object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-expired-pane-recovery.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-outcome-recovery.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/recovery/remote-runtime-pty-recovery-state.test.ts src/shared/remote-runtime/remote-runtime-socket-liveness.test.ts src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts src/shared/remote-runtime/control/remote-runtime-shared-control-socket-generation.test.ts src/shared/remote-runtime/remote-runtime-client-error-classification.test.ts src/main/runtime/rpc/remote-runtime-server-heartbeat.test.ts src/main/runtime/terminal/launch/orca-runtime-terminal-create-idempotency.test.ts\"", + "Audit3342 historical original testFiles object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n\"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-outcome-recovery.test.ts\"", + "Audit3342 historical original assertionRefs object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n{\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-outcome-recovery.test.ts\",\n \"assertions\": [\n \"unknown terminal-create recovery stops all request activity after one minute without a fatal error, clips post-probe RPC timeouts to the remaining budget, then manual retry re-probes capability and reconciles the same mutation\",\n \"an authoritative capability-probe failure replaces the stale connectivity error\"\n ]\n }", + "Audit3342 historical original assertionRefs object, preserved verbatim; retired objects are not active evidence or replacement coverage:\n{\n \"file\": \"src/renderer/src/store/repos/repos-ssh-host-reconciliation.test.ts\",\n \"assertions\": [\n \"a provider result becomes stale when same-ID repo ownership turns malformed or contradictory during the await\"\n ]\n }", + "Audit3359 retires whole host-surface-replacement and create-handoff suites, removing their compound unit command tokens, test-file entries and assertion references. Fake polling/deadline/subscription, supplied stale-handle ownership, close and replacement examples are intentionally lost without equivalent replacement. The unrelated Linux paired multi-pane reconnect receipt stays verbatim with its original scope. No fresh SSH/provider/network/PTY recovery, historical-import, mobile, mixed-version or cross-platform validation is claimed.", + "Audit3359 historical original commands object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal/background-terminal-worktree-mount.test.ts src/renderer/src/components/terminal-pane/mounting/queued-pane-startup.test.ts src/renderer/src/components/terminal-pane/parking/one-shot-park-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts src/renderer/src/store/terminals/terminal-pty-identity-replacement.test.ts\"", + "Audit3359 historical original commands object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-expired-pane-recovery.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/recovery/remote-runtime-pty-recovery-state.test.ts src/shared/remote-runtime/remote-runtime-socket-liveness.test.ts src/shared/remote-runtime/control/remote-runtime-shared-control-connection.test.ts src/shared/remote-runtime/control/remote-runtime-shared-control-socket-generation.test.ts src/shared/remote-runtime/remote-runtime-client-error-classification.test.ts src/main/runtime/rpc/remote-runtime-server-heartbeat.test.ts src/main/runtime/terminal/launch/orca-runtime-terminal-create-idempotency.test.ts\"", + "Audit3359 historical original testFiles object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts\"", + "Audit3359 historical original testFiles object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n\"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts\"", + "Audit3359 historical original assertionRefs object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts\",\n \"assertions\": [\n \"a stale web-mirror handle polls until a different ready handle is published without resubscribing the stale handle\",\n \"replacement does not emit pane exit or disconnect callbacks and explicit terminal exit still retires the mirror\",\n \"replacement polling and each in-flight request share a 15-second deadline, then accepted snapshots own recovery without input re-arming polling\"\n ]\n }", + "Audit3359 historical original assertionRefs object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts\",\n \"assertions\": [\n \"a stale create completion cannot replace or close a newer attachment, including when two runtimes use the same raw handle\"\n ]\n }", + "Audit3368 narrows stream-reconnect coverage to the actual ten synthetic transport epochs retaining one PTY identity, accepting and holding detached input for exactly-once later delivery, current decoded output and per-epoch subscription release. Prior rejection wording was inaccurate. Phase/backoff/cutoff/manual reconnect and parser/OSC/pause/retained-image/fatal/latch/claim/early-close alarms are intentionally lost without equivalent replacement. The Linux multi-pane reconnect receipt remains verbatim with its original scope; no fresh live SSH/provider/PTY/UI/mobile/mixed-version/cross-platform evidence is claimed.", + "Audit3368 historical original assertionRefs object, preserved verbatim; retired claims are not active evidence or replacement coverage:\n{\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts\",\n \"assertions\": [\n \"recovery exposes connecting, recovering, backoff, connected, and fatal-offline phases with fenced epochs\",\n \"ten partition cycles retain one PTY identity, reject detached input, and unsubscribe each epoch exactly once\",\n \"automatic retries stop after one minute with no fatal error, no further requests, and no stale input\",\n \"manual reconnect starts a new epoch, resubscribes the same PTY exactly once, and becomes healthy only after its snapshot\"\n ]\n }" ], "demotionRule": "Cannot promote if provider failure can close panes or if the oracle is screenshot-only." }, @@ -10095,7 +9823,7 @@ "commands": [ "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-native-text-forwarder.test.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-macos-keybinding-dict-trace.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-linux-fcitx4-trace-replay.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-midline-preedit-tail.test.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-resumed-preedit-visibility.test.ts src/renderer/src/lib/pane-manager/terminal-ime-candidate-anchor.test.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-composer-placeholder-mask.test.ts src/shared/terminal/input/terminal-composer-draft.test.ts src/main/daemon/emulation/testing/terminal-cursor-line-context.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-resumed-preedit-visibility.test.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-composer-placeholder-mask.test.ts src/shared/terminal/input/terminal-composer-draft.test.ts src/main/daemon/emulation/testing/terminal-cursor-line-context.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/dashboard-popout/preview-terminal-ime-bridge-kitty-bytes.test.ts src/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsx src/shared/terminal/protocol/input-modes/terminal-kitty-keyboard-mode-tracker.test.ts src/main/ipc/terminal-preview-output-stream.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/input/keyboard/terminal-option-kitty-release.test.ts src/renderer/src/lib/keyboard-layout/layout-base-character.test.ts src/main/ipc/macos-keyboard-layout-change-notifications.test.ts src/preload/app-restart-checkpoint-routing.test.ts src/renderer/src/web/web-preload-api-ui.test.ts", "pnpm run test:e2e -- tests/e2e/chinese-ime-chat-input-repro.spec.ts", @@ -10107,9 +9835,7 @@ "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-native-text-forwarder.test.ts", "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-macos-keybinding-dict-trace.test.ts", "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-linux-fcitx4-trace-replay.test.ts", - "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-midline-preedit-tail.test.ts", "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-resumed-preedit-visibility.test.ts", - "src/renderer/src/lib/pane-manager/terminal-ime-candidate-anchor.test.ts", "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-composer-placeholder-mask.test.ts", "src/shared/terminal/input/terminal-composer-draft.test.ts", "src/main/daemon/emulation/testing/terminal-cursor-line-context.test.ts", @@ -10136,13 +9862,6 @@ "an XIM pick's code-less keydown pairs with its keyup so kitty event reporting sends one release per pick" ] }, - { - "file": "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-midline-preedit-tail.test.ts", - "assertions": [ - "With supplied geometry, competing xterm render and Orca clamp preserve final-cell caret/candidate anchor positions.", - "Actual xterm buffer repaint updates the row tail while the preedit remains open." - ] - }, { "file": "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-resumed-preedit-visibility.test.ts", "assertions": ["A transaction inferred from update alone commits and cleans up."] @@ -10266,6 +9985,9 @@ "Pair with Windows ConPTY keyboard reset for Windows standard-key behavior." ], "knownGaps": [ + "NEXT65 current scope qualification: The NEXT65 knownGaps entries below govern the changed selectors and qualify any broader coverage implication in this gate’s unchanged oracle/coverageNotes narratives. Those narratives and preserved dated evidenceRuns retain their historical text and original exact execution scopes only; no fresh execution, transferred pass or equivalent replacement coverage is claimed. Upstream case removals remain upstream; original NEXT65 proposal descriptions grant no duplicate retirement credit.", + "NEXT65 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-midline-preedit-tail.test.ts, src/renderer/src/lib/pane-manager/terminal-ime-candidate-anchor.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence.", + "NEXT65 historical original active selector fields (verbatim JSON values; not current coverage):\ncommands: [\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-native-text-forwarder.test.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-macos-keybinding-dict-trace.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-linux-fcitx4-trace-replay.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-midline-preedit-tail.test.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-resumed-preedit-visibility.test.ts src/renderer/src/lib/pane-manager/terminal-ime-candidate-anchor.test.ts src/renderer/src/components/terminal-pane/input/ime/terminal-ime-composer-placeholder-mask.test.ts src/shared/terminal/input/terminal-composer-draft.test.ts src/main/daemon/emulation/testing/terminal-cursor-line-context.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/dashboard-popout/preview-terminal-ime-bridge-kitty-bytes.test.ts src/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsx src/shared/terminal/protocol/input-modes/terminal-kitty-keyboard-mode-tracker.test.ts src/main/ipc/terminal-preview-output-stream.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/input/keyboard/terminal-option-kitty-release.test.ts src/renderer/src/lib/keyboard-layout/layout-base-character.test.ts src/main/ipc/macos-keyboard-layout-change-notifications.test.ts src/preload/app-restart-checkpoint-routing.test.ts src/renderer/src/web/web-preload-api-ui.test.ts\",\n \"pnpm run test:e2e -- tests/e2e/chinese-ime-chat-input-repro.spec.ts\",\n \"pnpm run test:e2e -- tests/e2e/terminal-korean-endofrow-preedit-cell-span.spec.ts tests/e2e/terminal-korean-midline-preedit-occlusion.spec.ts\",\n \"pnpm run test:e2e -- tests/e2e/terminal-option-composed-ascii.spec.ts\"\n ]\ntestFiles: [\n \"tests/e2e/terminal-option-composed-ascii.spec.ts\",\n \"src/renderer/src/components/terminal-pane/input/ime/terminal-ime-native-text-forwarder.test.ts\",\n \"src/renderer/src/components/terminal-pane/input/ime/terminal-ime-macos-keybinding-dict-trace.test.ts\",\n \"src/renderer/src/components/terminal-pane/input/ime/terminal-ime-linux-fcitx4-trace-replay.test.ts\",\n \"src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-midline-preedit-tail.test.ts\",\n \"src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-resumed-preedit-visibility.test.ts\",\n \"src/renderer/src/lib/pane-manager/terminal-ime-candidate-anchor.test.ts\",\n \"src/renderer/src/components/terminal-pane/input/ime/terminal-ime-composer-placeholder-mask.test.ts\",\n \"src/shared/terminal/input/terminal-composer-draft.test.ts\",\n \"src/main/daemon/emulation/testing/terminal-cursor-line-context.test.ts\",\n \"src/renderer/src/components/terminal-pane/input/keyboard/terminal-option-kitty-release.test.ts\",\n \"src/renderer/src/lib/keyboard-layout/layout-base-character.test.ts\",\n \"src/main/ipc/macos-keyboard-layout-change-notifications.test.ts\",\n \"src/preload/app-restart-checkpoint-routing.test.ts\",\n \"src/renderer/src/web/web-preload-api-ui.test.ts\",\n \"src/renderer/src/components/dashboard-popout/preview-terminal-ime-bridge-kitty-bytes.test.ts\",\n \"src/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsx\",\n \"src/shared/terminal/protocol/input-modes/terminal-kitty-keyboard-mode-tracker.test.ts\",\n \"src/main/ipc/terminal-preview-output-stream.test.ts\",\n \"src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts\",\n \"tests/e2e/chinese-ime-chat-input-repro.spec.ts\",\n \"tests/e2e/terminal-korean-endofrow-preedit-cell-span.spec.ts\",\n \"tests/e2e/terminal-korean-midline-preedit-occlusion.spec.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"src/renderer/src/components/terminal-pane/input/ime/terminal-ime-linux-fcitx4-trace-replay.test.ts\",\n \"assertions\": [\n \"real fcitx4 Sogou captures (GTK module and XIM) send only the committed candidate for Space and digit picks, under legacy keys and kitty flags 1 and 5\",\n \"a real fcitx4 Google Pinyin in-client preedit still commits through the composition path\",\n \"an XIM pick's code-less keydown pairs with its keyup so kitty event reporting sends one release per pick\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-midline-preedit-tail.test.ts\",\n \"assertions\": [\n \"With supplied geometry, competing xterm render and Orca clamp preserve final-cell caret/candidate anchor positions.\",\n \"Actual xterm buffer repaint updates the row tail while the preedit remains open.\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-resumed-preedit-visibility.test.ts\",\n \"assertions\": [\"A transaction inferred from update alone commits and cleans up.\"]\n },\n {\n \"file\": \"tests/e2e/terminal-option-composed-ascii.spec.ts\",\n \"assertions\": [\n \"a live kitty-negotiated pane receives the Option-composed ASCII character, not the physical alt chord\",\n \"an Option layer that also needs Shift still reaches the pty as text\",\n \"configured Option-as-Alt still reports the layout-resolved physical chord\",\n \"a non-ASCII Option glyph still reaches the application as its alt hotkey\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/input/keyboard/terminal-option-kitty-release.test.ts\",\n \"assertions\": [\n \"Autorepeat cannot replace the first release sender; a fresh press can replace an orphaned sender for the same key.\"\n ]\n },\n {\n \"file\": \"src/main/ipc/macos-keyboard-layout-change-notifications.test.ts\",\n \"assertions\": [\n \"rapid input-source changes coalesce to one latest-generation refresh signal\"\n ]\n },\n {\n \"file\": \"src/preload/app-restart-checkpoint-routing.test.ts\",\n \"assertions\": [\n \"macOS keyboard reads and the change subscription remain wired after main integration\",\n \"the two-phase change payload reaches the renderer unchanged\",\n \"the subscription disposer removes the exact IPC listener\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/dashboard-popout/preview-terminal-ime-bridge-kitty-bytes.test.ts\",\n \"assertions\": [\n \"the real forwarder behind the Preview bridge encodes the commit from the snapshot-proven flags before any live output\",\n \"flags 0/1 commit raw text, flags 2 add one CSI-u release, flags 8 emit one CSI-u press, and flags 10 emit a CSI-u press followed by exactly one release\",\n \"both keydown->insertText->keyup and keydown->keyup->insertText orderings produce the same bytes\",\n \"the release is emitted by the forwarder while xterm's internal kitty flags stay 0\",\n \"the mutable flags getter is read exactly once, at commit time, never on keydown or keyup\",\n \"auto-repeat, two-key rollover, a swallowed commit, a retired claim, blur, and disposal each emit at most one release and never synthesize one\"\n ]\n },\n {\n \"file\": \"src/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsx\",\n \"assertions\": [\n \"the Preview hands the forwarder the live kitty mirror seeded from the snapshot's proven flags\"\n ]\n },\n {\n \"file\": \"src/shared/terminal/protocol/input-modes/terminal-kitty-keyboard-mode-tracker.test.ts\",\n \"assertions\": [\n \"a fresh PTY's known 0 is distinguishable from a snapshot's unproven 0 fallback\",\n \"restoreSnapshotFlags proves only the active screen\",\n \"provenance survives absolute sets, screen switches, RIS and DECSTR, but a pop past omitted push history returns to unknown rather than a manufactured 0\"\n ]\n },\n {\n \"file\": \"src/main/ipc/terminal-preview-output-stream.test.ts\",\n \"assertions\": [\n \"a partially covered sequenced chunk retains exactly its unseen suffix in live mode\",\n \"a transformed overlap remains unsliced in replay mode\"\n ]\n },\n {\n \"file\": \"tests/e2e/chinese-ime-chat-input-repro.spec.ts\",\n \"assertions\": [\n \"Sogou-style Space candidate selection submits only the committed Chinese character\",\n \"Sogou-style digit candidate selection submits only the committed Chinese phrase\",\n \"Post-composition Sogou-style digit selection stays out of the PTY after compositionend\",\n \"Legacy orphaned-letter-keyup digit selection submits no selector byte to the PTY; real legacy candidate commit preservation remains a platform gap\"\n ]\n },\n {\n \"file\": \"tests/e2e/terminal-korean-endofrow-preedit-cell-span.spec.ts\",\n \"assertions\": [\n \"the rendered final-column preedit caret remains inside the terminal screen\",\n \"a rendered full-width Korean preedit spans materially more than the one terminal cell reported in #12729\"\n ]\n },\n {\n \"file\": \"tests/e2e/terminal-korean-midline-preedit-occlusion.spec.ts\",\n \"assertions\": [\n \"the rendered opaque overlay reproduces every committed row-tail cell its measured rectangle hides\",\n \"a real Codex placeholder with bold prompt, blank footer gap, model footer, and cursor at column 2 stays masked\"\n ]\n }\n ]", "Audit2133 current-parent preparation (988 authored removals; independently reviewed2099/2107/2115/2116 decisions; upstream clear-buffer and recovery-image regressions retained): Intentionally retire these low-value alarms without replacement: tests/e2e/claude-agent-row-view.unit.test.ts: updates a mounted compact workflow description through the subscribed production parent; bounds upstream active-SSH visits for $population records, fallback=$fallback; derives %s destinations without requiring type or a workflow child ID; terminates a $path parent $status with no third request or intermediate toast; does not recover a first child %s. tests/e2e/cross-version-wire/agent-permission-legacy-spawn.unit.test.ts: keeps exact legacy ordering when structured creation cannot express afterTabId; can create a terminal without selecting the target worktree; preserves the legacy fresh-agent path when host authority is unavailable. tests/e2e/paired-instant-browser-tab.spec.ts: shows a paired browser tab before its create RPC resolves, then keeps it as one tab; adopts a paired browser tab without rebuilding its chrome. tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts: bounds host publication and renderer application across remote worktrees; globally caps decorative freshness while every working status stays fresh. tests/e2e/session-tabs/mobile-session-active-performance.unit.test.ts: bounds saved-order publication selection at N and 10N without rematerializing navigation; bounds admitted placement reconciliation during supported reads at N and 10N; bounds selection input visits at 50 and 500 rows, including unavailable-target projection; keeps publication scoped to a changed worktree and shared by listeners at N and 10N; bounds preserved-chat merge and runtime-owned hydration at N and 10N (legacy=%s); bounds actual native retirement and shared delivery work at N and 10N. tests/e2e/session-tabs/mobile-session-active-publication.unit.test.ts: does not substitute a preserved row for an unavailable explicit legacy selection; resolves main-layout group selection %s (omitted group=%s). tests/e2e/structured-agent-session-launch-admission.unit.test.ts: opens a direct caller's terminal with the caller's own CLI arguments on a decline; opens the chat on the server that admitted it; opens only the terminal when this machine declines, without a notice; opens a new agent tab's terminal with the typed prompt when the caller names none; opens the chat, not a terminal, when this machine cannot resolve a new workspace yet; keeps its terminal fallback, as before. tests/e2e/structured-attention-prompt-relay.unit.test.ts: settles once per relayed prompt, not on every later status update. tests/e2e/structured-attention-read-retirement.unit.test.ts: Mark read on a chat never opened withdraws the prompt alert it surfaced; Mark read on a chat hidden since an earlier view covers the newer prompt it surfaced; reads a newly accepted visible prompt without sending an RPC for text-only updates. tests/e2e/structured-chat-tab-lifetime-cost.unit.test.ts: counts real raw stores, unrelated window publications and captured cleanup at %i chats; counts complete supplied-member sweep and separate final retirement at S=%i N=%i. tests/e2e/structured-session-workspace-authority.unit.test.ts: bounds actual target reveal across %i repo roots and metadata aliases. tests/e2e/terminal-agent-pane-launch.unit.test.ts: starts the host's planned command once, at the pane's size, and says it started; plans a pane whose prompt the window submits without the startup update prompt; preserves caller shell-ready delivery only for a connection-scoped adapter ($connectionId); starts no shell on plan failure (original failure: $returnLaunchFailure); cannot confirm a start whose provider answer was lost. tests/e2e/terminal-parked-memory.spec.ts: releases renderer terminal memory when hidden tabs park. tests/e2e/terminal-shortcuts.spec.ts: @headful Codex-like background output stays visible without disabling WebGL in auto mode; Shift with Russian layout text reaches the PTY as Cyrillic under kitty keyboard reporting. tests/e2e/terminal-split-activation-latency.spec.ts: records attributed CWD, spawn, bind, fixture-ready, input, and echo phases. tests/e2e/terminal-split-activation-latency-phases.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-main-probe.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-artifact.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-report.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-tab-switch-visual-restore.spec.ts: restores skipped hidden Grok output on light tab resume. tests/e2e/web-runtime-session-terminal-host-authority.unit.test.ts: delivers independent %s effort through the real prepared web callback; keeps same-ID local and runtime worktrees on the selected runtime owner; creates paired web agents through host authority so activation is mirrored; delivers generated continuation context after host-authoritative creation; seeds the chat composer for a draft that rode in on the launch command. Current changed source bytes, wrapper registrations and reduced selectors have no fresh execution or red/green credit. Unrelated surviving receipt objects keep their original narrow scope; current literal graph reachability does not establish historical import closure or equivalent replacement coverage. Current conservative command/import graph reaches tests/e2e/claude-agent-row-view.unit.test.ts, tests/e2e/cross-version-wire/agent-permission-legacy-spawn.unit.test.ts, tests/e2e/paired-instant-browser-tab.spec.ts, tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts, tests/e2e/session-tabs/mobile-session-active-performance.unit.test.ts, tests/e2e/session-tabs/mobile-session-active-publication.unit.test.ts, tests/e2e/structured-agent-session-launch-admission.unit.test.ts, tests/e2e/structured-attention-prompt-relay.unit.test.ts, tests/e2e/structured-attention-read-retirement.unit.test.ts, tests/e2e/structured-chat-tab-lifetime-cost.unit.test.ts, tests/e2e/structured-session-workspace-authority.unit.test.ts, tests/e2e/terminal-agent-pane-launch.unit.test.ts, tests/e2e/terminal-parked-memory.spec.ts, tests/e2e/terminal-shortcuts.spec.ts, tests/e2e/terminal-split-activation-latency.spec.ts, tests/e2e/terminal-split-activation-latency-phases.ts, tests/e2e/terminal-split-activation-latency-main-probe.ts, tests/e2e/terminal-split-activation-latency-artifact.ts, tests/e2e/terminal-split-activation-latency-report.ts, tests/e2e/terminal-tab-switch-visual-restore.spec.ts, tests/e2e/web-runtime-session-terminal-host-authority.unit.test.ts. Unresolved local/computed edges remain explicit debt.", "Audit2095 current-parent preparation2126 (approved2092/2093 removals; source refresh2109/independent2112): Intentionally retire these low-value alarms without replacement: tests/e2e/automation-terminal-launch.unit.test.ts: launches explicit Chat for %s through the common entry and keeps its actual fallback; does not apply stored Terminal extras to Chat; forwards only complete Chat-consumed values, with no Terminal startup base; refuses an expired admission without minting another launch identity; records the actual chat identity and delegates new workspace setup and provenance. tests/e2e/github-project-provider-columns.unit.test.ts: renders %s through one bounded items request on a named cloud host; preserves zero and complete counters: %j; preserves populated and legacy rows through shared sorting, grouping and cells. tests/e2e/structured-agent-session-launch-continuation.unit.test.ts: carries renderer lifetime through host intent to the real %s provider builders. tests/e2e/terminal-account-restart.unit.test.ts: replaces a tombstoned owner while its persisted pane binding has not yet been cleared; paired restart retains the old owner (host authority: %s). tests/e2e/terminal-hidden-view-parking.spec.ts: does not park excluded tabs; reproduces a static frame byte-for-byte across 25 park/reveal cycles. tests/e2e/terminal-long-table-scroll-restore.spec.ts: reproduces long markdown table artifacts after workspace switch and scroll; keeps narrow wrapped signer markdown table coherent after restore and scroll; keeps real emoji markdown table right edge clean after restore and scroll. tests/e2e/terminal-long-table-fixtures.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-paste-ownership.spec.ts: Windows multiline keyboard paste normalizes terminal newlines with one PTY owner; right-click paste sends clipboard text to the focused terminal exactly once. tests/e2e/terminal-raw-emoji-table-scroll-restore.spec.ts: uses WebGL by default for ordinary terminal output when available @terminal-rendering-golden. tests/e2e/terminal-windows-shell-paste-ownership.spec.ts: cmd.exe default terminal keyboard paste preserves exact content with one PTY owner; Git Bash default terminal keyboard paste preserves POSIX-shaped content with one PTY owner; WSL terminal keyboard paste preserves Linux shell content with one PTY owner. tests/e2e/workspace-board-lane-virtualization.spec.ts: mounts a window of cards for a large lane and keeps lane indexes; renders later lane indexes after the lane scrolls. Current changed source bytes, wrapper registrations and reduced selectors have no fresh execution or red/green credit. Unrelated surviving receipt objects keep their original narrow scope; current literal graph reachability does not establish historical import closure or equivalent replacement coverage. Current conservative command/import graph reaches tests/e2e/automation-terminal-launch.unit.test.ts, tests/e2e/github-project-provider-columns.unit.test.ts, tests/e2e/structured-agent-session-launch-continuation.unit.test.ts, tests/e2e/terminal-account-restart.unit.test.ts, tests/e2e/terminal-hidden-view-parking.spec.ts, tests/e2e/terminal-long-table-scroll-restore.spec.ts, tests/e2e/terminal-long-table-fixtures.ts, tests/e2e/terminal-paste-ownership.spec.ts, tests/e2e/terminal-raw-emoji-table-scroll-restore.spec.ts, tests/e2e/terminal-windows-shell-paste-ownership.spec.ts, tests/e2e/workspace-board-lane-virtualization.spec.ts. Unresolved local/computed edges remain explicit debt. Complete dated receipts with direct selectors or current literal graph reaching tests/e2e/automation-terminal-launch.unit.test.ts, tests/e2e/github-project-provider-columns.unit.test.ts, tests/e2e/structured-agent-session-launch-continuation.unit.test.ts, tests/e2e/terminal-account-restart.unit.test.ts, tests/e2e/terminal-hidden-view-parking.spec.ts, tests/e2e/terminal-long-table-scroll-restore.spec.ts, tests/e2e/terminal-long-table-fixtures.ts, tests/e2e/terminal-paste-ownership.spec.ts, tests/e2e/terminal-raw-emoji-table-scroll-restore.spec.ts, tests/e2e/terminal-windows-shell-paste-ownership.spec.ts, tests/e2e/workspace-board-lane-virtualization.spec.ts are retired below as historical raw objects; their counts do not validate reduced commands. Historical retired receipt verbatim:\n{\n \"date\": \"2026-08-16\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm run test:e2e -- tests/e2e/terminal-option-composed-ascii.spec.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 66,\n \"summary\": \"Four live-Electron scenarios passed against a real pty whose kitty flags were armed by the application's own CSI > 1 u: Option-composed `@` and Option+Shift-composed `\\\\` arrive as text with no alt chord, configured Option-as-Alt still reports the layout-resolved chord, and a non-ASCII Option glyph still reaches the application as its alt hotkey. Discrimination was proven by mutation rather than assumed — restoring the pre-fix policy makes exactly the two composed-text scenarios fail with the character never reaching the pty, while both chord scenarios stay green.\"\n } Historical retired receipt verbatim:\n{\n \"date\": \"2026-08-16\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm run test:e2e -- tests/e2e/chinese-ime-chat-input-repro.spec.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 13.9,\n \"summary\": \"The Electron live-PTY IME gate passed three scenarios covering Windows IME Shift commit, candidate-selector suppression with committed Chinese text, and composed text/cursor/Backspace stability; the opt-in real-agent scenario remained skipped.\"\n } Historical retired receipt verbatim:\n{\n \"date\": \"2026-07-11\",\n \"runner\": \"local\",\n \"platform\": \"linux\",\n \"command\": \"pnpm run test:e2e -- tests/e2e/chinese-ime-chat-input-repro.spec.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 30.3,\n \"summary\": \"Debian 12 arm64 Docker with Node 24 and Xvfb passed both live Electron/PTY IME scenarios; the orphaned-letter-keyup candidate digit submitted no selector byte, and the real-Codex opt-in scenario was skipped.\"\n } Historical retired receipt verbatim:\n{\n \"date\": \"2026-07-07\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm run test:e2e -- tests/e2e/chinese-ime-chat-input-repro.spec.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 72,\n \"summary\": \"Electron/CDP IME repro passed: Sogou candidate selection, post-composition candidate selection, and existing Chinese IME harness passed; real Codex IME test was skipped behind ORCA_E2E_REAL_CODEX_IME.\"\n }", "Audit2090 (sources2088/2089): Intentionally retire these low-value alarms without replacement: tests/e2e/terminal-option-composed-ascii.spec.ts: still reports the Alt chord when Option is configured as Alt. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. The historical receipt/currentCommand selecting tests/e2e/terminal-option-composed-ascii.spec.ts remains historical and is not a passing result for the reduced current command.", @@ -11831,14 +11553,14 @@ "providers": ["local", "daemon", "ssh"], "coveredPlatforms": ["macos"], "coveredProviders": ["local"], - "coverageNotes": "Audit3086: retire the immediate-reply ceiling and thrown renderer-write recovery aliases. Narrow FIFO coverage to deferred preconnect validation and teardown coverage to natural-exit stale ordinary/accepted tails; live acknowledged barriers and disconnect/detach branches are intentionally retired. Prior queue cleanup and unchanged Electron receipts remain exact; no replacement or fresh execution is claimed. Audit1878 retires the dated reduced-source unit receipt. Only the unchanged macOS local Electron receipts remain current, scoped to their exact commands; reduced unit selectors and SSH have no current execution receipt. Historical pre-audit coverageNotes: Deterministic renderer and IPC-transport tests prove count and text ceilings, oldest-reply shedding, explicit query-reply source routing, ordinary-input preservation, acknowledged-write FIFO barriers, single-worker drain reentrancy, one-reply-per-write delivery for OSC, DA1, and CPR replies, real xterm OSC reply generation, drain-failure containment, teardown settlement, and clear/reuse generation fencing. Remote-runtime tests preserve separate query-reply writes across pending input, async validation, and viewport-claim buffering. Host-contract tests prove a later DA1/CPR reply cannot overtake a deferred OSC reply, including a coalesced legacy-client payload. Live macOS Electron tests cover local PTY OSC replies and interactive typing; a macOS-hosted Docker OpenSSH test proves an upstream-node-pty Linux relay keeps OSC/DA1 replies out of the next fish child's stdin. No live daemon, paired-runtime, WSL, physical Linux/Windows client, or binary mixed-version run is registered.", + "coverageNotes": "Audit3362 retires the 10,000-query newest64 viewport-claim flood-cap assertion and second-chunk refusal, coalescing/burst/limit/yield and constant examples. The surviving ordinary/query/ordinary binary-frame ordering and UTF8 emoji-safe acknowledged chunk cases retain narrower coverage. Unit commands/test-file selectors remain; the first binary-order assertion stays exact. Two unrelated macOS E2E receipts remain verbatim with their original scope. No equivalent replacement or fresh runtime/PTY/provider/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit 3312 reduces remote-runtime-pty-batching.test.ts, intentionally losing idle leading/trailing coalescing, leading-edge-disabled, accumulated byte-ceiling flush, standalone synchronous oversized-input rejection, accepted-input validation yield, deferred pending-tail byte order, and queued-viewport clear/flush and timer-cancellation alarms. The unchanged UTF-8 splitting, validation barrier ordering and asynchronous oversized-input nondelivery cases are narrower, not equivalent replacements. The barrier assertion and both existing Electron receipts remain unchanged and do not validate these retired cases. No fresh runtime, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3292 retires the empty-queue immediate query-reply delivery example from remote-runtime-pty-query-reply-immediate.test.ts. Pending ordinary-input separation and asynchronous paste-validation ordering cases remain byte-identical, matching the existing assertion reference. The no-pending-input delivery alarm is intentionally lost without equivalent replacement. Existing selectors, unchanged local Electron receipts and historical receipts remain exact; no new runtime, PTY deadline, platform or mixed-version result is claimed. Audit3086: retire the immediate-reply ceiling and thrown renderer-write recovery aliases. Narrow FIFO coverage to deferred preconnect validation and teardown coverage to natural-exit stale ordinary/accepted tails; live acknowledged barriers and disconnect/detach branches are intentionally retired. Prior queue cleanup and unchanged Electron receipts remain exact; no replacement or fresh execution is claimed. Audit1878 retires the dated reduced-source unit receipt. Only the unchanged macOS local Electron receipts remain current, scoped to their exact commands; reduced unit selectors and SSH have no current execution receipt. Historical pre-audit coverageNotes: Deterministic renderer and IPC-transport tests prove count and text ceilings, oldest-reply shedding, explicit query-reply source routing, ordinary-input preservation, acknowledged-write FIFO barriers, single-worker drain reentrancy, one-reply-per-write delivery for OSC, DA1, and CPR replies, real xterm OSC reply generation, drain-failure containment, teardown settlement, and clear/reuse generation fencing. Remote-runtime tests preserve separate query-reply writes across pending input, async validation, and viewport-claim buffering. Host-contract tests prove a later DA1/CPR reply cannot overtake a deferred OSC reply, including a coalesced legacy-client payload. Live macOS Electron tests cover local PTY OSC replies and interactive typing; a macOS-hosted Docker OpenSSH test proves an upstream-node-pty Linux relay keeps OSC/DA1 replies out of the next fish child's stdin. No live daemon, paired-runtime, WSL, physical Linux/Windows client, or binary mixed-version run is registered.", "motivatingLinks": [ "https://github.com/stablyai/orca/issues/13137", "https://github.com/stablyai/orca/issues/7329", "https://github.com/stablyai/orca/issues/13892" ], "invariant": "The desktop PTY input queue retains at most 64 explicitly sourced pending terminal query replies and 4096 UTF-16 code units. Every retained reply reaches the provider as one atomic write, and ordinary, acknowledged, and reply input share one invocation-ordered FIFO so no later write overtakes an acknowledged write. Reentrant write callbacks cannot start a second drain worker or strand input admitted after clear/reuse. A reply's own echo is contained on the output side by projecting its known echo shapes; the ESC-initial verbatim shape is matched only when complete, never held as a partial, so a query torn at its own ESC is still answered. Overflow removes only the oldest query replies, never ordinary input except the documented modified-F3/CPR byte collision, and failure or teardown cannot clear a newer queue generation or strand an acknowledged promise.", - "oracle": "Audit3086: retire the immediate-reply ceiling and thrown renderer-write recovery aliases. Narrow FIFO coverage to deferred preconnect validation and teardown coverage to natural-exit stale ordinary/accepted tails; live acknowledged barriers and disconnect/detach branches are intentionally retired. Prior queue cleanup and unchanged Electron receipts remain exact; no replacement or fresh execution is claimed. Audit1878 retires the dated reduced-source unit receipt. Only the unchanged macOS local Electron receipts remain current, scoped to their exact commands; reduced unit selectors and SSH have no current execution receipt. Historical pre-audit oracle: Synchronously enqueue separate 10,000-entry OSC and DA1 reply floods before the scheduled drain and assert that only the initial immediate reply and newest 64 pending replies are written, each as one provider write, before a trailing keystroke. Stall an acknowledged write between earlier and later ordinary/reply input, then require teardown to settle it and same-id reuse to receive no stale tail. Reenter the queue synchronously from an acknowledged write with both enqueue and clear/reuse, requiring one drain and fresh input delivery only after the stale acknowledged write settles false. At the host boundary, defer an OSC reply and assert that separate or legacy-coalesced DA1/CPR replies flush after it in observed query order. At the remote-runtime boundary, preserve separate writes around pending ordinary input, async validation, and viewport-claim buffering. Repeat behind 10,000 ordinary inputs and exercise the text ceiling, real xterm generation, provider-write failure, rejected yield, and clear/reuse generation fencing.", + "oracle": "Audit3362 retires the 10,000-query newest64 viewport-claim flood-cap assertion and second-chunk refusal, coalescing/burst/limit/yield and constant examples. The surviving ordinary/query/ordinary binary-frame ordering and UTF8 emoji-safe acknowledged chunk cases retain narrower coverage. Unit commands/test-file selectors remain; the first binary-order assertion stays exact. Two unrelated macOS E2E receipts remain verbatim with their original scope. No equivalent replacement or fresh runtime/PTY/provider/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit 3312 reduces remote-runtime-pty-batching.test.ts, intentionally losing idle leading/trailing coalescing, leading-edge-disabled, accumulated byte-ceiling flush, standalone synchronous oversized-input rejection, accepted-input validation yield, deferred pending-tail byte order, and queued-viewport clear/flush and timer-cancellation alarms. The unchanged UTF-8 splitting, validation barrier ordering and asynchronous oversized-input nondelivery cases are narrower, not equivalent replacements. The barrier assertion and both existing Electron receipts remain unchanged and do not validate these retired cases. No fresh runtime, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3292 retires the empty-queue immediate query-reply delivery example from remote-runtime-pty-query-reply-immediate.test.ts. Pending ordinary-input separation and asynchronous paste-validation ordering cases remain byte-identical, matching the existing assertion reference. The no-pending-input delivery alarm is intentionally lost without equivalent replacement. Existing selectors, unchanged local Electron receipts and historical receipts remain exact; no new runtime, PTY deadline, platform or mixed-version result is claimed. Audit3086: retire the immediate-reply ceiling and thrown renderer-write recovery aliases. Narrow FIFO coverage to deferred preconnect validation and teardown coverage to natural-exit stale ordinary/accepted tails; live acknowledged barriers and disconnect/detach branches are intentionally retired. Prior queue cleanup and unchanged Electron receipts remain exact; no replacement or fresh execution is claimed. Audit1878 retires the dated reduced-source unit receipt. Only the unchanged macOS local Electron receipts remain current, scoped to their exact commands; reduced unit selectors and SSH have no current execution receipt. Historical pre-audit oracle: Synchronously enqueue separate 10,000-entry OSC and DA1 reply floods before the scheduled drain and assert that only the initial immediate reply and newest 64 pending replies are written, each as one provider write, before a trailing keystroke. Stall an acknowledged write between earlier and later ordinary/reply input, then require teardown to settle it and same-id reuse to receive no stale tail. Reenter the queue synchronously from an acknowledged write with both enqueue and clear/reuse, requiring one drain and fresh input delivery only after the stale acknowledged write settles false. At the host boundary, defer an OSC reply and assert that separate or legacy-coalesced DA1/CPR replies flush after it in observed query order. At the remote-runtime boundary, preserve separate writes around pending ordinary input, async validation, and viewport-claim buffering. Repeat behind 10,000 ordinary inputs and exercise the text ceiling, real xterm generation, provider-write failure, rejected yield, and clear/reuse generation fencing.", "commands": [ "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/input/pty-input-write-queue.test.ts src/renderer/src/components/terminal-pane/pty-transport/ipc/pty-transport-input-write.test.ts src/shared/terminal/protocol/queries/terminal-query-reply.test.ts src/shared/terminal/pty/ingress/pty-startup-ingress-live-query-reply.test.ts src/shared/terminal/pty/ingress/pty-startup-reply-echo-shapes.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/output/remote-runtime-pty-batching.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-query-reply-immediate.test.ts src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-input-coalescing.test.ts", @@ -11891,8 +11613,7 @@ { "file": "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-input-coalescing.test.ts", "assertions": [ - "viewport-claim buffering replays ordinary input, a query reply, and later ordinary input as three ordered stream frames", - "a 10,000-reply viewport-claim flood retains and replays only the newest 64 query replies" + "viewport-claim buffering replays ordinary input, a query reply, and later ordinary input as three ordered stream frames" ] }, { @@ -11969,7 +11690,11 @@ "Reply overload intentionally sheds the oldest synthetic replies; the modified-F3/CPR byte collision shares that budget, and live application behavior under a pathological query flood is not measured.", "Audit1878 retires this complete dated receipt because a source in its selector was reduced. It does not validate the reduced selector. Original receipt verbatim:\n{\n \"date\": \"2026-08-30\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-input-write-queue.test.ts src/renderer/src/components/terminal-pane/pty-transport-input-write.test.ts src/shared/terminal-query-reply.test.ts src/shared/pty-startup-ingress-live-query-reply.test.ts src/shared/pty-startup-reply-echo-shapes.test.ts\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-transport/input/pty-input-write-queue.test.ts src/renderer/src/components/terminal-pane/pty-transport/ipc/pty-transport-input-write.test.ts src/shared/terminal/protocol/queries/terminal-query-reply.test.ts src/shared/terminal/pty/ingress/pty-startup-ingress-live-query-reply.test.ts src/shared/terminal/pty/ingress/pty-startup-reply-echo-shapes.test.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 15,\n \"summary\": \"Five files and 149 tests passed in 15.16 seconds, including explicit IPC reply-source routing, the 10,000-reply count and text ceilings, 10,000-entry ordinary backlog preservation, acknowledged-write FIFO barriers, synchronous reentrancy fencing, prompt teardown settlement, same-id generation fencing, real xterm OSC query floods, single-shot drain-failure recovery, and one-reply-per-write echo containment.\"\n }", "Audit1878 removes standalone reply-classifier inventory, ordinary-keystroke helper/no-write checks and a latency-order title that never executes the host path from pty-startup-ingress-live-query-reply.test.ts. It also removes projection needle/refusal/holdPartial and ConPTY/WSL string/array inventories from pty-startup-reply-echo-shapes.test.ts, including the direct short-needle and ESC-hold guard alarms. Captured echo matching and actual ingress writes/output state remain, without equivalent replacement coverage. Only the two unchanged macOS local Electron receipts remain active; neither proves the reduced five-file unit selector, SSH, a new soak result, or a new measured budget.", - "Audit3086: retire the immediate-reply ceiling and thrown renderer-write recovery aliases. Narrow FIFO coverage to deferred preconnect validation and teardown coverage to natural-exit stale ordinary/accepted tails; live acknowledged barriers and disconnect/detach branches are intentionally retired. Prior queue cleanup and unchanged Electron receipts remain exact; no replacement or fresh execution is claimed." + "Audit3086: retire the immediate-reply ceiling and thrown renderer-write recovery aliases. Narrow FIFO coverage to deferred preconnect validation and teardown coverage to natural-exit stale ordinary/accepted tails; live acknowledged barriers and disconnect/detach branches are intentionally retired. Prior queue cleanup and unchanged Electron receipts remain exact; no replacement or fresh execution is claimed.", + "Audit 3292 retires the empty-queue immediate query-reply delivery example from remote-runtime-pty-query-reply-immediate.test.ts. Pending ordinary-input separation and asynchronous paste-validation ordering cases remain byte-identical, matching the existing assertion reference. The no-pending-input delivery alarm is intentionally lost without equivalent replacement. Existing selectors, unchanged local Electron receipts and historical receipts remain exact; no new runtime, PTY deadline, platform or mixed-version result is claimed.", + "Audit 3312 reduces remote-runtime-pty-batching.test.ts, intentionally losing idle leading/trailing coalescing, leading-edge-disabled, accumulated byte-ceiling flush, standalone synchronous oversized-input rejection, accepted-input validation yield, deferred pending-tail byte order, and queued-viewport clear/flush and timer-cancellation alarms. The unchanged UTF-8 splitting, validation barrier ordering and asynchronous oversized-input nondelivery cases are narrower, not equivalent replacements. The barrier assertion and both existing Electron receipts remain unchanged and do not validate these retired cases. No fresh runtime, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed.", + "Audit3362 retires the 10,000-query newest64 viewport-claim flood-cap assertion and second-chunk refusal, coalescing/burst/limit/yield and constant examples. The surviving ordinary/query/ordinary binary-frame ordering and UTF8 emoji-safe acknowledged chunk cases retain narrower coverage. Unit commands/test-file selectors remain; the first binary-order assertion stays exact. Two unrelated macOS E2E receipts remain verbatim with their original scope. No equivalent replacement or fresh runtime/PTY/provider/UI/mobile/mixed-version/cross-platform evidence is claimed.", + "Audit3362 historical original assertionRefs object, preserved verbatim; retired source claims are not active evidence or replacement coverage:\n{\n \"file\": \"src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-input-coalescing.test.ts\",\n \"assertions\": [\n \"viewport-claim buffering replays ordinary input, a query reply, and later ordinary input as three ordered stream frames\",\n \"a 10,000-reply viewport-claim flood retains and replays only the newest 64 query replies\"\n ]\n }" ], "demotionRule": "Keep experimental or revert if ordinary input is evicted, pending replies exceed either ceiling, retained replies are coalesced, a trailing key sits behind more than the bounded reply window, or the gate develops unexplained flakes." }, @@ -12255,42 +11980,25 @@ "providers": ["local", "daemon", "ssh", "remote-runtime"], "coveredPlatforms": ["macos"], "coveredProviders": ["local"], - "coverageNotes": "Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Audit1417 intentionally deletes src/renderer/src/components/terminal-pane/pty-connection-hidden-tui-snapshot-replay.spec.ts: Loses rich hidden snapshot sequence replay/grid resize and forced repaint after hidden snapshot alarms, including live-trigger deduplication. No equivalent replacement coverage or fresh result is claimed. Historical coverage account: Audit1342 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Deterministic renderer contracts require foreground renderer-risk, synchronized, hidden, and alternate-screen PTY output to stay on pane-local repaint paths without a global atlas reset. Separate contracts preserve explicit paste, reveal, visibility-resume, system-resume, and confirmed-desync recovery. A macOS Electron run verifies that a document visibility cycle preserves real WebGL atlases and terminal pixels; the candidate has not been rerun against an isolated live paired server. The test-value audit removed registry recovery fanout, visibility, ordering and failure-isolation assertions. The remaining registry test constrains diagnostic sampling only and is excluded from this gate. No equivalent recovery coverage is claimed. Completed settled tab-reveal repaint execution is not covered after removal of pane-reveal-repaint.test.ts. The separate terminal-visibility-resume tests assert mocked scheduling and presentation calls; they do not establish completed repaint execution. Audit1342: src/renderer/src/lib/pane-manager/pane-webgl-context-recovery.test.ts removed. Context resume/reveal retry and deferred rebuild mock-pane alarms disappear. No equivalent replacement coverage is claimed. Audit1391: src/renderer/src/components/terminal-pane/pty-connection-remote-pause-drop-notice.spec.ts reduced. Lose repeated quiet switches avoiding snapshots and legacy host without drop-report capability requesting a snapshot. Retained imported registrar uses fake transport/xterm writes, exercising real gap/restore lifecycle rather than actual terminal rendering. No equivalent replacement coverage is claimed. The existing primary-selector receipt and its claims remain scoped to their unchanged sources; the broad optional command has no new execution result.", + "coverageNotes": "Audit3349 retires the whole terminal-render-desync-sentinel suite, including the same-cells persistence/recovery alarm, without equivalent replacement. Its unit command selector, test-file selector and assertion reference are removed prospectively. Earlier global-effects/window-wake retirements and the retired dated sentinel receipt remain historical verbatim. Two unrelated macOS document-visibility E2E receipts remain verbatim; the frozen static closure does not select changed tests through their literal roots. No fresh GPU/rendered UI, runtime, historical-import, mobile, mixed-version or cross-platform validation is claimed. NEXT46 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence. Historical prior account (preserved verbatim): Audit3335 retires the complete mocked window-wake recovery suite (11 authored registrations/12 expanded cases), intentionally losing fullscreen atlas-preservation, wake callback ordering, deferred-DPR deduplication/repair and private frame-budget alarms without equivalent replacement. The surviving focused selector is unexecuted in this source composition. Unrelated dated receipts keep their original scope; no fresh runtime/GPU/focus, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit3326 adopts reconciled source audit3324 and intentionally retires these low-value examples and their regression alarms: recovers visible terminal rendering and input when the window regains focus — Whole suite: fake React useEffect immediately invokes bodies and ignores cleanup/deps; fake useRef/store hooks plus mocked pane manager only assert callback choreography. Does not exercise window focus, actual input or pixels. Retires focus wake wiring alarm.; clears WebGL texture atlases when the OS resumes — Whole suite: same fake-hook harness invokes captured OS resume callback and counts mocked atlas-clear/repaint methods. No GPU, actual OS resume, or real hook lifetime. Retires atlas clear wiring alarm.; preserves WebGL texture atlases when the active terminal document becomes visible — Whole suite: direct fake document visibility listener and mock-call absence/presence under fake hooks cannot establish real WebGL preservation or cleanup. Retires visibility wake wiring alarm.. Retained tests do not replace these alarms. Dated unrelated evidence remains scoped to its original execution; no historical source/import-closure equivalence, fresh execution, real network/provider/SSH, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Audit1417 intentionally deletes src/renderer/src/components/terminal-pane/pty-connection-hidden-tui-snapshot-replay.spec.ts: Loses rich hidden snapshot sequence replay/grid resize and forced repaint after hidden snapshot alarms, including live-trigger deduplication. No equivalent replacement coverage or fresh result is claimed. Historical coverage account: Audit1342 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Deterministic renderer contracts require foreground renderer-risk, synchronized, hidden, and alternate-screen PTY output to stay on pane-local repaint paths without a global atlas reset. Separate contracts preserve explicit paste, reveal, visibility-resume, system-resume, and confirmed-desync recovery. A macOS Electron run verifies that a document visibility cycle preserves real WebGL atlases and terminal pixels; the candidate has not been rerun against an isolated live paired server. The test-value audit removed registry recovery fanout, visibility, ordering and failure-isolation assertions. The remaining registry test constrains diagnostic sampling only and is excluded from this gate. No equivalent recovery coverage is claimed. Completed settled tab-reveal repaint execution is not covered after removal of pane-reveal-repaint.test.ts. The separate terminal-visibility-resume tests assert mocked scheduling and presentation calls; they do not establish completed repaint execution. Audit1342: src/renderer/src/lib/pane-manager/pane-webgl-context-recovery.test.ts removed. Context resume/reveal retry and deferred rebuild mock-pane alarms disappear. No equivalent replacement coverage is claimed. Audit1391: src/renderer/src/components/terminal-pane/pty-connection-remote-pause-drop-notice.spec.ts reduced. Lose repeated quiet switches avoiding snapshots and legacy host without drop-report capability requesting a snapshot. Retained imported registrar uses fake transport/xterm writes, exercising real gap/restore lifecycle rather than actual terminal rendering. No equivalent replacement coverage is claimed. The existing primary-selector receipt and its claims remain scoped to their unchanged sources; the broad optional command has no new execution result.", "motivatingLinks": [ "https://github.com/stablyai/orca/pull/7054", "https://github.com/stablyai/orca/pull/7604", "https://github.com/stablyai/orca/issues/12094" ], "invariant": "Ordinary PTY output must never clear the shared WebGL glyph atlas, including synchronized frames, hidden output, renderer-risk glyphs, and alternate-screen entry, redraw, or exit. Affected visible panes still receive pane-local refresh after parsing. Explicit paste, reveal, visibility-resume, system-resume, context-loss, and confirmed-desync recovery remain available and may reset visible renderers.", - "oracle": "Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Historical pre-audit oracle account for changed sources: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Parse foreground renderer-risk, synchronized, hidden, and alternate-screen PTY output and require pane-local refresh where needed with zero calls to shared reset-and-refresh recovery. Require the atlas-recovery module to expose only explicit lifecycle entry points, then verify paste recovery. Completed settled tab-reveal repaint is not verified by the remaining unit evidence. Dispatch a visible document visibilitychange and require atlas-preserving wake recovery. Separately, drive an Electron visibility cycle with two real WebGL panes, require zero atlas clears, and retain at least 85% of each pane's baseline ink pixels.", + "oracle": "Audit3349 retires the whole terminal-render-desync-sentinel suite, including the same-cells persistence/recovery alarm, without equivalent replacement. Its unit command selector, test-file selector and assertion reference are removed prospectively. Earlier global-effects/window-wake retirements and the retired dated sentinel receipt remain historical verbatim. Two unrelated macOS document-visibility E2E receipts remain verbatim; the frozen static closure does not select changed tests through their literal roots. No fresh GPU/rendered UI, runtime, historical-import, mobile, mixed-version or cross-platform validation is claimed. Audit3335 retires the complete mocked window-wake recovery suite (11 authored registrations/12 expanded cases), intentionally losing fullscreen atlas-preservation, wake callback ordering, deferred-DPR deduplication/repair and private frame-budget alarms without equivalent replacement. The surviving focused selector is unexecuted in this source composition. Unrelated dated receipts keep their original scope; no fresh runtime/GPU/focus, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit3326 adopts reconciled source audit3324 and intentionally retires these low-value examples and their regression alarms: recovers visible terminal rendering and input when the window regains focus — Whole suite: fake React useEffect immediately invokes bodies and ignores cleanup/deps; fake useRef/store hooks plus mocked pane manager only assert callback choreography. Does not exercise window focus, actual input or pixels. Retires focus wake wiring alarm.; clears WebGL texture atlases when the OS resumes — Whole suite: same fake-hook harness invokes captured OS resume callback and counts mocked atlas-clear/repaint methods. No GPU, actual OS resume, or real hook lifetime. Retires atlas clear wiring alarm.; preserves WebGL texture atlases when the active terminal document becomes visible — Whole suite: direct fake document visibility listener and mock-call absence/presence under fake hooks cannot establish real WebGL preservation or cleanup. Retires visibility wake wiring alarm.. Retained tests do not replace these alarms. Dated unrelated evidence remains scoped to its original execution; no historical source/import-closure equivalence, fresh execution, real network/provider/SSH, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Retained exact unchanged-source receipts remain the only current execution evidence. Reduced selectors have no fresh execution result. Historical pre-audit oracle account for changed sources: The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Parse foreground renderer-risk, synchronized, hidden, and alternate-screen PTY output and require pane-local refresh where needed with zero calls to shared reset-and-refresh recovery. Require the atlas-recovery module to expose only explicit lifecycle entry points, then verify paste recovery. Completed settled tab-reveal repaint is not verified by the remaining unit evidence. Dispatch a visible document visibilitychange and require atlas-preserving wake recovery. Separately, drive an Electron visibility cycle with two real WebGL panes, require zero atlas clears, and retain at least 85% of each pane's baseline ink pixels.", "commands": [ - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-window-wake-recovery.test.ts src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-pane-global-effects-window-focus-recovery.test.ts src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts", "pnpm run ensure:electron-runtime && pnpm exec playwright test tests/e2e/terminal-document-visibility-webgl-recovery.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1", "pnpm run ensure:electron-runtime && pnpm exec playwright test tests/e2e/terminal-document-visibility-webgl-recovery.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1" ], "testFiles": [ - "src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-window-wake-recovery.test.ts", - "src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-pane-global-effects-window-focus-recovery.test.ts", - "src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts", "src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts", "src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts", "tests/e2e/terminal-document-visibility-webgl-recovery.spec.ts" ], "assertionRefs": [ - { - "file": "src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-window-wake-recovery.test.ts", - "assertions": ["preserves the glyph atlas when a fullscreen Space becomes visible"] - }, - { - "file": "src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-pane-global-effects-window-focus-recovery.test.ts", - "assertions": [ - "preserves WebGL texture atlases when the active terminal document becomes visible" - ] - }, - { - "file": "src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts", - "assertions": ["persists and recovers after the same cells stay missing twice"] - }, { "file": "src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts", "assertions": ["keeps hidden synchronized output off the global atlas recovery path"] @@ -12344,6 +12052,9 @@ "Add Linux and Windows WebGL visibility evidence before claiming cross-platform visual coverage." ], "knownGaps": [ + "NEXT65 current scope qualification: The NEXT65 knownGaps entries below govern the changed selectors and qualify any broader coverage implication in this gate’s unchanged oracle/coverageNotes narratives. Those narratives and preserved dated evidenceRuns retain their historical text and original exact execution scopes only; no fresh execution, transferred pass or equivalent replacement coverage is claimed. Upstream case removals remain upstream; original NEXT65 proposal descriptions grant no duplicate retirement credit.", + "NEXT65 active selector scope reduction (including directory-selected whole-file retirements): src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts. Remove complete registrations or registrar files within the selected scope for src/renderer/src/components/terminal-pane/pty-connection/reattach/pty-connection-daemon-snapshot-replay.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/emulation/pty-connection-mode-2031-subscriptions.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/reattach/pty-connection-stale-daemon-snapshot-replay.spec.ts. Intentionally lose these named regression alarms without replacement: catches a subscribed pane up once per mode change across repeated reconnects — Mode2031 theme reporting catch-up/deduplication across repeated reconnects loses this direct protocol example.; defers to the viewer holding the grid, then catches up once on release — Held-grid viewer deferral and one catch-up/current-mode resending on release lose this direct protocol example.; clears the captured pen for a normal-buffer fallback reattach — Fallback normal-buffer reattach clearing captured pen and dirty background loses this direct example.; waits for a recovered destination fit before forwarding its grid or live output — Recovered destination fitting before forwarding grid or live output loses this direct example.; suppresses the deferred reattach grid push when mobile claims the PTY while hidden — Mobile takeover while hidden suppressing deferred reattach grid forwarding loses this direct example.; drops stale callbacks but delivers fresh replacement output after an old replay clear — Fresh replacement output winning over stale callbacks after old replay clear loses this direct example.. Surviving parent statements and sibling registrations are preserved, but these reduced parent selectors have no fresh execution or transferred historical pass. Unrelated complete dated receipts retain only their original exact scopes; no equivalent replacement, rendered UI, provider, mobile, or cross-platform coverage is claimed.", + "NEXT65 historical original active parent-selector fields (verbatim native JSON values; not current coverage):\ncommands: [\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts\",\n \"pnpm run ensure:electron-runtime && pnpm exec playwright test tests/e2e/terminal-document-visibility-webgl-recovery.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\",\n \"pnpm run ensure:electron-runtime && pnpm exec playwright test tests/e2e/terminal-document-visibility-webgl-recovery.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\"\n ]\ntestFiles: [\n \"src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts\",\n \"tests/e2e/terminal-document-visibility-webgl-recovery.spec.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts\",\n \"assertions\": [\"persists and recovers after the same cells stay missing twice\"]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"assertions\": [\"keeps hidden synchronized output off the global atlas recovery path\"]\n },\n {\n \"file\": \"tests/e2e/terminal-document-visibility-webgl-recovery.spec.ts\",\n \"assertions\": [\n \"preserves the WebGL atlas and keeps terminal text painted after document visibility resumes\"\n ]\n }\n ]", "Audit3061 retires the park-model supplied snapshot suite and nominal mode, cursor, focus, geometry and remote resume metadata variants. Their distinct alarms are intentionally lost; six retained mode/remote cases preserve selected tail-order, authority and parse-readiness boundaries without equivalent replacement. Existing selectors and dated evidence retain their original scope.", "Audit3053 reduces hidden-replay coverage by retiring nominal overlap, resize, cursor metadata and standalone stalled-restore variants. Timeout, overflow, identity/generation fences and retained live-output coordination remain; the removed alarms are intentionally lost without equivalent replacement. Existing commands, assertion references and dated evidence retain their original scope.", "Audit3037 removes seven supplied-input baseline cases from the terminal-input-gating registrar. Input-and-repaint wrapper selectors and unrelated assertions remain; historical receipts do not validate the reduced source bytes. No renewed atlas, renderer, native or performance evidence is claimed.", @@ -12359,7 +12070,15 @@ "Audit1342 historical assertion inventory for deleted/reduced sources; not current validated assertions:\n[\n {\n \"file\": \"src/renderer/src/lib/pane-manager/pane-webgl-context-recovery.test.ts\",\n \"assertions\": [\n \"recovers a context-lost pane on the next rendering resume\"\n ]\n }\n]", "Audit1391: src/renderer/src/components/terminal-pane/pty-connection-remote-pause-drop-notice.spec.ts reduced. Lose repeated quiet switches avoiding snapshots and legacy host without drop-report capability requesting a snapshot. Retained imported registrar uses fake transport/xterm writes, exercising real gap/restore lifecycle rather than actual terminal rendering. No equivalent replacement coverage is claimed. Existing exact primary-selector receipts remain unchanged.", "Audit1417 intentionally deletes src/renderer/src/components/terminal-pane/pty-connection-hidden-tui-snapshot-replay.spec.ts: Loses rich hidden snapshot sequence replay/grid resize and forced repaint after hidden snapshot alarms, including live-trigger deduplication. No equivalent replacement coverage or fresh result is claimed.", - "Issue #22458 removes non-Windows repaint tests that only assert private synchronous refresh calls. Their renderer-risk and alternate-screen atlas assertions are no longer registered; historical results do not validate equivalent coverage." + "Issue #22458 removes non-Windows repaint tests that only assert private synchronous refresh calls. Their renderer-risk and alternate-screen atlas assertions are no longer registered; historical results do not validate equivalent coverage.", + "Audit3326 adopts reconciled source audit3324 and intentionally retires these low-value examples and their regression alarms: recovers visible terminal rendering and input when the window regains focus — Whole suite: fake React useEffect immediately invokes bodies and ignores cleanup/deps; fake useRef/store hooks plus mocked pane manager only assert callback choreography. Does not exercise window focus, actual input or pixels. Retires focus wake wiring alarm.; clears WebGL texture atlases when the OS resumes — Whole suite: same fake-hook harness invokes captured OS resume callback and counts mocked atlas-clear/repaint methods. No GPU, actual OS resume, or real hook lifetime. Retires atlas clear wiring alarm.; preserves WebGL texture atlases when the active terminal document becomes visible — Whole suite: direct fake document visibility listener and mock-call absence/presence under fake hooks cannot establish real WebGL preservation or cleanup. Retires visibility wake wiring alarm.. Retained tests do not replace these alarms. Dated unrelated evidence remains scoped to its original execution; no historical source/import-closure equivalence, fresh execution, real network/provider/SSH, rendered UI, mobile, mixed-version or cross-platform validation is claimed.", + "Audit3335 retires the complete mocked window-wake recovery suite (11 authored registrations/12 expanded cases), intentionally losing fullscreen atlas-preservation, wake callback ordering, deferred-DPR deduplication/repair and private frame-budget alarms without equivalent replacement. The surviving focused selector is unexecuted in this source composition. Unrelated dated receipts keep their original scope; no fresh runtime/GPU/focus, rendered UI, mobile, mixed-version or cross-platform validation is claimed.", + "NEXT46 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence.", + "NEXT46 historical original active selector fields (verbatim JSON values; not current coverage):\ncommands: [\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts\",\n \"pnpm run ensure:electron-runtime && pnpm exec playwright test tests/e2e/terminal-document-visibility-webgl-recovery.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1\",\n \"pnpm run ensure:electron-runtime && pnpm exec playwright test tests/e2e/terminal-document-visibility-webgl-recovery.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\"\n ]\ntestFiles: [\n \"src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts\",\n \"tests/e2e/terminal-document-visibility-webgl-recovery.spec.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts\",\n \"assertions\": [\"persists and recovers after the same cells stay missing twice\"]\n },\n {\n \"file\": \"src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts\",\n \"assertions\": [\"keeps hidden synchronized output off the global atlas recovery path\"]\n },\n {\n \"file\": \"tests/e2e/terminal-document-visibility-webgl-recovery.spec.ts\",\n \"assertions\": [\n \"preserves the WebGL atlas and keeps terminal text painted after document visibility resumes\"\n ]\n }\n ]", + "Audit3349 retires the whole terminal-render-desync-sentinel suite, including the same-cells persistence/recovery alarm, without equivalent replacement. Its unit command selector, test-file selector and assertion reference are removed prospectively. Earlier global-effects/window-wake retirements and the retired dated sentinel receipt remain historical verbatim. Two unrelated macOS document-visibility E2E receipts remain verbatim; the frozen static closure does not select changed tests through their literal roots. No fresh GPU/rendered UI, runtime, historical-import, mobile, mixed-version or cross-platform validation is claimed.", + "Audit3349 historical original commands object, preserved verbatim; retired source claims are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts\"", + "Audit3349 historical original testFiles object, preserved verbatim; retired source claims are not active evidence or replacement coverage:\n\"src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts\"", + "Audit3349 historical original assertionRefs object, preserved verbatim; retired source claims are not active evidence or replacement coverage:\n{\n \"file\": \"src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts\",\n \"assertions\": [\"persists and recovers after the same cells stay missing twice\"]\n }" ], "demotionRule": "Demote if ordinary PTY output re-enters shared reset/refresh recovery, pane-local redraw coverage regresses, ordinary visibility clears the atlas, real WebGL pixels regress, or the focused Electron test cannot remain deterministic." }, @@ -12431,38 +12150,19 @@ "providers": ["local", "daemon"], "coveredPlatforms": ["macos"], "coveredProviders": ["local"], - "coverageNotes": "Audit1948: Audit1944 keeps the two snapshot/imageless restore cases but removes three real-clock delayed-scheduling/null-retry cases from pty-connection-hidden-runtime-snapshot.test.ts. Inactive split scheduling and its mock boundary alarms are intentionally lost. The changed source has no transferred historical pass, timing or equivalent-rendered-coverage claim. Independent unchanged headed Electron receipts retain only their original exact scopes; static metadata/source review is no fresh execution evidence. The entire dated 98-contract renderer receipt is retired whole, with all original command/currentCommand/date/count/result fields preserved as historical. Historical prior account (preserved verbatim): A headed macOS Electron test drives explicit destructive atlas recovery while DEC 2026 output is held, then compares compositor screenshots before and after a direct full-buffer present. The same renderer choreography is provider-local, but daemon, SSH, remote-runtime, Linux, and Windows GPU runs remain gaps. The test-value audit removed registry recovery fanout, visibility, ordering and failure-isolation assertions. The remaining registry test constrains diagnostic sampling only and is excluded from this gate. No equivalent recovery coverage is claimed. The audit removes the canvas-DPR and render-pause-release unit suites and several renderer flag/retry examples. Their isolated DPR-cache, render-service routing and display-none retry alarms are no longer registered; retained unit and historical Electron evidence do not establish equivalent coverage. No live GPU rerun accompanies this administrative update.", + "coverageNotes": "NEXT46 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts, src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts, src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts, src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence. Historical prior account (preserved verbatim): Audit3335 retires the complete mocked window-wake recovery suite (11 authored registrations/12 expanded cases), intentionally losing fullscreen atlas-preservation, wake callback ordering, deferred-DPR deduplication/repair and private frame-budget alarms without equivalent replacement. The surviving focused selector is unexecuted in this source composition. Unrelated dated receipts keep their original scope; no fresh runtime/GPU/focus, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit1948: Audit1944 keeps the two snapshot/imageless restore cases but removes three real-clock delayed-scheduling/null-retry cases from pty-connection-hidden-runtime-snapshot.test.ts. Inactive split scheduling and its mock boundary alarms are intentionally lost. The changed source has no transferred historical pass, timing or equivalent-rendered-coverage claim. Independent unchanged headed Electron receipts retain only their original exact scopes; static metadata/source review is no fresh execution evidence. The entire dated 98-contract renderer receipt is retired whole, with all original command/currentCommand/date/count/result fields preserved as historical. Historical prior account (preserved verbatim): A headed macOS Electron test drives explicit destructive atlas recovery while DEC 2026 output is held, then compares compositor screenshots before and after a direct full-buffer present. The same renderer choreography is provider-local, but daemon, SSH, remote-runtime, Linux, and Windows GPU runs remain gaps. The test-value audit removed registry recovery fanout, visibility, ordering and failure-isolation assertions. The remaining registry test constrains diagnostic sampling only and is excluded from this gate. No equivalent recovery coverage is claimed. The audit removes the canvas-DPR and render-pause-release unit suites and several renderer flag/retry examples. Their isolated DPR-cache, render-service routing and display-none retry alarms are no longer registered; retained unit and historical Electron evidence do not establish equivalent coverage. No live GPU rerun accompanies this administrative update.", "motivatingLinks": [ "https://github.com/stablyai/orca/pull/7133", "https://github.com/stablyai/orca/pull/7054" ], "invariant": "After proven renderer damage triggers destructive recovery, visible pixels equal a full model-invalidating present of the current buffer.", - "oracle": "Audit1948: Audit1944 keeps the two snapshot/imageless restore cases but removes three real-clock delayed-scheduling/null-retry cases from pty-connection-hidden-runtime-snapshot.test.ts. Inactive split scheduling and its mock boundary alarms are intentionally lost. The changed source has no transferred historical pass, timing or equivalent-rendered-coverage claim. Independent unchanged headed Electron receipts retain only their original exact scopes; static metadata/source review is no fresh execution evidence. Historical prior account (preserved verbatim): Hold DEC 2026, invoke explicit atlas recovery, require an atlas clear, screenshot the pane, force a direct renderer present, and assert the bounded pixel diff is immaterial. Compositor screenshots only, because WebGL canvas readback is blank with preserveDrawingBuffer disabled.", + "oracle": "Audit3335 retires the complete mocked window-wake recovery suite (11 authored registrations/12 expanded cases), intentionally losing fullscreen atlas-preservation, wake callback ordering, deferred-DPR deduplication/repair and private frame-budget alarms without equivalent replacement. The surviving focused selector is unexecuted in this source composition. Unrelated dated receipts keep their original scope; no fresh runtime/GPU/focus, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Audit1948: Audit1944 keeps the two snapshot/imageless restore cases but removes three real-clock delayed-scheduling/null-retry cases from pty-connection-hidden-runtime-snapshot.test.ts. Inactive split scheduling and its mock boundary alarms are intentionally lost. The changed source has no transferred historical pass, timing or equivalent-rendered-coverage claim. Independent unchanged headed Electron receipts retain only their original exact scopes; static metadata/source review is no fresh execution evidence. Historical prior account (preserved verbatim): Hold DEC 2026, invoke explicit atlas recovery, require an atlas clear, screenshot the pane, force a direct renderer present, and assert the bounded pixel diff is immaterial. Compositor screenshots only, because WebGL canvas readback is blank with preserveDrawingBuffer disabled.", "commands": [ "pnpm run ensure:electron-runtime && pnpm exec playwright test tests/e2e/terminal-reveal-paused-render-repro.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-window-wake-recovery.test.ts src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts", "ORCA_E2E_RECORD_VIDEO=1 pnpm exec playwright test tests/e2e/terminal-reveal-paused-render-repro.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1 --repeat-each=3" ], - "testFiles": [ - "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts", - "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts", - "src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts", - "src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-window-wake-recovery.test.ts", - "src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts", - "tests/e2e/terminal-reveal-paused-render-repro.spec.ts" - ], + "testFiles": ["tests/e2e/terminal-reveal-paused-render-repro.spec.ts"], "assertionRefs": [ - { - "file": "src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-window-wake-recovery.test.ts", - "assertions": [ - "deduplicates a deferred dpr retry and consumes it after repair succeeds", - "caps a deferred dpr transition at sixteen animation-frame retries" - ] - }, - { - "file": "src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts", - "assertions": ["defers a heavy-reveal dpr present until the shared atlas recovery"] - }, { "file": "tests/e2e/terminal-reveal-paused-render-repro.spec.ts", "assertions": ["@headful atlas recovery presents a synchronized-output WebGL frame"] @@ -12516,7 +12216,10 @@ "The test-value audit removed registry recovery fanout, visibility, ordering and failure-isolation assertions. The remaining registry test constrains diagnostic sampling only and is excluded from this gate. No equivalent recovery coverage is claimed.", "The audit removes the canvas-DPR and render-pause-release unit suites and several renderer flag/retry examples. Their isolated DPR-cache, render-service routing and display-none retry alarms are no longer registered; retained unit and historical Electron evidence do not establish equivalent coverage. No live GPU rerun accompanies this administrative update.", "Audit1948: Audit1944 keeps the two snapshot/imageless restore cases but removes three real-clock delayed-scheduling/null-retry cases from pty-connection-hidden-runtime-snapshot.test.ts. Inactive split scheduling and its mock boundary alarms are intentionally lost. The changed source has no transferred historical pass, timing or equivalent-rendered-coverage claim. Independent unchanged headed Electron receipts retain only their original exact scopes; static metadata/source review is no fresh execution evidence.", - "Audit1948 historical original evidenceRuns object, preserved verbatim; retired objects are not active execution evidence or replacement coverage:\n{\n \"date\": \"2026-08-23\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-connection-hidden-backlog-snapshot.test.ts src/renderer/src/components/terminal-pane/terminal-visibility-resume.test.ts src/renderer/src/components/terminal-pane/use-terminal-window-wake-recovery.test.ts src/renderer/src/lib/pane-manager/pane-manager-registry.test.ts src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts src/renderer/src/lib/pane-manager/terminal-canvas-dpr-repair.test.ts src/renderer/src/lib/pane-manager/terminal-render-pause-release.test.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 2,\n \"summary\": \"All 98 renderer contracts passed, including same-DPR zero-scan behavior, visible-only fanout, tri-state DPR repair, deduplicated bounded retry, heavy-reveal repair, and listener cleanup. Historical command preserved after the test-value audit removed the referenced reveal/repaint or registry recovery assertions. currentCommand is an administrative link; this historical run has not validated the remaining command or equivalent coverage. Administrative command maintenance removes deleted unit suites; the executed command and result are historical, with no rerun or equivalence claim.\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-window-wake-recovery.test.ts src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts\"\n }" + "Audit1948 historical original evidenceRuns object, preserved verbatim; retired objects are not active execution evidence or replacement coverage:\n{\n \"date\": \"2026-08-23\",\n \"runner\": \"local\",\n \"platform\": \"macos\",\n \"command\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-connection-hidden-backlog-snapshot.test.ts src/renderer/src/components/terminal-pane/terminal-visibility-resume.test.ts src/renderer/src/components/terminal-pane/use-terminal-window-wake-recovery.test.ts src/renderer/src/lib/pane-manager/pane-manager-registry.test.ts src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts src/renderer/src/lib/pane-manager/terminal-canvas-dpr-repair.test.ts src/renderer/src/lib/pane-manager/terminal-render-pause-release.test.ts\",\n \"result\": \"passed\",\n \"durationSeconds\": 2,\n \"summary\": \"All 98 renderer contracts passed, including same-DPR zero-scan behavior, visible-only fanout, tri-state DPR repair, deduplicated bounded retry, heavy-reveal repair, and listener cleanup. Historical command preserved after the test-value audit removed the referenced reveal/repaint or registry recovery assertions. currentCommand is an administrative link; this historical run has not validated the remaining command or equivalent coverage. Administrative command maintenance removes deleted unit suites; the executed command and result are historical, with no rerun or equivalence claim.\",\n \"currentCommand\": \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-window-wake-recovery.test.ts src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts\"\n }", + "Audit3335 retires the complete mocked window-wake recovery suite (11 authored registrations/12 expanded cases), intentionally losing fullscreen atlas-preservation, wake callback ordering, deferred-DPR deduplication/repair and private frame-budget alarms without equivalent replacement. The surviving focused selector is unexecuted in this source composition. Unrelated dated receipts keep their original scope; no fresh runtime/GPU/focus, rendered UI, mobile, mixed-version or cross-platform validation is claimed.", + "NEXT46 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts, src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts, src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts, src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence.", + "NEXT46 historical original active selector fields (verbatim JSON values; not current coverage):\ncommands: [\n \"pnpm run ensure:electron-runtime && pnpm exec playwright test tests/e2e/terminal-reveal-paused-render-repro.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts\",\n \"ORCA_E2E_RECORD_VIDEO=1 pnpm exec playwright test tests/e2e/terminal-reveal-paused-render-repro.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1 --repeat-each=3\"\n ]\ntestFiles: [\n \"src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts\",\n \"src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts\",\n \"src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts\",\n \"tests/e2e/terminal-reveal-paused-render-repro.spec.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts\",\n \"assertions\": [\"defers a heavy-reveal dpr present until the shared atlas recovery\"]\n },\n {\n \"file\": \"tests/e2e/terminal-reveal-paused-render-repro.spec.ts\",\n \"assertions\": [\"@headful atlas recovery presents a synchronized-output WebGL frame\"]\n }\n ]" ], "demotionRule": "Drop from the golden suite back to nightly diagnostic if diff thresholds cannot be kept stable across CI runners." }, @@ -12532,7 +12235,7 @@ "providers": ["local", "daemon", "ssh", "remote-runtime"], "coveredPlatforms": ["macos"], "coveredProviders": ["local"], - "coverageNotes": "Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit1948: Audit1944 keeps the two snapshot/imageless restore cases but removes three real-clock delayed-scheduling/null-retry cases from pty-connection-hidden-runtime-snapshot.test.ts. Inactive split scheduling and its mock boundary alarms are intentionally lost. The changed source has no transferred historical pass, timing or equivalent-rendered-coverage claim. Independent unchanged headed Electron receipts retain only their original exact scopes; static metadata/source review is no fresh execution evidence. Historical prior account (preserved verbatim): A headed macOS Electron test uses a real xterm WebGL renderer and production tab reveal. It proves the coherent pre-hide canvas remains visible while DEC 2026 holds a newer buffer, then proves normal release and xterm's one-second watchdog publish complete frames. Renderer behavior is provider-neutral; live Linux, Windows, daemon, SSH, and remote-runtime GPU runs remain gaps. The audit removes isolated synchronized-frame viewport-present and render-pause-release unit examples. The historical headed Electron oracle remains recorded; retained scheduling tests do not establish equivalent render-service routing or completed-frame coverage. No live GPU rerun accompanies this administrative update.", + "coverageNotes": "NEXT46 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts, src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts, src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts, src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence. Historical prior account (preserved verbatim): Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit1948: Audit1944 keeps the two snapshot/imageless restore cases but removes three real-clock delayed-scheduling/null-retry cases from pty-connection-hidden-runtime-snapshot.test.ts. Inactive split scheduling and its mock boundary alarms are intentionally lost. The changed source has no transferred historical pass, timing or equivalent-rendered-coverage claim. Independent unchanged headed Electron receipts retain only their original exact scopes; static metadata/source review is no fresh execution evidence. Historical prior account (preserved verbatim): A headed macOS Electron test uses a real xterm WebGL renderer and production tab reveal. It proves the coherent pre-hide canvas remains visible while DEC 2026 holds a newer buffer, then proves normal release and xterm's one-second watchdog publish complete frames. Renderer behavior is provider-neutral; live Linux, Windows, daemon, SSH, and remote-runtime GPU runs remain gaps. The audit removes isolated synchronized-frame viewport-present and render-pause-release unit examples. The historical headed Electron oracle remains recorded; retained scheduling tests do not establish equivalent render-service routing or completed-frame coverage. No live GPU rerun accompanies this administrative update.", "motivatingLinks": [ "https://github.com/stablyai/orca/pull/7133", "https://github.com/stablyai/orca/pull/7054" @@ -12540,24 +12243,10 @@ "invariant": "terminal-render.synchronized-reveal-coherence: an ordinary reveal never clears a healthy shared atlas or publishes a partially built DEC 2026 frame; it retains the last coherent canvas until release or xterm's bounded watchdog.", "oracle": "Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit1948: Audit1944 keeps the two snapshot/imageless restore cases but removes three real-clock delayed-scheduling/null-retry cases from pty-connection-hidden-runtime-snapshot.test.ts. Inactive split scheduling and its mock boundary alarms are intentionally lost. The changed source has no transferred historical pass, timing or equivalent-rendered-coverage claim. Independent unchanged headed Electron receipts retain only their original exact scopes; static metadata/source review is no fresh execution evidence. Historical prior account (preserved verbatim): Paint and capture a coherent frame, hide the real terminal tab, build a distinct full-screen frame while DEC 2026 is held, reveal through production, and require zero atlas clears plus pixel-equivalence with the coherent frame. Then release normally and through the one-second watchdog, requiring both compositor frames to match a direct renderer present.", "commands": [ - "pnpm run ensure:electron-runtime && pnpm exec playwright test tests/e2e/terminal-reveal-paused-render-repro.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1", - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts" - ], - "testFiles": [ - "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts", - "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts", - "src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts", - "src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts", - "tests/e2e/terminal-reveal-paused-render-repro.spec.ts" + "pnpm run ensure:electron-runtime && pnpm exec playwright test tests/e2e/terminal-reveal-paused-render-repro.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1" ], + "testFiles": ["tests/e2e/terminal-reveal-paused-render-repro.spec.ts"], "assertionRefs": [ - { - "file": "src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts", - "assertions": [ - "schedules an atlas-preserving present on a light tab reveal", - "keeps heavy atlas recovery off a plain window refocus" - ] - }, { "file": "tests/e2e/terminal-reveal-paused-render-repro.spec.ts", "assertions": [ @@ -12603,7 +12292,9 @@ "Linux, Windows, daemon, SSH, and remote-runtime live GPU evidence is not yet recorded.", "The 1.5% compositor threshold tolerates cursor and shell-prompt timing noise; exact buffer content and atlas-clear counts are asserted separately.", "The audit removes isolated synchronized-frame viewport-present and render-pause-release unit examples. The historical headed Electron oracle remains recorded; retained scheduling tests do not establish equivalent render-service routing or completed-frame coverage. No live GPU rerun accompanies this administrative update.", - "Audit1948: Audit1944 keeps the two snapshot/imageless restore cases but removes three real-clock delayed-scheduling/null-retry cases from pty-connection-hidden-runtime-snapshot.test.ts. Inactive split scheduling and its mock boundary alarms are intentionally lost. The changed source has no transferred historical pass, timing or equivalent-rendered-coverage claim. Independent unchanged headed Electron receipts retain only their original exact scopes; static metadata/source review is no fresh execution evidence." + "Audit1948: Audit1944 keeps the two snapshot/imageless restore cases but removes three real-clock delayed-scheduling/null-retry cases from pty-connection-hidden-runtime-snapshot.test.ts. Inactive split scheduling and its mock boundary alarms are intentionally lost. The changed source has no transferred historical pass, timing or equivalent-rendered-coverage claim. Independent unchanged headed Electron receipts retain only their original exact scopes; static metadata/source review is no fresh execution evidence.", + "NEXT46 terminal-owner layout and whole-case policy: src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts, src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts, src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts, src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts. Complete retired/reduced selectors lose their listed alarms; retained cases have no transferred historical pass or equivalent replacement coverage. Unaffected dated receipts retain only their original exact scopes. This metadata edit is not fresh execution evidence.", + "NEXT46 historical original active selector fields (verbatim JSON values; not current coverage):\ncommands: [\n \"pnpm run ensure:electron-runtime && pnpm exec playwright test tests/e2e/terminal-reveal-paused-render-repro.spec.ts --config tests/playwright.config.ts --project electron-headful --workers=1\",\n \"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts\"\n ]\ntestFiles: [\n \"src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts\",\n \"src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts\",\n \"src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts\",\n \"src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts\",\n \"tests/e2e/terminal-reveal-paused-render-repro.spec.ts\"\n ]\nassertionRefs: [\n {\n \"file\": \"src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts\",\n \"assertions\": [\n \"schedules an atlas-preserving present on a light tab reveal\",\n \"keeps heavy atlas recovery off a plain window refocus\"\n ]\n },\n {\n \"file\": \"tests/e2e/terminal-reveal-paused-render-repro.spec.ts\",\n \"assertions\": [\n \"@headful reveal preserves the coherent frame until synchronized output releases\"\n ]\n }\n ]" ], "demotionRule": "Demote if ordinary reveal clears the shared atlas, the held frame stops matching its coherent baseline, release/watchdog output diverges from a direct present, or the headed oracle cannot remain deterministic." }, @@ -12736,14 +12427,14 @@ "providers": ["local", "remote-runtime", "ssh"], "coveredPlatforms": ["macos", "linux"], "coveredProviders": ["local", "remote-runtime", "ssh"], - "coverageNotes": "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/runtime/files/watching/runtime-file-client-watch.test.ts: delivers remote file changes to listeners for the same worktree. src/main/runtime/orca-runtime.test.ts: ordinary registration cleanup removes only await import('./orca-runtime-tests/mobile-session-tabs-part-14.spec'). src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-03.spec.ts: arms the stale-title timer for a seeded working title; arms the Command Code scrape from the noted spawn command; prefers the tracked title over a stale renderer lastTitle in the hydration seed; writes recent output into the current runtime output map; uses a later title handler replacement with the runtime receiver; calls the current injected listener with the runtime receiver; keeps optional reconciliation lazy after its callback is removed. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-14.spec.ts: lists them, so a paired client can mirror a migrated editor; closes one by retiring it from the host session; keeps an unsaved draft unless the close is forced; shares aggregate work but leaves a replacement pending promise alone; lets a targeted refresh finish while an aggregate refresh waits; refuses a close when the store lacks %s before the guard; keeps a later missing %s on the original caught failure path. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Exact retired assertionRefs, preserved as historical objects only: {\n \"file\": \"src/renderer/src/runtime/files/watching/runtime-file-client-watch.test.ts\",\n \"assertions\": [\n \"terminal watcher error and setup failure evict the shared entry before retrying callbacks run\",\n \"an old stream end cannot evict the replacement stream, which still delivers to its listener\",\n \"two same-worktree listeners share a synthetic subscription until the final stop unsubscribes and sends unwatch\"\n ]\n } Historical prior account (preserved verbatim): Audit1973: Delete the standalone mocked watcher cleanup suite and its entire sole-file prospective command. Retire the removed file-command transport-abort alias; preserve the independent cancellation suite and final-overflow/error/end cleanup callback, and13 unrelated receipt objects. Whole original changed dated receipts are retired, never narrowed or transferred. This metadata review claims no fresh execution, equivalent replacement, provider/PTY, live remote/mobile, rendered, cross-platform, soak or measured-budget result. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Partial runtime files-watch suite retains controlled Windows close-event waiting, shared-client survival, late physical-exit ownership/deadline cleanup and shutdown joining. Its combined Windows close/deadline/late-exit alias remains backed by unchanged callbacks. Retire native-error-close, pre-publication setup ownership and failed-delete rearm aliases; associated delegation, failure forwarding, removal routing and recovery examples are lost. These tests inject watch/subscription seams and do not observe an actual native watcher or physical process. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1925 (sources1922/1923): Partial runtime watcher-host suite loses mocked option/event/overflow/resubscription forwarding, supplied teardown-error propagation, aborted-signal/no-call and private ten-thousand-waiter-count inventories. Retire the 10,000-caller bound and failed-recovery-subscriber-ending assertion aliases. Keep same-root owner cancellation, pre-ready replacement, held root-close join, stale-generation recovery delivery and initial failed-root ownership mappings backed by retained real-host callbacks with injected subscription/error/physical-exit promises. No actual native watcher, process termination or resource bound was observed. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1683 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1645 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1634 removes low-value IPC, filesystem and runtime projections, argument inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained cancellation, ownership, authorization, filesystem and SQLite boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1627 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1623 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1516 removes package-electron-runtime-contract.test.mjs, a copied release-workflow platform and marker matrix. Its workflow wiring alarm is intentionally retired; no actual packaged watcher delivery was exercised and no equivalent replacement is claimed. Unaffected dated execution receipts retain their original scope; changed optional selectors have no fresh full-gate execution result. This audit removes the paired-web stopped-during-outage and late-ready direct-branch examples. The retained pre-ready cancellation, failed-unwatch retry and replay-continuity cases are not equivalent replacements for those ordering alarms. Current web-runtime-client.test.ts assertions below name only its retained pre-ready callback case; replay cases remain in their separate suite. Historical commands and results remain historical. Deterministic tests cover one shared healthy child per runtime process plus at most four bounded fault-quarantine children, native desktop, paired-runtime, and WSL snapshot processes sharing the same eight-physical-child reservation with typed serialized event-driven capacity recovery, including recursive re-wait when crash recovery reclaims an announced slot, one quarantine attempt per watch lifetime, generation-scoped cancellation, bounded termination with removable deadline waiters, replacement-crawl errors that cannot be blessed by a late readiness ack, pre-ready paired-web cancellation registered before an unbounded capacity wait, already-resolved and late physical-exit retry of a rejected paired-web teardown, physical desktop-install and local/SSH PTY teardown, stale-generation rejection, per-child stat bounds, final-overflow RPC delivery, and renderer eviction before terminal callbacks can retry. Destructive local and SSH removal fences both ID-derived and resolved-cwd terminal roots, including sibling-root/cwd combinations with reverse admission rollback, closes descendant relay watches before parent deletion, enumerates authoritative provider/cwd ownership, falls back to daemon spawn cwd before OSC 7, and keeps daemon/relay immediate shutdown pending until native exit or a bounded fail-closed error; a dead relay PID discovered during attach also settles concurrent shutdown before its stale entry is reaped, while Windows runtime watcher deadlines retain one removable physical-close waiter, treat Node's error-close path as positive physical-exit proof, and clear root ownership on late close. The relay policy test maps a standard repository's base, Git common directory, and worktree roots to one healthy supervisor, then proves a shared-child failure recovers those roots in separate quarantine supervisors with overflow and resumed events. Abortable capacity, quarantine, runtime-root, relay, SSH, and relay pre-install setup waits attach one reaction to each shared promise and explicitly remove 10,000 cancelled caller closures while one anchor remains. Built-entry macOS harnesses kill the desktop/runtime and SSH relay watcher children, then require automatic resubscription and later events while the host process and relay PTY survive. SSH bundles the child boundary beside relay.js, requires both artifacts for install completeness, and preserves registration-owned same-root cancellation. The test-value audit corrects the active renderer watch command/file reference to the existing runtime-file-client-watch.test.ts, whose three cases are retained unchanged. They observe synthetic subscription retry/fanout and unsubscribe/unwatch calls, not actual preload/main bookkeeping or physical watcher-process cleanup. The separate read/preview client suite loses forwarding, supplied-error and negative-only examples, retaining binary detection and Unicode SVG decoding. Historical evidence commands/results are unchanged. Test-value audit1293 removes src/main/providers/local-pty/local-pty-provider-session-inventory.test.ts (2 authored cases). Their isolated assertions no longer run; surviving tests are not claimed as equivalent coverage. Fresh execution against the candidate SHA is required. Audit1312 removes low-value imported specs from aggregate test drivers; old whole-driver execution receipts are archived. Retained registrations are unchanged. No equivalent replacement coverage is claimed. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result. Audit1412: src/main/workspaces/removal/watcher-removal-gate.test.ts reduced. Loses exact removal-error compatibility with renderer predicate under shared message constants. Kept public refusal outcomes do not establish that renderer classification. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result.", + "coverageNotes": "Audit3375 composes root-adopted3370/independent3371 and3373/independent3374: intentionally retires79 authored registrations/84 expanded cases, including39 whole suites, without equivalent replacement. Lost alarms include federation field/parser inventories; Claude rejected-key precedence, credential clone redaction, managed-versus-user hook preservation and CLI defaults; setting/status/activity projections, mocked SSH/notification/reveal/Linear refusal, fake-clock reconnect and noise; image-fold artifact visibility, paste eligibility, setup trust, scripted ACP error-to-journal publication and ligature cache tuple aliasing; plus supplied folder-runner uniqueness, mobile host-overlay/credential/update/preference races, status/markup/title/keyed-row projections, subscriber cleanup, cancellation/close/refusal/link-issue and mirror suppression alarms. Retained3373 merger contiguity, dual-clock overdue-resume exactly-once, rejected-paste IPC sink and annotation schema roundtrip remain bounded. Retained actual HTTP/OSC status composition, destructive sibling-filesystem isolation, external contrast invariant and fixture CSS pixel intervention remain narrower. Original reviewed87authored/92expanded become9/9; current OpenCode suite adds two preserved upstream cases and the synthetic-title suite gained one Cursor policy mock-call case, independently reviewed for removal in root3378; current90/95 become11/11. That Cursor suppression/ready-frame regression alarm is intentionally lost; it does not observe native title ownership or tab flicker. For3370 only the peer was independently blind, with author exposure explicit;3373/3374 both blind pins were verified. This broad root unit command selects the reduced root unit suite; UNIT_INCLUDE excludes mobile tests, which require the existing mobile runner; retained Playwright component-pixel spec uses its separate existing headless fixture runner and is not validated by the broad unit command. No fresh execution, actual agent/shell/provider, OS material/focus, historical import equivalence, mobile, mixed-version or cross-platform evidence is claimed. All dated receipts retain their original scope. Audit3368 composes root-adopted3363/3364 and3367/3369: intentionally retires181 authored registrations/196 expanded cases, including28 whole suites, without equivalent replacement. Lost alarms include hibernation attention/liveness/backoff/sequential teardown and inventory, host launch compatibility/legacy/Kimi/resource cleanup, terminal recovery parser/pause/quarantine/remount, window-visibility omission-fence lifetime, launch-option rendered Start, sleeping-resume saved recipe/WSL quoting/cancellation, plus removed project/window/input variants. Additional tiny-suite losses include sentence/label/field/default inventories, credential omission, Windows argument/environment mapping, URI decoding, diagnostics, provider classification and fake-clock callback/parser examples. Retained ten registrations/twelve expanded cases include two literal Unicode Mn/Cf zero-width range guards in the actual character-range algorithm and protect narrower delayed editor bytes/destructive ownership, mounted hidden collision repair, ten transport epochs, duplicate-command refusal, caller timeout typing, executor unknown-opener refusal and failed-chunk user bytes. This broad unit command selects the reduced suite; no fresh runtime, real provider/network/PTY, filesystem restart, native UI, historical import equivalence, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3362 composes root-adopted3358/independent3360: intentionally retires129 authored registrations/140 expanded cases, including four whole suites, without equivalent replacement. Lost alarms include supplied orphan-adoption retry/malformed inventory/cancellation; fake-terminal replay parser/wedge/disposal callbacks; all-host catalog metadata and Windows preferences; host keepalive/protocol/stale/settings failures; and removed exact-stop/suppression, source save lifetime, diff-note queue, rename/editor close, input flood/chunk refusal/limits, purge and creation examples. Retained18 registrations/21 expanded cases protect narrower ownership, generation, dirty-state, queue convergence, encoding and attachment-lease outcomes. No replacement or keeper quota claim. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY/xterm parser, disk restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3359 composes root-adopted source3355/independent3356: intentionally retires130 authored registrations/139 expanded cases, including eight whole suites, without equivalent replacement. Lost alarms include strict create naming/capability/legacy payloads; supplied transport host replacement, deadline reattach, create-handoff and split activation; agent-session fork/clipboard/platform flags; shutdown cleared-scrollback/unmounted bindings; simulator host-collision/selection/shutdown; and removed editor, catalog, mutation, launch and status examples. Retained12 adverse-ordering/state-consequence cases are narrower and do not replace all removed alarms. Two queue absences receive zero removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY, filesystem restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3349 composes adopted batches3343,3345 and refreshed3354: intentionally retires234 authored registrations/294 expanded cases, including13 whole suites, without equivalent replacement. Lost alarms include supplied terminal reconnect/replacement/typeahead/mirror/result and snapshot examples; synthetic render-desync persistence/recovery; worktree listing/owner/catalog/lineage/removal and activation/creation examples; host-scoped PR and task-record projections; editor diff/status/comment and UI send-target examples; automation observation/wake, supplied sleep/deadline clock and native-chat completion/notification/relaunch samples; held-tab layout and cleanup/progress guard examples. Retained adverse-ordering and wire-boundary cases are narrower and do not replace all removed alarms. The already-upstream visibility-resume deletion receives zero new removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH, native process/power/GPU, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3342 composes adopted source batches3333/3334,3336/3337 and3340/3341: intentionally retires180 authored registrations/263 expanded cases, including seven whole suites, without equivalent replacement. Lost alarms include corrupt editor hydration; mobile editor/diff publication and privacy projections; stale-resubscribe routing; model-picker projection/refetch/retry/fallback; editor check-details and frame property inventories; latched-pane cleanup/quiescence; client create replay identity/options/compatibility; and removed owner, async routing, terminal and layout examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts keep their original scope. Audit3335 composes adopted source unions3327/3328 and3330/3332: intentionally retires100 authored registrations/123 expanded cases, including ten whole suites, without equivalent replacement. Lost alarms include seeded host persistence/contention and stale-host cleanup; browser snapshot assembly; mocked wake/DPR callbacks and frame budgets; preflight projections; palette authority/cache suppression, URL intent and saved-title cross-repo collisions; metadata coverage/set patch and dropdown assembly; and removed terminal, worktree, review-refresh and owner-routing examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI/GPU/focus, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain only their original scope. Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed. Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed. Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed. Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical. Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims. Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands. Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/runtime/files/watching/runtime-file-client-watch.test.ts: delivers remote file changes to listeners for the same worktree. src/main/runtime/orca-runtime.test.ts: ordinary registration cleanup removes only await import('./orca-runtime-tests/mobile-session-tabs-part-14.spec'). src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-03.spec.ts: arms the stale-title timer for a seeded working title; arms the Command Code scrape from the noted spawn command; prefers the tracked title over a stale renderer lastTitle in the hydration seed; writes recent output into the current runtime output map; uses a later title handler replacement with the runtime receiver; calls the current injected listener with the runtime receiver; keeps optional reconciliation lazy after its callback is removed. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-14.spec.ts: lists them, so a paired client can mirror a migrated editor; closes one by retiring it from the host session; keeps an unsaved draft unless the close is forced; shares aggregate work but leaves a replacement pending promise alone; lets a targeted refresh finish while an aggregate refresh waits; refuses a close when the store lacks %s before the guard; keeps a later missing %s on the original caught failure path. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Exact retired assertionRefs, preserved as historical objects only: {\n \"file\": \"src/renderer/src/runtime/files/watching/runtime-file-client-watch.test.ts\",\n \"assertions\": [\n \"terminal watcher error and setup failure evict the shared entry before retrying callbacks run\",\n \"an old stream end cannot evict the replacement stream, which still delivers to its listener\",\n \"two same-worktree listeners share a synthetic subscription until the final stop unsubscribes and sends unwatch\"\n ]\n } Historical prior account (preserved verbatim): Audit1973: Delete the standalone mocked watcher cleanup suite and its entire sole-file prospective command. Retire the removed file-command transport-abort alias; preserve the independent cancellation suite and final-overflow/error/end cleanup callback, and13 unrelated receipt objects. Whole original changed dated receipts are retired, never narrowed or transferred. This metadata review claims no fresh execution, equivalent replacement, provider/PTY, live remote/mobile, rendered, cross-platform, soak or measured-budget result. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Partial runtime files-watch suite retains controlled Windows close-event waiting, shared-client survival, late physical-exit ownership/deadline cleanup and shutdown joining. Its combined Windows close/deadline/late-exit alias remains backed by unchanged callbacks. Retire native-error-close, pre-publication setup ownership and failed-delete rearm aliases; associated delegation, failure forwarding, removal routing and recovery examples are lost. These tests inject watch/subscription seams and do not observe an actual native watcher or physical process. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1925 (sources1922/1923): Partial runtime watcher-host suite loses mocked option/event/overflow/resubscription forwarding, supplied teardown-error propagation, aborted-signal/no-call and private ten-thousand-waiter-count inventories. Retire the 10,000-caller bound and failed-recovery-subscriber-ending assertion aliases. Keep same-root owner cancellation, pre-ready replacement, held root-close join, stale-generation recovery delivery and initial failed-root ownership mappings backed by retained real-host callbacks with injected subscription/error/physical-exit promises. No actual native watcher, process termination or resource bound was observed. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1683 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1645 removes low-value test projections, mock wiring, private-state assertions, inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained public behavior and refusal boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1640 removes low-value IPC, SSH, workspace and transcript-watcher tests without equivalent replacement coverage. Per-source reviews record retained public refusal, cancellation, execution-host and real-filesystem outcomes with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1634 removes low-value IPC, filesystem and runtime projections, argument inventories and duplicate examples without equivalent replacement coverage. Per-source reviews record retained cancellation, ownership, authorization, filesystem and SQLite boundaries with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1627 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1623 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1516 removes package-electron-runtime-contract.test.mjs, a copied release-workflow platform and marker matrix. Its workflow wiring alarm is intentionally retired; no actual packaged watcher delivery was exercised and no equivalent replacement is claimed. Unaffected dated execution receipts retain their original scope; changed optional selectors have no fresh full-gate execution result. This audit removes the paired-web stopped-during-outage and late-ready direct-branch examples. The retained pre-ready cancellation, failed-unwatch retry and replay-continuity cases are not equivalent replacements for those ordering alarms. Current web-runtime-client.test.ts assertions below name only its retained pre-ready callback case; replay cases remain in their separate suite. Historical commands and results remain historical. Deterministic tests cover one shared healthy child per runtime process plus at most four bounded fault-quarantine children, native desktop, paired-runtime, and WSL snapshot processes sharing the same eight-physical-child reservation with typed serialized event-driven capacity recovery, including recursive re-wait when crash recovery reclaims an announced slot, one quarantine attempt per watch lifetime, generation-scoped cancellation, bounded termination with removable deadline waiters, replacement-crawl errors that cannot be blessed by a late readiness ack, pre-ready paired-web cancellation registered before an unbounded capacity wait, already-resolved and late physical-exit retry of a rejected paired-web teardown, physical desktop-install and local/SSH PTY teardown, stale-generation rejection, per-child stat bounds, final-overflow RPC delivery, and renderer eviction before terminal callbacks can retry. Destructive local and SSH removal fences both ID-derived and resolved-cwd terminal roots, including sibling-root/cwd combinations with reverse admission rollback, closes descendant relay watches before parent deletion, enumerates authoritative provider/cwd ownership, falls back to daemon spawn cwd before OSC 7, and keeps daemon/relay immediate shutdown pending until native exit or a bounded fail-closed error; a dead relay PID discovered during attach also settles concurrent shutdown before its stale entry is reaped, while Windows runtime watcher deadlines retain one removable physical-close waiter, treat Node's error-close path as positive physical-exit proof, and clear root ownership on late close. The relay policy test maps a standard repository's base, Git common directory, and worktree roots to one healthy supervisor, then proves a shared-child failure recovers those roots in separate quarantine supervisors with overflow and resumed events. Abortable capacity, quarantine, runtime-root, relay, SSH, and relay pre-install setup waits attach one reaction to each shared promise and explicitly remove 10,000 cancelled caller closures while one anchor remains. Built-entry macOS harnesses kill the desktop/runtime and SSH relay watcher children, then require automatic resubscription and later events while the host process and relay PTY survive. SSH bundles the child boundary beside relay.js, requires both artifacts for install completeness, and preserves registration-owned same-root cancellation. The test-value audit corrects the active renderer watch command/file reference to the existing runtime-file-client-watch.test.ts, whose three cases are retained unchanged. They observe synthetic subscription retry/fanout and unsubscribe/unwatch calls, not actual preload/main bookkeeping or physical watcher-process cleanup. The separate read/preview client suite loses forwarding, supplied-error and negative-only examples, retaining binary detection and Unicode SVG decoding. Historical evidence commands/results are unchanged. Test-value audit1293 removes src/main/providers/local-pty/local-pty-provider-session-inventory.test.ts (2 authored cases). Their isolated assertions no longer run; surviving tests are not claimed as equivalent coverage. Fresh execution against the candidate SHA is required. Audit1312 removes low-value imported specs from aggregate test drivers; old whole-driver execution receipts are archived. Retained registrations are unchanged. No equivalent replacement coverage is claimed. Audit1383: src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts reduced. Lose command-list/receipt/default/background activation matrices whose provider spawn returns canned IDs. Retained test proves actual tab allocation separation, not terminal startup. No equivalent replacement coverage is claimed. Existing exact unaffected receipts and their platform/provider/budget claims remain scoped to unchanged selectors. Changed optional selectors have no new execution result. Audit1401: src/main/runtime/orca-runtime-tests/mobile-session-tabs-duplicate-pty-repair.spec.ts removed. Loses listing-on-already-repaired-data alarm; it never established runtime repair invocation. src/main/runtime/orca-runtime-tests/mobile-session-tabs-split-agent-tab.spec.ts removed. Loses actual mobile split sibling shell versus recorded-agent resume command alarms; no equivalent coverage asserted. src/main/runtime/orca-runtime-tests/worktree-native-chat-setup.spec.ts removed. Loses separate setup/startup tab result in that manually assembled path. src/main/runtime/orca-runtime.test.ts reduced. Driver registration/import of a whole-deleted selected spec is removed; directly authored cases remain unchanged. No extra authored removal credit. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result. Audit1412: src/main/workspaces/removal/watcher-removal-gate.test.ts reduced. Loses exact removal-error compatibility with renderer predicate under shared message constants. Kept public refusal outcomes do not establish that renderer classification. No equivalent replacement coverage is claimed. Existing exact unaffected receipts remain unchanged and apply only to their unchanged selectors. Changed optional selectors have no new execution result.", "motivatingLinks": [ "https://github.com/stablyai/orca/issues/5308", "https://github.com/stablyai/orca/issues/7547", "https://github.com/stablyai/orca/issues/8212" ], "invariant": "Local runtime and SSH relay roots share one watcher child per host process while healthy and use at most four quarantine children after shard failure; native desktop, paired-runtime, and direct WSL snapshot children consume the same process-wide eight-child reservation and retry transient exhaustion without permanently disabling a root. Cancellation remains owned by its child generation and settles only after acknowledgement or bounded physical exit; paired-web retains cleanup ownership and can cancel before readiness even while capacity is exhausted, retries a failed unwatch after already-resolved or late physical exit without duplicating stream termination, replacements never overlap a still-retiring generation, and aborted or timed-out callers detach immediately even while queued behind same-root relay teardown. Destructive local and SSH cleanup holds one containment-aware watcher/terminal removal fence through descendant watcher and PTY physical exit plus parent Git/filesystem deletion; daemon and relay kill requests retain ownership until the actual subprocess exit callback or an equivalent positive dead-PID proof and propagate rejected signals or a bounded failure otherwise. A crash-fused shared shard moves affected roots into the bounded quarantine pool, a second fused quarantine ends those watch lifetimes, interrupted setup emits overflow after recovery, metadata work stays bounded, and the SSH relay, PTYs, Git, and other filesystem operations never load the watcher native addon or share its fault boundary.", - "oracle": "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/runtime/files/watching/runtime-file-client-watch.test.ts: delivers remote file changes to listeners for the same worktree. src/main/runtime/orca-runtime.test.ts: ordinary registration cleanup removes only await import('./orca-runtime-tests/mobile-session-tabs-part-14.spec'). src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-03.spec.ts: arms the stale-title timer for a seeded working title; arms the Command Code scrape from the noted spawn command; prefers the tracked title over a stale renderer lastTitle in the hydration seed; writes recent output into the current runtime output map; uses a later title handler replacement with the runtime receiver; calls the current injected listener with the runtime receiver; keeps optional reconciliation lazy after its callback is removed. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-14.spec.ts: lists them, so a paired client can mirror a migrated editor; closes one by retiring it from the host session; keeps an unsaved draft unless the close is forced; shares aggregate work but leaves a replacement pending promise alone; lets a targeted refresh finish while an aggregate refresh waits; refuses a close when the store lacks %s before the guard; keeps a later missing %s on the original caught failure path. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Exact retired assertionRefs, preserved as historical objects only: {\n \"file\": \"src/renderer/src/runtime/files/watching/runtime-file-client-watch.test.ts\",\n \"assertions\": [\n \"terminal watcher error and setup failure evict the shared entry before retrying callbacks run\",\n \"an old stream end cannot evict the replacement stream, which still delivers to its listener\",\n \"two same-worktree listeners share a synthetic subscription until the final stop unsubscribes and sends unwatch\"\n ]\n } Historical prior account (preserved verbatim): Audit1973: Delete the standalone mocked watcher cleanup suite and its entire sole-file prospective command. Retire the removed file-command transport-abort alias; preserve the independent cancellation suite and final-overflow/error/end cleanup callback, and13 unrelated receipt objects. Whole original changed dated receipts are retired, never narrowed or transferred. This metadata review claims no fresh execution, equivalent replacement, provider/PTY, live remote/mobile, rendered, cross-platform, soak or measured-budget result. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Partial runtime files-watch suite retains controlled Windows close-event waiting, shared-client survival, late physical-exit ownership/deadline cleanup and shutdown joining. Its combined Windows close/deadline/late-exit alias remains backed by unchanged callbacks. Retire native-error-close, pre-publication setup ownership and failed-delete rearm aliases; associated delegation, failure forwarding, removal routing and recovery examples are lost. These tests inject watch/subscription seams and do not observe an actual native watcher or physical process. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1925 (sources1922/1923): Partial runtime watcher-host suite loses mocked option/event/overflow/resubscription forwarding, supplied teardown-error propagation, aborted-signal/no-call and private ten-thousand-waiter-count inventories. Retire the 10,000-caller bound and failed-recovery-subscriber-ending assertion aliases. Keep same-root owner cancellation, pre-ready replacement, held root-close join, stale-generation recovery delivery and initial failed-root ownership mappings backed by retained real-host callbacks with injected subscription/error/physical-exit promises. No actual native watcher, process termination or resource bound was observed. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1683 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Fill the global watcher-child reservation, require native desktop, paired-runtime, and WSL setup to retain typed transient capacity and retry after one serialized release, then cancel pending desktop and paired-client watches and require no retry. Hold one live anchor while aborting 10,000 callers at the capacity, quarantine-assignment, runtime-root, relay-setup, and SSH-registration layers; require exactly one explicit waiter and one base-promise reaction to remain, then zero after settlement. Hold an old relay unsubscribe, queue one same-root setup leader and one anchor, then abort 10,000 joiners; require every cancellation to settle before teardown releases, exactly one anchor waiter, and only one later physical install. Advance the former paired-web callback deadline while capacity remains full, require cancellation ownership to stay live, publish the server token before ready, and require files.unwatch to abort setup before a later slot release can install a native root. Reject the first ready-watch unwatch with a physical-exit promise, resolve that exit later, and require a fresh physical unwatch attempt, registry release, and exactly one stream end. Fill one healthy shared child with multiple roots, map a standard SSH repository's base, Git common directory, and worktree roots to one relay supervisor, then inject IPC disconnect-before-exit, queued and active cancellation, operations during termination, kill-without-exit, repeated unkillable generations, initial and recovery timeouts, and shard failure. During local and SSH deletion, attempt a late terminal spawn whose worktree identity and cwd name different roots, enumerate a non-prefix remote PTY by authoritative worktree ownership, withhold daemon/relay exit callbacks, make attach positively prove a concurrent-shutdown PID dead, and make the provider unavailable; require every acquired admission to roll back on rejection, dead-PID proof to settle physical exit before reaping, timeout to retain ownership, and Git/filesystem deletion never to start. Require bounded watcher process count, physical-exit settlement, healthy-root recovery, stale-generation rejection, overflow plus later events, and fail-closed destructive cleanup. Verify relay build hashes and remote install probes require both relay.js and relay-watcher.js. Launch the built relay with a real PTY and Parcel watch, kill only the watcher child, and require the same relay PID and PTY to answer before a replacement child delivers overflow and a post-crash event.", + "oracle": "Audit3375 composes root-adopted3370/independent3371 and3373/independent3374: intentionally retires79 authored registrations/84 expanded cases, including39 whole suites, without equivalent replacement. Lost alarms include federation field/parser inventories; Claude rejected-key precedence, credential clone redaction, managed-versus-user hook preservation and CLI defaults; setting/status/activity projections, mocked SSH/notification/reveal/Linear refusal, fake-clock reconnect and noise; image-fold artifact visibility, paste eligibility, setup trust, scripted ACP error-to-journal publication and ligature cache tuple aliasing; plus supplied folder-runner uniqueness, mobile host-overlay/credential/update/preference races, status/markup/title/keyed-row projections, subscriber cleanup, cancellation/close/refusal/link-issue and mirror suppression alarms. Retained3373 merger contiguity, dual-clock overdue-resume exactly-once, rejected-paste IPC sink and annotation schema roundtrip remain bounded. Retained actual HTTP/OSC status composition, destructive sibling-filesystem isolation, external contrast invariant and fixture CSS pixel intervention remain narrower. Original reviewed87authored/92expanded become9/9; current OpenCode suite adds two preserved upstream cases and the synthetic-title suite gained one Cursor policy mock-call case, independently reviewed for removal in root3378; current90/95 become11/11. That Cursor suppression/ready-frame regression alarm is intentionally lost; it does not observe native title ownership or tab flicker. For3370 only the peer was independently blind, with author exposure explicit;3373/3374 both blind pins were verified. This broad root unit command selects the reduced root unit suite; UNIT_INCLUDE excludes mobile tests, which require the existing mobile runner; retained Playwright component-pixel spec uses its separate existing headless fixture runner and is not validated by the broad unit command. No fresh execution, actual agent/shell/provider, OS material/focus, historical import equivalence, mobile, mixed-version or cross-platform evidence is claimed. All dated receipts retain their original scope. Audit3368 composes root-adopted3363/3364 and3367/3369: intentionally retires181 authored registrations/196 expanded cases, including28 whole suites, without equivalent replacement. Lost alarms include hibernation attention/liveness/backoff/sequential teardown and inventory, host launch compatibility/legacy/Kimi/resource cleanup, terminal recovery parser/pause/quarantine/remount, window-visibility omission-fence lifetime, launch-option rendered Start, sleeping-resume saved recipe/WSL quoting/cancellation, plus removed project/window/input variants. Additional tiny-suite losses include sentence/label/field/default inventories, credential omission, Windows argument/environment mapping, URI decoding, diagnostics, provider classification and fake-clock callback/parser examples. Retained ten registrations/twelve expanded cases include two literal Unicode Mn/Cf zero-width range guards in the actual character-range algorithm and protect narrower delayed editor bytes/destructive ownership, mounted hidden collision repair, ten transport epochs, duplicate-command refusal, caller timeout typing, executor unknown-opener refusal and failed-chunk user bytes. This broad unit command selects the reduced suite; no fresh runtime, real provider/network/PTY, filesystem restart, native UI, historical import equivalence, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3362 composes root-adopted3358/independent3360: intentionally retires129 authored registrations/140 expanded cases, including four whole suites, without equivalent replacement. Lost alarms include supplied orphan-adoption retry/malformed inventory/cancellation; fake-terminal replay parser/wedge/disposal callbacks; all-host catalog metadata and Windows preferences; host keepalive/protocol/stale/settings failures; and removed exact-stop/suppression, source save lifetime, diff-note queue, rename/editor close, input flood/chunk refusal/limits, purge and creation examples. Retained18 registrations/21 expanded cases protect narrower ownership, generation, dirty-state, queue convergence, encoding and attachment-lease outcomes. No replacement or keeper quota claim. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY/xterm parser, disk restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3359 composes root-adopted source3355/independent3356: intentionally retires130 authored registrations/139 expanded cases, including eight whole suites, without equivalent replacement. Lost alarms include strict create naming/capability/legacy payloads; supplied transport host replacement, deadline reattach, create-handoff and split activation; agent-session fork/clipboard/platform flags; shutdown cleared-scrollback/unmounted bindings; simulator host-collision/selection/shutdown; and removed editor, catalog, mutation, launch and status examples. Retained12 adverse-ordering/state-consequence cases are narrower and do not replace all removed alarms. Two queue absences receive zero removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY, filesystem restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3349 composes adopted batches3343,3345 and refreshed3354: intentionally retires234 authored registrations/294 expanded cases, including13 whole suites, without equivalent replacement. Lost alarms include supplied terminal reconnect/replacement/typeahead/mirror/result and snapshot examples; synthetic render-desync persistence/recovery; worktree listing/owner/catalog/lineage/removal and activation/creation examples; host-scoped PR and task-record projections; editor diff/status/comment and UI send-target examples; automation observation/wake, supplied sleep/deadline clock and native-chat completion/notification/relaunch samples; held-tab layout and cleanup/progress guard examples. Retained adverse-ordering and wire-boundary cases are narrower and do not replace all removed alarms. The already-upstream visibility-resume deletion receives zero new removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH, native process/power/GPU, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3342 composes adopted source batches3333/3334,3336/3337 and3340/3341: intentionally retires180 authored registrations/263 expanded cases, including seven whole suites, without equivalent replacement. Lost alarms include corrupt editor hydration; mobile editor/diff publication and privacy projections; stale-resubscribe routing; model-picker projection/refetch/retry/fallback; editor check-details and frame property inventories; latched-pane cleanup/quiescence; client create replay identity/options/compatibility; and removed owner, async routing, terminal and layout examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts keep their original scope. Audit3335 composes adopted source unions3327/3328 and3330/3332: intentionally retires100 authored registrations/123 expanded cases, including ten whole suites, without equivalent replacement. Lost alarms include seeded host persistence/contention and stale-host cleanup; browser snapshot assembly; mocked wake/DPR callbacks and frame budgets; preflight projections; palette authority/cache suppression, URL intent and saved-title cross-repo collisions; metadata coverage/set patch and dropdown assembly; and removed terminal, worktree, review-refresh and owner-routing examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI/GPU/focus, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain only their original scope. Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed. Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed. Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed. Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical. Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims. Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands. Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2090 (sources2088/2089): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2086 (sources2082/2083): Current reduced suites intentionally retire the alarms listed in knownGaps; prior dated execution and replacement claims do not validate changed source bytes or selectors. Historical prior account (preserved verbatim): Audit2076 (sources2073/2074): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-handles-part-02.spec.ts: recovers a moved SSH pane through the tab it now sits in, not the one its lease froze; reports a plain expired orphan; does not report a pane whose only recent lease was superseded; does not report a pane whose only recent lease had its relay id recycled; picks the eligible orphan over a superseded predecessor that matches first; collects the same tabs the per-tab reader reports, in one sweep of the leases; reports no candidate when no lease names any of the worktree tabs. src/main/runtime/orca-runtime-tests/runtime-availability.spec.ts: starts unavailable with no authoritative window; reports the configured Windows terminal shell on status; reports floating workspace availability from settings on status; polls floating tabs with targeted PTY liveness and no repo/provider inventory; hydrates persisted tabs when the store cannot report repos; advertises browser screencast only when a renderer window is available; routes mobile Codex reset consumption through the account mutation coordinator; maps a definite pre-provider rejection into an authoritative current snapshot. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Frozen current literal-import graph reaches these changed test bytes; unresolved local and computed edges remain debt, and current reachability is not historical execution or equivalent replacement evidence. Historical prior account (preserved verbatim): Audit2056 (sources2054/2055): Intentionally retire these low-value alarms without replacement: src/renderer/src/runtime/files/watching/runtime-file-client-watch.test.ts: delivers remote file changes to listeners for the same worktree. src/main/runtime/orca-runtime.test.ts: ordinary registration cleanup removes only await import('./orca-runtime-tests/mobile-session-tabs-part-14.spec'). src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-03.spec.ts: arms the stale-title timer for a seeded working title; arms the Command Code scrape from the noted spawn command; prefers the tracked title over a stale renderer lastTitle in the hydration seed; writes recent output into the current runtime output map; uses a later title handler replacement with the runtime receiver; calls the current injected listener with the runtime receiver; keeps optional reconciliation lazy after its callback is removed. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-14.spec.ts: lists them, so a paired client can mirror a migrated editor; closes one by retiring it from the host session; keeps an unsaved draft unless the close is forced; shares aggregate work but leaves a replacement pending promise alone; lets a targeted refresh finish while an aggregate refresh waits; refuses a close when the store lacks %s before the guard; keeps a later missing %s on the original caught failure path. Existing unrelated evidenceRuns retain their original scope; unchanged dated receipt objects do not validate changed source bytes or reduced selectors. No fresh gate execution or historical import-closure equivalence is claimed. Exact retired assertionRefs, preserved as historical objects only: {\n \"file\": \"src/renderer/src/runtime/files/watching/runtime-file-client-watch.test.ts\",\n \"assertions\": [\n \"terminal watcher error and setup failure evict the shared entry before retrying callbacks run\",\n \"an old stream end cannot evict the replacement stream, which still delivers to its listener\",\n \"two same-worktree listeners share a synthetic subscription until the final stop unsubscribes and sends unwatch\"\n ]\n } Historical prior account (preserved verbatim): Audit1973: Delete the standalone mocked watcher cleanup suite and its entire sole-file prospective command. Retire the removed file-command transport-abort alias; preserve the independent cancellation suite and final-overflow/error/end cleanup callback, and13 unrelated receipt objects. Whole original changed dated receipts are retired, never narrowed or transferred. This metadata review claims no fresh execution, equivalent replacement, provider/PTY, live remote/mobile, rendered, cross-platform, soak or measured-budget result. Historical prior account (preserved verbatim): Audit1931 (sources1928/1929): Partial runtime files-watch suite retains controlled Windows close-event waiting, shared-client survival, late physical-exit ownership/deadline cleanup and shutdown joining. Its combined Windows close/deadline/late-exit alias remains backed by unchanged callbacks. Retire native-error-close, pre-publication setup ownership and failed-delete rearm aliases; associated delegation, failure forwarding, removal routing and recovery examples are lost. These tests inject watch/subscription seams and do not observe an actual native watcher or physical process. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1925 (sources1922/1923): Partial runtime watcher-host suite loses mocked option/event/overflow/resubscription forwarding, supplied teardown-error propagation, aborted-signal/no-call and private ten-thousand-waiter-count inventories. Retire the 10,000-caller bound and failed-recovery-subscriber-ending assertion aliases. Keep same-root owner cancellation, pre-ready replacement, held root-close join, stale-generation recovery delivery and initial failed-root ownership mappings backed by retained real-host callbacks with injected subscription/error/physical-exit promises. No actual native watcher, process termination or resource bound was observed. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1683 retires changed-source assertion and execution scope without equivalent replacement coverage. Existing unchanged-selector receipts remain scoped to their original sources. Historical prior-source oracle: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Existing exact unchanged-selector receipts remain the only current execution evidence. Changed source selectors have no fresh execution result. Historical prior-source oracle account: Fill the global watcher-child reservation, require native desktop, paired-runtime, and WSL setup to retain typed transient capacity and retry after one serialized release, then cancel pending desktop and paired-client watches and require no retry. Hold one live anchor while aborting 10,000 callers at the capacity, quarantine-assignment, runtime-root, relay-setup, and SSH-registration layers; require exactly one explicit waiter and one base-promise reaction to remain, then zero after settlement. Hold an old relay unsubscribe, queue one same-root setup leader and one anchor, then abort 10,000 joiners; require every cancellation to settle before teardown releases, exactly one anchor waiter, and only one later physical install. Advance the former paired-web callback deadline while capacity remains full, require cancellation ownership to stay live, publish the server token before ready, and require files.unwatch to abort setup before a later slot release can install a native root. Reject the first ready-watch unwatch with a physical-exit promise, resolve that exit later, and require a fresh physical unwatch attempt, registry release, and exactly one stream end. Fill one healthy shared child with multiple roots, map a standard SSH repository's base, Git common directory, and worktree roots to one relay supervisor, then inject IPC disconnect-before-exit, queued and active cancellation, operations during termination, kill-without-exit, repeated unkillable generations, initial and recovery timeouts, and shard failure. During local and SSH deletion, attempt a late terminal spawn whose worktree identity and cwd name different roots, enumerate a non-prefix remote PTY by authoritative worktree ownership, withhold daemon/relay exit callbacks, make attach positively prove a concurrent-shutdown PID dead, and make the provider unavailable; require every acquired admission to roll back on rejection, dead-PID proof to settle physical exit before reaping, timeout to retain ownership, and Git/filesystem deletion never to start. Require bounded watcher process count, physical-exit settlement, healthy-root recovery, stale-generation rejection, overflow plus later events, and fail-closed destructive cleanup. Verify relay build hashes and remote install probes require both relay.js and relay-watcher.js. Launch the built relay with a real PTY and Parcel watch, kill only the watcher child, and require the same relay PID and PTY to answer before a replacement child delivers overflow and a post-crash event.", "commands": [ "pnpm exec vitest run --config config/vitest.config.ts src/main/ipc/filesystem/watcher-process/parcel-watcher-unsubscribe-timeout.test.ts --reporter=dot", "pnpm exec vitest run --config config/vitest.config.ts src/main/ipc/filesystem/watchers/filesystem-watcher.test.ts src/main/ipc/filesystem/watchers/filesystem-watcher-native-capacity.test.ts src/main/ipc/filesystem/watcher-process/parcel-watcher-child-registry.test.ts src/main/ipc/filesystem/watcher-process/parcel-watcher-child-launch.test.ts src/main/ipc/filesystem/watcher-process/parcel-watcher-process.test.ts src/main/ipc/filesystem/watcher-process/parcel-watcher-supervisor-capacity.test.ts src/main/ipc/filesystem/watcher-process/parcel-watcher-disconnect-termination.test.ts src/main/ipc/filesystem/watcher-process/runtime-watcher-pending-assignment.test.ts src/main/ipc/filesystem/watcher-process/parcel-watcher-event-delivery.test.ts src/main/ipc/filesystem/watchers/filesystem-watcher-local-unsubscribe.test.ts src/main/ipc/filesystem/watchers/filesystem-watcher-wsl.test.ts src/main/ipc/worktrees-delete-pty-teardown.test.ts src/main/ipc/worktrees-orphan-directory-cleanup.test.ts src/main/ipc/worktrees-remove-preflight.test.ts src/main/workspaces/removal/watcher-removal-gate.test.ts src/main/runtime/files/watch/orca-runtime-files-watch.test.ts src/main/runtime/workspaces/removal/worktree-teardown.test.ts src/main/runtime/construction/orca-runtime.test.ts src/main/runtime/rpc/methods/files/files.test.ts src/main/runtime/rpc/methods/files/files-watch-cancellation.test.ts src/renderer/src/web/web-runtime-client.test.ts src/shared/cross-platform-path.test.ts src/shared/physical-exit-tracker.test.ts src/shared/promise-settlement-waiters.test.ts src/main/ipc/pty/pty-spawn-cwd-fallback.test.ts src/main/providers/local-pty/local-pty-provider-shutdown.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter.test.ts src/main/daemon/pty-subprocess/testing/pty-subprocess.test.ts src/main/daemon/sessions/testing/session.test.ts src/main/daemon/terminal-host/testing/terminal-host.test.ts src/main/daemon/terminal-host/testing/terminal-host-session-reaping-leak.test.ts --reporter=dot", @@ -13094,6 +12785,7 @@ "Add a packaged orca serve pairing scenario that proves a connected client refreshes after child replacement." ], "knownGaps": [ + "Launch direct-owner cleanup current scope: This gate’s unfiltered unit command now selects a suite reduced by 82 whole registrations / 159 potential table examples in 10 whole test Programs, including 8 registrations / 15 examples from five once-registered create-message factory closures. Lost alarms include frozen first-message/options and legacy-host fallback; distinct actions and redelivery; uncertain/refused/reloaded input custody, Retry and late proof; rich prompt/attachment upload Stop/close and handback; ordinary draft/editor/IME/StrictMode lifetime and accepted topology; provisional fallback tab placement/group/pin/order and rich worktree handoff. Four whole consent/resume-identity cases remain in two Programs; they do not replace these alarms. This entry governs current reduced-unit scope and qualifies any broader implication of unchanged oracle/coverageNotes history. Entire dated evidenceRuns, original commands/currentCommand values, counts/results and existing history retain their original scopes only; no fresh execution, transferred pass, replacement equivalence or prior upstream-removal credit is claimed.", "Audit2145 accepts removal of canned runtime metadata/guard/forwarding, fake in-memory persistence, private work-count and wrapper-duplication tests from the construction/orca-runtime.test.ts aggregate, plus the two automation run-context guards from runtime-workspace-launch-contracts.test.ts. Retained race, framing, physical completion and ownership callbacks remain byte-identical. Existing commands remain valid selectors; historical receipts stay unchanged and provide no fresh validation or replacement coverage for the reduced suites.", "Audit2133 current-parent preparation (988 authored removals; independently reviewed2099/2107/2115/2116 decisions; upstream clear-buffer and recovery-image regressions retained): Intentionally retire these low-value alarms without replacement: src/main/runtime/construction/orca-runtime.test.ts: remove only literal registration import/call pairs await import('../orca-runtime-tests/worktree-setup-and-startup.spec'), await import('../orca-runtime-tests/gitlab-and-pr-bases.spec'); no additional authored credit. src/main/runtime/orca-runtime-tests/targeting-and-resilience.spec.ts: routes tab switch and capture start by explicit page id; accepts focus on tab switch without altering bridge args (focus is main-side concern); keeps terminal cwd resolution fail-soft when the provider is unavailable. src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-04.spec.ts: drops the bounded scan cache when orphan-cleanup removal completes; clears optimistic reconcile tokens when a CLI worktree removal succeeds; emits drift without mutating when the fetched base fast-forwards created HEAD; emits base_changed without mutation when the fetched base rewrote history; skips stale-token reconciles without mutating or emitting stale status; emits unknown without mutation when fetch fails or the base ref is missing. src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-03.spec.ts: routes runtime preserved-branch force-delete through the selected WSL project runtime; replies to a waiting client with the error of a delete that fails after acceptance; treats forced runtime deletion of an already-missing unregistered worktree as cleanup; treats normal runtime deletion of an already-missing unregistered worktree as cleanup. src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-02.spec.ts: warns that a missing-repo removal only forgot the workspace; restores runtime watchers when CLI worktree deletion fails after teardown; does not re-spend the drain budget on a removal after a wedged install was abandoned; routes runtime worktree removal through the selected WSL project runtime; force-deletes a branch that was preserved by runtime worktree removal. src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases-part-02.spec.ts: records GitLab pasted-project recents only after successful runtime lookup; threads explicit origin preference through runtime WSL PR base resolution; resolves local GitLab fork MR bases from the target project MR head ref; captures the fork MR head from a dedicated ref, not the shared FETCH_HEAD; keeps the durable MR head when the head fetch fails but the local ref resolves; routes runtime GitLab fork MR base git calls through the selected WSL project runtime. src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases.spec.ts: passes SSH connection ids through GitLab task operations; routes runtime GitLab issue, MR, work-item, and todo actions through the selected WSL project runtime; routes runtime GitLab MR details, review-management, job, and pasted URL actions through the selected WSL project runtime; normalizes runtime GitLab issue list arguments like the desktop IPC path. src/main/runtime/orca-runtime-tests/worktree-setup-and-startup-part-03.spec.ts: does not warn when setup is explicitly skipped for CLI-created worktrees; puts the agent a create starts in the first default tab, as the window does; keeps the 8s main-runtime startup readiness budget for agents without an override; gives OpenCode the 20s main-runtime startup readiness budget; launches explicit startup agents with prompts for CLI-created worktrees. src/main/runtime/orca-runtime-tests/worktree-setup-and-startup.spec.ts: returns a setup launch payload for CLI-created worktrees when hooks are explicitly enabled; does not hand the window a setup main never tried to start; passes the selected Windows setup shell into runtime runner generation; follows normal setup policy for CLI-created worktrees without activating them; uses returned WSL setup shell metadata when runtime spawns setup; uses the shell-aware setup runner for windowless creates without a startup command; reports the in-process setup hook as running when nothing can launch the runner. src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-02.spec.ts: coalesces two clients sleeping the same host worktree; stops exactly the expected live PTYs for a worktree; explains a refused workspace close instead of throwing the raw refusal enum. src/main/runtime/orca-runtime-tests/mobile-summaries-part-03.spec.ts: marks the desktop-active worktree as isActive; includes SSH-backed worktrees in the mobile worktree summary; caches repeated malformed path misses before normalizing them again. src/main/runtime/orca-runtime-tests/mobile-summaries-part-02.spec.ts: keeps title-only foreground work ahead of monitoring in another pane; keeps a local hook row while a connected PTY still backs its pane; keeps an OSC row via its connected PTY after the pane binding is cleared. src/main/runtime/orca-runtime-tests/mobile-summaries.spec.ts: resolves files through a source-visible linked-checkout worktree; marks saved session tabs with live PTYs as host sidebar activity; attributes live legacy PTYs from saved layout bindings when their panes are hidden; marks saved browser tabs as host sidebar activity like desktop; falls back to the path-keyed GitHub cache entry; includes folder workspaces in compact worktree summaries for mobile; attaches inline agent rows from the latest OSC 9999 status; projects monitoring over a title-derived working status. src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-03.spec.ts: pushes to an idle pane when the only live waiter filters out the message type; resolves a registered waiter without PTY-injecting when the leaf is already idle; keeps already-idle status after tui-idle wait for immediate message delivery; resolves message waiters when notifyMessageArrived is called; does not resolve type-filtered message waiters for unrelated message types; removes message waiter abort listeners after message arrival; resolves message waiters on timeout when no message arrives. src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-02.spec.ts: delivers pending mail via notifyMessageArrived when the recipient is already idle; does not keep retrying when every pending row was already pointed; repoints pending rows restored with a live-idle coordinator. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-13.spec.ts: rolls back a half-created terminal whose surface never publishes. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-12.spec.ts: rejects startup prompts for agents that require post-ready stdin; uses portable Unix quoting for mobile agent launch commands in WSL project runtimes; keeps PowerShell quoting for mobile agent launch commands in Windows host runtimes; uses cmd.exe quoting for mobile agent launch commands in local Windows host runtimes; publishes headless mobile session agent identity with synthesized PTY status; rejects disabled mobile session agent launches before spawning; validates mobile terminal insertion anchors before resolving agent launch commands. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-11.spec.ts: coalesces a reconnect close burst onto one authoritative PTY inventory; keeps an explicit user close destructive while the PTY is live; builds mobile session agent launch commands on the runtime host; injects mobile quick-command prompts into the host-built agent startup command. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-10.spec.ts: closes persisted headless terminal parents before any prior list call; tears down a serve-owned headless tab on close while a renderer is attached so it cannot resurrect; defers a renderer-published pending tab to the renderer instead of tearing it down; returns a delegated close outcome with no selection tombstone when the renderer owns the outcome; tears down a runtime pending shell the renderer never adopted on close. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-08.spec.ts: materializes a plain shell when the pending tab has no launch agent; hydrates legacy persisted terminal tabs without layout entries; reads and indexes the full agent-status snapshot once per mobile projection; kills persisted SSH PTYs when closing hydrated headless tabs before pane metadata is restored; materializes hydrated pending headless terminals with the persisted session identity. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-07.spec.ts: hydrates a persisted SSH-owned pane before an attached renderer publishes its graph. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-05.spec.ts: publishes the desktop's tab name over the live agent title, and the live title without one; uses fresh neutral PTY titles over stale mobile snapshot and OSC titles; operates PTY-backed mobile session terminals without a renderer graph; reuses pane close for live PTYs that do not own a renderer tab; lists PTY-backed mobile session terminals without a renderer graph; shows and resolves active PTY-backed mobile session terminals without a renderer graph. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-04.spec.ts: creates mobile session terminals for folder workspaces in a headless runtime server; spawns fresh headless SSH mobile session terminals instead of reattaching synthetic local ids; hydrates headless mobile session terminals from the host workspace session; keeps live headless mobile session terminals when a desktop renderer publishes without them; publishes laptop-created remote runtime split terminals to phone session tabs. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-02.spec.ts: does not report headless wake degradation without sleeping records; does not wake slept agents for non-mobile session-only activation; does not rewrite unread metadata when a mobile activation finds the worktree already read; returns unread:false from worktree.ps after a mobile activation clears the flag; materializes pending mobile session terminals without focusing desktop clients; closes browser mobile session tabs when addressed by browser workspace id. src/main/runtime/orca-runtime-tests/mobile-session-tabs.spec.ts: resolves mobile terminal surfaces by exact split leaf; closes the matching mobile terminal UUID leaf without closing the whole tab; closes the whole mobile terminal tab when addressed by parent tab id; activates the active split leaf when addressed by parent tab id; clears unread metadata on mobile worktree activation without focusing desktop clients; wakes slept agents on the host renderer when a phone activates a worktree. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-05.spec.ts: publishes the hook provider session on a headless mobile tab so native chat can address the transcript; recovers the agent type from the hook row when the pane was launched without an agent hint; reads one agent-status snapshot per projection, not one per terminal tab; waits for unknown-launch foreground owner before publishing Pi-compatible mobile status; keeps Pi-compatible mobile session status as Pi for an unknown-launch foreground pi PTY; keeps renderer-vetted mobile agent status for custom-titled terminals. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-04.spec.ts: publishes terminal surface agent status for paired web clients; preserves authoritative OMP identity for Pi-compatible remote terminal snapshots; normalizes a remote OMP title without republishing omitted launch identity; skips the foreground-process probe when the PTY launch agent is already known; probes the foreground process only on a status transition for unknown launch agents; passes the client signal and the slept-worktree refusal to the spawn. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-03.spec.ts: does not use stale runtime-created PTY status when a neutral PTY title exists; recognizes runtime-created Codex PTY handles from the ready prompt; recognizes runtime-created Antigravity PTY handles from the ready prompt; recognizes live leaf Antigravity terminals from the ready prompt; recognizes a later Antigravity header with a prompt but no model line; keeps mobile terminal surfaces visible while their leaf handle is pending. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-02.spec.ts: lets Claude agents management titles clear stale runtime-created title status; does not recognize live Claude agents panes from a Claude foreground process; does not let stale tab-level agent titles override current neutral pane titles; lists live terminals with fresh pane titles over stale tab titles; lets adopted neutral pane titles use non-shell foreground fallback; lets adopted neutral pane titles retry wrapper foregrounds until recognized; authorizes settled CLI prompts only after positive %s foreground identity; does not recognize arbitrary foreground TUIs as running agents; lets live neutral pane titles retry wrapper foregrounds until recognized; lets current Claude agents PTY titles override stale runtime-created OSC titles; does not let stale Claude agents OSC titles suppress current PTY title activity. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status.spec.ts: keeps preallocated terminal handles valid across renderer reloads; preserves runtime-created PTY process identity after graph unavailable; keeps prompt bindings fenced across runtime restarts without provider incarnation; recognizes runtime-created PTY handles with agent launch titles; does not treat a bare Cursor Agent native title as a running agent session; uses stale runtime-created PTY status when there is no title or foreground evidence. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-07.spec.ts: keeps orphaned list and show writability aligned with the send gate. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-04.spec.ts: cancels a coalesced SSH worker recovery retry when its provider disconnects. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-03.spec.ts: retries renderer reveal before clearing an adopted legacy worker sleeping record. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-02.spec.ts: recovers exported ORCA_TERMINAL_HANDLE from discovered live PTY sessions. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-12.spec.ts: applies ANSI erase-from-start line controls in retained previews; applies ANSI stripping for private or intermediate CSI line controls; applies ANSI stripping for unsupported erase-line modes; reveals an agent terminal under the pane the caller reserved; keeps a fresh %s pane host-owned when a desktop window is available; keeps desktop publication %s separate from the reserved host spawn; mints its own pane when the reserved leaf is malformed, and reports the one it used; starts an agent terminal with the model the caller picked; starts an agent terminal without a model flag when no pick was made; attributes a startup-agent launch named %s as %s; attributes a fresh agent session the host builds as unknown; leaves a bare agent command the user typed out of launch attribution. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-11.spec.ts: trims oversized terminal output bursts without per-line array shifts; builds terminal previews without mapping the full retained tail; keeps recent PTY replay output capped without needing previous data for large chunks; applies terminal redraw controls before retaining previews; applies ANSI terminal redraw controls before retaining previews; retains multi-line ANSI footer redraws instead of appending old frames; keeps the cursor column when erasing full lines in multi-line redraws; applies ANSI split redraw controls without leaking raw params. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-10.spec.ts: returns renderer visible screen lines through terminal.read RPC JSON result; separates composer drafts from provider-owned terminal screens. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-09.spec.ts: reports an in-flight PTY focus as not navigated when its notifier disappears; reports graph-leaf focus as not navigated without a host notifier; grounds the provider mode tracker before a later chunk, in the emulator order; grounds an in-flight provider snapshot capture so it cannot publish the pre-reset screen; waits for terminal exit and resolves with the exit status; keeps terminal read payloads bounded while retained output remains pageable; trims terminal read preview character budget without per-line array shifts. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-08.spec.ts: submits a silent Claude composer once after the bounded render fallback; chunks large terminal.send text before provider writes; yields chunked terminal input through immediates between writes; yields while validating accepted large terminal.send text before provider writes; reveals a background terminal session when focusing its handle; replays captured launch config when focusing a background agent session; reveals background terminal sessions with the freshest PTY title; renames background terminal handles without requiring a visible tab; keeps a background terminal handle stable while reveal adoption is racing. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-07.spec.ts: resolves tui-idle when a stale Codex prompt is followed by Antigravity readiness; returns an agent-neutral blocked wait result for update prompts; returns an agent-neutral blocked wait result for workspace trust prompts; returns an agent-neutral blocked wait result for cwd selection prompts; returns a blocked wait result for Codex model migration prompts; returns a blocked wait result for Codex startup hook review prompts; returns an agent-neutral blocked wait result for generic interactive prompts; splits text and enter writes for background terminal handles; types the lead line for %s: %s; submits through the agent-specific PTY timing policy for %s. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-06.spec.ts: waits for exit on background terminal handles; keeps retained PTY transcript memory when controller refresh fails; resolves tui-idle from an Antigravity ready prompt preview; resolves Antigravity ready prompts with newline-heavy pasted tails without splitting; resolves live-leaf tui-idle from an Antigravity ready prompt preview. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-03.spec.ts: spawns the available Qoder command for a captured same-session resume: %s; does not use the local Windows shell setting for remote Windows bare agent creates; matches canonical bare agent commands when a command override is configured; keeps non-bare agent command terminal creates unchanged; keeps disabled bare agent command terminal creates unchanged; injects runtime hook receiver env into terminal sessions; creates background terminal sessions for a $label; creates background terminal sessions for a $label; enables Claude Agent Teams only for direct Claude launches when configured in-process; reveals Claude Agent Teams launches with the rewritten launch config; preserves Claude Agent Teams for sequenced Claude launches. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness.spec.ts: creates visible terminal sessions without asking the renderer to focus a tab; asks the pty controller for the requested shell instead of a startup command; knows the agent a flagged launch command names before any process read; retires a flagged command pane identity when the command exits; retires only receipted restored PTY authority on command completion and exit; forgets synthetic handles when disconnected PTY records are pruned. src/main/runtime/orca-runtime-tests/headless-snapshots.spec.ts: returns OSC titles from headless main terminal snapshots; adopts renderer-seeded titles into headless main terminal snapshots; returns cwd metadata from seeded headless main terminal snapshots; adopts OSC7 host metadata from seeded headless terminal scrollback; falls back to the renderer snapshot for hidden-output recovery without headless state; keeps an empty headless snapshot authoritative for hidden-output recovery; advances the absolute output sequence across a daemon stream gap; emits explicit OSC 9999 agent status from runtime PTY data. src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-02.spec.ts: falls back to the provider snapshot for a restored PTY with no mounted renderer; falls back to the available mirror when authoritative provider history is unavailable; keeps an empty renderer snapshot when the provider has no retained content; keeps restored provider history authoritative after later live output; uses provider alternate-screen state while a partial model is unsafe; prefers the tracked title over the headless emulator lastTitle; keeps the cursor-agent literal in record-fallback snapshots only without a tracker title; touches mobile snapshots once for decorative spinner ticks, again on idle. src/main/runtime/orca-runtime-tests/local-worktree-creation-part-02.spec.ts: creates a same-repo PR branch override from a resolved head SHA and matching push target; skips broad remote fetch for an existing full-SHA PR base; creates a selected Bitbucket PR branch override from a matching remote branch; suffixes an existing PR when a matching push target lacks selected PR metadata; suffixes a matching push target branch when selected PR metadata has no PR number; suffixes a matching push target branch when the existing PR is different; suffixes a selected PR remote conflict when the PR lookup fails; checks out an unused runtime PR branch only when it is at the resolved head SHA; suffixes only the runtime worktree path when an exact PR branch checkout path exists. src/main/runtime/orca-runtime-tests/local-worktree-creation.spec.ts: returns runtime local base update suggestions from addWorktree; creates a runtime local worktree from a usable persisted local branch base; does not create a runtime local worktree when the refresh fails and no local base ref exists; creates a branchNameOverride worktree from the selected matching remote base ref. src/main/persistence/worktree-sort-order-write.test.ts: re-ranks every writable row when a blocked row sits in the requested order. src/main/runtime/integrations/skill/orca-runtime-skill-recovery.test.ts: continues skill management after startup recovery fails. src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-detached-routing.spec.ts: uses bounded ownership lookup for direct arrivals while the agent cannot take input; wakes a bound Run waiter when same-Run direct mail arrives; keeps an unowned detached-recipient message in its direct mailbox; uses primary-key lookups for bounded routing updates. src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-delivery.test.ts: remove only literal registration import/call pairs import './orchestration-mailbox-pointer-cli-command.spec'; no additional authored credit. src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-pointer-cli-command.spec.ts: renders the %s CLI command in a mailbox pointer. src/main/runtime/rpc/methods/terminal/terminal-multiplex-link-estimate.test.ts: sizes a slow high-latency link near twice its bandwidth-delay product; never paces a LAN, even when its client parses slowly; never paces a fast link; returns to legacy windows when the path RTT jumps. src/main/runtime/rpc/methods/terminal/terminal-snapshot-scrollback-rows.test.ts: steps down the row ladder when history is over the byte budget; tries the larger first row count, then the usual ladder within the same byte budget. src/main/runtime/rpc/server/pairing/network/windows-default-route-interfaces.test.ts: returns unknown when route inspection fails or emits malformed data; does not inspect routes outside Windows. src/main/runtime/rpc/server/pairing/pairing-offer-owner-cli.test.ts: is refused to a paired %s client; reports a failed widening instead of advertising an unreachable address. src/main/runtime/rpc/terminal-multiplex-end-verdict.test.ts: reports exited only when the owning runtime completes the exit waiter; reports unverifiable when the runtime cannot observe the exit waiter; reports unverifiable when a disconnected PTY resolves with unknown liveness. src/main/runtime/session-graph/headless-runtime-graph.spec.ts: lets a session tab inventory settle on a host no renderer publishes for. src/main/runtime/session-graph/runtime-graph-standing-contracts.test.ts: remove only literal registration import/call pairs import { registerHeadlessRuntimeGraphTests } from './headless-runtime-graph.spec', registerHeadlessRuntimeGraphTests(); no additional authored credit. src/main/runtime/session-tabs/structured-conversation-tab-title.test.ts: bumps the stored snapshot version only when the title changes. src/main/runtime/session-tabs/terminal-close-observed-exit.test.ts: keeps the healthy aggregate verification and delayed physical exit behavior; uses a stamped exit for the incarnation that was actually being closed. src/main/runtime/terminal/identity/terminal-identity-probe.test.ts: answers live for a structured worker without touching the PTY graph; answers live for a PTY handle the runtime still holds; runs the full leaf check for a handle with no live PTY; answers not-live for a stale handle; propagates \"could not look\" rather than reporting it as a dead handle. src/main/runtime/terminal/layout/paired-desktop-server-writes-layout-owner.test.ts: names the tab in main’s layout through terminal.rename; takes a window-style layout.apply close as already stopped, so the terminal runs on. src/main/runtime/terminal/lifecycle/pty-lifecycle-generation-retention.test.ts: retains no lifecycle generation after a spawn/exit cycle. src/main/runtime/terminal/lifecycle/run-terminal-user-open.test.ts: reads a freshly spawned terminal as used once a user opens its tab, not on a probe; keeps the open mark on the process a user open starts. src/main/runtime/terminal/surface/terminal-surface-replies-window.test.ts: from a desktop window that mounts both panes; from a server with no window. src/main/runtime/terminal/surface/workspace-layout-projection.test.ts: carries views for a partition that holds none yet. src/main/runtime/terminal/view/terminal-subscribe-exit-waiter-leak.test.ts: releases a signalled exit-waiter when the signal aborts. src/main/runtime/terminal/wait/orca-runtime-exact-worker-provider-session.test.ts: selects a local hook status for a local pane. src/main/runtime/terminal/wait/prime-agent-screen-readiness-transcripts.test.ts: keeps the footer and the bare caret on screen mid-turn; %s: the screen alone reads ready during %s. src/main/runtime/workspaces/startup/runtime-worktree-agent-startup.test.ts: uses per-launch arguments and preserves launch telemetry; attributes a startup agent whose caller named no surface as unknown; launches %s bare for an absent or blank prompt; attributes a %s draft launch named %s as %s; merges an automation's extras over the host defaults; threads worktree-create extras into the startup build; returns an enabled requested agent without detecting; returns the default when nothing was requested; detects instead of using the default when the requested agent is disabled; starts no agent when the default is blank; detects an enabled agent on this host when nothing usable was named; starts no agent when detection finds none. src/main/runtime/workspaces/startup/runtime-worktree-startup-readiness.test.ts: pastes and submits through composer readiness, never typing raw input; types the follow-up on WSL or SSH-to-Windows once the agent is in front, as before; cleans up the deadline when the composer was already captured; a draft that is not submitted is pasted on the box cursor, as before; takes the box after the grace when the row never comes, whatever repaints; takes the box at the deadline when the grace would outlast the budget; lets a dialog on screen veto a grace; refuses the deadline inside a pending grace while a shell is in front; takes the box at the deadline inside a pending grace with the agent in front; takes the box at the deadline after a refused grace once the agent is in front. src/main/skills/skill-install-transaction.test.ts: installs, previews unchanged bytes, and updates a clean receipt-owned skill; preserves the old version after a %s filesystem failure. src/main/speech/model-manager-download-resume.test.ts: requests the remaining bytes when a clean range response ends before the file total; bounds a server that advances by pathologically tiny segments forever. src/main/ssh/config/ssh-config-parser.test.ts: parses a basic host block; parses multiple host blocks; skips wildcard-only Host entries; skips Host entries with only pattern characters; parses IdentityFile with ~ expansion; parses Windows-style IdentityFile with ~ expansion; parses quoted scalar values like OpenSSH; parses equals-form scalar directives; parses IdentityAgent with ~ expansion; parses IdentitiesOnly; parses GSSAPIAuthentication; keeps the first GSSAPIAuthentication value like OpenSSH; parses ProxyCommand, ProxyUseFdpass, and ProxyJump; ignores comments and blank lines; handles case-insensitive keywords; stops current block on Match directive; returns empty array for empty input; creates one parsed host per concrete alias on a multi-pattern Host line; applies identity agent settings to every concrete alias on a multi-pattern Host line; defaults port to 22 for invalid port values; converts hosts to SshTarget objects; uses host alias as hostname when HostName is missing; skips hosts that are already imported; defaults username to empty string when not specified; carries through identityFile, identityAgent, identitiesOnly, proxyCommand, and jumpHost; carries through gssapiAuthentication; imports duplicate aliases only once and keeps the first concrete host; maps hosts for the picker and flags aliases already in Orca; de-dupes aliases and defaults missing fields; parses hostname, user, port from ssh -G output; collects multiple identity files; parses forwardagent yes; defaults port to 22 when missing; returns empty hostname when missing; returns undefined user when missing; handles empty output; skips lines without spaces; parses proxycommand and filters \"none\"; parses proxyusefdpass yes; parses proxyjump and filters \"none\"; handles ~ expansion in identity file paths; handles Windows-style ~ expansion in identity file paths; parses identityagent with ~ expansion; preserves identityagent none so auth can disable agent fallback; parses identitiesonly yes; parses gssapiauthentication; parses controlmaster options and filters controlpath none. src/main/ssh/config/ssh-known-hosts-source.test.ts: splits the space-separated list ssh -G prints on one line; expands ~ in a reported path; keeps a double-quoted path containing spaces whole; falls back to the default files when ssh -G reported nothing; drops an explicit none without falling back to the defaults; splits both known_hosts lists on one line each; reads StrictHostKeyChecking, including accept-new; reads HostKeyAlias and prefers it for the lookup; reads the non-default port; reports that the lookup came from an alias, so the port is not appended; reports no alias when the dialed host is used; unions the entries of every file; skips a path that is a directory; returns nothing when no file can be read; reports nothing unreadable when every file parses; does not count an empty file as unreadable; prefers HostKeyAlias over the resolved hostname; uses the dialed host, because a resolved hostname can just echo the label; still prefers an explicit HostKeyAlias over the dialed host; falls back to the dialed host when nothing was resolved; is rejoined when the split fragments resolve to nothing; leaves a single unresolvable path alone rather than inventing one; expands the __PROGRAMDATA__ token rather than passing it through as a path; does not rewrite a path that merely BEGINS with the token characters; keeps a drive-letter path with mixed separators intact; splits a spaced Windows home into the fragments the rejoin has to put back. src/main/ssh/config/ssh-known-hosts.test.ts: reads the algorithm from the blob rather than trusting the line; rejects %s; refuses a malformed blob: %s; uses the bare host on the default port; tries the bracketed form first and falls back to bare off-port; matches an exact line; matches case-insensitively; reports a changed key of the same type; reports unknown for %s; matches any host in a comma list; matches the bracketed form on its port; does not apply a bracketed entry to the default port; falls back to a bare line when off-port; never reports a change from the fallback pass; matches a bare literal on the default port; matches a bracketed literal on its port; reports a change for a literal; handles %s; still reports a change for a different key on a revoked host; skips a line carrying an unrecognised marker; does not report a change when only another key type is on file; matches within the same type; accepts CRLF terminators; skips blanks, comments and surrounding whitespace; accepts a hit regardless of which file holds it (%s); never brackets the alias, whatever the port; still brackets an ordinary host on a non-default port; matches a bare alias entry on a non-default port; still accepts the unmodified key field; accepts a hashed entry whose salt is a full SHA1 digest; still accepts the unmutated ssh-keygen -H vector; falls back to the bare host line on a non-default port, as ssh did; refuses a key type it has not seen for a host it knows, as ssh did. src/main/ssh/connection/ssh-connect-config.test.ts: returns undefined when no default keys exist; returns the first existing key file; probes regular and FIDO2 keys in stable default order; keeps a regular default ahead of a malformed FIDO2 default; uses target host/port/username; falls back to resolved config when target fields are empty; keeps imported endpoint fields as the fallback when ssh -G is unavailable; sets readyTimeout to CONNECT_TIMEOUT_MS; sets keepaliveInterval to 15s; enables keyboard-interactive auth so MFA challenges can be answered; uses agent auth when no explicit key and SSH_AUTH_SOCK is set; enables agent forwarding when OpenSSH config requests it and an agent is available; does not enable agent forwarding without a usable agent; resolves IdentityAgent SSH_AUTH_SOCK from the environment; uses the Windows OpenSSH agent pipe when no environment socket is available on Windows; wraps agent auth with IdentityFile filtering when IdentitiesOnly is enabled; applies a manual target IdentitiesOnly setting when ssh -G reports it off; includes unencrypted target.identityFile auth when an agent is available; defers encrypted target.identityFile auth when an agent is available; uses keyFile auth when target.identityFile is set and no agent is available; includes unencrypted resolved identityFile auth when an agent is available; defers a default-path resolved identityFile to the no-agent retry; offers the keyboard-interactive challenge when the agent defers no key; provides fallback key when no agent is available; can force private key inclusion for the post-agent fallback path; falls back to resolved proxyCommand; returns structured jump-host config for target.jumpHost; returns structured jump-host config for resolved proxyJump; returns undefined when no proxy is configured. src/main/ssh/connection/ssh-connection-auth-fallback.test.ts: resolves OpenSSH config using configHost when present; tries ssh-agent before reading an explicit private key; falls back to direct private key auth when agent auth fails; falls back to direct private key auth after too many agent authentication failures; answers bounded keyboard-interactive challenges such as Duo 2FA. src/main/ssh/connection/ssh-connection-store.test.ts: lists picker suppression aliases without consulting re-adoption tombstones; getTarget delegates to store; addTarget generates an id and persists; saves the CLI control switch as given, with no consent stamp; addTarget stamps source as manual by default; addTarget preserves an explicitly provided source; inserts a new config host stamped as ssh-config; asks the parser for all hosts — reconciliation happens in the store; updates an existing config-sourced target when the port changed; refreshes gssapiAuthentication on sync; never overwrites a manual target that owns the alias; does not rewrite an unchanged config-sourced target; returns empty array when nothing changed; tombstones a deleted config-sourced host so re-import skips it; suppresses a deleted manual target from config discovery; re-adding a deleted host reclaims its alias so sync stops suppressing it; editing a target reclaims its alias from the deleted set; records a tombstone when removing any user-facing target; re-adopts orphaned repos when the same host is re-added. src/main/ssh/connection/ssh-connection.test.ts: transitions to connected on successful connect; captures the negotiated SSH server key fingerprint; allows concurrent exec commands for ssh2 transport; removes startup listeners after ssh2 connect succeeds; scopes lifecycle events and pending handshake timers to one mock client; enables TCP_NODELAY on the new ssh2 client after a reconnect cycle; transitions through connecting → connected states; reports error state on connection failure; disconnect cleans up and sets state to disconnected; getTarget returns a copy of the target; getState returns a copy of the state; throws when connecting a disposed connection. src/main/ssh/orcad-migration-stuck-host-profiles.test.ts: never leaves a running terminal behind; is offered only when leaving saved state behind would clear the refusal. src/main/ssh/orcad-runtime-maintenance.test.ts: keeps a connect from retrying a build an explicit Update also failed; offers Force when Update was refused by policy; forwards anew after an activation, since the new slot may bind another port; passes a refusal through and leaves the server linked; forwards anew once a serving slot is restored, which may have bound another port. src/main/ssh/port-forwarding/ssh-port-forward.test.ts: reports the port the OS bound when an ssh2 forward asks for port 0; adds an ssh2 port forward and returns entry; adds a system SSH port forward when no ssh2 client is available; reports the port a system SSH forward resolved when asked for port 0; passes resolved OpenSSH config to system SSH port forwards; disposes a system SSH tunnel when removing the forward; lists forwards filtered by connectionId; removes a forward by id; awaits forward close when removing a forward for user actions; returns null when removing nonexistent forward; removes all forwards for a connection; dispose removes all forwards; stores label in the entry; preserves the existing id when updating a forward succeeds. src/main/ssh/ssh-channel-multiplexer.test.ts: sends a JSON-RPC request and resolves on response; assigns unique request IDs; sends notifications without expecting a response; dispatches incoming notifications to handler; sends one keepalive frame per cadence tick; drives keepalive sends AND dead-link detection from a single interval; resolves false immediately on a disposed mux; throws on request after dispose; reports isDisposed correctly; clears registered handlers on dispose; does not retain handlers registered after dispose. src/main/ssh/system-transport/system-ssh-forward-process.test.ts: spawns exactly the argv the orphan matcher is given, LogLevel=INFO included; runs port forwards unmultiplexed even when ssh_config disables muxing; preserves manual target port and identity options in the forwarded ssh command; does not spawn ssh when the requested local forward port is already in use; spawns ssh after the requested local forward port preflight succeeds; resolves startup after the grace period when ssh keeps running; sends SIGTERM then SIGKILL when the process does not exit; does not resolve stop until the process exits. src/main/ssh/system-transport/system-ssh-loopback-route.test.ts: dials the held forward ahead of the alias so OpenSSH keeps these over ssh_config; drops a manual target's own port and proxies, which would fight the route; never routes a forward, whose argv must stay stable for orphan recovery; %s → %s; opens the forward over the real proxy, then proves a login over the route; lands the forward on the sshd and known_hosts name the direct route resolved; holds the forward with server-alive probes; never lets the background forward or probe ask for credentials; starts no forward when admission refuses the route; stops the forward when sshd refuses logins over it; stops the whole forward process tree on Windows, once; reports a forward that already exited before anyone listened for it. src/main/startup/browser-process-user-agent-ordering.test.ts: explains admission refusal before a desktop launch exits; explains an orcad holding the profile instead of exiting silently; does not acquire profile admission for a duplicate launch; executes after the dev app name and before later preflight work; exits and releases admission after pending profile move recovery fails; keeps Linux background startup failures console-only and immediate; keeps Linux serve startup failures console-only and immediate. src/main/startup/quit/quit-path-durable-write-blocking.test.ts: store.flushAsync() issues no synchronous fs syscalls; store.flushAsync() also moves the active-view and github-cache sidecars off the thread; stats.flushAsync() issues no synchronous fs syscalls; Grok session cleanup issues no synchronous fs syscalls; stats.flushAsync() closes out live agents before it returns, not when its write lands; a stalled mount leaves the event loop live instead of parking it; store.flushAsync() is one idempotent final barrier; store.flushAsync() resolves instead of throwing when the profile mount rejects writes. src/main/stats/agent-session-transition-recorder.test.ts: counts a hook-only agent that never writes an agent-shaped terminal title; never opens a session from a replayed or disk-restored working status; still closes a live session when the terminating status arrives as a replay; counts one session per turn across repeated working/done cycles; closes an open session when its pane is torn down; bounds the mirror and closes what it evicts; stops the session when the main agent settles and only a watch loop holds the row working; keeps the session open while a subagent outlives the main agent, and closes it when the child settles; dates the stop by the evidence when a shell outlives the last subagent; opens a new session dated by the observation when the main agent resumes after monitoring; never dates a reopen before the close a fact-less OSC repaint caused; dates the first live row after a restored one by the evidence, not the restored clock; treats an unchanged answer as a snapshot, never a transition; opens only on a live working edge; closes only a session it opened. src/main/text-generation/commit-message-text-generation-model-discovery.test.ts: returns static catalog models without spawning for static agents; discovers dynamic models through the agent CLI; discovers dynamic models through the configured agent command override; falls back to static models when dynamic discovery returns no parseable models; falls back to the first discovered non-Pi model when its static default is unavailable. src/main/text-generation/pull-request-context.test.ts: does not fetch unrelated fork remotes before generating PR context; bounds exact remote-ref probe concurrency for a large remote list; reports no branch change because PR context preparation is read-only; keeps a remote-qualified base when the selected base includes the remote. src/main/text-generation/source-control-local-process.test.ts: asks the supervisor to stop and leaves its group to it; signals nothing once the supervisor has exited; stops an agent that ignores its stdin end through its supervisor. src/main/updater/linux-package/linux-package-update-recovery.test.ts: retains the downloaded package with the digest from the event metadata; requires a string downloaded path; accepts an uppercase extension; requires a non-empty string version; matches an absolute file URL by basename; accepts duplicate entries that agree on the digest; refuses an entry with a missing or non-string digest; refuses a digest that is not base64 at all; refuses a malformed percent-encoded URL; refuses a missing or non-array file list; tolerates a non-object event; replaces the retained artifact with a newer download; keeps the retained artifact when a new download has no usable digest; keeps the retained artifact when an unrelated download event arrives; clears the retained artifact; preserves the artifact across a recheck of the same version; clears the artifact when another version takes over; preserves the artifact for an unknown or empty version; is a no-op without a retained artifact; returns the built command and package file name for a verified package; reports missing without a retained artifact; propagates a package-manager discovery failure; rejects a well-formed digest that belongs to another file; never hashes a package that a malformed digest failed to arm; rejects a path outside the cache root; rejects the cache root itself; rejects a package in the updater directory itself; rejects a pending directory that is a symlink out of the cache; performs one hash pass for concurrent requests; revalidates once the in-flight pass settles; does not reuse an in-flight pass for a different artifact; starts a fresh proof when the same package is captured again; returns the verified package path; returns missing without a retained artifact. src/main/updater/releases/updater-prerelease-feed-readiness.test.ts: accepts a GitHub %s asset redirect as ready; reports a GitHub asset request error as unavailable; reports not-ready with a verified last-good tag when the newest assets are unavailable; does not classify a non-positive tag limit as feed unavailability; reproduces the v1.4.142 publishing incident as not-ready; reports transport failures as unavailable instead of not-ready; treats an explicit asset 404 as not-ready when another asset is unavailable; accepts absolute manifest asset URLs without rewriting them to release asset paths; returns not-ready with an older ready update as last-good while newest is publishing. src/main/updater/releases/updater-release-builds.test.ts: lists hourly builds from the dedicated repo, newest first; lists daily builds from the dedicated repo, newest first; separates stable from rc in the shared main repo; skips drafts and unparseable tags; keeps a composed release title and drops one that repeats the tag; hides builds that published no artifact for this platform; returns an empty list when no build has this platform artifact; keeps mac builds visible on macOS regardless of the Windows leg; resolves the platform installer download url; leaves the installer url null when the release published no installer; tolerates a release whose assets are missing or malformed; sends the local gh token as a bearer header when one is available; sends no authorization header when gh has no token; retries unauthenticated once when GitHub rejects the token; does not retry a 401 that was already unauthenticated; falls back to the per-IP bucket when the token is rate limited and tells the gh breaker; reports a secondary limit carrying retry-after without retrying or tripping the breaker; records a primary limit in the token scope %s; keeps %s authenticated when only %s is blocked; skips the token while its scope %s is blocked; surfaces a rate limit with its reset time and a sign-in hint when unauthenticated; omits the sign-in hint when the rate-limited request was authenticated; treats 429 as a rate limit; reports a 403 without rate-limit headers as a plain HTTP error; reports a missing hourly repo distinctly; is null when GitHub sent no reset; prefers retry-after over the primary reset epoch; falls back to the primary reset epoch when there is no retry-after; reads retry-after as seconds; reads retry-after as an HTTP date; pins an hourly tag at the hourly repo download path; pins a daily tag at the daily repo download path; pins a stable tag at the main repo download path; rejects a tag that is not a version. src/main/updater/updater.build-channel-selection.test.ts: uses the display label in the unsupported-platform %s pinned-build error; still pins %s from an unsigned Windows dev build; restores ordinary release checks after local build selection fails; opts into the RC channel when checkForUpdatesFromMenu is called with includePrerelease; pins the generic feed to a perf-tagged prerelease when requested; surfaces no-update feedback when no newer perf-tagged prerelease exists; keeps prerelease publishing-window misses on the generic retry path; leaves the feed URL alone for a normal user-initiated check. src/main/updater/updater.check-preflight.test.ts: ignores a stale update-not-available event after a new check starts preflight; deduplicates repeated manual checks while the immediate checking status is active. src/main/updater/updater.prerelease-fallback.test.ts: retries a prerelease check once against the previous feed tag when the manifest is missing; surfaces a promise-only prerelease fallback failure after the primary error event. src/main/updater/updater.publishing-window-feed.test.ts: repins the generic feed to the newest RC tag for a prerelease user; repins the generic feed to a newer stable tag for a prerelease user; pins a stable fallback when Atom has no newer prerelease; uses last-good concrete feed when a user-initiated check lands during publishing; can offer an older fully published update while the newest release is publishing; keeps background publishing-window fallback on the short retry cadence. src/main/updater/updater.quit-and-install.test.ts: surfaces an accepted retry before electron-updater emits download progress; defers quitAndInstall and runs its launcher within the launch PATH scope; runs pre-quit cleanup before local PTY cleanup during update install; keeps optional pre-quit cleanup fail-and-continue behavior by default; ignores duplicate quitAndInstall requests while the shared delay is pending; arms the forced-exit watchdog once the install commits; disarms the forced-exit watchdog when sync install error recovery keeps the app open. src/main/window/createMainWindow-markdown-editor-focus.test.ts: ignores traffic light sync IPC on non-macOS; still intercepts Cmd+Shift+B and Cmd+Alt+B when the markdown editor is focused; coerces non-boolean setMarkdownEditorFocused payloads to false; opens a table-aware context menu synchronously without a renderer query; builds the plain edit menu for the one right-click the renderer marks as plain text. src/main/window/createMainWindow-renderer-crash-recovery.test.ts: notifies the caller when the renderer process is gone; passes the renderer webContents id through crash recording and recovery callbacks; forwards expected renderer teardowns so the recorder can diagnose suppression; reloads the app shell after an unexpected renderer process loss; does not reload after renderer loss when recovery is disabled; stops auto-reloading after a rapid renderer crash loop trips the breaker. src/main/window/dashboard-popout-window.test.ts: updates the title after language initialization and unsubscribes when closed; lets its preload expose saved WSL hosts in serve-only, and passes nothing otherwise; creates a native-frame window with the shared preload and no webview surface; shows the window on ready-to-show; loads the prod file entry; loads the dev server URL when in dev; focuses the existing window instead of creating a second one; trusts only the live popout webContents; restores a minimized window when re-requested; restores valid persisted bounds; discards off-screen persisted bounds and falls back to defaults; persists bounds on resize after the debounce, guarding near-minimum sizes; keeps saving bounds after a vetoed quit and freezes them only on an allowed quit; closeDashboardPopout closes an open window; applies the persisted app zoom level on dom-ready; follows app zoom changes while open and unsubscribes on close; zoomDashboardPopoutIfFocused steps the popout zoom only while focused; handles the zoom-in chord via before-input-event and ignores other keys; handles mouse-wheel zoom requests outside before-input-event; respects zoom keybinding overrides for keyboard and mouse-wheel paths. src/main/window/dropped-path-preparation.test.ts: opens and stores each unique source once as drop size grows tenfold; passes ordinary paths without copying for %s; preserves ordinary successes and copied successes when another file fails; serializes copy requests from different owners; reports all lost paths without a shared reason when their failures differ. src/main/window/main-window-updater-deferred-setup.test.ts: releases all 64 completed fallback handles without repeating initialization; keeps setup after ready-to-show and releases its fallback afterward; preserves the 15-second fallback when first paint never arrives; preserves destroyed-window guard reads before and at the fallback deadline; keeps the exact %s error and releases its completed fallback; keeps the exact fallback %s error without retrying initialization; preserves pending manual setup after failed ready registration; keeps setup options, live store reads, nudge writes and required quit flush. src/main/worker-threads/worker-thread-request-queue.test.ts: posts one request at a time and in the order it was dispatched; fires a posted call at its own deadline; stops respawning and fails the rest of the queue once deaths hit the cap; clears the death count when a fresh burst starts from full idle. src/main/workspace-hooks/hooks-setup-runner-script.test.ts: builds Windows runners for newline-heavy scripts without line-array splitting; builds POSIX runners without regex-wide CRLF normalization; writes POSIX setup runners for shebang-declared scripts on native Windows paths; keeps batch setup scripts on cmd.exe when the terminal is Git Bash; hands a Git Bash pane a launch command MSYS cannot rewrite for a cmd runner; replays interpreter flags declared on the shebang line; preserves cmd.exe setup runner semantics for configured cmd users; keeps POSIX runner behavior on POSIX platforms; waits when either local or project policy requires completed setup; marks setup-runner terminals for the always-on credential guard; maps git-bash to POSIX setup launch metadata on Windows; falls back to the cmd runner when the git-bash setting has no installed Git Bash; keeps the cmd runner for a non-Git bash such as Cygwin; keeps the cmd runner for a bare bash whose flavor cannot be resolved; uses the POSIX runner for a bare bash that resolves to Git Bash; uses the POSIX runner for an extension-less Git Bash path; preserves the existing cmd runner for PowerShell terminals; preserves cmd setup compatibility when a Windows-host project has a WSL shell setting; classifies an installed explicit Git Bash executable as a POSIX runner; falls back to the cmd runner when the explicit Git Bash path no longer exists. src/main/workspaces/catalog/repo-git-remote-identity-enrichment.test.ts: schedules remote identity enrichment without blocking the caller; probes a drive project whose runtime is WSL %s; sweeps a local repo: %s; probes an SSH row that carries only executionHostId on its own host; keeps same-path rows on two different SSH hosts from sharing one backoff; coalesces concurrent probes for the same repo location; caches no-identity probes briefly so list calls do not retry every time; does not rewrite the no-remote marker on a later retry; resolves a settled no-remote repo once it gains a remote; does not re-probe a resolved identity before the refresh window elapses; re-probes a resolved identity after the refresh window elapses; bounds re-probes per sweep so a large repo list drains gradually; forgets a removed repo location so its deadline cannot outlive the repo; keeps a surviving repo backoff when a sibling repo is removed; probes again when the same location is re-added after its probe was retired; coalesces concurrent sweeps instead of running one pass per list call. src/main/workspaces/creation/preparation/worktree-create-preparation.test.ts: preserves create priority through claim probes on %s; starts the checkout only once the async workspace root resolves; still deduplicates when both callers await the same pending root lookup; namespaces native Windows preparation directories for long paths; deduplicates preparation for the same repo, base, runtime, and workspace root; does not spend a divergence walk when the base matches exactly; claims when the two sides spell the same ref differently; evicts a repo's own stale preparation before another repo's; still discards armed checkouts when the project runtime needs repair; routes preparation and finalization through the selected WSL runtime; retries stale cleanup after a transient listing failure; does not discard a detached worktree with caller-controlled preparation metadata; does not re-arm after an isolated create; re-arms a preparation once creates arrive in a burst; holds the re-arm checkout until the create runs the deferred thunk; starts one explicit prefetch after the create completes; does not re-arm when finalization failed; reports a pending create while a stale-cleanup scan is running. src/main/workspaces/removal/local-worktree-removal-recovery.test.ts: recovers Git for Windows partial filesystem deletion failures; finishes a clean non-force deletion after Git leaves a Windows directory behind; recovers localized Windows failures after Git already removed the registration; does not recover unrelated localized failures while Git still owns the row; finishes a macOS deletion Git deregistered before failing with Directory not empty; leaves an orphaned checkout to the orphan cleanup instead of deleting it; prunes and strictly verifies on the selected WSL host without deleting files or branches. src/main/workspaces/removal/worktree-removal-safety.test.ts: rejects deleting a worktree that contains another registered worktree; rejects POSIX home directories even when host homedir has a different path shape; refuses a home the host reported even when no path rule recognises it; refuses the Windows host's home directory from a POSIX client; refuses the Windows host's home directory even when the host reported nothing. src/main/wsl/discovery/distro-catalog.test.ts: retries asynchronous discovery after a transient wsl.exe failure; retries synchronous discovery after a transient wsl.exe failure; retries asynchronous discovery after wsl.exe reports no distros yet; retries synchronous discovery after wsl.exe reports no distros yet; bounds the wsl.exe spawn rate while no distros are installed; bounds the asynchronous spawn rate while no distros are installed; still caches a non-empty distro list for the process lifetime; re-probes a docker-desktop-only machine once a user distro can appear; backs off while the list keeps coming back empty; backs off after repeated distro-list failures; caps the empty-list backoff at five minutes; keeps reporting an empty result after it goes stale; keeps reporting a known distro list indefinitely; bounds cached homes while retaining the most recently used distros; still lists distros, and an excluded distro home probe fails like any other probe; gives the async home probe time for a cold boot instead of killing it at 5 s; retries availability after a probe timeout instead of latching false; bounds the probe rate while the failure window is open; caches a successful probe for the process lifetime; names an explicit spawn directory, so no deleted cwd can read as ENOENT; shares one wsl.exe spawn between concurrent probes; keeps reporting the last observed answer after it goes stale; holds a definitive failure far longer than a timeout when %s; backs off after repeated probe failures; re-probes a seeded retryable failure once its window lapses; re-probes availability once a distro list succeeds after %s; does not drop an availability failure for an empty distro list; keeps reporting unavailable off Windows without probing. src/main/wsl/discovery/wsl-distro-holder.test.ts: runs a busybox-safe loop through --exec and names the distro; spawns a detached-style holder, records it, and waits for the distro to run; a holder exiting with code 1 notes its distro may have stopped (E9); rejects a pid whose command line is not our holder for that distro; cleans up stale and corrupt records; keeps a holder and its record when release cannot verify it; reports unverifiable when the command line is unreadable even with a matching pid; release kills a verified holder and removes its record; release never kills a pid that is no longer our holder; reports a spawned holder exit so liveness can re-check. src/main/wsl/filesystem/wsl-guest-drive-mountinfo.test.ts: skips 9p shares that are not drvfs, and malformed lines. src/main/wsl/orcad/wsl-orcad-deploy-app-update.test.ts: plans the update on the census the running orcad reports, not an unknown one; forwards force to the update planner; does not serve the incumbent past a refusal that is not a wait; does not re-activate the build this host rolled back from; labels the launch with the build the adoption found serving, not the stale record; defers while another run holds the host fence; lets an explicit force deploy past both skips; names a newer host refusal apart from a rolled-back one, so only Force is offered; updates an older host as before, without asking to adopt it; never asks the incumbent when it already runs this build. src/renderer/src/components/agent/agent-launch-picker-acquisition.test.ts: keeps a completed listing usable when the host rejects the wait parameter. src/renderer/src/components/feature-tips/feature-tip-telemetry.test.ts: delivers to chat-default users in all targeting while holding out not-switched users. src/renderer/src/components/native-chat/composer/pickers/use-native-chat-side-chat-command.test.ts: completes the row on a pick, even when the command is already typed; ignores a pick of the row while side chats are unavailable. src/renderer/src/components/native-chat/media/images/native-chat-image-copy.test.ts: explains a too-large refusal that arrives through the IPC error prefix. src/renderer/src/components/native-chat/messages/actions/native-chat-fork-launch.test.ts: keeps the question with the caller and says once that it never went; tells the user to check the side chat when delivery is unconfirmed; reports a delivered question as sent, silently. src/renderer/src/components/native-chat/messages/actions/native-chat-side-chat-fork-point.test.ts: decides each of %i tool-only turns once per layout, and nothing without a listener. src/renderer/src/components/native-chat/messages/actions/use-native-chat-fork.test.tsx: places a side chat whose question was %s: %o. src/renderer/src/components/terminal-pane/provider-notices/agent-presence/agent-terminal-presence.test.ts: calls back once for %s; stops watching once unsubscribed. src/renderer/src/components/terminal-pane/pty-connection/emulation/pty-connection-mode2031-raw-subscription.spec.ts: records a mode 2031 subscribe from the raw chunk boundary without answering. src/renderer/src/components/terminal-pane/pty-connection/input/pty-connection-deferred-input-forwarding.spec.ts: routes terminal input through deferPtyInput so the host can withhold it; forwards terminal input directly when the host supplies no deferPtyInput. src/renderer/src/components/terminal-pane/pty-connection/notifications/pty-connection-terminal-bell-attention.spec.ts: forwards onBell to pane attention and notification policy; hands the bell to the attention module with its pane even when pane attention is off. src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-dropped-output-snapshot-healing.spec.ts: repaints from the main-owned snapshot when main drops pending output at the cap. src/renderer/src/components/terminal-pane/pty-connection/output/pty-connection-fresh-native-follow-reset.spec.ts: retries a fresh-spawn native follow reset when renderer dimensions return. src/renderer/src/components/terminal-pane/pty-connection/spawn/unbound-pane-spawn-recovery.test.ts: requests a tab remount for an unbound spawn; leaves recovery to a remote transport that armed its own retry; requests a remount when the transport reports no recovery of its own; settles the spawn as failed before requesting a remount; prefers the restored leaf id when reporting the anomaly; falls back to the pane leaf id when no restored leaf exists. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-foreground-agent.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionDeferredInputForwardingTests } from '../input/pty-connection-deferred-input-forwarding.spec', registerPtyConnectionDeferredInputForwardingTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts: structural support changed only; no new authored removal credit. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionFreshNativeFollowResetTests } from '../output/pty-connection-fresh-native-follow-reset.spec', registerPtyConnectionFreshNativeFollowResetTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionTerminalBellAttentionTests } from '../notifications/pty-connection-terminal-bell-attention.spec', registerPtyConnectionTerminalBellAttentionTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-delivery-interest.test.ts: registers interest on the first sidecar and releases on the last unsubscribe; releases sidecar interest only once for repeated unsubscribes; does not let an eager pre-mount buffer defeat hidden delivery gating; keeps eager buffers outside delivery interest when the PTY exits before mount; lets a sidecar exclusively own interest while an eager buffer overlaps. src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-push-reattach.test.ts: blackholed delivery reproduces the wedge: no handler dispatch, no ACK ever. src/renderer/src/components/terminal-pane/pty-transport/ipc/ipc-pty-opencode-model.test.ts: sends preferences to the execution host and attaches only to its returned PTY; preserves one operation ID across a lost reply and reconnect; preserves ordinary raw startup and captured-session attachment. src/renderer/src/components/terminal-pane/pty-transport/output/pty-side-effect-pending-census.test.ts: sums registered gauges and drops disposed ones; ignores a repeated dispose instead of dropping another gauge; stops tracking new gauges past the cap so a missed dispose cannot grow it; tracks a live output processor queue through enqueue, drain, and dispose; excludes cleared consumed entries from retention after a bounded drain. src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-prebind-discard-notice.test.ts: says nothing once the pane is closed. src/renderer/src/components/terminal-pane/render-health/terminal-webgl-atlas-recovery.test.ts: refreshes after each scheduled atlas reset; falls back to a timeout when animation frames are unavailable; continues recovery when a manager throws after scheduling. src/renderer/src/components/terminal-pane/snapshots/pty-buffer-serializer.test.ts: tracks a remounted quiet title source even when the stale owner unregisters later; preserves the renderer-parsed output sequence in the response; preserves a pending escape tail for snapshot replay; routes a host's Reset Terminal request to the pane that owns the PTY. src/renderer/src/components/terminal-pane/snapshots/saved-terminal-output-replay.test.ts: marks panes with restored scrollback for fresh-shell viewport blanking. src/renderer/src/components/terminal-pane/viewport/split-right-white-screen.test.ts: recovers a 0x0 spawn whose container is briefly unmeasurable then settles. src/renderer/src/components/terminal-pane/viewport/visibility/stale-document-visibility.test.ts: removes global listeners when the last pane unregisters. src/renderer/src/components/ui/security-surface-theme-contrast.test.tsx: keeps trust text readable on a host-owned dialog surface; applies the hostile surface to ordinary dialogs, so the case above is exercised. src/renderer/src/components/use-terminal-parking-pass.test.tsx: does not queue a render when a pass produces the same parking sets; keeps parking transitions working under StrictMode. src/renderer/src/hooks/client-workspace-view-report.test.ts: reports an away user’s screen with no presence, and renews as soon as input returns; retries a failed send, empty or not, no sooner than a refresh. src/renderer/src/hooks/ipc-events/terminal-request-ipc-bridge-placement.test.ts: is new work in a workspace with no live terminal: its first bind moves it up in Recent. src/renderer/src/hooks/use-bundled-skill-install.test.tsx: ignores a repeated click while the install runs; retries the last requested skills on this host. src/renderer/src/hooks/useGitHubSlugMetadata.assignee-reuse.test.tsx: adds seeds to a successful empty list but not to loading or failed results; retains seed projection after expiry and fetches fresh metadata for a new reader. src/renderer/src/hooks/useSettingsNavigationMetadata.language-switch.test.tsx: retranslates the settings nav labels when the UI language changes live. src/renderer/src/lib/codex-stale-pane-account-identity.test.ts: keeps the prompt when the roster read fails and every label collapses. src/renderer/src/lib/image-blob-png.test.ts: downscales a pasted image above the pixel cap; releases its temporary URL on a decode error; releases its temporary URL when PNG encoding fails or exceeds the byte cap. src/renderer/src/lib/react-commit-cascade-store-write-samples.test.ts: names callers above the frame the write came from; restores Error.stackTraceLimit when the capture throws; stops collecting after the sample cap when captureStackTrace is unavailable; caps reported changed keys from a single wide write. src/renderer/src/lib/work-items/linear/linear-issue-context-snapshot.test.ts: applies the rendered text hard cap last and reserves the final overflow marker. src/renderer/src/runtime/rpc/targets/use-worktree-runtime-target.test.ts: keeps the runtime target identity stable across unrelated store writes. src/renderer/src/runtime/source-control/git/runtime-git-branch-client.test.ts: keeps creation available on old hosts and explains the missing operation; preserves landed warnings and direct collision recovery data; propagates remote discovery failure instead of a false empty page. src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-key-reuse.test.ts: reuses unchanged worktree tab projections when one worktree title changes; bumps only the changed worktree version when a sibling stays byte-identical. src/renderer/src/store/repos/repos-catalog-request-coordination.test.ts: shares safe-auto fork sync cooldown attempts across store instances. src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-batch.test.ts: collapses a 193-workspace hydration to one store write; leaves the store byte-identical to the per-workspace path; re-reconciling the batched result is a no-op, as it is for the per-workspace path. src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-fixture.ts: dedicated zero-case helper retirement; no authored test credit. src/renderer/src/store/slices/worktrees/metadata/update-worktrees-meta.test.ts: persists each batch metadata update to its workspace owner. src/renderer/src/store/slices/worktrees/metadata/worktree-meta-rename.test.ts: dismisses a rename error on its capable remote owner; clears pending first-agent rename when the title is updated. src/renderer/src/store/terminals/store-sleep-shutdown-order.test.ts: orders capture, guards, handlers, main's stop, commit, cleanup, and exit settlement. src/renderer/src/store/terminals/terminal-first-tab-publication.test.ts: publishes the first terminal and root tab group atomically; publishes the first terminal and root tab group atomically, then marks it starting in main. src/renderer/src/store/terminals/workspace-terminal-reconnect-hydration.test.ts: restores daemon terminal wake hints before declaring the session ready. src/renderer/src/web/web-runtime-connection-auth-framing.test.ts: keeps legacy framing for sockets that cannot absorb a refused attempt. src/shared/terminal/appearance/terminal-font-weight-windows-regular.test.ts: moves the old Windows default to Regular once and queues the notice; keeps custom weights and fresh profiles without a notice; leaves macOS and Linux profiles untouched. tests/e2e/claude-agent-row-view.unit.test.ts: updates a mounted compact workflow description through the subscribed production parent; bounds upstream active-SSH visits for $population records, fallback=$fallback; derives %s destinations without requiring type or a workflow child ID; terminates a $path parent $status with no third request or intermediate toast; does not recover a first child %s. tests/e2e/cross-version-wire/agent-permission-legacy-spawn.unit.test.ts: keeps exact legacy ordering when structured creation cannot express afterTabId; can create a terminal without selecting the target worktree; preserves the legacy fresh-agent path when host authority is unavailable. tests/e2e/paired-instant-browser-tab.spec.ts: shows a paired browser tab before its create RPC resolves, then keeps it as one tab; adopts a paired browser tab without rebuilding its chrome. tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts: bounds host publication and renderer application across remote worktrees; globally caps decorative freshness while every working status stays fresh. tests/e2e/session-tabs/mobile-session-active-performance.unit.test.ts: bounds saved-order publication selection at N and 10N without rematerializing navigation; bounds admitted placement reconciliation during supported reads at N and 10N; bounds selection input visits at 50 and 500 rows, including unavailable-target projection; keeps publication scoped to a changed worktree and shared by listeners at N and 10N; bounds preserved-chat merge and runtime-owned hydration at N and 10N (legacy=%s); bounds actual native retirement and shared delivery work at N and 10N. tests/e2e/session-tabs/mobile-session-active-publication.unit.test.ts: does not substitute a preserved row for an unavailable explicit legacy selection; resolves main-layout group selection %s (omitted group=%s). tests/e2e/structured-agent-session-launch-admission.unit.test.ts: opens a direct caller's terminal with the caller's own CLI arguments on a decline; opens the chat on the server that admitted it; opens only the terminal when this machine declines, without a notice; opens a new agent tab's terminal with the typed prompt when the caller names none; opens the chat, not a terminal, when this machine cannot resolve a new workspace yet; keeps its terminal fallback, as before. tests/e2e/structured-attention-prompt-relay.unit.test.ts: settles once per relayed prompt, not on every later status update. tests/e2e/structured-attention-read-retirement.unit.test.ts: Mark read on a chat never opened withdraws the prompt alert it surfaced; Mark read on a chat hidden since an earlier view covers the newer prompt it surfaced; reads a newly accepted visible prompt without sending an RPC for text-only updates. tests/e2e/structured-chat-tab-lifetime-cost.unit.test.ts: counts real raw stores, unrelated window publications and captured cleanup at %i chats; counts complete supplied-member sweep and separate final retirement at S=%i N=%i. tests/e2e/structured-session-workspace-authority.unit.test.ts: bounds actual target reveal across %i repo roots and metadata aliases. tests/e2e/terminal-agent-pane-launch.unit.test.ts: starts the host's planned command once, at the pane's size, and says it started; plans a pane whose prompt the window submits without the startup update prompt; preserves caller shell-ready delivery only for a connection-scoped adapter ($connectionId); starts no shell on plan failure (original failure: $returnLaunchFailure); cannot confirm a start whose provider answer was lost. tests/e2e/terminal-parked-memory.spec.ts: releases renderer terminal memory when hidden tabs park. tests/e2e/terminal-shortcuts.spec.ts: @headful Codex-like background output stays visible without disabling WebGL in auto mode; Shift with Russian layout text reaches the PTY as Cyrillic under kitty keyboard reporting. tests/e2e/terminal-split-activation-latency.spec.ts: records attributed CWD, spawn, bind, fixture-ready, input, and echo phases. tests/e2e/terminal-split-activation-latency-phases.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-main-probe.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-artifact.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-report.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-tab-switch-visual-restore.spec.ts: restores skipped hidden Grok output on light tab resume. tests/e2e/web-runtime-session-terminal-host-authority.unit.test.ts: delivers independent %s effort through the real prepared web callback; keeps same-ID local and runtime worktrees on the selected runtime owner; creates paired web agents through host authority so activation is mirrored; delivers generated continuation context after host-authoritative creation; seeds the chat composer for a draft that rode in on the launch command. Current changed source bytes, wrapper registrations and reduced selectors have no fresh execution or red/green credit. Unrelated surviving receipt objects keep their original narrow scope; current literal graph reachability does not establish historical import closure or equivalent replacement coverage. Current conservative command/import graph reaches src/main/runtime/construction/orca-runtime.test.ts, src/main/runtime/orca-runtime-tests/targeting-and-resilience.spec.ts, src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-04.spec.ts, src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-03.spec.ts, src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-02.spec.ts, src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases-part-02.spec.ts, src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases.spec.ts, src/main/runtime/orca-runtime-tests/worktree-setup-and-startup-part-03.spec.ts, src/main/runtime/orca-runtime-tests/worktree-setup-and-startup.spec.ts, src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-summaries-part-03.spec.ts, src/main/runtime/orca-runtime-tests/mobile-summaries-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-summaries.spec.ts, src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-03.spec.ts, src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-13.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-12.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-11.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-10.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-08.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-07.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-05.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-04.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-05.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-04.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-03.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-02.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-07.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-04.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-03.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-02.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-12.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-11.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-10.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-09.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-08.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-07.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-06.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-03.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness.spec.ts, src/main/runtime/orca-runtime-tests/headless-snapshots.spec.ts, src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-02.spec.ts, src/main/runtime/orca-runtime-tests/local-worktree-creation-part-02.spec.ts, src/main/runtime/orca-runtime-tests/local-worktree-creation.spec.ts, src/main/persistence/worktree-sort-order-write.test.ts, src/main/runtime/integrations/skill/orca-runtime-skill-recovery.test.ts, src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-detached-routing.spec.ts, src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-delivery.test.ts, src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-pointer-cli-command.spec.ts, src/main/runtime/rpc/methods/terminal/terminal-multiplex-link-estimate.test.ts, src/main/runtime/rpc/methods/terminal/terminal-snapshot-scrollback-rows.test.ts, src/main/runtime/rpc/server/pairing/network/windows-default-route-interfaces.test.ts, src/main/runtime/rpc/server/pairing/pairing-offer-owner-cli.test.ts, src/main/runtime/rpc/terminal-multiplex-end-verdict.test.ts, src/main/runtime/session-graph/headless-runtime-graph.spec.ts, src/main/runtime/session-graph/runtime-graph-standing-contracts.test.ts, src/main/runtime/session-tabs/structured-conversation-tab-title.test.ts, src/main/runtime/session-tabs/terminal-close-observed-exit.test.ts, src/main/runtime/terminal/identity/terminal-identity-probe.test.ts, src/main/runtime/terminal/layout/paired-desktop-server-writes-layout-owner.test.ts, src/main/runtime/terminal/lifecycle/pty-lifecycle-generation-retention.test.ts, src/main/runtime/terminal/lifecycle/run-terminal-user-open.test.ts, src/main/runtime/terminal/surface/terminal-surface-replies-window.test.ts, src/main/runtime/terminal/surface/workspace-layout-projection.test.ts, src/main/runtime/terminal/view/terminal-subscribe-exit-waiter-leak.test.ts, src/main/runtime/terminal/wait/orca-runtime-exact-worker-provider-session.test.ts, src/main/runtime/terminal/wait/prime-agent-screen-readiness-transcripts.test.ts, src/main/runtime/workspaces/startup/runtime-worktree-agent-startup.test.ts, src/main/runtime/workspaces/startup/runtime-worktree-startup-readiness.test.ts, src/main/skills/skill-install-transaction.test.ts, src/main/speech/model-manager-download-resume.test.ts, src/main/ssh/config/ssh-config-parser.test.ts, src/main/ssh/config/ssh-known-hosts-source.test.ts, src/main/ssh/config/ssh-known-hosts.test.ts, src/main/ssh/connection/ssh-connect-config.test.ts, src/main/ssh/connection/ssh-connection-auth-fallback.test.ts, src/main/ssh/connection/ssh-connection-store.test.ts, src/main/ssh/connection/ssh-connection.test.ts, src/main/ssh/orcad-migration-stuck-host-profiles.test.ts, src/main/ssh/orcad-runtime-maintenance.test.ts, src/main/ssh/port-forwarding/ssh-port-forward.test.ts, src/main/ssh/ssh-channel-multiplexer.test.ts, src/main/ssh/system-transport/system-ssh-forward-process.test.ts, src/main/ssh/system-transport/system-ssh-loopback-route.test.ts, src/main/startup/browser-process-user-agent-ordering.test.ts, src/main/startup/quit/quit-path-durable-write-blocking.test.ts, src/main/stats/agent-session-transition-recorder.test.ts, src/main/text-generation/commit-message-text-generation-model-discovery.test.ts, src/main/text-generation/pull-request-context.test.ts, src/main/text-generation/source-control-local-process.test.ts, src/main/updater/linux-package/linux-package-update-recovery.test.ts, src/main/updater/releases/updater-prerelease-feed-readiness.test.ts, src/main/updater/releases/updater-release-builds.test.ts, src/main/updater/updater.build-channel-selection.test.ts, src/main/updater/updater.check-preflight.test.ts, src/main/updater/updater.prerelease-fallback.test.ts, src/main/updater/updater.publishing-window-feed.test.ts, src/main/updater/updater.quit-and-install.test.ts, src/main/window/createMainWindow-markdown-editor-focus.test.ts, src/main/window/createMainWindow-renderer-crash-recovery.test.ts, src/main/window/dashboard-popout-window.test.ts, src/main/window/dropped-path-preparation.test.ts, src/main/window/main-window-updater-deferred-setup.test.ts, src/main/worker-threads/worker-thread-request-queue.test.ts, src/main/workspace-hooks/hooks-setup-runner-script.test.ts, src/main/workspaces/catalog/repo-git-remote-identity-enrichment.test.ts, src/main/workspaces/creation/preparation/worktree-create-preparation.test.ts, src/main/workspaces/removal/local-worktree-removal-recovery.test.ts, src/main/workspaces/removal/worktree-removal-safety.test.ts, src/main/wsl/discovery/distro-catalog.test.ts, src/main/wsl/discovery/wsl-distro-holder.test.ts, src/main/wsl/filesystem/wsl-guest-drive-mountinfo.test.ts, src/main/wsl/orcad/wsl-orcad-deploy-app-update.test.ts, src/renderer/src/components/agent/agent-launch-picker-acquisition.test.ts, src/renderer/src/components/feature-tips/feature-tip-telemetry.test.ts, src/renderer/src/components/native-chat/composer/pickers/use-native-chat-side-chat-command.test.ts, src/renderer/src/components/native-chat/media/images/native-chat-image-copy.test.ts, src/renderer/src/components/native-chat/messages/actions/native-chat-fork-launch.test.ts, src/renderer/src/components/native-chat/messages/actions/native-chat-side-chat-fork-point.test.ts, src/renderer/src/components/native-chat/messages/actions/use-native-chat-fork.test.tsx, src/renderer/src/components/terminal-pane/provider-notices/agent-presence/agent-terminal-presence.test.ts, src/renderer/src/components/terminal-pane/pty-connection/emulation/pty-connection-mode2031-raw-subscription.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/input/pty-connection-deferred-input-forwarding.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/notifications/pty-connection-terminal-bell-attention.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-dropped-output-snapshot-healing.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/output/pty-connection-fresh-native-follow-reset.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/spawn/unbound-pane-spawn-recovery.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-foreground-agent.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts, src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-delivery-interest.test.ts, src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-push-reattach.test.ts, src/renderer/src/components/terminal-pane/pty-transport/ipc/ipc-pty-opencode-model.test.ts, src/renderer/src/components/terminal-pane/pty-transport/output/pty-side-effect-pending-census.test.ts, src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-prebind-discard-notice.test.ts, src/renderer/src/components/terminal-pane/render-health/terminal-webgl-atlas-recovery.test.ts, src/renderer/src/components/terminal-pane/snapshots/pty-buffer-serializer.test.ts, src/renderer/src/components/terminal-pane/snapshots/saved-terminal-output-replay.test.ts, src/renderer/src/components/terminal-pane/viewport/split-right-white-screen.test.ts, src/renderer/src/components/terminal-pane/viewport/visibility/stale-document-visibility.test.ts, src/renderer/src/components/ui/security-surface-theme-contrast.test.tsx, src/renderer/src/components/use-terminal-parking-pass.test.tsx, src/renderer/src/hooks/client-workspace-view-report.test.ts, src/renderer/src/hooks/ipc-events/terminal-request-ipc-bridge-placement.test.ts, src/renderer/src/hooks/use-bundled-skill-install.test.tsx, src/renderer/src/hooks/useGitHubSlugMetadata.assignee-reuse.test.tsx, src/renderer/src/hooks/useSettingsNavigationMetadata.language-switch.test.tsx, src/renderer/src/lib/codex-stale-pane-account-identity.test.ts, src/renderer/src/lib/image-blob-png.test.ts, src/renderer/src/lib/react-commit-cascade-store-write-samples.test.ts, src/renderer/src/lib/work-items/linear/linear-issue-context-snapshot.test.ts, src/renderer/src/runtime/rpc/targets/use-worktree-runtime-target.test.ts, src/renderer/src/runtime/source-control/git/runtime-git-branch-client.test.ts, src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-key-reuse.test.ts, src/renderer/src/store/repos/repos-catalog-request-coordination.test.ts, src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-batch.test.ts, src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-fixture.ts, src/renderer/src/store/slices/worktrees/metadata/update-worktrees-meta.test.ts, src/renderer/src/store/slices/worktrees/metadata/worktree-meta-rename.test.ts, src/renderer/src/store/terminals/store-sleep-shutdown-order.test.ts, src/renderer/src/store/terminals/terminal-first-tab-publication.test.ts, src/renderer/src/store/terminals/workspace-terminal-reconnect-hydration.test.ts, src/renderer/src/web/web-runtime-connection-auth-framing.test.ts, src/shared/terminal/appearance/terminal-font-weight-windows-regular.test.ts, tests/e2e/claude-agent-row-view.unit.test.ts, tests/e2e/cross-version-wire/agent-permission-legacy-spawn.unit.test.ts, tests/e2e/paired-instant-browser-tab.spec.ts, tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts, tests/e2e/session-tabs/mobile-session-active-performance.unit.test.ts, tests/e2e/session-tabs/mobile-session-active-publication.unit.test.ts, tests/e2e/structured-agent-session-launch-admission.unit.test.ts, tests/e2e/structured-attention-prompt-relay.unit.test.ts, tests/e2e/structured-attention-read-retirement.unit.test.ts, tests/e2e/structured-chat-tab-lifetime-cost.unit.test.ts, tests/e2e/structured-session-workspace-authority.unit.test.ts, tests/e2e/terminal-agent-pane-launch.unit.test.ts, tests/e2e/terminal-parked-memory.spec.ts, tests/e2e/terminal-shortcuts.spec.ts, tests/e2e/terminal-split-activation-latency.spec.ts, tests/e2e/terminal-split-activation-latency-phases.ts, tests/e2e/terminal-split-activation-latency-main-probe.ts, tests/e2e/terminal-split-activation-latency-artifact.ts, tests/e2e/terminal-split-activation-latency-report.ts, tests/e2e/terminal-tab-switch-visual-restore.spec.ts, tests/e2e/web-runtime-session-terminal-host-authority.unit.test.ts. Unresolved local/computed edges remain explicit debt.", "Audit2095 current-parent preparation2126 (approved2092/2093 removals; source refresh2109/independent2112): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-03.spec.ts: rejects exact terminal stop for multiple expected PTYs before stopping anything; omits stale renderer leaves when fresh PTY liveness is required; omits unbound renderer placeholders when fresh PTY liveness is required; captures the event method before the nested sleep receipt changes it; returns the close receipt without requiring a PTY stop; uses the same stop result as an empty explicit stop. src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-04.spec.ts: builds a compact worktree summary from persisted and live runtime state; reads the linked-PR state from the renderer repoId-keyed GitHub cache; carries persisted worktree host ownership in mobile summaries; emits only instance- and boundary-validated lineage parents in mobile summaries; resolves WSL platforms only for repos represented in mobile summaries; omits worktrees hidden by the host visibility policy from mobile summaries; applies linked-checkout source visibility to mobile summaries. src/main/runtime/orca-runtime-tests/hooks-and-hosted-review-part-02.spec.ts: routes runtime GitHub PR details and actions through the selected WSL project runtime; passes SSH connection context through hosted review creation flows; routes local WSL project hosted review flows through runtime git options; treats SSH worktree drift as unknown without local git probes. src/main/runtime/orca-runtime-tests/terminal-listing.spec.ts: emits one mobile session terminal tab per live PTY even if two tabs resolve to it; resolves projected split authority from the parent layout PTY binding; keeps explicit-id terminal lists from resolving all worktrees; keeps explicit-id cold-cache terminal lists from classifying unrelated same-repo worktrees; keeps unknown bare terminal-list ids on the no-scan exact-id path; matches explicit-id cwd PTYs for folder workspace instance IDs; routes PTY output through the PTY leaf index in large terminal graphs. src/main/runtime/orca-runtime-tests/window-authority.spec.ts: claims the first window as authoritative and ignores later windows; transfers authority from the headless sentinel to the first real window; relays terminal browser launches only while headless owns the graph; marks live headless PTYs for renderer reattach before desktop promotion; reports the activation gate state while no desktop window is available; bumps the epoch and enters reloading when the authoritative window reloads; can mark the graph ready for the authoritative window; drops back to unavailable and clears authority when the window disappears; hands the graph back to headless when a promoted serve window closes (#27292); keeps a crashed promoted serve renderer on its own window while the window is open; stays unavailable during initial loads before a graph is published. src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-routing-races.spec.ts: stops paged routing when the check is cancelled; keeps an unfiltered redrive unrestricted when reservations merge; keeps an unfiltered parked delivery unrestricted when reservations merge; uses a bounded indexed pane lookup for reminted Dispatch identity. src/main/runtime/workspaces/removal/worktree-teardown-unstopped-pty.test.ts: removes the reported wedged automation workspace without --force; clears PTY state once a failed stop is proven to have exited; names only the PTYs that are actually live, not every failed stop; warns with the specific sweep failure, not the generic deadline; still fails closed on a sweep-level failure without force. src/main/skills/bundled-skill-install/layouts.test.ts: links into a project only where its agent folder already exists; reads a pending cloud transaction as busy and a cloud receipt as another skill. src/main/skills/skill-upload-session-service.test.ts: joins concurrent disposal callers through exact cleanup completion. src/main/source-control/hosted-review-creation.test.ts: creates the pull request after fresh main-process validation passes; routes local WSL git and GitHub review creation through the selected runtime; creates a pull request on a GitHub Enterprise Server remote (#8312); creates a GitLab merge request after fresh main-process validation passes; creates an Azure DevOps pull request after fresh main-process validation passes; creates a Gitea pull request after fresh main-process validation passes. src/main/source-control/hosted-review-execution-host-routing.test.ts: reads a GitHub review on the SSH host a row names only in executionHostId; reads a GitLab review on the executionHostId host when connectionId names a different one; does not dial this client for a runtime row whose nested target shares a local name; keeps a runtime row with no nested target on this process (self-addressed stamp); keeps a legacy connectionId-only SSH row on its target; does not share a cached answer between two rows at one path on different hosts; creates a Bitbucket review locally for a runtime row rather than dialing its nested target; reports creation eligibility from the executionHostId-only SSH host; resolves the GitHub slug for a repo listing on the row it is asked about; refuses to dial a runtime host from this process; answers with the SSH target for both spellings and local otherwise; reads a runtime stamp on a row in this store as self-addressing, not a second machine. src/main/source-control/hosted-review-inflight-invalidation.test.ts: keeps other hosts, paths and their pending promises isolated. src/main/speech/model-manager.test.ts: requires pinned, internally consistent metadata for every model file; verifies downloaded model file hashes before installation; rejects non-HTTPS model downloads; marks OpenAI transcription models ready only when an API key is configured. src/main/ssh/connection/ssh-connection-sftp-namespace.test.ts: writes to the SFTP namespace path discovered on the same session; uploads the bundle into the SFTP namespace directory; issues no discovery requests when the caller supplies no mapping; ignores a mapping on a Windows host; never resolves on the system-SSH transport; leaves writeBuffer and openFileUploadSession on the shell path; keeps the shell path when discovery is inconclusive; preserves a session-limit channel-open error unchanged. src/main/ssh/connection/ssh-connection-system-transport.test.ts: uses system SSH transport when ProxyUseFdpass is resolved by OpenSSH; allows concurrent exec commands for system SSH with an Orca ControlMaster socket; keeps concurrent exec commands disabled for system SSH without a reusable socket; uses system SSH transport for ProxyCommand targets before ssh2 auth; keeps the original ssh2 reachability error when the system SSH probe fails; reports the system SSH failure when ssh2 cannot negotiate with the host; uses system transport for target or resolved OpenSSH proxy directives; allows an environment override for e2e coverage; ignores stale imported proxy fields when fresh OpenSSH config has no proxy. src/main/ssh/orcad-migration-catalog-client.test.ts: keeps each server project’s execution host, so a nested SSH row is never read as local; reads the server’s folder workspaces and the groups that place them on a host; sends and validates the %s operation; validates an abort result without letting it erase committed state; validates a committed receipt against the requested manifest; rejects malformed stage timestamps and abort envelopes; fails closed for method absence, malformed identity, and invalid pairing; refuses a destination without the capability before sending any migration request; reads method-not-found as the same refusal, not as a lost answer. src/main/ssh/runtime-ssh-access.test.ts: persists intent then claim before connecting and publishes redacted authenticated access; names the saved dependency when dependent state blocks an SSH access link; handles lost link responses without connecting or verifying again; invalidates old transport only after authenticated access is published; rejects changed request tuple after a completed link; rejects provisioning and missing durable generations without connecting; treats a lost successful unlink response as an idempotent no-op; hashes connection identity, not display state or owner; strictly validates ports and request IDs. src/main/startup/cli-launch-redirect.test.ts: detects a launch that received the unpacked CLI entrypoint; ignores normal desktop launches; ignores the entrypoint when it is only the executable itself (argv[0]); applies on Linux too; strips injected Chromium switches before node-mode CLI arguments; keeps user flags after the command and malformed boolean assignments; does not treat a later positional entrypoint path as the launcher; redirects a direct binary launch with no AppImage env at all; strips Chromium switches node mode would reject; preserves desktop-shaped switches after the command; leaves direct serve in-process but redirects its help; treats help as a CLI launch even without a command; treats %s as a CLI launch even without a command; does not treat a value of %s as a CLI early-exit flag; does not treat a serve option value as a help request; does not reinterpret help after the argument terminator; leaves a plain desktop launch alone; skips flag values when looking for the command positional; preserves a project selector in %j; does not apply the command form on macOS or Windows; never redirects an unpackaged build; runs the in-package CLI in Electron node mode with sanitized env; refuses to redirect twice so a dropped ELECTRON_RUN_AS_NODE cannot loop; reports a missing CLI entrypoint instead of booting the desktop app; execs a direct serve into the CLI so it keeps its pid and honours profile and supervise; keeps ORCA_USER_DATA_PATH for a direct serve without --user-data-dir; serves in-process when this runtime cannot exec or the exec fails; never execs the --serve child the CLI itself spawns, or serve on other platforms; surfaces a spawn failure as a non-zero exit; re-execs a direct --serve onto X11 when Electron resolved Wayland; leaves $name alone. src/main/startup/main-process-runtime-launch-activation.test.ts: marks startup settled for the launch record only after the window has loaded and settled; loads SSH targets on a windowless serve before paired clients can connect (#25886); pins the serve listener to loopback only for orcad browser sidecars (sidecar=$sidecar, #31895); saves Codex auth before a headless serve update restart, like the desktop does. src/main/startup/run-electron-vite-dev.test.ts: forwards dev instance identity to electron-vite; prepares userData orca and orca-dev wrappers for dev terminals; consumes the stable-name flag before forwarding args to electron-vite. src/main/updater/releases/updater-prerelease-feed.test.ts: returns the newest stable tag when the user is on an RC and a newer stable exists; returns the newest RC tag when no stable is newer than the current RC; can exclude prerelease tags for stable-channel checks; probes the %s %s platform manifest; returns null for stable-channel checks when only prereleases are newer; returns null when nothing in the feed is newer than the current version; ignores entries with unparseable tags; returns null when the fetch is not ok; returns null when the fetch throws; picks semver-newest across a mixed-order feed; ignores perf-tagged prereleases for regular RC checks; reports no RC update when only perf-tagged prereleases are newer; picks the semver-newest perf-tagged prerelease; matches only literal rc.N.perf prerelease tags for perf checks; reports no perf update instead of falling back to stable or RC tags; returns a bounded fallback candidate after the newest newer tag; returns null when the only newer tag has a manifest but its asset still 404s; requires a known old timestamp for a stable-fallback tag. src/main/updater/updater-events.test.ts: hands the whole downloaded event to artifact capture; publishes manual-install recovery after a %s download; publishes the normal downloaded state for AppImage builds; blocks downloaded-state handling when the packaged marker is unusable; passes the actual updater error into the install-failure handler; keeps manual-install recovery when a later check finds only the installed release; drops the artifact when another version takes over the cycle; ignores a downloaded event for an older target; accepts a matching event when the pending cache target was cleared; drops the artifact when progress reports a different pending version. src/main/updater/updater-linux-package-recovery-actions.test.ts: rejects both actions while no package-install recovery is active; validates the retained package on every invocation; restores recovery after a recheck resolves without a terminal event; restores recovery after a recheck fails; restores recovery when a pinned check resolves to the current version; restores recovery when resolving a pinned check fails; clears recovery for both actions once the package is gone; resolves %s as a result and keeps the card usable instead of rejecting; keeps recovery available after a transient read failure. src/main/updater/updater.check-settlement.test.ts: leaves a dismissed release update on the release source; surfaces net::ERR_FAILED to user-initiated checks with a friendly message; shows checking immediately for a user-initiated check while feed pinning is pending; keeps background checks event-driven before checking-for-update fires. src/main/usage/usage-provider-store-lifecycle.test.ts: persists identities for a whole first scan with one write; skips disabled and fresh matching states; invalidates prior sources on fingerprint changes and reuses them for forced scans. src/main/window/createMainWindow-close-confirmation.test.ts: clears the quit latch when the renderer prevents unload; does not notify the crash recorder when renderer teardown follows a confirmed window close; allows close when Electron reports a crashed webContents; requests confirmation for a hung-but-alive renderer instead of bypassing. src/main/workspaces/catalog/worktree-identity-persistence.test.ts: stores independent metadata for colliding locators on two hosts; projects canonical-only metadata for exactly one host; keeps canonical metadata current for legacy writers on a known owner; removes only the selected legacy-owner metadata when locators collide; keeps the canonical identity stable when the locator changes; leaves other hosts at the old locator when one host renames its folder. src/main/wsl/filesystem/wsl-drive-unc-conversion-startup.test.ts: leaves a journaled conversion untouched with the gate closed, %s. src/main/wsl/orcad/wsl-orcad-deploy.test.ts: holds the distro before it deploys and launches, and reports what C5 dials; passes its connect-state read (%s) on as hints; applies the SSH census and downgrade admission to the first deploy; refuses a WSL 1 distro before holding it or touching its files; tells an unregistered distro how to find the installed ones, before holding anything; surfaces an unsupported libc as the SSH host refusal does; starts an already-active slot the distro stop ended, instead of reporting it ready; deploys over an adopted unrecorded orcad under the SSH terminal gate, never a fresh launch; reports the adopted instance once the same version is serving; returns a deferral rather than launching over live terminals; hands a failed first deploy to the fresh-install cleanup before reporting it. src/main/zcode/zcode-v2-plan-credentials.test.ts: prefers migrated credentials over a stale legacy account; keeps legacy support when no personal v2 file exists; honors the upstream personal config override independently of the credential directory; does not borrow credentials from another execution host; preserves the protected Orca key priority even if v2 is corrupt; rejects upstream-invalid selection %j without legacy fallback; accepts a valid optional reasoning level; rejects upstream-invalid rule containers %j without legacy fallback; accepts a valid selected-provider empty personal rule and smart model rule; cannot establish selected credentials from %s rules; leaves encrypted CLI files unchanged across repeated account reads. tests/e2e/automation-terminal-launch.unit.test.ts: launches explicit Chat for %s through the common entry and keeps its actual fallback; does not apply stored Terminal extras to Chat; forwards only complete Chat-consumed values, with no Terminal startup base; refuses an expired admission without minting another launch identity; records the actual chat identity and delegates new workspace setup and provenance. tests/e2e/github-project-provider-columns.unit.test.ts: renders %s through one bounded items request on a named cloud host; preserves zero and complete counters: %j; preserves populated and legacy rows through shared sorting, grouping and cells. tests/e2e/structured-agent-session-launch-continuation.unit.test.ts: carries renderer lifetime through host intent to the real %s provider builders. tests/e2e/terminal-account-restart.unit.test.ts: replaces a tombstoned owner while its persisted pane binding has not yet been cleared; paired restart retains the old owner (host authority: %s). tests/e2e/terminal-hidden-view-parking.spec.ts: does not park excluded tabs; reproduces a static frame byte-for-byte across 25 park/reveal cycles. tests/e2e/terminal-long-table-scroll-restore.spec.ts: reproduces long markdown table artifacts after workspace switch and scroll; keeps narrow wrapped signer markdown table coherent after restore and scroll; keeps real emoji markdown table right edge clean after restore and scroll. tests/e2e/terminal-long-table-fixtures.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-paste-ownership.spec.ts: Windows multiline keyboard paste normalizes terminal newlines with one PTY owner; right-click paste sends clipboard text to the focused terminal exactly once. tests/e2e/terminal-raw-emoji-table-scroll-restore.spec.ts: uses WebGL by default for ordinary terminal output when available @terminal-rendering-golden. tests/e2e/terminal-windows-shell-paste-ownership.spec.ts: cmd.exe default terminal keyboard paste preserves exact content with one PTY owner; Git Bash default terminal keyboard paste preserves POSIX-shaped content with one PTY owner; WSL terminal keyboard paste preserves Linux shell content with one PTY owner. tests/e2e/workspace-board-lane-virtualization.spec.ts: mounts a window of cards for a large lane and keeps lane indexes; renders later lane indexes after the lane scrolls. Current changed source bytes, wrapper registrations and reduced selectors have no fresh execution or red/green credit. Unrelated surviving receipt objects keep their original narrow scope; current literal graph reachability does not establish historical import closure or equivalent replacement coverage. Current conservative command/import graph reaches src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-03.spec.ts, src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-04.spec.ts, src/main/runtime/orca-runtime-tests/hooks-and-hosted-review-part-02.spec.ts, src/main/runtime/orca-runtime-tests/terminal-listing.spec.ts, src/main/runtime/orca-runtime-tests/window-authority.spec.ts, src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-routing-races.spec.ts, src/main/runtime/workspaces/removal/worktree-teardown-unstopped-pty.test.ts, src/main/skills/bundled-skill-install/layouts.test.ts, src/main/skills/skill-upload-session-service.test.ts, src/main/source-control/hosted-review-creation.test.ts, src/main/source-control/hosted-review-execution-host-routing.test.ts, src/main/source-control/hosted-review-inflight-invalidation.test.ts, src/main/speech/model-manager.test.ts, src/main/ssh/connection/ssh-connection-sftp-namespace.test.ts, src/main/ssh/connection/ssh-connection-system-transport.test.ts, src/main/ssh/orcad-migration-catalog-client.test.ts, src/main/ssh/runtime-ssh-access.test.ts, src/main/startup/cli-launch-redirect.test.ts, src/main/startup/main-process-runtime-launch-activation.test.ts, src/main/startup/run-electron-vite-dev.test.ts, src/main/updater/releases/updater-prerelease-feed.test.ts, src/main/updater/updater-events.test.ts, src/main/updater/updater-linux-package-recovery-actions.test.ts, src/main/updater/updater.check-settlement.test.ts, src/main/usage/usage-provider-store-lifecycle.test.ts, src/main/window/createMainWindow-close-confirmation.test.ts, src/main/workspaces/catalog/worktree-identity-persistence.test.ts, src/main/wsl/filesystem/wsl-drive-unc-conversion-startup.test.ts, src/main/wsl/orcad/wsl-orcad-deploy.test.ts, src/main/zcode/zcode-v2-plan-credentials.test.ts, tests/e2e/automation-terminal-launch.unit.test.ts, tests/e2e/github-project-provider-columns.unit.test.ts, tests/e2e/structured-agent-session-launch-continuation.unit.test.ts, tests/e2e/terminal-account-restart.unit.test.ts, tests/e2e/terminal-hidden-view-parking.spec.ts, tests/e2e/terminal-long-table-scroll-restore.spec.ts, tests/e2e/terminal-long-table-fixtures.ts, tests/e2e/terminal-paste-ownership.spec.ts, tests/e2e/terminal-raw-emoji-table-scroll-restore.spec.ts, tests/e2e/terminal-windows-shell-paste-ownership.spec.ts, tests/e2e/workspace-board-lane-virtualization.spec.ts. Unresolved local/computed edges remain explicit debt.", @@ -13177,7 +12869,21 @@ "Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed.", "Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed.", "Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed.", - "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired." + "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired.", + "Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands.", + "Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims.", + "Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical.", + "Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed.", + "Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed.", + "Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed.", + "Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed.", + "Audit3335 composes adopted source unions3327/3328 and3330/3332: intentionally retires100 authored registrations/123 expanded cases, including ten whole suites, without equivalent replacement. Lost alarms include seeded host persistence/contention and stale-host cleanup; browser snapshot assembly; mocked wake/DPR callbacks and frame budgets; preflight projections; palette authority/cache suppression, URL intent and saved-title cross-repo collisions; metadata coverage/set patch and dropdown assembly; and removed terminal, worktree, review-refresh and owner-routing examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI/GPU/focus, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain only their original scope.", + "Audit3342 composes adopted source batches3333/3334,3336/3337 and3340/3341: intentionally retires180 authored registrations/263 expanded cases, including seven whole suites, without equivalent replacement. Lost alarms include corrupt editor hydration; mobile editor/diff publication and privacy projections; stale-resubscribe routing; model-picker projection/refetch/retry/fallback; editor check-details and frame property inventories; latched-pane cleanup/quiescence; client create replay identity/options/compatibility; and removed owner, async routing, terminal and layout examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts keep their original scope.", + "Audit3349 composes adopted batches3343,3345 and refreshed3354: intentionally retires234 authored registrations/294 expanded cases, including13 whole suites, without equivalent replacement. Lost alarms include supplied terminal reconnect/replacement/typeahead/mirror/result and snapshot examples; synthetic render-desync persistence/recovery; worktree listing/owner/catalog/lineage/removal and activation/creation examples; host-scoped PR and task-record projections; editor diff/status/comment and UI send-target examples; automation observation/wake, supplied sleep/deadline clock and native-chat completion/notification/relaunch samples; held-tab layout and cleanup/progress guard examples. Retained adverse-ordering and wire-boundary cases are narrower and do not replace all removed alarms. The already-upstream visibility-resume deletion receives zero new removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH, native process/power/GPU, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3359 composes root-adopted source3355/independent3356: intentionally retires130 authored registrations/139 expanded cases, including eight whole suites, without equivalent replacement. Lost alarms include strict create naming/capability/legacy payloads; supplied transport host replacement, deadline reattach, create-handoff and split activation; agent-session fork/clipboard/platform flags; shutdown cleared-scrollback/unmounted bindings; simulator host-collision/selection/shutdown; and removed editor, catalog, mutation, launch and status examples. Retained12 adverse-ordering/state-consequence cases are narrower and do not replace all removed alarms. Two queue absences receive zero removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY, filesystem restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3362 composes root-adopted3358/independent3360: intentionally retires129 authored registrations/140 expanded cases, including four whole suites, without equivalent replacement. Lost alarms include supplied orphan-adoption retry/malformed inventory/cancellation; fake-terminal replay parser/wedge/disposal callbacks; all-host catalog metadata and Windows preferences; host keepalive/protocol/stale/settings failures; and removed exact-stop/suppression, source save lifetime, diff-note queue, rename/editor close, input flood/chunk refusal/limits, purge and creation examples. Retained18 registrations/21 expanded cases protect narrower ownership, generation, dirty-state, queue convergence, encoding and attachment-lease outcomes. No replacement or keeper quota claim. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY/xterm parser, disk restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3368 composes root-adopted3363/3364 and3367/3369: intentionally retires181 authored registrations/196 expanded cases, including28 whole suites, without equivalent replacement. Lost alarms include hibernation attention/liveness/backoff/sequential teardown and inventory, host launch compatibility/legacy/Kimi/resource cleanup, terminal recovery parser/pause/quarantine/remount, window-visibility omission-fence lifetime, launch-option rendered Start, sleeping-resume saved recipe/WSL quoting/cancellation, plus removed project/window/input variants. Additional tiny-suite losses include sentence/label/field/default inventories, credential omission, Windows argument/environment mapping, URI decoding, diagnostics, provider classification and fake-clock callback/parser examples. Retained ten registrations/twelve expanded cases include two literal Unicode Mn/Cf zero-width range guards in the actual character-range algorithm and protect narrower delayed editor bytes/destructive ownership, mounted hidden collision repair, ten transport epochs, duplicate-command refusal, caller timeout typing, executor unknown-opener refusal and failed-chunk user bytes. This broad unit command selects the reduced suite; no fresh runtime, real provider/network/PTY, filesystem restart, native UI, historical import equivalence, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3375 composes root-adopted3370/independent3371 and3373/independent3374: intentionally retires79 authored registrations/84 expanded cases, including39 whole suites, without equivalent replacement. Lost alarms include federation field/parser inventories; Claude rejected-key precedence, credential clone redaction, managed-versus-user hook preservation and CLI defaults; setting/status/activity projections, mocked SSH/notification/reveal/Linear refusal, fake-clock reconnect and noise; image-fold artifact visibility, paste eligibility, setup trust, scripted ACP error-to-journal publication and ligature cache tuple aliasing; plus supplied folder-runner uniqueness, mobile host-overlay/credential/update/preference races, status/markup/title/keyed-row projections, subscriber cleanup, cancellation/close/refusal/link-issue and mirror suppression alarms. Retained3373 merger contiguity, dual-clock overdue-resume exactly-once, rejected-paste IPC sink and annotation schema roundtrip remain bounded. Retained actual HTTP/OSC status composition, destructive sibling-filesystem isolation, external contrast invariant and fixture CSS pixel intervention remain narrower. Original reviewed87authored/92expanded become9/9; current OpenCode suite adds two preserved upstream cases and the synthetic-title suite gained one Cursor policy mock-call case, independently reviewed for removal in root3378; current90/95 become11/11. That Cursor suppression/ready-frame regression alarm is intentionally lost; it does not observe native title ownership or tab flicker. For3370 only the peer was independently blind, with author exposure explicit;3373/3374 both blind pins were verified. This broad root unit command selects the reduced root unit suite; UNIT_INCLUDE excludes mobile tests, which require the existing mobile runner; retained Playwright component-pixel spec uses its separate existing headless fixture runner and is not validated by the broad unit command. No fresh execution, actual agent/shell/provider, OS material/focus, historical import equivalence, mobile, mixed-version or cross-platform evidence is claimed. All dated receipts retain their original scope." ], "demotionRule": "Demote or quarantine if the fault harness flakes without a product or harness bug, if healthy operation exceeds one runtime watcher child, if total physical operation exceeds eight children including retiring generations, if quarantine children outlive their roots or repeat after fusing, if event delivery becomes unbounded, or if metadata/stat work returns to the serve process." }, @@ -13953,7 +13659,7 @@ "providers": ["local-daemon", "ssh-daemon", "paired-runtime"], "coveredPlatforms": ["macos"], "coveredProviders": ["local-daemon", "paired-runtime"], - "coverageNotes": "Audit1939 (sources1934/1935): Pruned cold-parking hook and parked-watcher suites retain local timer/selection/split and exit/cancel/disposal progression. Lose supplied capability/eligibility/topology/admission and duplicate state examples recorded below. No assertion objects map to these sources here; preserve independent actual E2E receipt scopes without transferring their results to reduced units. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1623 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1342 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Deterministic policy and multiplex tests separate renderer parking from authoritative stream liveness, while runtime-graph tests cover exact parked leaf, pane runtime ID, title, multi-pane active-leaf, disposal behavior, and queued split routing to an exact cold-parked tab. A real Electron journey runs the shipped dev CLI against the app's isolated profile, proves the exact parked target alone remounts under a bounded lease, completes before the historical 10-second timeout without stealing active tab or focus, re-parks, then reveals two stable-identity panes with independent keyboard/output round trips. Focused mirror-recovery tests preserve a verified binding across pending-handle snapshots, quarantine positive PTY-identity mismatches, accept authoritative ready replacement or removal, and fence recovery to the pairing revision. Daemon attach-only tests prove a replacement runtime re-registers one active session and one history writer. Headed cold-park and headless runtime-restart paired journeys prove rendered output, input, resize convergence, process identity, authoritative close, checkpoint continuity, and post-restart history append against real daemon PTYs. The parked-leaf graph fixture now retains only PTY exit during the park handoff gap. Its standalone exact leaf/title, multi-pane active-leaf and disposal assertions were removed. web-runtime-session.test.ts no longer supplies the eager worktree-switch/post-create recovery assertion. Those alarms are lost; the remaining cold-park and recovery journeys do not establish equivalent replacement coverage. Recovery references retain old-host-to-new-tab mirroring, adoption/list recovery, blocked local ownership changes, coalescing/overtaking/global concurrency, adoption-conflict serialization and pane-resolution retries. Stable unsupported/malformed adoption tables, supplied inventory/topology/identity and verified-binding shape examples were removed. Their separate alarms are lost; remaining compositions are not equivalent coverage. Historical executed commands and results remain historical. The separate Unsubscribe-to-raw-subscriber-veto-clear sample was removed. Its exact raw-presence transition alarm is lost; remaining fake-provider streaming/attachment checks and real paired journeys do not establish equivalent replacement coverage. The deterministic second subscription is a second live connection, not a disconnect/reconnect proof. Audit1292: The entire orphan-inventory retry suite is removed. Unchanged-snapshot retry for temporarily absent, pending or attached PTYs, live-binding preservation, and consecutive-absence confirmation reset after a ready frame are lost. Mock adoption/list behavior and assembled snapshot handling did not establish actual orphan adoption or equivalent replacement coverage. Audit1342: src/renderer/src/runtime/web-session-terminal-orphan-recovery-regressions.test.ts reduced. Exact global RPC concurrency4/counts for fabricated worktrees. No equivalent replacement coverage is claimed.", + "coverageNotes": "Audit3362 retires the whole orphan-recovery adoption-regressions suite, including thrown-adoption/post-adoption malformed or unavailable retries, prior-binding preservation, projected sibling retirement merging and blocked local-close/group-move fencing. Its compound unit token, test-file entry and assertion reference are removed. Injected inventory/adoption projections did not demonstrate usable input delivery. Two unrelated macOS E2E receipts remain verbatim; no equivalent replacement or fresh runtime/PTY/provider/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit 3318 reduces web-session-terminal-pending-handle-recovery.test.ts, intentionally retiring disconnected retry, two-authoritative-absence retirement, explicit close-record short circuit, older-host disconnected absence, positive published-presence protection and unpublished-frame no-count alarms. Remove only the disconnected-retry assertion alias; preserve transient-retry assertion and both unchanged active Electron receipts. The remaining absence-reset interleaving is narrower, not an equivalent replacement for these six removed cases. Historical receipts retain their original scope. No fresh runtime, host/PTY/network, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit1939 (sources1934/1935): Pruned cold-parking hook and parked-watcher suites retain local timer/selection/split and exit/cancel/disposal progression. Lose supplied capability/eligibility/topology/admission and duplicate state examples recorded below. No assertion objects map to these sources here; preserve independent actual E2E receipt scopes without transferring their results to reduced units. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): Audit1623 removes low-value mocked daemon projections, scalar tables and duplicate terminal examples without equivalent replacement coverage. Per-source reviews record retained terminal content preservation, process ownership refusal and recovery boundaries together with injected/native/remote limits. Affected historical receipts are retired; gates without active current evidence are downgraded. Historical scope before this audit: Audit1342 changes referenced sources. Retained unchanged-source receipts apply only to their unchanged commands; the reduced selectors have no new execution result. Historical coverage account (not a current claim for changed sources): Deterministic policy and multiplex tests separate renderer parking from authoritative stream liveness, while runtime-graph tests cover exact parked leaf, pane runtime ID, title, multi-pane active-leaf, disposal behavior, and queued split routing to an exact cold-parked tab. A real Electron journey runs the shipped dev CLI against the app's isolated profile, proves the exact parked target alone remounts under a bounded lease, completes before the historical 10-second timeout without stealing active tab or focus, re-parks, then reveals two stable-identity panes with independent keyboard/output round trips. Focused mirror-recovery tests preserve a verified binding across pending-handle snapshots, quarantine positive PTY-identity mismatches, accept authoritative ready replacement or removal, and fence recovery to the pairing revision. Daemon attach-only tests prove a replacement runtime re-registers one active session and one history writer. Headed cold-park and headless runtime-restart paired journeys prove rendered output, input, resize convergence, process identity, authoritative close, checkpoint continuity, and post-restart history append against real daemon PTYs. The parked-leaf graph fixture now retains only PTY exit during the park handoff gap. Its standalone exact leaf/title, multi-pane active-leaf and disposal assertions were removed. web-runtime-session.test.ts no longer supplies the eager worktree-switch/post-create recovery assertion. Those alarms are lost; the remaining cold-park and recovery journeys do not establish equivalent replacement coverage. Recovery references retain old-host-to-new-tab mirroring, adoption/list recovery, blocked local ownership changes, coalescing/overtaking/global concurrency, adoption-conflict serialization and pane-resolution retries. Stable unsupported/malformed adoption tables, supplied inventory/topology/identity and verified-binding shape examples were removed. Their separate alarms are lost; remaining compositions are not equivalent coverage. Historical executed commands and results remain historical. The separate Unsubscribe-to-raw-subscriber-veto-clear sample was removed. Its exact raw-presence transition alarm is lost; remaining fake-provider streaming/attachment checks and real paired journeys do not establish equivalent replacement coverage. The deterministic second subscription is a second live connection, not a disconnect/reconnect proof. Audit1292: The entire orphan-inventory retry suite is removed. Unchanged-snapshot retry for temporarily absent, pending or attached PTYs, live-binding preservation, and consecutive-absence confirmation reset after a ready frame are lost. Mock adoption/list behavior and assembled snapshot handling did not establish actual orphan adoption or equivalent replacement coverage. Audit1342: src/renderer/src/runtime/web-session-terminal-orphan-recovery-regressions.test.ts reduced. Exact global RPC concurrency4/counts for fabricated worktrees. No equivalent replacement coverage is claimed.", "motivatingLinks": [ "https://linear.app/stably/issue/STA-2854", "https://github.com/stablyai/orca/pull/15514", @@ -13961,9 +13667,9 @@ "https://github.com/stablyai/orca/issues/17297" ], "invariant": "Cold parking or restarting a host renderer/runtime never retires a live PTY's runtime-graph leaf, erases a paired viewer's last verified leaf binding merely because the host temporarily publishes pending-handle, or drops the surviving PTY's history writer. A split request for a cold-parked tab replays against its stable source leaf after exact-tab remount without switching workspaces or focusing the tab. The paired stream, input, resize, pane identity, multi-pane routing, checkpoint, and output log converge to the authoritative ready handle; the binding clears only after positive replacement, mismatch, or two consecutive authoritative absence observations without an intervening ready surface.", - "oracle": "Audit1939 (sources1934/1935): Pruned cold-parking hook and parked-watcher suites retain local timer/selection/split and exit/cancel/disposal progression. Lose supplied capability/eligibility/topology/admission and duplicate state examples recorded below. No assertion objects map to these sources here; preserve independent actual E2E receipt scopes without transferring their results to reduced units. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Cold-park a host-owned pane while a paired client actively views it, require the host manager to unmount, then type through the client and require the same PTY to receive and echo the token without any disconnected sample. Restart a real pinned-port headless runtime while its daemon PTY survives, observe a pending-handle snapshot, require the viewer binding never to become empty, then require rendered output, focused keyboard input, a post-recovery window resize, the pre-restart checkpoint, and post-restart output-log append to reach the same PTY and process before authoritative close clears the binding. Invoke the real `orca-dev terminal split` against a cold-parked renderer-owned tab, require only that tab to acquire and release the existing background-mount lease, complete before the historical timeout, preserve the active worktree/tab/focus, then reveal two rendered panes and type through each while retaining the stable source leaf and PTY. Deterministically require synchronous stable-leaf replay after lifecycle registration and fail closed for a missing or stale leaf. Separately publish multi-pane parked leaves with exact pane runtime IDs and require per-PTY disposal to remove only the retired leaf.", + "oracle": "Audit3362 retires the whole orphan-recovery adoption-regressions suite, including thrown-adoption/post-adoption malformed or unavailable retries, prior-binding preservation, projected sibling retirement merging and blocked local-close/group-move fencing. Its compound unit token, test-file entry and assertion reference are removed. Injected inventory/adoption projections did not demonstrate usable input delivery. Two unrelated macOS E2E receipts remain verbatim; no equivalent replacement or fresh runtime/PTY/provider/UI/mobile/mixed-version/cross-platform evidence is claimed. Audit 3318 reduces web-session-terminal-pending-handle-recovery.test.ts, intentionally retiring disconnected retry, two-authoritative-absence retirement, explicit close-record short circuit, older-host disconnected absence, positive published-presence protection and unpublished-frame no-count alarms. Remove only the disconnected-retry assertion alias; preserve transient-retry assertion and both unchanged active Electron receipts. The remaining absence-reset interleaving is narrower, not an equivalent replacement for these six removed cases. Historical receipts retain their original scope. No fresh runtime, host/PTY/network, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit1939 (sources1934/1935): Pruned cold-parking hook and parked-watcher suites retain local timer/selection/split and exit/cancel/disposal progression. Lose supplied capability/eligibility/topology/admission and duplicate state examples recorded below. No assertion objects map to these sources here; preserve independent actual E2E receipt scopes without transferring their results to reduced units. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Historical prior account (preserved verbatim): The retained unchanged-source receipts are the only current execution evidence; reduced-source assertions await validation. Historical oracle account (not a current claim for changed sources): Cold-park a host-owned pane while a paired client actively views it, require the host manager to unmount, then type through the client and require the same PTY to receive and echo the token without any disconnected sample. Restart a real pinned-port headless runtime while its daemon PTY survives, observe a pending-handle snapshot, require the viewer binding never to become empty, then require rendered output, focused keyboard input, a post-recovery window resize, the pre-restart checkpoint, and post-restart output-log append to reach the same PTY and process before authoritative close clears the binding. Invoke the real `orca-dev terminal split` against a cold-parked renderer-owned tab, require only that tab to acquire and release the existing background-mount lease, complete before the historical timeout, preserve the active worktree/tab/focus, then reveal two rendered panes and type through each while retaining the stable source leaf and PTY. Deterministically require synchronous stable-leaf replay after lifecycle registration and fail closed for a missing or stale leaf. Separately publish multi-pane parked leaves with exact pane runtime IDs and require per-PTY disposal to remove only the retired leaf.", "commands": [ - "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-tab-watchers.test.ts src/renderer/src/components/terminal-pane/layout/split/terminal-pane-split-request-routing.test.ts src/renderer/src/components/terminal-pane/parking/lifecycle/use-terminal-tab-cold-parking.test.ts src/renderer/src/hooks/ipc-events/terminal-ui-routing-ipc-bridge-split.test.ts src/main/runtime/terminal/layout/orca-runtime-terminal-split-authority.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-parked-leaf.test.ts src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-mixed-version.test.ts src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-recovery.test.ts src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-recovery-regressions.test.ts src/renderer/src/runtime/hosted-terminals/recovery/adoption/web-session-terminal-orphan-recovery-adoption-regressions.test.ts src/renderer/src/runtime/hosted-terminals/recovery/panes/web-session-terminal-pending-handle-recovery.test.ts tests/e2e/host-cold-park-remote-subscriber.unit.test.ts --reporter=dot", + "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-tab-watchers.test.ts src/renderer/src/components/terminal-pane/layout/split/terminal-pane-split-request-routing.test.ts src/renderer/src/components/terminal-pane/parking/lifecycle/use-terminal-tab-cold-parking.test.ts src/renderer/src/hooks/ipc-events/terminal-ui-routing-ipc-bridge-split.test.ts src/main/runtime/terminal/layout/orca-runtime-terminal-split-authority.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-parked-leaf.test.ts src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-mixed-version.test.ts src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-recovery.test.ts src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-recovery-regressions.test.ts src/renderer/src/runtime/hosted-terminals/recovery/panes/web-session-terminal-pending-handle-recovery.test.ts tests/e2e/host-cold-park-remote-subscriber.unit.test.ts --reporter=dot", "pnpm exec vitest run --config config/vitest.config.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter-cold-restore-reanchor.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter-session-adoption.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter-protocol-compatibility.test.ts src/main/daemon/providers/adapter/testing/daemon-pty-adapter-history-recovery.test.ts --reporter=dot", "pnpm exec playwright test tests/e2e/host-parked-pane-remote-viewer.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1", "pnpm exec playwright test tests/e2e/terminal-parked-cli-split.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1", @@ -13979,7 +13685,6 @@ "src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-mixed-version.test.ts", "src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-recovery.test.ts", "src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-recovery-regressions.test.ts", - "src/renderer/src/runtime/hosted-terminals/recovery/adoption/web-session-terminal-orphan-recovery-adoption-regressions.test.ts", "src/renderer/src/runtime/hosted-terminals/recovery/panes/web-session-terminal-pending-handle-recovery.test.ts", "src/main/daemon/providers/adapter/testing/daemon-pty-adapter-cold-restore-reanchor.test.ts", "src/main/daemon/providers/adapter/testing/daemon-pty-adapter-session-adoption.test.ts", @@ -14037,17 +13742,6 @@ "file": "src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-mixed-version.test.ts", "assertions": ["mirrors a new CLI tab after old-host recovery when $name"] }, - { - "file": "src/renderer/src/runtime/hosted-terminals/recovery/adoption/web-session-terminal-orphan-recovery-adoption-regressions.test.ts", - "assertions": [ - "retries a transient thrown adoption on an unchanged semantic frame", - "retains the client epoch and retries when the post-adoption list has $failure", - "preserves prior terminal bindings after a post-adoption $failure and retries", - "merges host-projected $verdict sibling state after adoption without treating pending as exited", - "does not apply an adoption result after the local tab closes while adoption is blocked", - "does not apply an adoption result after the local tab moves groups while adoption is blocked" - ] - }, { "file": "src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-recovery.test.ts", "assertions": [ @@ -14057,8 +13751,7 @@ { "file": "src/renderer/src/runtime/hosted-terminals/recovery/panes/web-session-terminal-pending-handle-recovery.test.ts", "assertions": [ - "retries a transient pane-resolution failure for an unchanged replayed snapshot", - "retries a disconnected pane resolution for an unchanged replayed snapshot" + "retries a transient pane-resolution failure for an unchanged replayed snapshot" ] } ], @@ -14120,7 +13813,12 @@ "Audit1342 historical platform/provider scope before source changes: {\"coveredPlatforms\":[\"macos\",\"linux\"],\"coveredProviders\":[\"local-daemon\",\"paired-runtime\"]}. Remaining provider scope applies only to unchanged-source receipts.", "Audit1342 historical assertion inventory for deleted/reduced sources; not current validated assertions:\n[\n {\n \"file\": \"src/renderer/src/runtime/web-session-terminal-orphan-recovery-regressions.test.ts\",\n \"assertions\": [\n \"coalesces degraded frames to one active and one latest queued recovery\",\n \"lets a newer fully ready frame overtake an in-flight degraded recovery\",\n \"limits recovery RPC concurrency globally across worktrees\"\n ]\n }\n]", "Audit1939 (sources1934/1935): Pruned cold-parking hook and parked-watcher suites retain local timer/selection/split and exit/cancel/disposal progression. Lose supplied capability/eligibility/topology/admission and duplicate state examples recorded below. No assertion objects map to these sources here; preserve independent actual E2E receipt scopes without transferring their results to reduced units. Preserve meaningful remaining selectors/assertions and unchanged dated receipts within their original scope. Reduced selectors have no fresh gate execution evidence in this metadata packet. No equivalent replacement, physical watcher/PTY/provider, live SSH/remote/mobile, rendered, cross-platform, soak or measured-budget result is claimed. Exact retired authored alarms: 'parks paired-runtime tabs only when their exact host advertises restore'; 'skips parking scans for capability-equivalent status writes and scans membership changes'; 'keeps eviction-exempt tabs mounted when the worktree is force-parked'; 'resolves eviction exemptions once per force-park input change'; 'does not exempt a tab from a truncated malformed pane key'; 'never starts a watcher for a PTY that exited into the park handoff gap'; 'collapses the exited leaf out of the stored layout when deferring'; 'retires launch/title hints when the launch-owning parked leaf exits'; 'keeps launch ownership when only a parked shell sibling exits'; 'rejects ordinary parking for a preserved daemon with a lossy snapshot'; 'rejects a capture containing a PTY without snapshot backing'; 'accepts layout-derived candidates when the capture is stale'; 'rejects layout-derived candidates missing a leaf PTY binding'.", - "Terminal/runtime defining-owner cleanup retires complete parking timer, lifecycle, mocked close/disposal and render/flip/mount work-count cases under repository test policy. The retained watcher source has only two literal-oracle coverage decisions; the retained cold-parking hook source has only the layout-PTY exemption invalidation case. Lost alarms include cooldown/measure/pin wakeups, split exit/close attribution and cancellation, watcher disposal/restart, flood timer rearm, worktree verdict damping, and destroyed-transport cold restore. No equivalent replacement coverage or execution pass for the reduced cases is claimed; prior dated receipts retain their original scope." + "Terminal/runtime defining-owner cleanup retires complete parking timer, lifecycle, mocked close/disposal and render/flip/mount work-count cases under repository test policy. The retained watcher source has only two literal-oracle coverage decisions; the retained cold-parking hook source has only the layout-PTY exemption invalidation case. Lost alarms include cooldown/measure/pin wakeups, split exit/close attribution and cancellation, watcher disposal/restart, flood timer rearm, worktree verdict damping, and destroyed-transport cold restore. No equivalent replacement coverage or execution pass for the reduced cases is claimed; prior dated receipts retain their original scope.", + "Audit 3318 reduces web-session-terminal-pending-handle-recovery.test.ts, intentionally retiring disconnected retry, two-authoritative-absence retirement, explicit close-record short circuit, older-host disconnected absence, positive published-presence protection and unpublished-frame no-count alarms. Remove only the disconnected-retry assertion alias; preserve transient-retry assertion and both unchanged active Electron receipts. The remaining absence-reset interleaving is narrower, not an equivalent replacement for these six removed cases. Historical receipts retain their original scope. No fresh runtime, host/PTY/network, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed.", + "Audit3362 retires the whole orphan-recovery adoption-regressions suite, including thrown-adoption/post-adoption malformed or unavailable retries, prior-binding preservation, projected sibling retirement merging and blocked local-close/group-move fencing. Its compound unit token, test-file entry and assertion reference are removed. Injected inventory/adoption projections did not demonstrate usable input delivery. Two unrelated macOS E2E receipts remain verbatim; no equivalent replacement or fresh runtime/PTY/provider/UI/mobile/mixed-version/cross-platform evidence is claimed.", + "Audit3362 historical original commands object, preserved verbatim; retired source claims are not active evidence or replacement coverage:\n\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-tab-watchers.test.ts src/renderer/src/components/terminal-pane/layout/split/terminal-pane-split-request-routing.test.ts src/renderer/src/components/terminal-pane/parking/lifecycle/use-terminal-tab-cold-parking.test.ts src/renderer/src/hooks/ipc-events/terminal-ui-routing-ipc-bridge-split.test.ts src/main/runtime/terminal/layout/orca-runtime-terminal-split-authority.test.ts src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-parked-leaf.test.ts src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-mixed-version.test.ts src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-recovery.test.ts src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-recovery-regressions.test.ts src/renderer/src/runtime/hosted-terminals/recovery/adoption/web-session-terminal-orphan-recovery-adoption-regressions.test.ts src/renderer/src/runtime/hosted-terminals/recovery/panes/web-session-terminal-pending-handle-recovery.test.ts tests/e2e/host-cold-park-remote-subscriber.unit.test.ts --reporter=dot\"", + "Audit3362 historical original testFiles object, preserved verbatim; retired source claims are not active evidence or replacement coverage:\n\"src/renderer/src/runtime/hosted-terminals/recovery/adoption/web-session-terminal-orphan-recovery-adoption-regressions.test.ts\"", + "Audit3362 historical original assertionRefs object, preserved verbatim; retired source claims are not active evidence or replacement coverage:\n{\n \"file\": \"src/renderer/src/runtime/hosted-terminals/recovery/adoption/web-session-terminal-orphan-recovery-adoption-regressions.test.ts\",\n \"assertions\": [\n \"retries a transient thrown adoption on an unchanged semantic frame\",\n \"retains the client epoch and retries when the post-adoption list has $failure\",\n \"preserves prior terminal bindings after a post-adoption $failure and retries\",\n \"merges host-projected $verdict sibling state after adoption without treating pending as exited\",\n \"does not apply an adoption result after the local tab closes while adoption is blocked\",\n \"does not apply an adoption result after the local tab moves groups while adoption is blocked\"\n ]\n }" ], "demotionRule": "Demote if a live parked/restarting PTY loses its exact graph leaf or verified viewer binding, a retired PTY remains published, multi-pane identity drifts, or either routed client round trip flakes without a diagnosed cause." }, @@ -14422,10 +14120,10 @@ "providers": ["paired-runtime"], "coveredPlatforms": ["linux"], "coveredProviders": ["paired-runtime"], - "coverageNotes": "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit1579 removes workflow/manifest/regex/private binary-header and diagnostic metric inventories, fixture selectors, injected forwarding/platform/signature/process examples, unproven overlap and internal churn counters without equivalent replacement coverage. Retains actual Git trust/diffs; filesystem hash/ELF-region/native discovery; child CLI module repair; compiler/lock/publication/rollback and synthetic Electron install/cache ownership; executable shell quoting/exit; controlled notary/timer cleanup; local patched extractor file/AST freshness; real Chromium/WebKit CSP/sandbox/HTTPS image/referrer/link/preservation controls under parsed Android headers. Five unchanged setup-pnpm/VM request-cleanup definitions reviewed and not rerun. GitHub, installer/archive, OS metric, client, native delegate, compressor, builder and Apple boundaries injected or absent where recorded. No actual native PTY, shipped full/native app, real Actions/cache/npm signature authority, downloaded Electron archive, real objdump/linker/native CLI/AppImage, signing/NSIS/notary/upload/updater or live freeze proof. Historical scope before this audit: Published Linux 1.4.188 desktop against current source in both directions; scheduled weekly and manually runnable. No required PR check.", + "coverageNotes": "Audit3375 composes root-adopted3370/independent3371 and3373/independent3374: intentionally retires79 authored registrations/84 expanded cases, including39 whole suites, without equivalent replacement. Lost alarms include federation field/parser inventories; Claude rejected-key precedence, credential clone redaction, managed-versus-user hook preservation and CLI defaults; setting/status/activity projections, mocked SSH/notification/reveal/Linear refusal, fake-clock reconnect and noise; image-fold artifact visibility, paste eligibility, setup trust, scripted ACP error-to-journal publication and ligature cache tuple aliasing; plus supplied folder-runner uniqueness, mobile host-overlay/credential/update/preference races, status/markup/title/keyed-row projections, subscriber cleanup, cancellation/close/refusal/link-issue and mirror suppression alarms. Retained3373 merger contiguity, dual-clock overdue-resume exactly-once, rejected-paste IPC sink and annotation schema roundtrip remain bounded. Retained actual HTTP/OSC status composition, destructive sibling-filesystem isolation, external contrast invariant and fixture CSS pixel intervention remain narrower. Original reviewed87authored/92expanded become9/9; current OpenCode suite adds two preserved upstream cases and the synthetic-title suite gained one Cursor policy mock-call case, independently reviewed for removal in root3378; current90/95 become11/11. That Cursor suppression/ready-frame regression alarm is intentionally lost; it does not observe native title ownership or tab flicker. For3370 only the peer was independently blind, with author exposure explicit;3373/3374 both blind pins were verified. This broad root unit command selects the reduced root unit suite; UNIT_INCLUDE excludes mobile tests, which require the existing mobile runner; retained Playwright component-pixel spec uses its separate existing headless fixture runner and is not validated by the broad unit command. No fresh execution, actual agent/shell/provider, OS material/focus, historical import equivalence, mobile, mixed-version or cross-platform evidence is claimed. All dated receipts retain their original scope. Audit3368 composes root-adopted3363/3364 and3367/3369: intentionally retires181 authored registrations/196 expanded cases, including28 whole suites, without equivalent replacement. Lost alarms include hibernation attention/liveness/backoff/sequential teardown and inventory, host launch compatibility/legacy/Kimi/resource cleanup, terminal recovery parser/pause/quarantine/remount, window-visibility omission-fence lifetime, launch-option rendered Start, sleeping-resume saved recipe/WSL quoting/cancellation, plus removed project/window/input variants. Additional tiny-suite losses include sentence/label/field/default inventories, credential omission, Windows argument/environment mapping, URI decoding, diagnostics, provider classification and fake-clock callback/parser examples. Retained ten registrations/twelve expanded cases include two literal Unicode Mn/Cf zero-width range guards in the actual character-range algorithm and protect narrower delayed editor bytes/destructive ownership, mounted hidden collision repair, ten transport epochs, duplicate-command refusal, caller timeout typing, executor unknown-opener refusal and failed-chunk user bytes. This broad unit command selects the reduced suite; no fresh runtime, real provider/network/PTY, filesystem restart, native UI, historical import equivalence, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3362 composes root-adopted3358/independent3360: intentionally retires129 authored registrations/140 expanded cases, including four whole suites, without equivalent replacement. Lost alarms include supplied orphan-adoption retry/malformed inventory/cancellation; fake-terminal replay parser/wedge/disposal callbacks; all-host catalog metadata and Windows preferences; host keepalive/protocol/stale/settings failures; and removed exact-stop/suppression, source save lifetime, diff-note queue, rename/editor close, input flood/chunk refusal/limits, purge and creation examples. Retained18 registrations/21 expanded cases protect narrower ownership, generation, dirty-state, queue convergence, encoding and attachment-lease outcomes. No replacement or keeper quota claim. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY/xterm parser, disk restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3359 composes root-adopted source3355/independent3356: intentionally retires130 authored registrations/139 expanded cases, including eight whole suites, without equivalent replacement. Lost alarms include strict create naming/capability/legacy payloads; supplied transport host replacement, deadline reattach, create-handoff and split activation; agent-session fork/clipboard/platform flags; shutdown cleared-scrollback/unmounted bindings; simulator host-collision/selection/shutdown; and removed editor, catalog, mutation, launch and status examples. Retained12 adverse-ordering/state-consequence cases are narrower and do not replace all removed alarms. Two queue absences receive zero removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY, filesystem restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3349 composes adopted batches3343,3345 and refreshed3354: intentionally retires234 authored registrations/294 expanded cases, including13 whole suites, without equivalent replacement. Lost alarms include supplied terminal reconnect/replacement/typeahead/mirror/result and snapshot examples; synthetic render-desync persistence/recovery; worktree listing/owner/catalog/lineage/removal and activation/creation examples; host-scoped PR and task-record projections; editor diff/status/comment and UI send-target examples; automation observation/wake, supplied sleep/deadline clock and native-chat completion/notification/relaunch samples; held-tab layout and cleanup/progress guard examples. Retained adverse-ordering and wire-boundary cases are narrower and do not replace all removed alarms. The already-upstream visibility-resume deletion receives zero new removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH, native process/power/GPU, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3342 composes adopted source batches3333/3334,3336/3337 and3340/3341: intentionally retires180 authored registrations/263 expanded cases, including seven whole suites, without equivalent replacement. Lost alarms include corrupt editor hydration; mobile editor/diff publication and privacy projections; stale-resubscribe routing; model-picker projection/refetch/retry/fallback; editor check-details and frame property inventories; latched-pane cleanup/quiescence; client create replay identity/options/compatibility; and removed owner, async routing, terminal and layout examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts keep their original scope. Audit3335 composes adopted source unions3327/3328 and3330/3332: intentionally retires100 authored registrations/123 expanded cases, including ten whole suites, without equivalent replacement. Lost alarms include seeded host persistence/contention and stale-host cleanup; browser snapshot assembly; mocked wake/DPR callbacks and frame budgets; preflight projections; palette authority/cache suppression, URL intent and saved-title cross-repo collisions; metadata coverage/set patch and dropdown assembly; and removed terminal, worktree, review-refresh and owner-routing examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI/GPU/focus, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain only their original scope. Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed. Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed. Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed. Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical. Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims. Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands. Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit1579 removes workflow/manifest/regex/private binary-header and diagnostic metric inventories, fixture selectors, injected forwarding/platform/signature/process examples, unproven overlap and internal churn counters without equivalent replacement coverage. Retains actual Git trust/diffs; filesystem hash/ELF-region/native discovery; child CLI module repair; compiler/lock/publication/rollback and synthetic Electron install/cache ownership; executable shell quoting/exit; controlled notary/timer cleanup; local patched extractor file/AST freshness; real Chromium/WebKit CSP/sandbox/HTTPS image/referrer/link/preservation controls under parsed Android headers. Five unchanged setup-pnpm/VM request-cleanup definitions reviewed and not rerun. GitHub, installer/archive, OS metric, client, native delegate, compressor, builder and Apple boundaries injected or absent where recorded. No actual native PTY, shipped full/native app, real Actions/cache/npm signature authority, downloaded Electron archive, real objdump/linker/native CLI/AppImage, signing/NSIS/notary/upload/updater or live freeze proof. Historical scope before this audit: Published Linux 1.4.188 desktop against current source in both directions; scheduled weekly and manually runnable. No required PR check.", "motivatingLinks": ["https://github.com/stablyai/orca/actions/runs/34069063016"], "invariant": "A paired client and host without client-hosted browser capabilities retain server-hosted browser placement across supported version skew.", - "oracle": "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Require both existing named browser placement scenarios to pass three times with one attempt, zero skips, zero failures, and no report errors.", + "oracle": "Audit3375 composes root-adopted3370/independent3371 and3373/independent3374: intentionally retires79 authored registrations/84 expanded cases, including39 whole suites, without equivalent replacement. Lost alarms include federation field/parser inventories; Claude rejected-key precedence, credential clone redaction, managed-versus-user hook preservation and CLI defaults; setting/status/activity projections, mocked SSH/notification/reveal/Linear refusal, fake-clock reconnect and noise; image-fold artifact visibility, paste eligibility, setup trust, scripted ACP error-to-journal publication and ligature cache tuple aliasing; plus supplied folder-runner uniqueness, mobile host-overlay/credential/update/preference races, status/markup/title/keyed-row projections, subscriber cleanup, cancellation/close/refusal/link-issue and mirror suppression alarms. Retained3373 merger contiguity, dual-clock overdue-resume exactly-once, rejected-paste IPC sink and annotation schema roundtrip remain bounded. Retained actual HTTP/OSC status composition, destructive sibling-filesystem isolation, external contrast invariant and fixture CSS pixel intervention remain narrower. Original reviewed87authored/92expanded become9/9; current OpenCode suite adds two preserved upstream cases and the synthetic-title suite gained one Cursor policy mock-call case, independently reviewed for removal in root3378; current90/95 become11/11. That Cursor suppression/ready-frame regression alarm is intentionally lost; it does not observe native title ownership or tab flicker. For3370 only the peer was independently blind, with author exposure explicit;3373/3374 both blind pins were verified. This broad root unit command selects the reduced root unit suite; UNIT_INCLUDE excludes mobile tests, which require the existing mobile runner; retained Playwright component-pixel spec uses its separate existing headless fixture runner and is not validated by the broad unit command. No fresh execution, actual agent/shell/provider, OS material/focus, historical import equivalence, mobile, mixed-version or cross-platform evidence is claimed. All dated receipts retain their original scope. Audit3368 composes root-adopted3363/3364 and3367/3369: intentionally retires181 authored registrations/196 expanded cases, including28 whole suites, without equivalent replacement. Lost alarms include hibernation attention/liveness/backoff/sequential teardown and inventory, host launch compatibility/legacy/Kimi/resource cleanup, terminal recovery parser/pause/quarantine/remount, window-visibility omission-fence lifetime, launch-option rendered Start, sleeping-resume saved recipe/WSL quoting/cancellation, plus removed project/window/input variants. Additional tiny-suite losses include sentence/label/field/default inventories, credential omission, Windows argument/environment mapping, URI decoding, diagnostics, provider classification and fake-clock callback/parser examples. Retained ten registrations/twelve expanded cases include two literal Unicode Mn/Cf zero-width range guards in the actual character-range algorithm and protect narrower delayed editor bytes/destructive ownership, mounted hidden collision repair, ten transport epochs, duplicate-command refusal, caller timeout typing, executor unknown-opener refusal and failed-chunk user bytes. This broad unit command selects the reduced suite; no fresh runtime, real provider/network/PTY, filesystem restart, native UI, historical import equivalence, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3362 composes root-adopted3358/independent3360: intentionally retires129 authored registrations/140 expanded cases, including four whole suites, without equivalent replacement. Lost alarms include supplied orphan-adoption retry/malformed inventory/cancellation; fake-terminal replay parser/wedge/disposal callbacks; all-host catalog metadata and Windows preferences; host keepalive/protocol/stale/settings failures; and removed exact-stop/suppression, source save lifetime, diff-note queue, rename/editor close, input flood/chunk refusal/limits, purge and creation examples. Retained18 registrations/21 expanded cases protect narrower ownership, generation, dirty-state, queue convergence, encoding and attachment-lease outcomes. No replacement or keeper quota claim. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY/xterm parser, disk restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3359 composes root-adopted source3355/independent3356: intentionally retires130 authored registrations/139 expanded cases, including eight whole suites, without equivalent replacement. Lost alarms include strict create naming/capability/legacy payloads; supplied transport host replacement, deadline reattach, create-handoff and split activation; agent-session fork/clipboard/platform flags; shutdown cleared-scrollback/unmounted bindings; simulator host-collision/selection/shutdown; and removed editor, catalog, mutation, launch and status examples. Retained12 adverse-ordering/state-consequence cases are narrower and do not replace all removed alarms. Two queue absences receive zero removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY, filesystem restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3349 composes adopted batches3343,3345 and refreshed3354: intentionally retires234 authored registrations/294 expanded cases, including13 whole suites, without equivalent replacement. Lost alarms include supplied terminal reconnect/replacement/typeahead/mirror/result and snapshot examples; synthetic render-desync persistence/recovery; worktree listing/owner/catalog/lineage/removal and activation/creation examples; host-scoped PR and task-record projections; editor diff/status/comment and UI send-target examples; automation observation/wake, supplied sleep/deadline clock and native-chat completion/notification/relaunch samples; held-tab layout and cleanup/progress guard examples. Retained adverse-ordering and wire-boundary cases are narrower and do not replace all removed alarms. The already-upstream visibility-resume deletion receives zero new removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH, native process/power/GPU, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope. Audit3342 composes adopted source batches3333/3334,3336/3337 and3340/3341: intentionally retires180 authored registrations/263 expanded cases, including seven whole suites, without equivalent replacement. Lost alarms include corrupt editor hydration; mobile editor/diff publication and privacy projections; stale-resubscribe routing; model-picker projection/refetch/retry/fallback; editor check-details and frame property inventories; latched-pane cleanup/quiescence; client create replay identity/options/compatibility; and removed owner, async routing, terminal and layout examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts keep their original scope. Audit3335 composes adopted source unions3327/3328 and3330/3332: intentionally retires100 authored registrations/123 expanded cases, including ten whole suites, without equivalent replacement. Lost alarms include seeded host persistence/contention and stale-host cleanup; browser snapshot assembly; mocked wake/DPR callbacks and frame budgets; preflight projections; palette authority/cache suppression, URL intent and saved-title cross-repo collisions; metadata coverage/set patch and dropdown assembly; and removed terminal, worktree, review-refresh and owner-routing examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI/GPU/focus, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain only their original scope. Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed. Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed. Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed. Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed. Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical. Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims. Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands. Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired. Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed. Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed. Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed. Audit3200 composes approved source3194: deliberately retires thirteen authored registrations/twenty-seven expanded cases in six whole automation host/list policy suites without equivalent replacement. Real RPC category/retryability and wrapped-timeout recognition, unscoped-failure/scoped-success health evidence precedence, exact-ID create selectors and per-run workspace omission, paired-web local/SSH/absent host catalog routing, incompatible/removed/unhydrated/offline execution health, runtime-before-nested-SSH recovery dispatch, and no-owned-focus/successor/foreign-list focus policy alarms are consciously lost. Retain exact20line orphan allow/refuse/precondition and exact90line cross-host same-ID search suites. No retry-timer/fence lifecycle, actual reconnect/network/write delivery, native focus, mobile/mixed-version runtime or disk persistence coverage is claimed. Audit3191 combines approved source3182/3187/3188: deliberately retires thirteen authored Vitest registrations and fifteen expanded cases, including five whole suites, without equivalent replacement. Attachment intake loses real portal/native-capture terminal interception and unowned-container refusal, immediate child-only committed availability/claim-ref negotiation and delivery, and direct-target over stable focused/background composer routing through disable/re-enable/remount and independent question focus. Exact destination/cache/draft and final-stat owner/workspace/File-release suites remain; they do not replace Surface recipient routing. Automation authoring loses destination runtime catalog membership, local/direct-SSH exclusion of paired-runtime repos, unknown-runtime empty catalog, logical project/host/setup/repo/path context payload, and missing/nonready setup refusal; these were genuine direct helper alarms, while exact schedule transformation, legacy schedule and setup-decision suites remain. Agent picker loses setup-chat/terminal/missing-installer/unsupported-or-unknown-host row projection samples and the ordinary unsearched menu variant; the entire original26-line resume recipe suite remains, including reported bypass versus default/absent permission modes, as does the exact search-result menu callback with its fixtures, model/effort commits and staged Arguments reopen outcome. Rejected predecessor3180 full recipe deletion is excluded. No actual native drag/cursor/focus/IME, upload bytes or disk/restart persistence, full automation save/scheduler/runtime transport, real resume-process flags/environment delivery, or native menu/rendered layout validation is claimed. Audit3178 combines source3169/3170/3175: deliberately retires eight authored units (six Vitest cases and two imperative custom relay scenarios), including two whole suites, without equivalent replacement. Voice Section loses per-model pending-delete isolation across interleaved A/B completion and the two-success refresh-call alarm; exact VoicePane delayed key-clear/newer enabled-toggle merge remains and does not replace row deletion coverage. Speech loses dedicated rating-scale/inclusive-ceiling, unsupported-versus-unmeasured, explicit/system-language precedence/locale alias, accuracy versus fast named/default/best-measured selection, and unmeasured/no-match examples; exact offered-user-pick versus retired-selection case and its fixture remain. Relay loses legacy ping-delivery count/liveness sampled before the silence deadline and grouped malformed Bearer/host-ID 401/429 routing checks; twelve real Worker/DurableObject/shipped-client scenarios remain, not equivalent replacement for those narrow alarms. Six prior speech cases are not all deleted: approved successor3175 keeps the original user-choice case. No actual credential/file persistence, native/GPU/engine/download delivery, production assignment policy or deployed-runtime validation is claimed by this reduction. Audit3165 combines source3160/3162: deliberately retires six authored/expanded cases across three whole suites without equivalent replacement. Launch/status losses: observed React-render pending/resuming coordination across settings and deferred offer read; stale-offer reread suppressing dialog reopen; held-local-chat recovery visibility with new-chat preferences off; disabled-local admission avoiding offer RPC despite an injected but unconsumed paired-tab fixture; and run-only lost-reply uncertainty reachability until direct viewed-run retirement. Launch probe does not prove arbitrary synchronous-store atomicity, the paired fixture is not remote runtime enrollment, and the status case directly marks viewed state rather than rendering the summary. Crew-hook losses: old-host method_not_found cache persists across party changes but is released by independently supplied connection generation/verified pairing status or pairing revision, with actual frame publication and teardown. These are real narrow coordination, admission, uncertainty and mixed-version cache alarms consciously lost. Exact web verified-runtime writer handoff guard remains; it does not replace those alarms or prove live host/native/mobile delivery. Audit3156 combines3147/3150/3152/3153/3154: deliberately retires39authored/40expanded native-chat recovery cases, eight whole suites and two orphan test-support files without equivalent replacement. Lost alarms: lost-reply unconfirmed reconciliation, skipped rows/counts and missed-frame repair, unknown/pending outcome and omitted-failure-list compatibility, uncertain history after dismissal, retry/refusal/dismiss lifecycle, hidden/consumed picker ownership, result-tree keyboard focus/disclosure and all-skipped retirement; unconfirmed-over-conflict guidance and failed-chat changes despite older host timestamps; nearest-listed ancestor/cyclic forest shape, descendant membership, host ordering/missing-host local fallback; skipped/readiness/admission counts, provisional skip/progress monotonicity, early per-chat verdicts with batch pending protection, older-host waiting, start-slot/delivery distinction, retry-over-failure and unknown-after-withdrawal attention; remote snooze/reconnect/reoffer, unseen mixed summary through open/close, watched completion retirement, new success beside old failure, failed-reread mixed-result preservation, filter/collapse completion resets, retry summary replacement and current-offer/history selection; cross-host workspace identity, rendered cyclic reachability, nested tri-state/toggle propagation, project eligibility isolation and collapse preserving selection. Exact fallback-list completion barrier, batched verdict/cleanup retention, stale-read versus dismissal publication race, and requested-but-never-rendered finished-run retirement remain; they do not replace retired alarms. Audit3146 combines source reviews3132/3133/3135/3138/3143: intentionally retire20authored/31expanded cases without equivalent replacement. Provider-session losses: structured-native terminal-resume exclusion, metadata-less completed identity, new-turn completion clearing, Pi provider-only/periodic/manual promotion, changed-transcript launch-config isolation, Pi/omp/prime-agent completed-session remote/manual-shutdown promotion, and quit/done precedence over heartbeat. Side-thread/question losses: finished-pane acquisition, hidden title/recap states, local/relay/relay-done conversation takeover with prompt/session/child resets, plain-message abandonment, compaction/session replacement and completion resets. Codex startup losses: incoming-owner cached child replacement, old-relay foreign live-session correction, completed foreign-root turn-fact permutations. Transcript losses: real temporary-JSONL partial sibling/final-child completion, unlabelled child attribution, compact cached replay preservation and100/1000completed-child roster retention/release. Compiler-ratchet losses: valid-line uncompiled-list parser grammar examples and injected-existence stale-path filtering; these did not exercise actual filesystem canonicalization or build exclusion. These are real lifecycle, ownership, replay, liveness and retention alarms, including recent#40246 regressions, deliberately lost. Retained conditional record replacement, clockless root/SSH owner isolation, persisted main-thread fork rejection, partial/final question-answer lifetime, cached-roster/missing-ID/live HTTP/durable startup boundaries and restarted-relay refusal/acceptance do not replace those losses. No native/SSH/WSL execution or equivalent coverage is claimed. Audit3128 scoped coverage reduction: Audit3121 removes VoiceDictationLanguageSetting.test.tsx (Spanish-to-es callback and unsupported-model Korean option presence) and voice-speech-model-rows.test.ts (provider/language-order/retired-on-disk list policy); these real narrow alarms are deliberately retired without replacement. VoiceSpeechModelSection per-model concurrent deletion remains unchanged. Audit3122 removes the direct absolute/parent-segment sparse-directory exception-type sample and the five-row IPC sparse-preset error-code/non-save table (two authored/six expanded cases). Those real typed-validation and IPC refusal/error-code alarms are deliberately retired. Keep both real symlink/junction floating-directory trust cases and the minimal RPC structured validation-reason serialization case. The RPC case does not replace IPC save/refusal behavior, typed normalization for both path inputs, actual Git sparse checkout or rendered localization. No equivalent replacement or fresh test/runtime/platform/remote/performance validation is claimed. Audit3124 removes ExperimentalPane.test.tsx (ordinary Pet switch callback), WorkspaceDirectorySetting.test.tsx (padded absolute saved-path normalization/no-write blur), and repository-search.perf.test.ts (navigation/selected-pane builder-call policy, fixture cardinality/nonempty entries and renamed project keyword inclusion). These real narrow alarms are retired without replacement; RepositoryPane.search.test.tsx search-to-sparse-editor request remains unchanged. Audit3129: resolver Windows case-insensitive and POSIX case-sensitive configured-env composition plus mocked-base launch-preflight Windows composition are intentionally no longer checked by the two deleted suites. No equivalent coverage claimed. Keep runtime-structured-agent-host-env.test.ts unchanged: configured Windows Claude-home account identity and host-account precedence remain checked. Audit3114 incorporates source3101: retire three structured Claude child-environment wrapper cases covering inherited stamp isolation/default and explicit entrypoint, Windows SDK-key canonicalization/default/duplicate-key order, and configured lookup/final environment/config-dir conjunction. Keep direct auth/session sanitation and Windows-versus-Linux overlay checks, actual executable lookup from supplied inherited PATH, native Windows child environment delivery, and stale option-mutation fencing. These are not equivalent replacements for the retired wrapper alarms. No fresh test/runtime, real login-shell probe, Claude SDK startup, remote/mixed-version, UI or performance result is claimed. Audit3114 incorporates source3105: retire 17 authored/20 expanded daemon launch-note cases, including the entire two-case SessionLaunchNote suite. Deliberately lose split-marker carry across same-token re-arm, stale-token retirement refusal, foreground tri-state and serial settlement, omitted-note/no-incarnation mixed-version policy, sticky retirement, first-incarnation/replacement launch preservation and held-launch precedence. Keep only the unchanged unresolved foreground-read race against a later finished attach. Supplied notes/foreground and runtime calls do not establish actual daemon/main restart, SSH, native Windows observation, mobile UI, equivalent replacement or fresh runtime/performance validation. Audit3114 incorporates source3109: retire six authored/35 expanded pricing cases: 21 accepted model-name examples, 10 unsupported/future-model fail-closed examples, malformed TTL clamp, unknown-model estimate refusal, flat-model long-context disregard and oversized long-context clamp. Keep mixed five-minute/one-hour write allocation and short/all-long/mixed long-context allocation with original fixed oracles. Real parser/refusal/bounds alarms are knowingly lost without equivalent replacement; retained tests do not validate provider rates, actual billing or request threshold classification. Preserve the archived usage-scan-append source-freeze receipt without transferring historical execution/performance credit. No fresh runtime result is claimed. Audit3108 source-only reduction (3094/3095/3100): retire 27 authored/30 expanded cases, including complete markdown view-state, file-preview link-open and CLI agent-server-route suites, without replacement. Deliberate losses include preview visibility/reference lifetime and same-path owners; SSH stat, directory/missing-target, explicit-null owner, nonmarkdown line/column, local URI routing, remote-to-client guard and same-file reuse; document-preview source-owner/folder/reuse routing, stable grant location and outside-workspace POSIX/Windows request projection; and verified remote CLI send/check refusal, suggested --on argv/copy, shell no-probe bypass, unverified-launch admission and older-peer refusal. Retain two markdown source-runtime/qualified-reveal alarms, one stale grant-rejection fence and two remote read/mutation evidence policies, with original callbacks. Final last-wins reveal did not prove transient cancellation; CLI prerequisite did not prove no real send, and envelope tests do not execute server refusal. No fresh runtime, rendered UI, actual file/SSH/paired transport, authorization, mixed-version or performance result is claimed. Audit3096 source-only reduction (3087/3088): retire 69 authored/76 expanded cases, including complete recovery-portals and reconnect-banner suites. Intentionally lose dead/default TUI replay, generated alternate-frame style composition, reset/mode/dimension and legacy missing-mode-boundary alarms, UI notice/action/reveal policies, and isolated recovery lifecycle variants, without equivalent replacement. Retained registrations and callbacks are unchanged; headless cells are not pixels, and no fresh runtime, host, SSH, WSL, rendered-app or performance result is claimed. Audit3086 source-only reduction (3079/3080/3081): intentionally retire 93 authored/100 expanded mock-boundary cases, including the complete spawn-errors and SSH reconnect overlay suites, without replacement. Retired alarms include spawn classification/ownership, reply ceilings and renderer-write failure recovery, disconnect/detach fencing branches, authority facts, and overlay retry/visibility wiring. Retained callbacks are unchanged; no fresh execution, real PTY/SSH, rendered UI, or performance result is claimed. Audit2432: The broad unit command loses the isolated BranchPicker open-change notification sample. Its unique true/false callback alarm is intentionally retired; reopening/status-refresh behavior was not exercised. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2425: The broad unit command loses the workspace-copy-status supplied readError forwarding sample. It did not exercise the branch-switch blocking promised by its title. This alarm is intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2417: The broad unit command loses two ordinary clean Git cherry-pick/revert success samples and two terminal startup foreground-read work-budget samples. These unique alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2412: The broad unit command loses the whole six-case fake-React-hook scroll-anchor suite, two generic draft-retention samples, a simple new-agent order sample, a real history-publication batching-count sample, an unmounted handoff abort/timer sample and three basic WSL preview/error samples. These alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2404: The broad unit command loses the standalone share-name lookup 503 propagation suite, initial deletion placement-kind sample, direct changed-mtime stale sample, first-pass rollback existence example and abandoned-preparation directory sample. These exact alarms are intentionally retired without equivalent replacement or fresh validation of the reduced selector. Audit2397 review amendment: The broad unit command loses three standalone suites, two partial-case definitions and two URL table rows across package/download/placement tests. Keep initial wrong-port authorization, modified independent-copy digest refusal and abort-after-begin cancellation dispatch. The remaining alarms are deliberately retired; no equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2393 current-parent refresh2401: Remove the basic skill-install service alias sample and original public managed-remove receiptless refusal case. Preserve the upstream request ownership suite and transaction interruption coverage. No equivalent complete replacement or fresh validation of the reduced selector is claimed. Audit2389: The broad unit command loses the missing-preview suite, plain-global destination sample and prepublished-receipt recovery example. No equivalent replacement or fresh validation of the reduced selector is claimed. Audit2385: The broad unit command loses four authored walker/staging/protocol examples (six expanded cases); no equivalent replacement or fresh validation is claimed for the reduced suite. Audit2383: The unscoped Vitest command no longer includes the removed Antigravity catalogue suite; its exact provider-root/owner example has no equivalent replacement or fresh validation claim. Audit2377/2381: The unscoped Vitest command includes the reduced bundled-skill and native-discovery suites; the eight removed backup/legacy/catalogue/symlink/SSH-builder examples have no replacement-equivalence or fresh validation claim here. Audit2133 current-parent preparation: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Audit2095 current-parent preparation2126: Current reduced sources/selectors intentionally retire the alarms listed in knownGaps; prior dated runs and replacement claims do not validate the changed set. Historical prior account (preserved verbatim): Require both existing named browser placement scenarios to pass three times with one attempt, zero skips, zero failures, and no report errors.", "commands": [ "gh workflow run packaged-browser-e2e.yml", "pnpm exec playwright test tests/e2e/packaged-mixed-version-browser-placement.spec.ts --config tests/playwright.config.ts --project=electron-headless --workers=1 --repeat-each=3 --retries=0", @@ -14474,6 +14172,7 @@ "Collect repeated scheduled history before making this required." ], "knownGaps": [ + "Launch direct-owner cleanup current scope: This gate’s unfiltered unit command now selects a suite reduced by 82 whole registrations / 159 potential table examples in 10 whole test Programs, including 8 registrations / 15 examples from five once-registered create-message factory closures. Lost alarms include frozen first-message/options and legacy-host fallback; distinct actions and redelivery; uncertain/refused/reloaded input custody, Retry and late proof; rich prompt/attachment upload Stop/close and handback; ordinary draft/editor/IME/StrictMode lifetime and accepted topology; provisional fallback tab placement/group/pin/order and rich worktree handoff. Four whole consent/resume-identity cases remain in two Programs; they do not replace these alarms. This entry governs current reduced-unit scope and qualifies any broader implication of unchanged oracle/coverageNotes history. Entire dated evidenceRuns, original commands/currentCommand values, counts/results and existing history retain their original scopes only; no fresh execution, transferred pass, replacement equivalence or prior upstream-removal credit is claimed.", "Audit2133 current-parent preparation (988 authored removals; independently reviewed2099/2107/2115/2116 decisions; upstream clear-buffer and recovery-image regressions retained): Intentionally retire these low-value alarms without replacement: src/main/persistence/worktree-sort-order-write.test.ts: re-ranks every writable row when a blocked row sits in the requested order. src/main/runtime/construction/orca-runtime.test.ts: remove only literal registration import/call pairs await import('../orca-runtime-tests/worktree-setup-and-startup.spec'), await import('../orca-runtime-tests/gitlab-and-pr-bases.spec'); no additional authored credit. src/main/runtime/orca-runtime-tests/targeting-and-resilience.spec.ts: routes tab switch and capture start by explicit page id; accepts focus on tab switch without altering bridge args (focus is main-side concern); keeps terminal cwd resolution fail-soft when the provider is unavailable. src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-04.spec.ts: drops the bounded scan cache when orphan-cleanup removal completes; clears optimistic reconcile tokens when a CLI worktree removal succeeds; emits drift without mutating when the fetched base fast-forwards created HEAD; emits base_changed without mutation when the fetched base rewrote history; skips stale-token reconciles without mutating or emitting stale status; emits unknown without mutation when fetch fails or the base ref is missing. src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-03.spec.ts: routes runtime preserved-branch force-delete through the selected WSL project runtime; replies to a waiting client with the error of a delete that fails after acceptance; treats forced runtime deletion of an already-missing unregistered worktree as cleanup; treats normal runtime deletion of an already-missing unregistered worktree as cleanup. src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-02.spec.ts: warns that a missing-repo removal only forgot the workspace; restores runtime watchers when CLI worktree deletion fails after teardown; does not re-spend the drain budget on a removal after a wedged install was abandoned; routes runtime worktree removal through the selected WSL project runtime; force-deletes a branch that was preserved by runtime worktree removal. src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases-part-02.spec.ts: records GitLab pasted-project recents only after successful runtime lookup; threads explicit origin preference through runtime WSL PR base resolution; resolves local GitLab fork MR bases from the target project MR head ref; captures the fork MR head from a dedicated ref, not the shared FETCH_HEAD; keeps the durable MR head when the head fetch fails but the local ref resolves; routes runtime GitLab fork MR base git calls through the selected WSL project runtime. src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases.spec.ts: passes SSH connection ids through GitLab task operations; routes runtime GitLab issue, MR, work-item, and todo actions through the selected WSL project runtime; routes runtime GitLab MR details, review-management, job, and pasted URL actions through the selected WSL project runtime; normalizes runtime GitLab issue list arguments like the desktop IPC path. src/main/runtime/orca-runtime-tests/worktree-setup-and-startup-part-03.spec.ts: does not warn when setup is explicitly skipped for CLI-created worktrees; puts the agent a create starts in the first default tab, as the window does; keeps the 8s main-runtime startup readiness budget for agents without an override; gives OpenCode the 20s main-runtime startup readiness budget; launches explicit startup agents with prompts for CLI-created worktrees. src/main/runtime/orca-runtime-tests/worktree-setup-and-startup.spec.ts: returns a setup launch payload for CLI-created worktrees when hooks are explicitly enabled; does not hand the window a setup main never tried to start; passes the selected Windows setup shell into runtime runner generation; follows normal setup policy for CLI-created worktrees without activating them; uses returned WSL setup shell metadata when runtime spawns setup; uses the shell-aware setup runner for windowless creates without a startup command; reports the in-process setup hook as running when nothing can launch the runner. src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-02.spec.ts: coalesces two clients sleeping the same host worktree; stops exactly the expected live PTYs for a worktree; explains a refused workspace close instead of throwing the raw refusal enum. src/main/runtime/orca-runtime-tests/mobile-summaries-part-03.spec.ts: marks the desktop-active worktree as isActive; includes SSH-backed worktrees in the mobile worktree summary; caches repeated malformed path misses before normalizing them again. src/main/runtime/orca-runtime-tests/mobile-summaries-part-02.spec.ts: keeps title-only foreground work ahead of monitoring in another pane; keeps a local hook row while a connected PTY still backs its pane; keeps an OSC row via its connected PTY after the pane binding is cleared. src/main/runtime/orca-runtime-tests/mobile-summaries.spec.ts: resolves files through a source-visible linked-checkout worktree; marks saved session tabs with live PTYs as host sidebar activity; attributes live legacy PTYs from saved layout bindings when their panes are hidden; marks saved browser tabs as host sidebar activity like desktop; falls back to the path-keyed GitHub cache entry; includes folder workspaces in compact worktree summaries for mobile; attaches inline agent rows from the latest OSC 9999 status; projects monitoring over a title-derived working status. src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-03.spec.ts: pushes to an idle pane when the only live waiter filters out the message type; resolves a registered waiter without PTY-injecting when the leaf is already idle; keeps already-idle status after tui-idle wait for immediate message delivery; resolves message waiters when notifyMessageArrived is called; does not resolve type-filtered message waiters for unrelated message types; removes message waiter abort listeners after message arrival; resolves message waiters on timeout when no message arrives. src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-02.spec.ts: delivers pending mail via notifyMessageArrived when the recipient is already idle; does not keep retrying when every pending row was already pointed; repoints pending rows restored with a live-idle coordinator. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-13.spec.ts: rolls back a half-created terminal whose surface never publishes. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-12.spec.ts: rejects startup prompts for agents that require post-ready stdin; uses portable Unix quoting for mobile agent launch commands in WSL project runtimes; keeps PowerShell quoting for mobile agent launch commands in Windows host runtimes; uses cmd.exe quoting for mobile agent launch commands in local Windows host runtimes; publishes headless mobile session agent identity with synthesized PTY status; rejects disabled mobile session agent launches before spawning; validates mobile terminal insertion anchors before resolving agent launch commands. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-11.spec.ts: coalesces a reconnect close burst onto one authoritative PTY inventory; keeps an explicit user close destructive while the PTY is live; builds mobile session agent launch commands on the runtime host; injects mobile quick-command prompts into the host-built agent startup command. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-10.spec.ts: closes persisted headless terminal parents before any prior list call; tears down a serve-owned headless tab on close while a renderer is attached so it cannot resurrect; defers a renderer-published pending tab to the renderer instead of tearing it down; returns a delegated close outcome with no selection tombstone when the renderer owns the outcome; tears down a runtime pending shell the renderer never adopted on close. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-08.spec.ts: materializes a plain shell when the pending tab has no launch agent; hydrates legacy persisted terminal tabs without layout entries; reads and indexes the full agent-status snapshot once per mobile projection; kills persisted SSH PTYs when closing hydrated headless tabs before pane metadata is restored; materializes hydrated pending headless terminals with the persisted session identity. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-07.spec.ts: hydrates a persisted SSH-owned pane before an attached renderer publishes its graph. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-05.spec.ts: publishes the desktop's tab name over the live agent title, and the live title without one; uses fresh neutral PTY titles over stale mobile snapshot and OSC titles; operates PTY-backed mobile session terminals without a renderer graph; reuses pane close for live PTYs that do not own a renderer tab; lists PTY-backed mobile session terminals without a renderer graph; shows and resolves active PTY-backed mobile session terminals without a renderer graph. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-04.spec.ts: creates mobile session terminals for folder workspaces in a headless runtime server; spawns fresh headless SSH mobile session terminals instead of reattaching synthetic local ids; hydrates headless mobile session terminals from the host workspace session; keeps live headless mobile session terminals when a desktop renderer publishes without them; publishes laptop-created remote runtime split terminals to phone session tabs. src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-02.spec.ts: does not report headless wake degradation without sleeping records; does not wake slept agents for non-mobile session-only activation; does not rewrite unread metadata when a mobile activation finds the worktree already read; returns unread:false from worktree.ps after a mobile activation clears the flag; materializes pending mobile session terminals without focusing desktop clients; closes browser mobile session tabs when addressed by browser workspace id. src/main/runtime/orca-runtime-tests/mobile-session-tabs.spec.ts: resolves mobile terminal surfaces by exact split leaf; closes the matching mobile terminal UUID leaf without closing the whole tab; closes the whole mobile terminal tab when addressed by parent tab id; activates the active split leaf when addressed by parent tab id; clears unread metadata on mobile worktree activation without focusing desktop clients; wakes slept agents on the host renderer when a phone activates a worktree. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-05.spec.ts: publishes the hook provider session on a headless mobile tab so native chat can address the transcript; recovers the agent type from the hook row when the pane was launched without an agent hint; reads one agent-status snapshot per projection, not one per terminal tab; waits for unknown-launch foreground owner before publishing Pi-compatible mobile status; keeps Pi-compatible mobile session status as Pi for an unknown-launch foreground pi PTY; keeps renderer-vetted mobile agent status for custom-titled terminals. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-04.spec.ts: publishes terminal surface agent status for paired web clients; preserves authoritative OMP identity for Pi-compatible remote terminal snapshots; normalizes a remote OMP title without republishing omitted launch identity; skips the foreground-process probe when the PTY launch agent is already known; probes the foreground process only on a status transition for unknown launch agents; passes the client signal and the slept-worktree refusal to the spawn. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-03.spec.ts: does not use stale runtime-created PTY status when a neutral PTY title exists; recognizes runtime-created Codex PTY handles from the ready prompt; recognizes runtime-created Antigravity PTY handles from the ready prompt; recognizes live leaf Antigravity terminals from the ready prompt; recognizes a later Antigravity header with a prompt but no model line; keeps mobile terminal surfaces visible while their leaf handle is pending. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-02.spec.ts: lets Claude agents management titles clear stale runtime-created title status; does not recognize live Claude agents panes from a Claude foreground process; does not let stale tab-level agent titles override current neutral pane titles; lists live terminals with fresh pane titles over stale tab titles; lets adopted neutral pane titles use non-shell foreground fallback; lets adopted neutral pane titles retry wrapper foregrounds until recognized; authorizes settled CLI prompts only after positive %s foreground identity; does not recognize arbitrary foreground TUIs as running agents; lets live neutral pane titles retry wrapper foregrounds until recognized; lets current Claude agents PTY titles override stale runtime-created OSC titles; does not let stale Claude agents OSC titles suppress current PTY title activity. src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status.spec.ts: keeps preallocated terminal handles valid across renderer reloads; preserves runtime-created PTY process identity after graph unavailable; keeps prompt bindings fenced across runtime restarts without provider incarnation; recognizes runtime-created PTY handles with agent launch titles; does not treat a bare Cursor Agent native title as a running agent session; uses stale runtime-created PTY status when there is no title or foreground evidence. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-07.spec.ts: keeps orphaned list and show writability aligned with the send gate. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-04.spec.ts: cancels a coalesced SSH worker recovery retry when its provider disconnects. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-03.spec.ts: retries renderer reveal before clearing an adopted legacy worker sleeping record. src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-02.spec.ts: recovers exported ORCA_TERMINAL_HANDLE from discovered live PTY sessions. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-12.spec.ts: applies ANSI erase-from-start line controls in retained previews; applies ANSI stripping for private or intermediate CSI line controls; applies ANSI stripping for unsupported erase-line modes; reveals an agent terminal under the pane the caller reserved; keeps a fresh %s pane host-owned when a desktop window is available; keeps desktop publication %s separate from the reserved host spawn; mints its own pane when the reserved leaf is malformed, and reports the one it used; starts an agent terminal with the model the caller picked; starts an agent terminal without a model flag when no pick was made; attributes a startup-agent launch named %s as %s; attributes a fresh agent session the host builds as unknown; leaves a bare agent command the user typed out of launch attribution. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-11.spec.ts: trims oversized terminal output bursts without per-line array shifts; builds terminal previews without mapping the full retained tail; keeps recent PTY replay output capped without needing previous data for large chunks; applies terminal redraw controls before retaining previews; applies ANSI terminal redraw controls before retaining previews; retains multi-line ANSI footer redraws instead of appending old frames; keeps the cursor column when erasing full lines in multi-line redraws; applies ANSI split redraw controls without leaking raw params. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-10.spec.ts: returns renderer visible screen lines through terminal.read RPC JSON result; separates composer drafts from provider-owned terminal screens. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-09.spec.ts: reports an in-flight PTY focus as not navigated when its notifier disappears; reports graph-leaf focus as not navigated without a host notifier; grounds the provider mode tracker before a later chunk, in the emulator order; grounds an in-flight provider snapshot capture so it cannot publish the pre-reset screen; waits for terminal exit and resolves with the exit status; keeps terminal read payloads bounded while retained output remains pageable; trims terminal read preview character budget without per-line array shifts. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-08.spec.ts: submits a silent Claude composer once after the bounded render fallback; chunks large terminal.send text before provider writes; yields chunked terminal input through immediates between writes; yields while validating accepted large terminal.send text before provider writes; reveals a background terminal session when focusing its handle; replays captured launch config when focusing a background agent session; reveals background terminal sessions with the freshest PTY title; renames background terminal handles without requiring a visible tab; keeps a background terminal handle stable while reveal adoption is racing. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-07.spec.ts: resolves tui-idle when a stale Codex prompt is followed by Antigravity readiness; returns an agent-neutral blocked wait result for update prompts; returns an agent-neutral blocked wait result for workspace trust prompts; returns an agent-neutral blocked wait result for cwd selection prompts; returns a blocked wait result for Codex model migration prompts; returns a blocked wait result for Codex startup hook review prompts; returns an agent-neutral blocked wait result for generic interactive prompts; splits text and enter writes for background terminal handles; types the lead line for %s: %s; submits through the agent-specific PTY timing policy for %s. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-06.spec.ts: waits for exit on background terminal handles; keeps retained PTY transcript memory when controller refresh fails; resolves tui-idle from an Antigravity ready prompt preview; resolves Antigravity ready prompts with newline-heavy pasted tails without splitting; resolves live-leaf tui-idle from an Antigravity ready prompt preview. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-03.spec.ts: spawns the available Qoder command for a captured same-session resume: %s; does not use the local Windows shell setting for remote Windows bare agent creates; matches canonical bare agent commands when a command override is configured; keeps non-bare agent command terminal creates unchanged; keeps disabled bare agent command terminal creates unchanged; injects runtime hook receiver env into terminal sessions; creates background terminal sessions for a $label; creates background terminal sessions for a $label; enables Claude Agent Teams only for direct Claude launches when configured in-process; reveals Claude Agent Teams launches with the rewritten launch config; preserves Claude Agent Teams for sequenced Claude launches. src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness.spec.ts: creates visible terminal sessions without asking the renderer to focus a tab; asks the pty controller for the requested shell instead of a startup command; knows the agent a flagged launch command names before any process read; retires a flagged command pane identity when the command exits; retires only receipted restored PTY authority on command completion and exit; forgets synthetic handles when disconnected PTY records are pruned. src/main/runtime/orca-runtime-tests/headless-snapshots.spec.ts: returns OSC titles from headless main terminal snapshots; adopts renderer-seeded titles into headless main terminal snapshots; returns cwd metadata from seeded headless main terminal snapshots; adopts OSC7 host metadata from seeded headless terminal scrollback; falls back to the renderer snapshot for hidden-output recovery without headless state; keeps an empty headless snapshot authoritative for hidden-output recovery; advances the absolute output sequence across a daemon stream gap; emits explicit OSC 9999 agent status from runtime PTY data. src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-02.spec.ts: falls back to the provider snapshot for a restored PTY with no mounted renderer; falls back to the available mirror when authoritative provider history is unavailable; keeps an empty renderer snapshot when the provider has no retained content; keeps restored provider history authoritative after later live output; uses provider alternate-screen state while a partial model is unsafe; prefers the tracked title over the headless emulator lastTitle; keeps the cursor-agent literal in record-fallback snapshots only without a tracker title; touches mobile snapshots once for decorative spinner ticks, again on idle. src/main/runtime/orca-runtime-tests/local-worktree-creation-part-02.spec.ts: creates a same-repo PR branch override from a resolved head SHA and matching push target; skips broad remote fetch for an existing full-SHA PR base; creates a selected Bitbucket PR branch override from a matching remote branch; suffixes an existing PR when a matching push target lacks selected PR metadata; suffixes a matching push target branch when selected PR metadata has no PR number; suffixes a matching push target branch when the existing PR is different; suffixes a selected PR remote conflict when the PR lookup fails; checks out an unused runtime PR branch only when it is at the resolved head SHA; suffixes only the runtime worktree path when an exact PR branch checkout path exists. src/main/runtime/orca-runtime-tests/local-worktree-creation.spec.ts: returns runtime local base update suggestions from addWorktree; creates a runtime local worktree from a usable persisted local branch base; does not create a runtime local worktree when the refresh fails and no local base ref exists; creates a branchNameOverride worktree from the selected matching remote base ref. src/main/runtime/integrations/skill/orca-runtime-skill-recovery.test.ts: continues skill management after startup recovery fails. src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-detached-routing.spec.ts: uses bounded ownership lookup for direct arrivals while the agent cannot take input; wakes a bound Run waiter when same-Run direct mail arrives; keeps an unowned detached-recipient message in its direct mailbox; uses primary-key lookups for bounded routing updates. src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-delivery.test.ts: remove only literal registration import/call pairs import './orchestration-mailbox-pointer-cli-command.spec'; no additional authored credit. src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-pointer-cli-command.spec.ts: renders the %s CLI command in a mailbox pointer. src/main/runtime/rpc/methods/terminal/terminal-multiplex-link-estimate.test.ts: sizes a slow high-latency link near twice its bandwidth-delay product; never paces a LAN, even when its client parses slowly; never paces a fast link; returns to legacy windows when the path RTT jumps. src/main/runtime/rpc/methods/terminal/terminal-snapshot-scrollback-rows.test.ts: steps down the row ladder when history is over the byte budget; tries the larger first row count, then the usual ladder within the same byte budget. src/main/runtime/rpc/server/pairing/network/windows-default-route-interfaces.test.ts: returns unknown when route inspection fails or emits malformed data; does not inspect routes outside Windows. src/main/runtime/rpc/server/pairing/pairing-offer-owner-cli.test.ts: is refused to a paired %s client; reports a failed widening instead of advertising an unreachable address. src/main/runtime/rpc/terminal-multiplex-end-verdict.test.ts: reports exited only when the owning runtime completes the exit waiter; reports unverifiable when the runtime cannot observe the exit waiter; reports unverifiable when a disconnected PTY resolves with unknown liveness. src/main/runtime/session-graph/headless-runtime-graph.spec.ts: lets a session tab inventory settle on a host no renderer publishes for. src/main/runtime/session-graph/runtime-graph-standing-contracts.test.ts: remove only literal registration import/call pairs import { registerHeadlessRuntimeGraphTests } from './headless-runtime-graph.spec', registerHeadlessRuntimeGraphTests(); no additional authored credit. src/main/runtime/session-tabs/structured-conversation-tab-title.test.ts: bumps the stored snapshot version only when the title changes. src/main/runtime/session-tabs/terminal-close-observed-exit.test.ts: keeps the healthy aggregate verification and delayed physical exit behavior; uses a stamped exit for the incarnation that was actually being closed. src/main/runtime/terminal/identity/terminal-identity-probe.test.ts: answers live for a structured worker without touching the PTY graph; answers live for a PTY handle the runtime still holds; runs the full leaf check for a handle with no live PTY; answers not-live for a stale handle; propagates \"could not look\" rather than reporting it as a dead handle. src/main/runtime/terminal/layout/paired-desktop-server-writes-layout-owner.test.ts: names the tab in main’s layout through terminal.rename; takes a window-style layout.apply close as already stopped, so the terminal runs on. src/main/runtime/terminal/lifecycle/pty-lifecycle-generation-retention.test.ts: retains no lifecycle generation after a spawn/exit cycle. src/main/runtime/terminal/lifecycle/run-terminal-user-open.test.ts: reads a freshly spawned terminal as used once a user opens its tab, not on a probe; keeps the open mark on the process a user open starts. src/main/runtime/terminal/surface/terminal-surface-replies-window.test.ts: from a desktop window that mounts both panes; from a server with no window. src/main/runtime/terminal/surface/workspace-layout-projection.test.ts: carries views for a partition that holds none yet. src/main/runtime/terminal/view/terminal-subscribe-exit-waiter-leak.test.ts: releases a signalled exit-waiter when the signal aborts. src/main/runtime/terminal/wait/orca-runtime-exact-worker-provider-session.test.ts: selects a local hook status for a local pane. src/main/runtime/terminal/wait/prime-agent-screen-readiness-transcripts.test.ts: keeps the footer and the bare caret on screen mid-turn; %s: the screen alone reads ready during %s. src/main/runtime/workspaces/startup/runtime-worktree-agent-startup.test.ts: uses per-launch arguments and preserves launch telemetry; attributes a startup agent whose caller named no surface as unknown; launches %s bare for an absent or blank prompt; attributes a %s draft launch named %s as %s; merges an automation's extras over the host defaults; threads worktree-create extras into the startup build; returns an enabled requested agent without detecting; returns the default when nothing was requested; detects instead of using the default when the requested agent is disabled; starts no agent when the default is blank; detects an enabled agent on this host when nothing usable was named; starts no agent when detection finds none. src/main/runtime/workspaces/startup/runtime-worktree-startup-readiness.test.ts: pastes and submits through composer readiness, never typing raw input; types the follow-up on WSL or SSH-to-Windows once the agent is in front, as before; cleans up the deadline when the composer was already captured; a draft that is not submitted is pasted on the box cursor, as before; takes the box after the grace when the row never comes, whatever repaints; takes the box at the deadline when the grace would outlast the budget; lets a dialog on screen veto a grace; refuses the deadline inside a pending grace while a shell is in front; takes the box at the deadline inside a pending grace with the agent in front; takes the box at the deadline after a refused grace once the agent is in front. src/main/skills/skill-install-transaction.test.ts: installs, previews unchanged bytes, and updates a clean receipt-owned skill; preserves the old version after a %s filesystem failure. src/main/speech/model-manager-download-resume.test.ts: requests the remaining bytes when a clean range response ends before the file total; bounds a server that advances by pathologically tiny segments forever. src/main/ssh/config/ssh-config-parser.test.ts: parses a basic host block; parses multiple host blocks; skips wildcard-only Host entries; skips Host entries with only pattern characters; parses IdentityFile with ~ expansion; parses Windows-style IdentityFile with ~ expansion; parses quoted scalar values like OpenSSH; parses equals-form scalar directives; parses IdentityAgent with ~ expansion; parses IdentitiesOnly; parses GSSAPIAuthentication; keeps the first GSSAPIAuthentication value like OpenSSH; parses ProxyCommand, ProxyUseFdpass, and ProxyJump; ignores comments and blank lines; handles case-insensitive keywords; stops current block on Match directive; returns empty array for empty input; creates one parsed host per concrete alias on a multi-pattern Host line; applies identity agent settings to every concrete alias on a multi-pattern Host line; defaults port to 22 for invalid port values; converts hosts to SshTarget objects; uses host alias as hostname when HostName is missing; skips hosts that are already imported; defaults username to empty string when not specified; carries through identityFile, identityAgent, identitiesOnly, proxyCommand, and jumpHost; carries through gssapiAuthentication; imports duplicate aliases only once and keeps the first concrete host; maps hosts for the picker and flags aliases already in Orca; de-dupes aliases and defaults missing fields; parses hostname, user, port from ssh -G output; collects multiple identity files; parses forwardagent yes; defaults port to 22 when missing; returns empty hostname when missing; returns undefined user when missing; handles empty output; skips lines without spaces; parses proxycommand and filters \"none\"; parses proxyusefdpass yes; parses proxyjump and filters \"none\"; handles ~ expansion in identity file paths; handles Windows-style ~ expansion in identity file paths; parses identityagent with ~ expansion; preserves identityagent none so auth can disable agent fallback; parses identitiesonly yes; parses gssapiauthentication; parses controlmaster options and filters controlpath none. src/main/ssh/config/ssh-known-hosts-source.test.ts: splits the space-separated list ssh -G prints on one line; expands ~ in a reported path; keeps a double-quoted path containing spaces whole; falls back to the default files when ssh -G reported nothing; drops an explicit none without falling back to the defaults; splits both known_hosts lists on one line each; reads StrictHostKeyChecking, including accept-new; reads HostKeyAlias and prefers it for the lookup; reads the non-default port; reports that the lookup came from an alias, so the port is not appended; reports no alias when the dialed host is used; unions the entries of every file; skips a path that is a directory; returns nothing when no file can be read; reports nothing unreadable when every file parses; does not count an empty file as unreadable; prefers HostKeyAlias over the resolved hostname; uses the dialed host, because a resolved hostname can just echo the label; still prefers an explicit HostKeyAlias over the dialed host; falls back to the dialed host when nothing was resolved; is rejoined when the split fragments resolve to nothing; leaves a single unresolvable path alone rather than inventing one; expands the __PROGRAMDATA__ token rather than passing it through as a path; does not rewrite a path that merely BEGINS with the token characters; keeps a drive-letter path with mixed separators intact; splits a spaced Windows home into the fragments the rejoin has to put back. src/main/ssh/config/ssh-known-hosts.test.ts: reads the algorithm from the blob rather than trusting the line; rejects %s; refuses a malformed blob: %s; uses the bare host on the default port; tries the bracketed form first and falls back to bare off-port; matches an exact line; matches case-insensitively; reports a changed key of the same type; reports unknown for %s; matches any host in a comma list; matches the bracketed form on its port; does not apply a bracketed entry to the default port; falls back to a bare line when off-port; never reports a change from the fallback pass; matches a bare literal on the default port; matches a bracketed literal on its port; reports a change for a literal; handles %s; still reports a change for a different key on a revoked host; skips a line carrying an unrecognised marker; does not report a change when only another key type is on file; matches within the same type; accepts CRLF terminators; skips blanks, comments and surrounding whitespace; accepts a hit regardless of which file holds it (%s); never brackets the alias, whatever the port; still brackets an ordinary host on a non-default port; matches a bare alias entry on a non-default port; still accepts the unmodified key field; accepts a hashed entry whose salt is a full SHA1 digest; still accepts the unmutated ssh-keygen -H vector; falls back to the bare host line on a non-default port, as ssh did; refuses a key type it has not seen for a host it knows, as ssh did. src/main/ssh/connection/ssh-connect-config.test.ts: returns undefined when no default keys exist; returns the first existing key file; probes regular and FIDO2 keys in stable default order; keeps a regular default ahead of a malformed FIDO2 default; uses target host/port/username; falls back to resolved config when target fields are empty; keeps imported endpoint fields as the fallback when ssh -G is unavailable; sets readyTimeout to CONNECT_TIMEOUT_MS; sets keepaliveInterval to 15s; enables keyboard-interactive auth so MFA challenges can be answered; uses agent auth when no explicit key and SSH_AUTH_SOCK is set; enables agent forwarding when OpenSSH config requests it and an agent is available; does not enable agent forwarding without a usable agent; resolves IdentityAgent SSH_AUTH_SOCK from the environment; uses the Windows OpenSSH agent pipe when no environment socket is available on Windows; wraps agent auth with IdentityFile filtering when IdentitiesOnly is enabled; applies a manual target IdentitiesOnly setting when ssh -G reports it off; includes unencrypted target.identityFile auth when an agent is available; defers encrypted target.identityFile auth when an agent is available; uses keyFile auth when target.identityFile is set and no agent is available; includes unencrypted resolved identityFile auth when an agent is available; defers a default-path resolved identityFile to the no-agent retry; offers the keyboard-interactive challenge when the agent defers no key; provides fallback key when no agent is available; can force private key inclusion for the post-agent fallback path; falls back to resolved proxyCommand; returns structured jump-host config for target.jumpHost; returns structured jump-host config for resolved proxyJump; returns undefined when no proxy is configured. src/main/ssh/connection/ssh-connection-auth-fallback.test.ts: resolves OpenSSH config using configHost when present; tries ssh-agent before reading an explicit private key; falls back to direct private key auth when agent auth fails; falls back to direct private key auth after too many agent authentication failures; answers bounded keyboard-interactive challenges such as Duo 2FA. src/main/ssh/connection/ssh-connection-store.test.ts: lists picker suppression aliases without consulting re-adoption tombstones; getTarget delegates to store; addTarget generates an id and persists; saves the CLI control switch as given, with no consent stamp; addTarget stamps source as manual by default; addTarget preserves an explicitly provided source; inserts a new config host stamped as ssh-config; asks the parser for all hosts — reconciliation happens in the store; updates an existing config-sourced target when the port changed; refreshes gssapiAuthentication on sync; never overwrites a manual target that owns the alias; does not rewrite an unchanged config-sourced target; returns empty array when nothing changed; tombstones a deleted config-sourced host so re-import skips it; suppresses a deleted manual target from config discovery; re-adding a deleted host reclaims its alias so sync stops suppressing it; editing a target reclaims its alias from the deleted set; records a tombstone when removing any user-facing target; re-adopts orphaned repos when the same host is re-added. src/main/ssh/connection/ssh-connection.test.ts: transitions to connected on successful connect; captures the negotiated SSH server key fingerprint; allows concurrent exec commands for ssh2 transport; removes startup listeners after ssh2 connect succeeds; scopes lifecycle events and pending handshake timers to one mock client; enables TCP_NODELAY on the new ssh2 client after a reconnect cycle; transitions through connecting → connected states; reports error state on connection failure; disconnect cleans up and sets state to disconnected; getTarget returns a copy of the target; getState returns a copy of the state; throws when connecting a disposed connection. src/main/ssh/orcad-migration-stuck-host-profiles.test.ts: never leaves a running terminal behind; is offered only when leaving saved state behind would clear the refusal. src/main/ssh/orcad-runtime-maintenance.test.ts: keeps a connect from retrying a build an explicit Update also failed; offers Force when Update was refused by policy; forwards anew after an activation, since the new slot may bind another port; passes a refusal through and leaves the server linked; forwards anew once a serving slot is restored, which may have bound another port. src/main/ssh/port-forwarding/ssh-port-forward.test.ts: reports the port the OS bound when an ssh2 forward asks for port 0; adds an ssh2 port forward and returns entry; adds a system SSH port forward when no ssh2 client is available; reports the port a system SSH forward resolved when asked for port 0; passes resolved OpenSSH config to system SSH port forwards; disposes a system SSH tunnel when removing the forward; lists forwards filtered by connectionId; removes a forward by id; awaits forward close when removing a forward for user actions; returns null when removing nonexistent forward; removes all forwards for a connection; dispose removes all forwards; stores label in the entry; preserves the existing id when updating a forward succeeds. src/main/ssh/ssh-channel-multiplexer.test.ts: sends a JSON-RPC request and resolves on response; assigns unique request IDs; sends notifications without expecting a response; dispatches incoming notifications to handler; sends one keepalive frame per cadence tick; drives keepalive sends AND dead-link detection from a single interval; resolves false immediately on a disposed mux; throws on request after dispose; reports isDisposed correctly; clears registered handlers on dispose; does not retain handlers registered after dispose. src/main/ssh/system-transport/system-ssh-forward-process.test.ts: spawns exactly the argv the orphan matcher is given, LogLevel=INFO included; runs port forwards unmultiplexed even when ssh_config disables muxing; preserves manual target port and identity options in the forwarded ssh command; does not spawn ssh when the requested local forward port is already in use; spawns ssh after the requested local forward port preflight succeeds; resolves startup after the grace period when ssh keeps running; sends SIGTERM then SIGKILL when the process does not exit; does not resolve stop until the process exits. src/main/ssh/system-transport/system-ssh-loopback-route.test.ts: dials the held forward ahead of the alias so OpenSSH keeps these over ssh_config; drops a manual target's own port and proxies, which would fight the route; never routes a forward, whose argv must stay stable for orphan recovery; %s → %s; opens the forward over the real proxy, then proves a login over the route; lands the forward on the sshd and known_hosts name the direct route resolved; holds the forward with server-alive probes; never lets the background forward or probe ask for credentials; starts no forward when admission refuses the route; stops the forward when sshd refuses logins over it; stops the whole forward process tree on Windows, once; reports a forward that already exited before anyone listened for it. src/main/startup/browser-process-user-agent-ordering.test.ts: explains admission refusal before a desktop launch exits; explains an orcad holding the profile instead of exiting silently; does not acquire profile admission for a duplicate launch; executes after the dev app name and before later preflight work; exits and releases admission after pending profile move recovery fails; keeps Linux background startup failures console-only and immediate; keeps Linux serve startup failures console-only and immediate. src/main/startup/quit/quit-path-durable-write-blocking.test.ts: store.flushAsync() issues no synchronous fs syscalls; store.flushAsync() also moves the active-view and github-cache sidecars off the thread; stats.flushAsync() issues no synchronous fs syscalls; Grok session cleanup issues no synchronous fs syscalls; stats.flushAsync() closes out live agents before it returns, not when its write lands; a stalled mount leaves the event loop live instead of parking it; store.flushAsync() is one idempotent final barrier; store.flushAsync() resolves instead of throwing when the profile mount rejects writes. src/main/stats/agent-session-transition-recorder.test.ts: counts a hook-only agent that never writes an agent-shaped terminal title; never opens a session from a replayed or disk-restored working status; still closes a live session when the terminating status arrives as a replay; counts one session per turn across repeated working/done cycles; closes an open session when its pane is torn down; bounds the mirror and closes what it evicts; stops the session when the main agent settles and only a watch loop holds the row working; keeps the session open while a subagent outlives the main agent, and closes it when the child settles; dates the stop by the evidence when a shell outlives the last subagent; opens a new session dated by the observation when the main agent resumes after monitoring; never dates a reopen before the close a fact-less OSC repaint caused; dates the first live row after a restored one by the evidence, not the restored clock; treats an unchanged answer as a snapshot, never a transition; opens only on a live working edge; closes only a session it opened. src/main/text-generation/commit-message-text-generation-model-discovery.test.ts: returns static catalog models without spawning for static agents; discovers dynamic models through the agent CLI; discovers dynamic models through the configured agent command override; falls back to static models when dynamic discovery returns no parseable models; falls back to the first discovered non-Pi model when its static default is unavailable. src/main/text-generation/pull-request-context.test.ts: does not fetch unrelated fork remotes before generating PR context; bounds exact remote-ref probe concurrency for a large remote list; reports no branch change because PR context preparation is read-only; keeps a remote-qualified base when the selected base includes the remote. src/main/text-generation/source-control-local-process.test.ts: asks the supervisor to stop and leaves its group to it; signals nothing once the supervisor has exited; stops an agent that ignores its stdin end through its supervisor. src/main/updater/linux-package/linux-package-update-recovery.test.ts: retains the downloaded package with the digest from the event metadata; requires a string downloaded path; accepts an uppercase extension; requires a non-empty string version; matches an absolute file URL by basename; accepts duplicate entries that agree on the digest; refuses an entry with a missing or non-string digest; refuses a digest that is not base64 at all; refuses a malformed percent-encoded URL; refuses a missing or non-array file list; tolerates a non-object event; replaces the retained artifact with a newer download; keeps the retained artifact when a new download has no usable digest; keeps the retained artifact when an unrelated download event arrives; clears the retained artifact; preserves the artifact across a recheck of the same version; clears the artifact when another version takes over; preserves the artifact for an unknown or empty version; is a no-op without a retained artifact; returns the built command and package file name for a verified package; reports missing without a retained artifact; propagates a package-manager discovery failure; rejects a well-formed digest that belongs to another file; never hashes a package that a malformed digest failed to arm; rejects a path outside the cache root; rejects the cache root itself; rejects a package in the updater directory itself; rejects a pending directory that is a symlink out of the cache; performs one hash pass for concurrent requests; revalidates once the in-flight pass settles; does not reuse an in-flight pass for a different artifact; starts a fresh proof when the same package is captured again; returns the verified package path; returns missing without a retained artifact. src/main/updater/releases/updater-prerelease-feed-readiness.test.ts: accepts a GitHub %s asset redirect as ready; reports a GitHub asset request error as unavailable; reports not-ready with a verified last-good tag when the newest assets are unavailable; does not classify a non-positive tag limit as feed unavailability; reproduces the v1.4.142 publishing incident as not-ready; reports transport failures as unavailable instead of not-ready; treats an explicit asset 404 as not-ready when another asset is unavailable; accepts absolute manifest asset URLs without rewriting them to release asset paths; returns not-ready with an older ready update as last-good while newest is publishing. src/main/updater/releases/updater-release-builds.test.ts: lists hourly builds from the dedicated repo, newest first; lists daily builds from the dedicated repo, newest first; separates stable from rc in the shared main repo; skips drafts and unparseable tags; keeps a composed release title and drops one that repeats the tag; hides builds that published no artifact for this platform; returns an empty list when no build has this platform artifact; keeps mac builds visible on macOS regardless of the Windows leg; resolves the platform installer download url; leaves the installer url null when the release published no installer; tolerates a release whose assets are missing or malformed; sends the local gh token as a bearer header when one is available; sends no authorization header when gh has no token; retries unauthenticated once when GitHub rejects the token; does not retry a 401 that was already unauthenticated; falls back to the per-IP bucket when the token is rate limited and tells the gh breaker; reports a secondary limit carrying retry-after without retrying or tripping the breaker; records a primary limit in the token scope %s; keeps %s authenticated when only %s is blocked; skips the token while its scope %s is blocked; surfaces a rate limit with its reset time and a sign-in hint when unauthenticated; omits the sign-in hint when the rate-limited request was authenticated; treats 429 as a rate limit; reports a 403 without rate-limit headers as a plain HTTP error; reports a missing hourly repo distinctly; is null when GitHub sent no reset; prefers retry-after over the primary reset epoch; falls back to the primary reset epoch when there is no retry-after; reads retry-after as seconds; reads retry-after as an HTTP date; pins an hourly tag at the hourly repo download path; pins a daily tag at the daily repo download path; pins a stable tag at the main repo download path; rejects a tag that is not a version. src/main/updater/updater.build-channel-selection.test.ts: uses the display label in the unsupported-platform %s pinned-build error; still pins %s from an unsigned Windows dev build; restores ordinary release checks after local build selection fails; opts into the RC channel when checkForUpdatesFromMenu is called with includePrerelease; pins the generic feed to a perf-tagged prerelease when requested; surfaces no-update feedback when no newer perf-tagged prerelease exists; keeps prerelease publishing-window misses on the generic retry path; leaves the feed URL alone for a normal user-initiated check. src/main/updater/updater.check-preflight.test.ts: ignores a stale update-not-available event after a new check starts preflight; deduplicates repeated manual checks while the immediate checking status is active. src/main/updater/updater.prerelease-fallback.test.ts: retries a prerelease check once against the previous feed tag when the manifest is missing; surfaces a promise-only prerelease fallback failure after the primary error event. src/main/updater/updater.publishing-window-feed.test.ts: repins the generic feed to the newest RC tag for a prerelease user; repins the generic feed to a newer stable tag for a prerelease user; pins a stable fallback when Atom has no newer prerelease; uses last-good concrete feed when a user-initiated check lands during publishing; can offer an older fully published update while the newest release is publishing; keeps background publishing-window fallback on the short retry cadence. src/main/updater/updater.quit-and-install.test.ts: surfaces an accepted retry before electron-updater emits download progress; defers quitAndInstall and runs its launcher within the launch PATH scope; runs pre-quit cleanup before local PTY cleanup during update install; keeps optional pre-quit cleanup fail-and-continue behavior by default; ignores duplicate quitAndInstall requests while the shared delay is pending; arms the forced-exit watchdog once the install commits; disarms the forced-exit watchdog when sync install error recovery keeps the app open. src/main/window/createMainWindow-markdown-editor-focus.test.ts: ignores traffic light sync IPC on non-macOS; still intercepts Cmd+Shift+B and Cmd+Alt+B when the markdown editor is focused; coerces non-boolean setMarkdownEditorFocused payloads to false; opens a table-aware context menu synchronously without a renderer query; builds the plain edit menu for the one right-click the renderer marks as plain text. src/main/window/createMainWindow-renderer-crash-recovery.test.ts: notifies the caller when the renderer process is gone; passes the renderer webContents id through crash recording and recovery callbacks; forwards expected renderer teardowns so the recorder can diagnose suppression; reloads the app shell after an unexpected renderer process loss; does not reload after renderer loss when recovery is disabled; stops auto-reloading after a rapid renderer crash loop trips the breaker. src/main/window/dashboard-popout-window.test.ts: updates the title after language initialization and unsubscribes when closed; lets its preload expose saved WSL hosts in serve-only, and passes nothing otherwise; creates a native-frame window with the shared preload and no webview surface; shows the window on ready-to-show; loads the prod file entry; loads the dev server URL when in dev; focuses the existing window instead of creating a second one; trusts only the live popout webContents; restores a minimized window when re-requested; restores valid persisted bounds; discards off-screen persisted bounds and falls back to defaults; persists bounds on resize after the debounce, guarding near-minimum sizes; keeps saving bounds after a vetoed quit and freezes them only on an allowed quit; closeDashboardPopout closes an open window; applies the persisted app zoom level on dom-ready; follows app zoom changes while open and unsubscribes on close; zoomDashboardPopoutIfFocused steps the popout zoom only while focused; handles the zoom-in chord via before-input-event and ignores other keys; handles mouse-wheel zoom requests outside before-input-event; respects zoom keybinding overrides for keyboard and mouse-wheel paths. src/main/window/dropped-path-preparation.test.ts: opens and stores each unique source once as drop size grows tenfold; passes ordinary paths without copying for %s; preserves ordinary successes and copied successes when another file fails; serializes copy requests from different owners; reports all lost paths without a shared reason when their failures differ. src/main/window/main-window-updater-deferred-setup.test.ts: releases all 64 completed fallback handles without repeating initialization; keeps setup after ready-to-show and releases its fallback afterward; preserves the 15-second fallback when first paint never arrives; preserves destroyed-window guard reads before and at the fallback deadline; keeps the exact %s error and releases its completed fallback; keeps the exact fallback %s error without retrying initialization; preserves pending manual setup after failed ready registration; keeps setup options, live store reads, nudge writes and required quit flush. src/main/worker-threads/worker-thread-request-queue.test.ts: posts one request at a time and in the order it was dispatched; fires a posted call at its own deadline; stops respawning and fails the rest of the queue once deaths hit the cap; clears the death count when a fresh burst starts from full idle. src/main/workspace-hooks/hooks-setup-runner-script.test.ts: builds Windows runners for newline-heavy scripts without line-array splitting; builds POSIX runners without regex-wide CRLF normalization; writes POSIX setup runners for shebang-declared scripts on native Windows paths; keeps batch setup scripts on cmd.exe when the terminal is Git Bash; hands a Git Bash pane a launch command MSYS cannot rewrite for a cmd runner; replays interpreter flags declared on the shebang line; preserves cmd.exe setup runner semantics for configured cmd users; keeps POSIX runner behavior on POSIX platforms; waits when either local or project policy requires completed setup; marks setup-runner terminals for the always-on credential guard; maps git-bash to POSIX setup launch metadata on Windows; falls back to the cmd runner when the git-bash setting has no installed Git Bash; keeps the cmd runner for a non-Git bash such as Cygwin; keeps the cmd runner for a bare bash whose flavor cannot be resolved; uses the POSIX runner for a bare bash that resolves to Git Bash; uses the POSIX runner for an extension-less Git Bash path; preserves the existing cmd runner for PowerShell terminals; preserves cmd setup compatibility when a Windows-host project has a WSL shell setting; classifies an installed explicit Git Bash executable as a POSIX runner; falls back to the cmd runner when the explicit Git Bash path no longer exists. src/main/workspaces/catalog/repo-git-remote-identity-enrichment.test.ts: schedules remote identity enrichment without blocking the caller; probes a drive project whose runtime is WSL %s; sweeps a local repo: %s; probes an SSH row that carries only executionHostId on its own host; keeps same-path rows on two different SSH hosts from sharing one backoff; coalesces concurrent probes for the same repo location; caches no-identity probes briefly so list calls do not retry every time; does not rewrite the no-remote marker on a later retry; resolves a settled no-remote repo once it gains a remote; does not re-probe a resolved identity before the refresh window elapses; re-probes a resolved identity after the refresh window elapses; bounds re-probes per sweep so a large repo list drains gradually; forgets a removed repo location so its deadline cannot outlive the repo; keeps a surviving repo backoff when a sibling repo is removed; probes again when the same location is re-added after its probe was retired; coalesces concurrent sweeps instead of running one pass per list call. src/main/workspaces/creation/preparation/worktree-create-preparation.test.ts: preserves create priority through claim probes on %s; starts the checkout only once the async workspace root resolves; still deduplicates when both callers await the same pending root lookup; namespaces native Windows preparation directories for long paths; deduplicates preparation for the same repo, base, runtime, and workspace root; does not spend a divergence walk when the base matches exactly; claims when the two sides spell the same ref differently; evicts a repo's own stale preparation before another repo's; still discards armed checkouts when the project runtime needs repair; routes preparation and finalization through the selected WSL runtime; retries stale cleanup after a transient listing failure; does not discard a detached worktree with caller-controlled preparation metadata; does not re-arm after an isolated create; re-arms a preparation once creates arrive in a burst; holds the re-arm checkout until the create runs the deferred thunk; starts one explicit prefetch after the create completes; does not re-arm when finalization failed; reports a pending create while a stale-cleanup scan is running. src/main/workspaces/removal/local-worktree-removal-recovery.test.ts: recovers Git for Windows partial filesystem deletion failures; finishes a clean non-force deletion after Git leaves a Windows directory behind; recovers localized Windows failures after Git already removed the registration; does not recover unrelated localized failures while Git still owns the row; finishes a macOS deletion Git deregistered before failing with Directory not empty; leaves an orphaned checkout to the orphan cleanup instead of deleting it; prunes and strictly verifies on the selected WSL host without deleting files or branches. src/main/workspaces/removal/worktree-removal-safety.test.ts: rejects deleting a worktree that contains another registered worktree; rejects POSIX home directories even when host homedir has a different path shape; refuses a home the host reported even when no path rule recognises it; refuses the Windows host's home directory from a POSIX client; refuses the Windows host's home directory even when the host reported nothing. src/main/wsl/discovery/distro-catalog.test.ts: retries asynchronous discovery after a transient wsl.exe failure; retries synchronous discovery after a transient wsl.exe failure; retries asynchronous discovery after wsl.exe reports no distros yet; retries synchronous discovery after wsl.exe reports no distros yet; bounds the wsl.exe spawn rate while no distros are installed; bounds the asynchronous spawn rate while no distros are installed; still caches a non-empty distro list for the process lifetime; re-probes a docker-desktop-only machine once a user distro can appear; backs off while the list keeps coming back empty; backs off after repeated distro-list failures; caps the empty-list backoff at five minutes; keeps reporting an empty result after it goes stale; keeps reporting a known distro list indefinitely; bounds cached homes while retaining the most recently used distros; still lists distros, and an excluded distro home probe fails like any other probe; gives the async home probe time for a cold boot instead of killing it at 5 s; retries availability after a probe timeout instead of latching false; bounds the probe rate while the failure window is open; caches a successful probe for the process lifetime; names an explicit spawn directory, so no deleted cwd can read as ENOENT; shares one wsl.exe spawn between concurrent probes; keeps reporting the last observed answer after it goes stale; holds a definitive failure far longer than a timeout when %s; backs off after repeated probe failures; re-probes a seeded retryable failure once its window lapses; re-probes availability once a distro list succeeds after %s; does not drop an availability failure for an empty distro list; keeps reporting unavailable off Windows without probing. src/main/wsl/discovery/wsl-distro-holder.test.ts: runs a busybox-safe loop through --exec and names the distro; spawns a detached-style holder, records it, and waits for the distro to run; a holder exiting with code 1 notes its distro may have stopped (E9); rejects a pid whose command line is not our holder for that distro; cleans up stale and corrupt records; keeps a holder and its record when release cannot verify it; reports unverifiable when the command line is unreadable even with a matching pid; release kills a verified holder and removes its record; release never kills a pid that is no longer our holder; reports a spawned holder exit so liveness can re-check. src/main/wsl/filesystem/wsl-guest-drive-mountinfo.test.ts: skips 9p shares that are not drvfs, and malformed lines. src/main/wsl/orcad/wsl-orcad-deploy-app-update.test.ts: plans the update on the census the running orcad reports, not an unknown one; forwards force to the update planner; does not serve the incumbent past a refusal that is not a wait; does not re-activate the build this host rolled back from; labels the launch with the build the adoption found serving, not the stale record; defers while another run holds the host fence; lets an explicit force deploy past both skips; names a newer host refusal apart from a rolled-back one, so only Force is offered; updates an older host as before, without asking to adopt it; never asks the incumbent when it already runs this build. src/renderer/src/components/agent/agent-launch-picker-acquisition.test.ts: keeps a completed listing usable when the host rejects the wait parameter. src/renderer/src/components/feature-tips/feature-tip-telemetry.test.ts: delivers to chat-default users in all targeting while holding out not-switched users. src/renderer/src/components/native-chat/composer/pickers/use-native-chat-side-chat-command.test.ts: completes the row on a pick, even when the command is already typed; ignores a pick of the row while side chats are unavailable. src/renderer/src/components/native-chat/media/images/native-chat-image-copy.test.ts: explains a too-large refusal that arrives through the IPC error prefix. src/renderer/src/components/native-chat/messages/actions/native-chat-fork-launch.test.ts: keeps the question with the caller and says once that it never went; tells the user to check the side chat when delivery is unconfirmed; reports a delivered question as sent, silently. src/renderer/src/components/native-chat/messages/actions/native-chat-side-chat-fork-point.test.ts: decides each of %i tool-only turns once per layout, and nothing without a listener. src/renderer/src/components/native-chat/messages/actions/use-native-chat-fork.test.tsx: places a side chat whose question was %s: %o. src/renderer/src/components/terminal-pane/provider-notices/agent-presence/agent-terminal-presence.test.ts: calls back once for %s; stops watching once unsubscribed. src/renderer/src/components/terminal-pane/pty-connection/emulation/pty-connection-mode2031-raw-subscription.spec.ts: records a mode 2031 subscribe from the raw chunk boundary without answering. src/renderer/src/components/terminal-pane/pty-connection/input/pty-connection-deferred-input-forwarding.spec.ts: routes terminal input through deferPtyInput so the host can withhold it; forwards terminal input directly when the host supplies no deferPtyInput. src/renderer/src/components/terminal-pane/pty-connection/notifications/pty-connection-terminal-bell-attention.spec.ts: forwards onBell to pane attention and notification policy; hands the bell to the attention module with its pane even when pane attention is off. src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-dropped-output-snapshot-healing.spec.ts: repaints from the main-owned snapshot when main drops pending output at the cap. src/renderer/src/components/terminal-pane/pty-connection/output/pty-connection-fresh-native-follow-reset.spec.ts: retries a fresh-spawn native follow reset when renderer dimensions return. src/renderer/src/components/terminal-pane/pty-connection/spawn/unbound-pane-spawn-recovery.test.ts: requests a tab remount for an unbound spawn; leaves recovery to a remote transport that armed its own retry; requests a remount when the transport reports no recovery of its own; settles the spawn as failed before requesting a remount; prefers the restored leaf id when reporting the anomaly; falls back to the pane leaf id when no restored leaf exists. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-foreground-agent.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionDeferredInputForwardingTests } from '../input/pty-connection-deferred-input-forwarding.spec', registerPtyConnectionDeferredInputForwardingTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts: structural support changed only; no new authored removal credit. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionFreshNativeFollowResetTests } from '../output/pty-connection-fresh-native-follow-reset.spec', registerPtyConnectionFreshNativeFollowResetTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts: remove only literal registration import/call pairs import { registerPtyConnectionTerminalBellAttentionTests } from '../notifications/pty-connection-terminal-bell-attention.spec', registerPtyConnectionTerminalBellAttentionTests(); no additional authored credit. src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-delivery-interest.test.ts: registers interest on the first sidecar and releases on the last unsubscribe; releases sidecar interest only once for repeated unsubscribes; does not let an eager pre-mount buffer defeat hidden delivery gating; keeps eager buffers outside delivery interest when the PTY exits before mount; lets a sidecar exclusively own interest while an eager buffer overlaps. src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-push-reattach.test.ts: blackholed delivery reproduces the wedge: no handler dispatch, no ACK ever. src/renderer/src/components/terminal-pane/pty-transport/ipc/ipc-pty-opencode-model.test.ts: sends preferences to the execution host and attaches only to its returned PTY; preserves one operation ID across a lost reply and reconnect; preserves ordinary raw startup and captured-session attachment. src/renderer/src/components/terminal-pane/pty-transport/output/pty-side-effect-pending-census.test.ts: sums registered gauges and drops disposed ones; ignores a repeated dispose instead of dropping another gauge; stops tracking new gauges past the cap so a missed dispose cannot grow it; tracks a live output processor queue through enqueue, drain, and dispose; excludes cleared consumed entries from retention after a bounded drain. src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-prebind-discard-notice.test.ts: says nothing once the pane is closed. src/renderer/src/components/terminal-pane/render-health/terminal-webgl-atlas-recovery.test.ts: refreshes after each scheduled atlas reset; falls back to a timeout when animation frames are unavailable; continues recovery when a manager throws after scheduling. src/renderer/src/components/terminal-pane/snapshots/pty-buffer-serializer.test.ts: tracks a remounted quiet title source even when the stale owner unregisters later; preserves the renderer-parsed output sequence in the response; preserves a pending escape tail for snapshot replay; routes a host's Reset Terminal request to the pane that owns the PTY. src/renderer/src/components/terminal-pane/snapshots/saved-terminal-output-replay.test.ts: marks panes with restored scrollback for fresh-shell viewport blanking. src/renderer/src/components/terminal-pane/viewport/split-right-white-screen.test.ts: recovers a 0x0 spawn whose container is briefly unmeasurable then settles. src/renderer/src/components/terminal-pane/viewport/visibility/stale-document-visibility.test.ts: removes global listeners when the last pane unregisters. src/renderer/src/components/ui/security-surface-theme-contrast.test.tsx: keeps trust text readable on a host-owned dialog surface; applies the hostile surface to ordinary dialogs, so the case above is exercised. src/renderer/src/components/use-terminal-parking-pass.test.tsx: does not queue a render when a pass produces the same parking sets; keeps parking transitions working under StrictMode. src/renderer/src/hooks/client-workspace-view-report.test.ts: reports an away user’s screen with no presence, and renews as soon as input returns; retries a failed send, empty or not, no sooner than a refresh. src/renderer/src/hooks/ipc-events/terminal-request-ipc-bridge-placement.test.ts: is new work in a workspace with no live terminal: its first bind moves it up in Recent. src/renderer/src/hooks/use-bundled-skill-install.test.tsx: ignores a repeated click while the install runs; retries the last requested skills on this host. src/renderer/src/hooks/useGitHubSlugMetadata.assignee-reuse.test.tsx: adds seeds to a successful empty list but not to loading or failed results; retains seed projection after expiry and fetches fresh metadata for a new reader. src/renderer/src/hooks/useSettingsNavigationMetadata.language-switch.test.tsx: retranslates the settings nav labels when the UI language changes live. src/renderer/src/lib/codex-stale-pane-account-identity.test.ts: keeps the prompt when the roster read fails and every label collapses. src/renderer/src/lib/image-blob-png.test.ts: downscales a pasted image above the pixel cap; releases its temporary URL on a decode error; releases its temporary URL when PNG encoding fails or exceeds the byte cap. src/renderer/src/lib/react-commit-cascade-store-write-samples.test.ts: names callers above the frame the write came from; restores Error.stackTraceLimit when the capture throws; stops collecting after the sample cap when captureStackTrace is unavailable; caps reported changed keys from a single wide write. src/renderer/src/lib/work-items/linear/linear-issue-context-snapshot.test.ts: applies the rendered text hard cap last and reserves the final overflow marker. src/renderer/src/runtime/rpc/targets/use-worktree-runtime-target.test.ts: keeps the runtime target identity stable across unrelated store writes. src/renderer/src/runtime/source-control/git/runtime-git-branch-client.test.ts: keeps creation available on old hosts and explains the missing operation; preserves landed warnings and direct collision recovery data; propagates remote discovery failure instead of a false empty page. src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-key-reuse.test.ts: reuses unchanged worktree tab projections when one worktree title changes; bumps only the changed worktree version when a sibling stays byte-identical. src/renderer/src/store/repos/repos-catalog-request-coordination.test.ts: shares safe-auto fork sync cooldown attempts across store instances. src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-batch.test.ts: collapses a 193-workspace hydration to one store write; leaves the store byte-identical to the per-workspace path; re-reconciling the batched result is a no-op, as it is for the per-workspace path. src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-fixture.ts: dedicated zero-case helper retirement; no authored test credit. src/renderer/src/store/slices/worktrees/metadata/update-worktrees-meta.test.ts: persists each batch metadata update to its workspace owner. src/renderer/src/store/slices/worktrees/metadata/worktree-meta-rename.test.ts: dismisses a rename error on its capable remote owner; clears pending first-agent rename when the title is updated. src/renderer/src/store/terminals/store-sleep-shutdown-order.test.ts: orders capture, guards, handlers, main's stop, commit, cleanup, and exit settlement. src/renderer/src/store/terminals/terminal-first-tab-publication.test.ts: publishes the first terminal and root tab group atomically; publishes the first terminal and root tab group atomically, then marks it starting in main. src/renderer/src/store/terminals/workspace-terminal-reconnect-hydration.test.ts: restores daemon terminal wake hints before declaring the session ready. src/renderer/src/web/web-runtime-connection-auth-framing.test.ts: keeps legacy framing for sockets that cannot absorb a refused attempt. src/shared/terminal/appearance/terminal-font-weight-windows-regular.test.ts: moves the old Windows default to Regular once and queues the notice; keeps custom weights and fresh profiles without a notice; leaves macOS and Linux profiles untouched. tests/e2e/claude-agent-row-view.unit.test.ts: updates a mounted compact workflow description through the subscribed production parent; bounds upstream active-SSH visits for $population records, fallback=$fallback; derives %s destinations without requiring type or a workflow child ID; terminates a $path parent $status with no third request or intermediate toast; does not recover a first child %s. tests/e2e/cross-version-wire/agent-permission-legacy-spawn.unit.test.ts: keeps exact legacy ordering when structured creation cannot express afterTabId; can create a terminal without selecting the target worktree; preserves the legacy fresh-agent path when host authority is unavailable. tests/e2e/paired-instant-browser-tab.spec.ts: shows a paired browser tab before its create RPC resolves, then keeps it as one tab; adopts a paired browser tab without rebuilding its chrome. tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts: bounds host publication and renderer application across remote worktrees; globally caps decorative freshness while every working status stays fresh. tests/e2e/session-tabs/mobile-session-active-performance.unit.test.ts: bounds saved-order publication selection at N and 10N without rematerializing navigation; bounds admitted placement reconciliation during supported reads at N and 10N; bounds selection input visits at 50 and 500 rows, including unavailable-target projection; keeps publication scoped to a changed worktree and shared by listeners at N and 10N; bounds preserved-chat merge and runtime-owned hydration at N and 10N (legacy=%s); bounds actual native retirement and shared delivery work at N and 10N. tests/e2e/session-tabs/mobile-session-active-publication.unit.test.ts: does not substitute a preserved row for an unavailable explicit legacy selection; resolves main-layout group selection %s (omitted group=%s). tests/e2e/structured-agent-session-launch-admission.unit.test.ts: opens a direct caller's terminal with the caller's own CLI arguments on a decline; opens the chat on the server that admitted it; opens only the terminal when this machine declines, without a notice; opens a new agent tab's terminal with the typed prompt when the caller names none; opens the chat, not a terminal, when this machine cannot resolve a new workspace yet; keeps its terminal fallback, as before. tests/e2e/structured-attention-prompt-relay.unit.test.ts: settles once per relayed prompt, not on every later status update. tests/e2e/structured-attention-read-retirement.unit.test.ts: Mark read on a chat never opened withdraws the prompt alert it surfaced; Mark read on a chat hidden since an earlier view covers the newer prompt it surfaced; reads a newly accepted visible prompt without sending an RPC for text-only updates. tests/e2e/structured-chat-tab-lifetime-cost.unit.test.ts: counts real raw stores, unrelated window publications and captured cleanup at %i chats; counts complete supplied-member sweep and separate final retirement at S=%i N=%i. tests/e2e/structured-session-workspace-authority.unit.test.ts: bounds actual target reveal across %i repo roots and metadata aliases. tests/e2e/terminal-agent-pane-launch.unit.test.ts: starts the host's planned command once, at the pane's size, and says it started; plans a pane whose prompt the window submits without the startup update prompt; preserves caller shell-ready delivery only for a connection-scoped adapter ($connectionId); starts no shell on plan failure (original failure: $returnLaunchFailure); cannot confirm a start whose provider answer was lost. tests/e2e/terminal-parked-memory.spec.ts: releases renderer terminal memory when hidden tabs park. tests/e2e/terminal-shortcuts.spec.ts: @headful Codex-like background output stays visible without disabling WebGL in auto mode; Shift with Russian layout text reaches the PTY as Cyrillic under kitty keyboard reporting. tests/e2e/terminal-split-activation-latency.spec.ts: records attributed CWD, spawn, bind, fixture-ready, input, and echo phases. tests/e2e/terminal-split-activation-latency-phases.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-main-probe.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-artifact.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-split-activation-latency-report.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-tab-switch-visual-restore.spec.ts: restores skipped hidden Grok output on light tab resume. tests/e2e/web-runtime-session-terminal-host-authority.unit.test.ts: delivers independent %s effort through the real prepared web callback; keeps same-ID local and runtime worktrees on the selected runtime owner; creates paired web agents through host authority so activation is mirrored; delivers generated continuation context after host-authoritative creation; seeds the chat composer for a draft that rode in on the launch command. Current changed source bytes, wrapper registrations and reduced selectors have no fresh execution or red/green credit. Unrelated surviving receipt objects keep their original narrow scope; current literal graph reachability does not establish historical import closure or equivalent replacement coverage. Current conservative command/import graph reaches src/main/persistence/worktree-sort-order-write.test.ts, src/main/runtime/construction/orca-runtime.test.ts, src/main/runtime/orca-runtime-tests/targeting-and-resilience.spec.ts, src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-04.spec.ts, src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-03.spec.ts, src/main/runtime/orca-runtime-tests/worktree-removal-and-reconciliation-part-02.spec.ts, src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases-part-02.spec.ts, src/main/runtime/orca-runtime-tests/gitlab-and-pr-bases.spec.ts, src/main/runtime/orca-runtime-tests/worktree-setup-and-startup-part-03.spec.ts, src/main/runtime/orca-runtime-tests/worktree-setup-and-startup.spec.ts, src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-summaries-part-03.spec.ts, src/main/runtime/orca-runtime-tests/mobile-summaries-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-summaries.spec.ts, src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-03.spec.ts, src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-13.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-12.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-11.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-10.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-08.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-07.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-05.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-04.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-02.spec.ts, src/main/runtime/orca-runtime-tests/mobile-session-tabs.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-05.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-04.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-03.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status-part-02.spec.ts, src/main/runtime/orca-runtime-tests/terminal-handles-and-agent-status.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-07.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-04.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-03.spec.ts, src/main/runtime/orca-runtime-tests/terminal-output-and-worker-recovery-part-02.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-12.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-11.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-10.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-09.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-08.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-07.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-06.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness-part-03.spec.ts, src/main/runtime/orca-runtime-tests/terminal-creation-and-readiness.spec.ts, src/main/runtime/orca-runtime-tests/headless-snapshots.spec.ts, src/main/runtime/orca-runtime-tests/terminal-side-effect-facts-part-02.spec.ts, src/main/runtime/orca-runtime-tests/local-worktree-creation-part-02.spec.ts, src/main/runtime/orca-runtime-tests/local-worktree-creation.spec.ts, src/main/runtime/integrations/skill/orca-runtime-skill-recovery.test.ts, src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-detached-routing.spec.ts, src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-delivery.test.ts, src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-mailbox-pointer-cli-command.spec.ts, src/main/runtime/rpc/methods/terminal/terminal-multiplex-link-estimate.test.ts, src/main/runtime/rpc/methods/terminal/terminal-snapshot-scrollback-rows.test.ts, src/main/runtime/rpc/server/pairing/network/windows-default-route-interfaces.test.ts, src/main/runtime/rpc/server/pairing/pairing-offer-owner-cli.test.ts, src/main/runtime/rpc/terminal-multiplex-end-verdict.test.ts, src/main/runtime/session-graph/headless-runtime-graph.spec.ts, src/main/runtime/session-graph/runtime-graph-standing-contracts.test.ts, src/main/runtime/session-tabs/structured-conversation-tab-title.test.ts, src/main/runtime/session-tabs/terminal-close-observed-exit.test.ts, src/main/runtime/terminal/identity/terminal-identity-probe.test.ts, src/main/runtime/terminal/layout/paired-desktop-server-writes-layout-owner.test.ts, src/main/runtime/terminal/lifecycle/pty-lifecycle-generation-retention.test.ts, src/main/runtime/terminal/lifecycle/run-terminal-user-open.test.ts, src/main/runtime/terminal/surface/terminal-surface-replies-window.test.ts, src/main/runtime/terminal/surface/workspace-layout-projection.test.ts, src/main/runtime/terminal/view/terminal-subscribe-exit-waiter-leak.test.ts, src/main/runtime/terminal/wait/orca-runtime-exact-worker-provider-session.test.ts, src/main/runtime/terminal/wait/prime-agent-screen-readiness-transcripts.test.ts, src/main/runtime/workspaces/startup/runtime-worktree-agent-startup.test.ts, src/main/runtime/workspaces/startup/runtime-worktree-startup-readiness.test.ts, src/main/skills/skill-install-transaction.test.ts, src/main/speech/model-manager-download-resume.test.ts, src/main/ssh/config/ssh-config-parser.test.ts, src/main/ssh/config/ssh-known-hosts-source.test.ts, src/main/ssh/config/ssh-known-hosts.test.ts, src/main/ssh/connection/ssh-connect-config.test.ts, src/main/ssh/connection/ssh-connection-auth-fallback.test.ts, src/main/ssh/connection/ssh-connection-store.test.ts, src/main/ssh/connection/ssh-connection.test.ts, src/main/ssh/orcad-migration-stuck-host-profiles.test.ts, src/main/ssh/orcad-runtime-maintenance.test.ts, src/main/ssh/port-forwarding/ssh-port-forward.test.ts, src/main/ssh/ssh-channel-multiplexer.test.ts, src/main/ssh/system-transport/system-ssh-forward-process.test.ts, src/main/ssh/system-transport/system-ssh-loopback-route.test.ts, src/main/startup/browser-process-user-agent-ordering.test.ts, src/main/startup/quit/quit-path-durable-write-blocking.test.ts, src/main/stats/agent-session-transition-recorder.test.ts, src/main/text-generation/commit-message-text-generation-model-discovery.test.ts, src/main/text-generation/pull-request-context.test.ts, src/main/text-generation/source-control-local-process.test.ts, src/main/updater/linux-package/linux-package-update-recovery.test.ts, src/main/updater/releases/updater-prerelease-feed-readiness.test.ts, src/main/updater/releases/updater-release-builds.test.ts, src/main/updater/updater.build-channel-selection.test.ts, src/main/updater/updater.check-preflight.test.ts, src/main/updater/updater.prerelease-fallback.test.ts, src/main/updater/updater.publishing-window-feed.test.ts, src/main/updater/updater.quit-and-install.test.ts, src/main/window/createMainWindow-markdown-editor-focus.test.ts, src/main/window/createMainWindow-renderer-crash-recovery.test.ts, src/main/window/dashboard-popout-window.test.ts, src/main/window/dropped-path-preparation.test.ts, src/main/window/main-window-updater-deferred-setup.test.ts, src/main/worker-threads/worker-thread-request-queue.test.ts, src/main/workspace-hooks/hooks-setup-runner-script.test.ts, src/main/workspaces/catalog/repo-git-remote-identity-enrichment.test.ts, src/main/workspaces/creation/preparation/worktree-create-preparation.test.ts, src/main/workspaces/removal/local-worktree-removal-recovery.test.ts, src/main/workspaces/removal/worktree-removal-safety.test.ts, src/main/wsl/discovery/distro-catalog.test.ts, src/main/wsl/discovery/wsl-distro-holder.test.ts, src/main/wsl/filesystem/wsl-guest-drive-mountinfo.test.ts, src/main/wsl/orcad/wsl-orcad-deploy-app-update.test.ts, src/renderer/src/components/agent/agent-launch-picker-acquisition.test.ts, src/renderer/src/components/feature-tips/feature-tip-telemetry.test.ts, src/renderer/src/components/native-chat/composer/pickers/use-native-chat-side-chat-command.test.ts, src/renderer/src/components/native-chat/media/images/native-chat-image-copy.test.ts, src/renderer/src/components/native-chat/messages/actions/native-chat-fork-launch.test.ts, src/renderer/src/components/native-chat/messages/actions/native-chat-side-chat-fork-point.test.ts, src/renderer/src/components/native-chat/messages/actions/use-native-chat-fork.test.tsx, src/renderer/src/components/terminal-pane/provider-notices/agent-presence/agent-terminal-presence.test.ts, src/renderer/src/components/terminal-pane/pty-connection/emulation/pty-connection-mode2031-raw-subscription.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/input/pty-connection-deferred-input-forwarding.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/notifications/pty-connection-terminal-bell-attention.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-dropped-output-snapshot-healing.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/output/pty-connection-fresh-native-follow-reset.spec.ts, src/renderer/src/components/terminal-pane/pty-connection/spawn/unbound-pane-spawn-recovery.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-foreground-agent.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts, src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-spawn-and-startup.test.ts, src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-delivery-interest.test.ts, src/renderer/src/components/terminal-pane/pty-transport/delivery/pty-dispatcher-push-reattach.test.ts, src/renderer/src/components/terminal-pane/pty-transport/ipc/ipc-pty-opencode-model.test.ts, src/renderer/src/components/terminal-pane/pty-transport/output/pty-side-effect-pending-census.test.ts, src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-prebind-discard-notice.test.ts, src/renderer/src/components/terminal-pane/render-health/terminal-webgl-atlas-recovery.test.ts, src/renderer/src/components/terminal-pane/snapshots/pty-buffer-serializer.test.ts, src/renderer/src/components/terminal-pane/snapshots/saved-terminal-output-replay.test.ts, src/renderer/src/components/terminal-pane/viewport/split-right-white-screen.test.ts, src/renderer/src/components/terminal-pane/viewport/visibility/stale-document-visibility.test.ts, src/renderer/src/components/ui/security-surface-theme-contrast.test.tsx, src/renderer/src/components/use-terminal-parking-pass.test.tsx, src/renderer/src/hooks/client-workspace-view-report.test.ts, src/renderer/src/hooks/ipc-events/terminal-request-ipc-bridge-placement.test.ts, src/renderer/src/hooks/use-bundled-skill-install.test.tsx, src/renderer/src/hooks/useGitHubSlugMetadata.assignee-reuse.test.tsx, src/renderer/src/hooks/useSettingsNavigationMetadata.language-switch.test.tsx, src/renderer/src/lib/codex-stale-pane-account-identity.test.ts, src/renderer/src/lib/image-blob-png.test.ts, src/renderer/src/lib/react-commit-cascade-store-write-samples.test.ts, src/renderer/src/lib/work-items/linear/linear-issue-context-snapshot.test.ts, src/renderer/src/runtime/rpc/targets/use-worktree-runtime-target.test.ts, src/renderer/src/runtime/source-control/git/runtime-git-branch-client.test.ts, src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-key-reuse.test.ts, src/renderer/src/store/repos/repos-catalog-request-coordination.test.ts, src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-batch.test.ts, src/renderer/src/store/slices/tabs/hydrated-workspace-reconciliation-fixture.ts, src/renderer/src/store/slices/worktrees/metadata/update-worktrees-meta.test.ts, src/renderer/src/store/slices/worktrees/metadata/worktree-meta-rename.test.ts, src/renderer/src/store/terminals/store-sleep-shutdown-order.test.ts, src/renderer/src/store/terminals/terminal-first-tab-publication.test.ts, src/renderer/src/store/terminals/workspace-terminal-reconnect-hydration.test.ts, src/renderer/src/web/web-runtime-connection-auth-framing.test.ts, src/shared/terminal/appearance/terminal-font-weight-windows-regular.test.ts, tests/e2e/claude-agent-row-view.unit.test.ts, tests/e2e/cross-version-wire/agent-permission-legacy-spawn.unit.test.ts, tests/e2e/paired-instant-browser-tab.spec.ts, tests/e2e/session-tabs-decorative-title-fanout.unit.test.ts, tests/e2e/session-tabs/mobile-session-active-performance.unit.test.ts, tests/e2e/session-tabs/mobile-session-active-publication.unit.test.ts, tests/e2e/structured-agent-session-launch-admission.unit.test.ts, tests/e2e/structured-attention-prompt-relay.unit.test.ts, tests/e2e/structured-attention-read-retirement.unit.test.ts, tests/e2e/structured-chat-tab-lifetime-cost.unit.test.ts, tests/e2e/structured-session-workspace-authority.unit.test.ts, tests/e2e/terminal-agent-pane-launch.unit.test.ts, tests/e2e/terminal-parked-memory.spec.ts, tests/e2e/terminal-shortcuts.spec.ts, tests/e2e/terminal-split-activation-latency.spec.ts, tests/e2e/terminal-split-activation-latency-phases.ts, tests/e2e/terminal-split-activation-latency-main-probe.ts, tests/e2e/terminal-split-activation-latency-artifact.ts, tests/e2e/terminal-split-activation-latency-report.ts, tests/e2e/terminal-tab-switch-visual-restore.spec.ts, tests/e2e/web-runtime-session-terminal-host-authority.unit.test.ts. Unresolved local/computed edges remain explicit debt.", "Audit2095 current-parent preparation2126 (approved2092/2093 removals; source refresh2109/independent2112): Intentionally retire these low-value alarms without replacement: src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-03.spec.ts: rejects exact terminal stop for multiple expected PTYs before stopping anything; omits stale renderer leaves when fresh PTY liveness is required; omits unbound renderer placeholders when fresh PTY liveness is required; captures the event method before the nested sleep receipt changes it; returns the close receipt without requiring a PTY stop; uses the same stop result as an empty explicit stop. src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-04.spec.ts: builds a compact worktree summary from persisted and live runtime state; reads the linked-PR state from the renderer repoId-keyed GitHub cache; carries persisted worktree host ownership in mobile summaries; emits only instance- and boundary-validated lineage parents in mobile summaries; resolves WSL platforms only for repos represented in mobile summaries; omits worktrees hidden by the host visibility policy from mobile summaries; applies linked-checkout source visibility to mobile summaries. src/main/runtime/orca-runtime-tests/hooks-and-hosted-review-part-02.spec.ts: routes runtime GitHub PR details and actions through the selected WSL project runtime; passes SSH connection context through hosted review creation flows; routes local WSL project hosted review flows through runtime git options; treats SSH worktree drift as unknown without local git probes. src/main/runtime/orca-runtime-tests/terminal-listing.spec.ts: emits one mobile session terminal tab per live PTY even if two tabs resolve to it; resolves projected split authority from the parent layout PTY binding; keeps explicit-id terminal lists from resolving all worktrees; keeps explicit-id cold-cache terminal lists from classifying unrelated same-repo worktrees; keeps unknown bare terminal-list ids on the no-scan exact-id path; matches explicit-id cwd PTYs for folder workspace instance IDs; routes PTY output through the PTY leaf index in large terminal graphs. src/main/runtime/orca-runtime-tests/window-authority.spec.ts: claims the first window as authoritative and ignores later windows; transfers authority from the headless sentinel to the first real window; relays terminal browser launches only while headless owns the graph; marks live headless PTYs for renderer reattach before desktop promotion; reports the activation gate state while no desktop window is available; bumps the epoch and enters reloading when the authoritative window reloads; can mark the graph ready for the authoritative window; drops back to unavailable and clears authority when the window disappears; hands the graph back to headless when a promoted serve window closes (#27292); keeps a crashed promoted serve renderer on its own window while the window is open; stays unavailable during initial loads before a graph is published. src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-routing-races.spec.ts: stops paged routing when the check is cancelled; keeps an unfiltered redrive unrestricted when reservations merge; keeps an unfiltered parked delivery unrestricted when reservations merge; uses a bounded indexed pane lookup for reminted Dispatch identity. src/main/runtime/workspaces/removal/worktree-teardown-unstopped-pty.test.ts: removes the reported wedged automation workspace without --force; clears PTY state once a failed stop is proven to have exited; names only the PTYs that are actually live, not every failed stop; warns with the specific sweep failure, not the generic deadline; still fails closed on a sweep-level failure without force. src/main/skills/bundled-skill-install/layouts.test.ts: links into a project only where its agent folder already exists; reads a pending cloud transaction as busy and a cloud receipt as another skill. src/main/skills/skill-upload-session-service.test.ts: joins concurrent disposal callers through exact cleanup completion. src/main/source-control/hosted-review-creation.test.ts: creates the pull request after fresh main-process validation passes; routes local WSL git and GitHub review creation through the selected runtime; creates a pull request on a GitHub Enterprise Server remote (#8312); creates a GitLab merge request after fresh main-process validation passes; creates an Azure DevOps pull request after fresh main-process validation passes; creates a Gitea pull request after fresh main-process validation passes. src/main/source-control/hosted-review-execution-host-routing.test.ts: reads a GitHub review on the SSH host a row names only in executionHostId; reads a GitLab review on the executionHostId host when connectionId names a different one; does not dial this client for a runtime row whose nested target shares a local name; keeps a runtime row with no nested target on this process (self-addressed stamp); keeps a legacy connectionId-only SSH row on its target; does not share a cached answer between two rows at one path on different hosts; creates a Bitbucket review locally for a runtime row rather than dialing its nested target; reports creation eligibility from the executionHostId-only SSH host; resolves the GitHub slug for a repo listing on the row it is asked about; refuses to dial a runtime host from this process; answers with the SSH target for both spellings and local otherwise; reads a runtime stamp on a row in this store as self-addressing, not a second machine. src/main/source-control/hosted-review-inflight-invalidation.test.ts: keeps other hosts, paths and their pending promises isolated. src/main/speech/model-manager.test.ts: requires pinned, internally consistent metadata for every model file; verifies downloaded model file hashes before installation; rejects non-HTTPS model downloads; marks OpenAI transcription models ready only when an API key is configured. src/main/ssh/connection/ssh-connection-sftp-namespace.test.ts: writes to the SFTP namespace path discovered on the same session; uploads the bundle into the SFTP namespace directory; issues no discovery requests when the caller supplies no mapping; ignores a mapping on a Windows host; never resolves on the system-SSH transport; leaves writeBuffer and openFileUploadSession on the shell path; keeps the shell path when discovery is inconclusive; preserves a session-limit channel-open error unchanged. src/main/ssh/connection/ssh-connection-system-transport.test.ts: uses system SSH transport when ProxyUseFdpass is resolved by OpenSSH; allows concurrent exec commands for system SSH with an Orca ControlMaster socket; keeps concurrent exec commands disabled for system SSH without a reusable socket; uses system SSH transport for ProxyCommand targets before ssh2 auth; keeps the original ssh2 reachability error when the system SSH probe fails; reports the system SSH failure when ssh2 cannot negotiate with the host; uses system transport for target or resolved OpenSSH proxy directives; allows an environment override for e2e coverage; ignores stale imported proxy fields when fresh OpenSSH config has no proxy. src/main/ssh/orcad-migration-catalog-client.test.ts: keeps each server project’s execution host, so a nested SSH row is never read as local; reads the server’s folder workspaces and the groups that place them on a host; sends and validates the %s operation; validates an abort result without letting it erase committed state; validates a committed receipt against the requested manifest; rejects malformed stage timestamps and abort envelopes; fails closed for method absence, malformed identity, and invalid pairing; refuses a destination without the capability before sending any migration request; reads method-not-found as the same refusal, not as a lost answer. src/main/ssh/runtime-ssh-access.test.ts: persists intent then claim before connecting and publishes redacted authenticated access; names the saved dependency when dependent state blocks an SSH access link; handles lost link responses without connecting or verifying again; invalidates old transport only after authenticated access is published; rejects changed request tuple after a completed link; rejects provisioning and missing durable generations without connecting; treats a lost successful unlink response as an idempotent no-op; hashes connection identity, not display state or owner; strictly validates ports and request IDs. src/main/startup/cli-launch-redirect.test.ts: detects a launch that received the unpacked CLI entrypoint; ignores normal desktop launches; ignores the entrypoint when it is only the executable itself (argv[0]); applies on Linux too; strips injected Chromium switches before node-mode CLI arguments; keeps user flags after the command and malformed boolean assignments; does not treat a later positional entrypoint path as the launcher; redirects a direct binary launch with no AppImage env at all; strips Chromium switches node mode would reject; preserves desktop-shaped switches after the command; leaves direct serve in-process but redirects its help; treats help as a CLI launch even without a command; treats %s as a CLI launch even without a command; does not treat a value of %s as a CLI early-exit flag; does not treat a serve option value as a help request; does not reinterpret help after the argument terminator; leaves a plain desktop launch alone; skips flag values when looking for the command positional; preserves a project selector in %j; does not apply the command form on macOS or Windows; never redirects an unpackaged build; runs the in-package CLI in Electron node mode with sanitized env; refuses to redirect twice so a dropped ELECTRON_RUN_AS_NODE cannot loop; reports a missing CLI entrypoint instead of booting the desktop app; execs a direct serve into the CLI so it keeps its pid and honours profile and supervise; keeps ORCA_USER_DATA_PATH for a direct serve without --user-data-dir; serves in-process when this runtime cannot exec or the exec fails; never execs the --serve child the CLI itself spawns, or serve on other platforms; surfaces a spawn failure as a non-zero exit; re-execs a direct --serve onto X11 when Electron resolved Wayland; leaves $name alone. src/main/startup/main-process-runtime-launch-activation.test.ts: marks startup settled for the launch record only after the window has loaded and settled; loads SSH targets on a windowless serve before paired clients can connect (#25886); pins the serve listener to loopback only for orcad browser sidecars (sidecar=$sidecar, #31895); saves Codex auth before a headless serve update restart, like the desktop does. src/main/startup/run-electron-vite-dev.test.ts: forwards dev instance identity to electron-vite; prepares userData orca and orca-dev wrappers for dev terminals; consumes the stable-name flag before forwarding args to electron-vite. src/main/updater/releases/updater-prerelease-feed.test.ts: returns the newest stable tag when the user is on an RC and a newer stable exists; returns the newest RC tag when no stable is newer than the current RC; can exclude prerelease tags for stable-channel checks; probes the %s %s platform manifest; returns null for stable-channel checks when only prereleases are newer; returns null when nothing in the feed is newer than the current version; ignores entries with unparseable tags; returns null when the fetch is not ok; returns null when the fetch throws; picks semver-newest across a mixed-order feed; ignores perf-tagged prereleases for regular RC checks; reports no RC update when only perf-tagged prereleases are newer; picks the semver-newest perf-tagged prerelease; matches only literal rc.N.perf prerelease tags for perf checks; reports no perf update instead of falling back to stable or RC tags; returns a bounded fallback candidate after the newest newer tag; returns null when the only newer tag has a manifest but its asset still 404s; requires a known old timestamp for a stable-fallback tag. src/main/updater/updater-events.test.ts: hands the whole downloaded event to artifact capture; publishes manual-install recovery after a %s download; publishes the normal downloaded state for AppImage builds; blocks downloaded-state handling when the packaged marker is unusable; passes the actual updater error into the install-failure handler; keeps manual-install recovery when a later check finds only the installed release; drops the artifact when another version takes over the cycle; ignores a downloaded event for an older target; accepts a matching event when the pending cache target was cleared; drops the artifact when progress reports a different pending version. src/main/updater/updater-linux-package-recovery-actions.test.ts: rejects both actions while no package-install recovery is active; validates the retained package on every invocation; restores recovery after a recheck resolves without a terminal event; restores recovery after a recheck fails; restores recovery when a pinned check resolves to the current version; restores recovery when resolving a pinned check fails; clears recovery for both actions once the package is gone; resolves %s as a result and keeps the card usable instead of rejecting; keeps recovery available after a transient read failure. src/main/updater/updater.check-settlement.test.ts: leaves a dismissed release update on the release source; surfaces net::ERR_FAILED to user-initiated checks with a friendly message; shows checking immediately for a user-initiated check while feed pinning is pending; keeps background checks event-driven before checking-for-update fires. src/main/usage/usage-provider-store-lifecycle.test.ts: persists identities for a whole first scan with one write; skips disabled and fresh matching states; invalidates prior sources on fingerprint changes and reuses them for forced scans. src/main/window/createMainWindow-close-confirmation.test.ts: clears the quit latch when the renderer prevents unload; does not notify the crash recorder when renderer teardown follows a confirmed window close; allows close when Electron reports a crashed webContents; requests confirmation for a hung-but-alive renderer instead of bypassing. src/main/workspaces/catalog/worktree-identity-persistence.test.ts: stores independent metadata for colliding locators on two hosts; projects canonical-only metadata for exactly one host; keeps canonical metadata current for legacy writers on a known owner; removes only the selected legacy-owner metadata when locators collide; keeps the canonical identity stable when the locator changes; leaves other hosts at the old locator when one host renames its folder. src/main/wsl/filesystem/wsl-drive-unc-conversion-startup.test.ts: leaves a journaled conversion untouched with the gate closed, %s. src/main/wsl/orcad/wsl-orcad-deploy.test.ts: holds the distro before it deploys and launches, and reports what C5 dials; passes its connect-state read (%s) on as hints; applies the SSH census and downgrade admission to the first deploy; refuses a WSL 1 distro before holding it or touching its files; tells an unregistered distro how to find the installed ones, before holding anything; surfaces an unsupported libc as the SSH host refusal does; starts an already-active slot the distro stop ended, instead of reporting it ready; deploys over an adopted unrecorded orcad under the SSH terminal gate, never a fresh launch; reports the adopted instance once the same version is serving; returns a deferral rather than launching over live terminals; hands a failed first deploy to the fresh-install cleanup before reporting it. src/main/zcode/zcode-v2-plan-credentials.test.ts: prefers migrated credentials over a stale legacy account; keeps legacy support when no personal v2 file exists; honors the upstream personal config override independently of the credential directory; does not borrow credentials from another execution host; preserves the protected Orca key priority even if v2 is corrupt; rejects upstream-invalid selection %j without legacy fallback; accepts a valid optional reasoning level; rejects upstream-invalid rule containers %j without legacy fallback; accepts a valid selected-provider empty personal rule and smart model rule; cannot establish selected credentials from %s rules; leaves encrypted CLI files unchanged across repeated account reads. tests/e2e/automation-terminal-launch.unit.test.ts: launches explicit Chat for %s through the common entry and keeps its actual fallback; does not apply stored Terminal extras to Chat; forwards only complete Chat-consumed values, with no Terminal startup base; refuses an expired admission without minting another launch identity; records the actual chat identity and delegates new workspace setup and provenance. tests/e2e/github-project-provider-columns.unit.test.ts: renders %s through one bounded items request on a named cloud host; preserves zero and complete counters: %j; preserves populated and legacy rows through shared sorting, grouping and cells. tests/e2e/structured-agent-session-launch-continuation.unit.test.ts: carries renderer lifetime through host intent to the real %s provider builders. tests/e2e/terminal-account-restart.unit.test.ts: replaces a tombstoned owner while its persisted pane binding has not yet been cleared; paired restart retains the old owner (host authority: %s). tests/e2e/terminal-hidden-view-parking.spec.ts: does not park excluded tabs; reproduces a static frame byte-for-byte across 25 park/reveal cycles. tests/e2e/terminal-long-table-scroll-restore.spec.ts: reproduces long markdown table artifacts after workspace switch and scroll; keeps narrow wrapped signer markdown table coherent after restore and scroll; keeps real emoji markdown table right edge clean after restore and scroll. tests/e2e/terminal-long-table-fixtures.ts: dedicated zero-case helper retirement; no authored test credit. tests/e2e/terminal-paste-ownership.spec.ts: Windows multiline keyboard paste normalizes terminal newlines with one PTY owner; right-click paste sends clipboard text to the focused terminal exactly once. tests/e2e/terminal-raw-emoji-table-scroll-restore.spec.ts: uses WebGL by default for ordinary terminal output when available @terminal-rendering-golden. tests/e2e/terminal-windows-shell-paste-ownership.spec.ts: cmd.exe default terminal keyboard paste preserves exact content with one PTY owner; Git Bash default terminal keyboard paste preserves POSIX-shaped content with one PTY owner; WSL terminal keyboard paste preserves Linux shell content with one PTY owner. tests/e2e/workspace-board-lane-virtualization.spec.ts: mounts a window of cards for a large lane and keeps lane indexes; renders later lane indexes after the lane scrolls. Current changed source bytes, wrapper registrations and reduced selectors have no fresh execution or red/green credit. Unrelated surviving receipt objects keep their original narrow scope; current literal graph reachability does not establish historical import closure or equivalent replacement coverage. Current conservative command/import graph reaches src/main/runtime/orca-runtime-tests/terminal-sleep-and-teardown-part-03.spec.ts, src/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-04.spec.ts, src/main/runtime/orca-runtime-tests/hooks-and-hosted-review-part-02.spec.ts, src/main/runtime/orca-runtime-tests/terminal-listing.spec.ts, src/main/runtime/orca-runtime-tests/window-authority.spec.ts, src/main/runtime/orchestration/mailbox/routing/orchestration-mailbox-routing-races.spec.ts, src/main/runtime/workspaces/removal/worktree-teardown-unstopped-pty.test.ts, src/main/skills/bundled-skill-install/layouts.test.ts, src/main/skills/skill-upload-session-service.test.ts, src/main/source-control/hosted-review-creation.test.ts, src/main/source-control/hosted-review-execution-host-routing.test.ts, src/main/source-control/hosted-review-inflight-invalidation.test.ts, src/main/speech/model-manager.test.ts, src/main/ssh/connection/ssh-connection-sftp-namespace.test.ts, src/main/ssh/connection/ssh-connection-system-transport.test.ts, src/main/ssh/orcad-migration-catalog-client.test.ts, src/main/ssh/runtime-ssh-access.test.ts, src/main/startup/cli-launch-redirect.test.ts, src/main/startup/main-process-runtime-launch-activation.test.ts, src/main/startup/run-electron-vite-dev.test.ts, src/main/updater/releases/updater-prerelease-feed.test.ts, src/main/updater/updater-events.test.ts, src/main/updater/updater-linux-package-recovery-actions.test.ts, src/main/updater/updater.check-settlement.test.ts, src/main/usage/usage-provider-store-lifecycle.test.ts, src/main/window/createMainWindow-close-confirmation.test.ts, src/main/workspaces/catalog/worktree-identity-persistence.test.ts, src/main/wsl/filesystem/wsl-drive-unc-conversion-startup.test.ts, src/main/wsl/orcad/wsl-orcad-deploy.test.ts, src/main/zcode/zcode-v2-plan-credentials.test.ts, tests/e2e/automation-terminal-launch.unit.test.ts, tests/e2e/github-project-provider-columns.unit.test.ts, tests/e2e/structured-agent-session-launch-continuation.unit.test.ts, tests/e2e/terminal-account-restart.unit.test.ts, tests/e2e/terminal-hidden-view-parking.spec.ts, tests/e2e/terminal-long-table-scroll-restore.spec.ts, tests/e2e/terminal-long-table-fixtures.ts, tests/e2e/terminal-paste-ownership.spec.ts, tests/e2e/terminal-raw-emoji-table-scroll-restore.spec.ts, tests/e2e/terminal-windows-shell-paste-ownership.spec.ts, tests/e2e/workspace-board-lane-virtualization.spec.ts. Unresolved local/computed edges remain explicit debt.", "Audit1579 removes workflow/manifest/regex/private binary-header and diagnostic metric inventories, fixture selectors, injected forwarding/platform/signature/process examples, unproven overlap and internal churn counters without equivalent replacement coverage. Retains actual Git trust/diffs; filesystem hash/ELF-region/native discovery; child CLI module repair; compiler/lock/publication/rollback and synthetic Electron install/cache ownership; executable shell quoting/exit; controlled notary/timer cleanup; local patched extractor file/AST freshness; real Chromium/WebKit CSP/sandbox/HTTPS image/referrer/link/preservation controls under parsed Android headers. Five unchanged setup-pnpm/VM request-cleanup definitions reviewed and not rerun. GitHub, installer/archive, OS metric, client, native delegate, compressor, builder and Apple boundaries injected or absent where recorded. No actual native PTY, shipped full/native app, real Actions/cache/npm signature authority, downloaded Electron archive, real objdump/linker/native CLI/AppImage, signing/NSIS/notary/upload/updater or live freeze proof.", @@ -14507,7 +14206,21 @@ "Audit3209 composes approved sources3202/3206: deliberately retires seven authored/expanded cases in four whole suites without equivalent replacement. Work-item queries lose real GitHub/GitLab oversized ASCII secret-prefix empty-query and whitespace-before-trim refusal alarms; inputs share the imported size bound and exercise only its fast length branch, with no multibyte or actual provider/exposure guarantee. Skill sharing loses complete/partial managed-bundle and destination-ambiguity association checks plus three negative origin/path/scheme admission examples; these do not establish uploaded contents, arbitrary-URL fetching, authorization or execution. Retain exact originless-project direct-link fallback, cloud-delete confirmation, bundled-target repair/owner isolation and explicit Windows-host preference over stale WSL suites. Rejected3201 runtime-preference removal is excluded. No real cloud/network/host/disk, mobile or mixed-version execution validation is claimed.", "Audit3219 removes the synthetic Cmd+J extra-source suite; this broad command no longer checks its match/tie placement and selection, announced count, empty-query cap, or workspace hiding with retained recent tabs. No replacement coverage is claimed.", "Audit3231 retires supported-host restore-pane key mapping, closed/open creation-sidebar toggle visibility, unrelated scope-error/null classification and quick-submit reveal/no-create checks. These broad commands lose those real narrow alarms; no replacement coverage is claimed.", - "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired." + "Audit3246 retires NewRowsMarker reveal/no-repeat and pane-scoped beforeinput checks; skill-owner option availability/count/dedup/order; six styled Input/Textarea IME forwarding rows; the static Codex/OpenCode smart-key inventory; tab-map AST ratchet diagnostic fixtures; child-roster work-budget and retained-aggregate alarms; malformed persisted floating-cwd fallback/no-crash/empty exact-root checks; the unanswered-host empty-list discriminator; the direct invalidated-cache commit-false assertion; one redundant digit-keyup IME row; cached non-supported Claude title-generator rows; and the duplicate late naming-result singleton. These root broad commands lose those specific alarms without equivalent replacement. Distinct retained owner/state checks have their own bounded claims; the real scheduler still rejects stale response data, while the direct false-return alarm is retired.", + "Audit 3256 removes these specific alarms from the broad root unit commands: skill dialog active-share selection, close and pending-share handoff; simple keyed-record deletion; marker live-region insertion, simple landing and nine baseline policy examples; General search/control navigation inventory; orphan-count cache bootstrap; seven Codex code classifications and HTTP 429 warning mapping; two skill unread-root verdict examples; peer-mail payload and conversation-ID rejection; and the GitHub organization TABLE text-field optimistic rollback/failed-envelope example. These include real behaviors; retained tests do not provide equivalent coverage for every removed scenario. Mobile losses are recorded separately and are not coverage of these root commands.", + "Audit 3273 removes 14 authored declarations and 19 expanded scenarios across four whole suites and eight partial suites. Retired alarms cover saved-local cancellation/layout ownership, ambiguous-owner warning reset, folder attachment routing, VM false-capability bypass, abandoned reveal warmup cleanup and viewport claim deduplication/rearming, quiet unrelated remote-removal refusal, startup-command one-shot consumption, repository/floating recovery-ledger rows, fake-React pinned-scroll intent, split-ratio state identity/subscriber suppression and fractional change, cross-host project-group join refusal, three PR request-lifetime permutations, upstream-status preservation on error, and unresolved Git-owner refusal. These regression checks are intentionally lost under the test-value audit; retained scenarios are not equivalent replacements. Historical coverage receipts remain historical, including gate35 subscriber claims.", + "Audit 3283 removes 20 authored declarations and 31 expanded scenarios, including two whole suites. Retired alarms cover PR refresh-state pruning, shared runtime subscription cleanup and store isolation, language content-change routing and older completion ownership, ordinary panel retry-timer cleanup and pending loading, four hosted-review lifetime permutations, mocked terminal creation error/order wiring, five sleep-inventory variants with pending-frame-only assertions, palette fallback/composite highlights, Windows/UNC encoded-editor input rows, mixed-repository partial failure counts, title setters and generated-title bypass/replacement, five window-close coordinator delegation/guard/finally branches, and ambiguous-old-record frame reveal. These regression checks are intentionally lost under the test-value audit; retained cases are not equivalent replacements. Prior coverage notes and receipts remain historical.", + "Audit 3292 combines adopted 3285/3287/3289/3293 removals: 40 authored declarations and 47 expanded scenarios, including whole frame-editor-view, ambiguous remote-delete-refusal, unverifiable-host subscription and editor-close cleanup suites. The previously reviewed dock-badge suite was already removed upstream in PR 40895 and receives zero new removal credit. Intentionally retired alarms include background browser selection and last-tab landing; main startup fallback, SSH project cleanup/survivor routing, exact-PR contradiction/saved-push positives, replay/sidecar rollback and wrapped remote error normalization; records/snapshot missing-diff hydration, ambiguous folder-owner delete refusal, focus no-op notifications, nested editor context-only cache check, pending broadcast-first status and ordinary four-confirmation aggregation; preview-source frontmatter pruning, approved local/runtime agent dispatch, non-GitHub legacy PR cache invalidation, stale merged-head transient-error fallback, empty-queue immediate query reply and unverified-to-concrete preflight risk. Additional intentionally retired alarms are injected host subscription/unsubscribe counts, synthetic editor reveal/draft/fallback/scoped close, ambiguous unread refusals and hidden mark/read roundtrip, immediate connect backoff/noError, positive mirrored evidence-clock renewal, supplied VM failure/success projections and git-local/folder-SSH wake permutations. Remaining temporal/ownership cases are narrower; no equivalent replacement or fresh execution is claimed.", + "Audit 3301 combines adopted source batches 3296 and 3299: retire 27 authored declarations and 36 expanded scenarios, including six whole suites. Intentionally lost alarms cover failed-verification/recovery/restart counters and mocked hosting/toast; early overlapping pane-read scheduling/count; unreadable removal listing draft guard; bulk-purge remote-qualified and raw-local guard maps; initial-snapshot blank/mode/oversize/printable/fresh-spawn callback and replay examples; fallback mobile file close and ordinary MRU; default queue overload/drain; seeded browser-page reuse and supplied missing-page URL recreation; ambiguous sleep/hibernation owner refusal and untouched bindings/origins; ordinary selection/activity/fallback priority; skip-remote success and retained hints; supplied structured-chat unsent retention and scoped removal draft eviction; caller-chat focus precedence; open/draft PR cache eviction and merged-head fallback result inventories. Retained adverse-ordering and ownership cases are narrower and do not establish equivalent replacements. No fresh runtime, native, physical provider, cross-platform, mobile or mixed-version evidence is claimed.", + "Audit 3312 composes adopted sources 3302 and 3308: deliberately retires 33 authored declarations and 36 expanded cases, including the whole backend startup-focus, active-browser IPC-close-routing, remote-browser-creation and agent-terminal-presence suites. Intentionally lost alarms cover distinct six-pane reconnect handles; SSH host label/Connect callback, unhydrated visit cleanup, repo cache aliases and hidden worktree/tab/PTY cleanup; adopted-agent startup focus and viewer navigation/reuse; staged, pageless, source, stale and orphan browser-close routing; web local-materialization refusal, desktop incapable-host fallback, failed/thrown remote creation and paired-web sign-in refusal; BOM/NUL and remote/local custom-editor byte-read examples; immediate folder activation and unread clearing; and batching idle/coalescing, accumulated byte ceiling, leading-edge-disabled, standalone synchronous oversize rejection, validation yield, deferred pending-tail order and both viewport-clear examples. The newly reintroduced agent-terminal-presence suite also loses actual terminal-status membership positive and nonterminal-status callback suppression alarms, including the recent 40916 guard regression; the older different 2133 presence-suite history remains historical and receives zero duplicate removal credit. These real regression alarms are intentionally lost. The unchanged survivors provide narrower coverage, with no equivalent replacement or fresh gate, provider, rendered, remote/mobile, mixed-version, cross-platform, soak or measured-budget validation claimed.", + "Audit 3318 composes adopted sources 3310, 3313 and 3317: intentionally retires 71 authored declarations and 102 expanded cases, including whole terminal-detach agent-retention, seeded batch/single open-files equivalence, shallow context-menu shortcut-badge, mocked active-workspace delete-dispatch, workspace session hydration, SSH target cleanup, editor session hydration and worktree terminal purge suites. Lost alarms include chained transfer alias and immediate close/exit retention; batch/single divergence, survivor/selection/map preservation and input nonmutation across 400 imperative seeds (one registered case); disconnected pending-handle retry, authoritative absences/close-record shortcut/older-host absence and published-presence/unpublished-frame examples; published empty host-graph omission to pane exit; legacy search ranking/exclusion fallback; provider request upgrade/dedupe/finalizer ownership; asynchronous PR suppression/primary-change and same-number different-repository URL rejection. Deletion routing loses host/instance qualification, paired and legacy mapping, folder ownership, active-versus-hover/menu-row selection, ambiguity, modal/editable/creation/view/main/deleting/missing guards and shortcut advertisement. Unchanged real keyboard/hover/confirmation/catalog E2E remains narrower, not an equivalent replacement. Additional losses include scripted old-host disk/UTF-8/noop/baseline and landed/unlanded lost-reply/replacement-retry outcomes; ordinary/repeated healthy-link reattach; cross-owner terminal/chat binding; oversized replay permanent-unavailable classification; floating reveal keyboard ownership/close/disable/listener disposal; naming/retained-turn/Sleep/error/close/reject status tables; SSH membership prune/new-target-only reads and environment/local bucket isolation; same-frame receipt capacity and positive bare/headless publisher readmission. These actual regression alarms are deliberately lost; no fresh gate, provider, rendered, mobile, mixed-version, cross-platform, soak or measured-budget validation is claimed.", + "Audit3335 composes adopted source unions3327/3328 and3330/3332: intentionally retires100 authored registrations/123 expanded cases, including ten whole suites, without equivalent replacement. Lost alarms include seeded host persistence/contention and stale-host cleanup; browser snapshot assembly; mocked wake/DPR callbacks and frame budgets; preflight projections; palette authority/cache suppression, URL intent and saved-title cross-repo collisions; metadata coverage/set patch and dropdown assembly; and removed terminal, worktree, review-refresh and owner-routing examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI/GPU/focus, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain only their original scope.", + "Audit3342 composes adopted source batches3333/3334,3336/3337 and3340/3341: intentionally retires180 authored registrations/263 expanded cases, including seven whole suites, without equivalent replacement. Lost alarms include corrupt editor hydration; mobile editor/diff publication and privacy projections; stale-resubscribe routing; model-picker projection/refetch/retry/fallback; editor check-details and frame property inventories; latched-pane cleanup/quiescence; client create replay identity/options/compatibility; and removed owner, async routing, terminal and layout examples. Retained definitions do not replace these alarms. This broad root unit command selects the reduced suite; no fresh execution, historical source/import equivalence, real provider/network/SSH, rendered UI, durability restart, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts keep their original scope.", + "Audit3349 composes adopted batches3343,3345 and refreshed3354: intentionally retires234 authored registrations/294 expanded cases, including13 whole suites, without equivalent replacement. Lost alarms include supplied terminal reconnect/replacement/typeahead/mirror/result and snapshot examples; synthetic render-desync persistence/recovery; worktree listing/owner/catalog/lineage/removal and activation/creation examples; host-scoped PR and task-record projections; editor diff/status/comment and UI send-target examples; automation observation/wake, supplied sleep/deadline clock and native-chat completion/notification/relaunch samples; held-tab layout and cleanup/progress guard examples. Retained adverse-ordering and wire-boundary cases are narrower and do not replace all removed alarms. The already-upstream visibility-resume deletion receives zero new removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH, native process/power/GPU, rendered UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3359 composes root-adopted source3355/independent3356: intentionally retires130 authored registrations/139 expanded cases, including eight whole suites, without equivalent replacement. Lost alarms include strict create naming/capability/legacy payloads; supplied transport host replacement, deadline reattach, create-handoff and split activation; agent-session fork/clipboard/platform flags; shutdown cleared-scrollback/unmounted bindings; simulator host-collision/selection/shutdown; and removed editor, catalog, mutation, launch and status examples. Retained12 adverse-ordering/state-consequence cases are narrower and do not replace all removed alarms. Two queue absences receive zero removal credit. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY, filesystem restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3362 composes root-adopted3358/independent3360: intentionally retires129 authored registrations/140 expanded cases, including four whole suites, without equivalent replacement. Lost alarms include supplied orphan-adoption retry/malformed inventory/cancellation; fake-terminal replay parser/wedge/disposal callbacks; all-host catalog metadata and Windows preferences; host keepalive/protocol/stale/settings failures; and removed exact-stop/suppression, source save lifetime, diff-note queue, rename/editor close, input flood/chunk refusal/limits, purge and creation examples. Retained18 registrations/21 expanded cases protect narrower ownership, generation, dirty-state, queue convergence, encoding and attachment-lease outcomes. No replacement or keeper quota claim. This broad unit command selects the reduced suite; no fresh execution, historical import equivalence, real provider/network/SSH/PTY/xterm parser, disk restart, native UI, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3368 composes root-adopted3363/3364 and3367/3369: intentionally retires181 authored registrations/196 expanded cases, including28 whole suites, without equivalent replacement. Lost alarms include hibernation attention/liveness/backoff/sequential teardown and inventory, host launch compatibility/legacy/Kimi/resource cleanup, terminal recovery parser/pause/quarantine/remount, window-visibility omission-fence lifetime, launch-option rendered Start, sleeping-resume saved recipe/WSL quoting/cancellation, plus removed project/window/input variants. Additional tiny-suite losses include sentence/label/field/default inventories, credential omission, Windows argument/environment mapping, URI decoding, diagnostics, provider classification and fake-clock callback/parser examples. Retained ten registrations/twelve expanded cases include two literal Unicode Mn/Cf zero-width range guards in the actual character-range algorithm and protect narrower delayed editor bytes/destructive ownership, mounted hidden collision repair, ten transport epochs, duplicate-command refusal, caller timeout typing, executor unknown-opener refusal and failed-chunk user bytes. This broad unit command selects the reduced suite; no fresh runtime, real provider/network/PTY, filesystem restart, native UI, historical import equivalence, mobile, mixed-version or cross-platform validation is claimed. Unrelated dated receipts retain their original scope.", + "Audit3375 composes root-adopted3370/independent3371 and3373/independent3374: intentionally retires79 authored registrations/84 expanded cases, including39 whole suites, without equivalent replacement. Lost alarms include federation field/parser inventories; Claude rejected-key precedence, credential clone redaction, managed-versus-user hook preservation and CLI defaults; setting/status/activity projections, mocked SSH/notification/reveal/Linear refusal, fake-clock reconnect and noise; image-fold artifact visibility, paste eligibility, setup trust, scripted ACP error-to-journal publication and ligature cache tuple aliasing; plus supplied folder-runner uniqueness, mobile host-overlay/credential/update/preference races, status/markup/title/keyed-row projections, subscriber cleanup, cancellation/close/refusal/link-issue and mirror suppression alarms. Retained3373 merger contiguity, dual-clock overdue-resume exactly-once, rejected-paste IPC sink and annotation schema roundtrip remain bounded. Retained actual HTTP/OSC status composition, destructive sibling-filesystem isolation, external contrast invariant and fixture CSS pixel intervention remain narrower. Original reviewed87authored/92expanded become9/9; current OpenCode suite adds two preserved upstream cases and the synthetic-title suite gained one Cursor policy mock-call case, independently reviewed for removal in root3378; current90/95 become11/11. That Cursor suppression/ready-frame regression alarm is intentionally lost; it does not observe native title ownership or tab flicker. For3370 only the peer was independently blind, with author exposure explicit;3373/3374 both blind pins were verified. This broad root unit command selects the reduced root unit suite; UNIT_INCLUDE excludes mobile tests, which require the existing mobile runner; retained Playwright component-pixel spec uses its separate existing headless fixture runner and is not validated by the broad unit command. No fresh execution, actual agent/shell/provider, OS material/focus, historical import equivalence, mobile, mixed-version or cross-platform evidence is claimed. All dated receipts retain their original scope." ], "demotionRule": "Keep experimental if any direction skips or fails; do not extend timeouts or retry to green." }, diff --git a/config/renderer-layout-writer-baseline.txt b/config/renderer-layout-writer-baseline.txt index 750730bd624..26d3f04ab48 100644 --- a/config/renderer-layout-writer-baseline.txt +++ b/config/renderer-layout-writer-baseline.txt @@ -18,7 +18,7 @@ 3 src/renderer/src/components/worktree-jump/worktree-jump-palette-status-inputs.ts 1 src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.ts 4 src/renderer/src/components/floating-terminal/floating-workspace-terminal-actions.ts -1 src/renderer/src/lib/pane-manager/client-hosted-browser-row-state.ts +1 src/renderer/src/runtime/browser/client-hosting/client-hosted-browser-row-state.ts 4 src/renderer/src/lib/workspace/persistence/session-write-subscriber.ts 1 src/renderer/src/lib/workspace/persistence/workspace-session-browser-tabs.ts 7 src/renderer/src/lib/workspace/persistence/workspace-session-host-hydration.ts diff --git a/config/scripts/ci/sharding/ci-shard-timings.json b/config/scripts/ci/sharding/ci-shard-timings.json index 9ed17e62079..346c41d52a5 100644 --- a/config/scripts/ci/sharding/ci-shard-timings.json +++ b/config/scripts/ci/sharding/ci-shard-timings.json @@ -3433,7 +3433,6 @@ "src/main/runtime/orchestration/db/orchestration-db.test.ts": 1239, "src/main/runtime/orchestration/db/dispatch-depth.test.ts": 866, "src/main/runtime/orchestration/db/dispatch-mailbox-consumer-fencing.test.ts": 570, - "src/main/runtime/orchestration/db/federated-worker-report-outcome.test.ts": 39, "src/main/runtime/orchestration/db/federation/federated-dispatch-observation-fence.test.ts": 500, "src/main/runtime/orchestration/db/lifecycle-transition.test.ts": 522, "src/main/runtime/orchestration/db/messages/mailbox-consumer-lifecycle-fencing.test.ts": 899, @@ -3608,14 +3607,12 @@ "src/main/runtime/rpc/methods/orchestration/structured-workers/orchestration-worker-start-mode-selection.test.ts": 5749, "src/main/runtime/rpc/methods/orchestration/agent-message-command-contract.test.ts": 6968, "src/main/runtime/rpc/methods/orchestration/cli-runtime-boundary.test.ts": 5671, - "src/main/runtime/rpc/methods/orchestration/federation/federated-attach-receipt.test.ts": 49, "src/main/runtime/rpc/methods/orchestration/federation/federated-fleet-snapshot.test.ts": 1230, "src/main/runtime/rpc/methods/orchestration/federation/federated-message-targeting.test.ts": 5277, "src/main/runtime/rpc/methods/orchestration/federation/federated-release-safety.test.ts": 5469, "src/main/runtime/rpc/methods/orchestration/federation/federated-transport-safety.test.ts": 4257, "src/main/runtime/rpc/methods/orchestration/federation/federated-worker-start-receipt.test.ts": 5223, "src/main/runtime/rpc/methods/orchestration/federation/federation-control-mail.test.ts": 5700, - "src/main/runtime/rpc/methods/orchestration/federation/federation-effects.test.ts": 39, "src/main/runtime/rpc/methods/orchestration/federation/federation-folder-placement.test.ts": 4867, "src/main/runtime/rpc/methods/orchestration/federation/federation-lifecycle-settlement.test.ts": 7140, "src/main/runtime/rpc/methods/orchestration/federation/federation-liveness-verdict.test.ts": 5303, @@ -4127,10 +4124,8 @@ "src/main/ssh/legacy-relay/bridge/legacy-relay-bridge-relay-restart.test.ts": 98, "src/main/ssh/legacy-relay/bridge/legacy-relay-bridge-restart-stop.test.ts": 3114, "src/main/ssh/legacy-relay/bridge/legacy-relay-bridge-runtime-exit.test.ts": 3411, - "src/main/ssh/legacy-relay/cli/legacy-relay-cli-call-limits.test.ts": 7977, "src/main/ssh/legacy-relay/cli/legacy-relay-cli-legacy-records.test.ts": 6234, - "src/main/ssh/legacy-relay/cli/legacy-relay-cli-server.test.ts": 9385, "src/main/ssh/legacy-relay/bridge/legacy-relay-client.test.ts": 109, "src/main/ssh/legacy-relay/bridge/legacy-relay-hidden-output.test.ts": 179, @@ -4620,7 +4615,6 @@ "src/preload/ssh-authority-forwarding.test.ts": 1111, "src/preload/updater-package-recovery.test.ts": 1102, "src/preload/usage-provider-api.test.ts": 46, - "src/renderer/src/app-shell/app-command-handlers-tab-rename.test.ts": 1786, "src/renderer/src/app-shell/shutdown-checkpoint-persist.test.ts": 65, "src/renderer/src/app-shell/startup-window-parity.test.ts": 2306, "src/renderer/src/app-shell/use-profile-state-save-delay-notice.sonner.test.tsx": 355, @@ -4673,24 +4667,19 @@ "src/renderer/src/components/automations/AutomationPromptDisclosure.test.tsx": 893, "src/renderer/src/components/automations/AutomationRunsTable.test.tsx": 668, "src/renderer/src/components/automations/authoring/AutomationSchedulePicker.test.ts": 431, - "src/renderer/src/components/automations/AutomationsPage.behavior.test.tsx": 3389, "src/renderer/src/components/automations/AutomationsPage.edit-destination.test.tsx": 2932, - "src/renderer/src/components/automations/ExternalAutomationManagers.test.tsx": 852, "src/renderer/src/components/automations/hosts/automation-captured-owner.test.ts": 379, "src/renderer/src/components/automations/automation-host-cache-controller.test.ts": 411, "src/renderer/src/components/automations/hosts/automation-host-cache.test.ts": 79, - "src/renderer/src/components/automations/automation-host-diagnostics.test.ts": 460, - "src/renderer/src/components/automations/automation-host-invalidation-window-events.test.ts": 83, "src/renderer/src/components/automations/automation-host-invalidation.test.ts": 85, "src/renderer/src/components/automations/hosts/automation-host-list-rows.test.ts": 419, "src/renderer/src/components/automations/automation-host-scale-gates.test.ts": 638, "src/renderer/src/components/automations/hosts/automation-host-scheduler.test.ts": 439, "src/renderer/src/components/automations/authoring/automation-legacy-schedule-editing.test.ts": 449, - "src/renderer/src/components/automations/automation-list-view.test.ts": 257, "src/renderer/src/components/automations/runs/automation-run-history-keyboard-navigation.test.ts": 434, "src/renderer/src/components/automations/runs/automation-run-open-target.test.ts": 442, @@ -4703,7 +4692,6 @@ "src/renderer/src/components/automations/external-automation-scope-keys.test.ts": 53, "src/renderer/src/components/automations/hosts/use-automation-host-catalog-readoption.test.tsx": 802, "src/renderer/src/components/automations/hosts/use-automation-host-catalog.test.tsx": 920, - "src/renderer/src/components/automations/listing/use-automation-list-search.test.tsx": 679, "src/renderer/src/components/automations/runs/use-automation-runs-dashboard-payload.test.tsx": 6692, "src/renderer/src/components/automations/runs/use-automation-runs-dashboard.test.tsx": 854, @@ -4745,7 +4733,6 @@ "src/renderer/src/components/browser-pane/history/use-browser-history-shortcut.test.tsx": 1990, "src/renderer/src/components/browser-pane/host-guest/agent-input-focus-guard.test.ts": 228, "src/renderer/src/components/browser-pane/host-guest/browser-automation-visibility.test.ts": 45, - "src/renderer/src/components/browser-pane/host-guest/browser-guest-eviction-veto.test.ts": 1724, "src/renderer/src/components/browser-pane/host-guest/browser-page-evicted-guest-recovery.test.ts": 1839, "src/renderer/src/components/browser-pane/host-guest/browser-page-guest-recovery.test.ts": 515, "src/renderer/src/components/browser-pane/host-guest/browser-page-registration-ownership.test.ts": 2197, @@ -4775,7 +4762,6 @@ "src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.failure-message.test.tsx": 3251, "src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.toolbar.test.tsx": 4357, "src/renderer/src/components/browser-pane/workspace-doc/doc-preview-artifact-share.test.ts": 1754, - "src/renderer/src/components/browser-pane/workspace-doc/doc-preview-document-actions.test.ts": 327, "src/renderer/src/components/browser-pane/workspace-doc/doc-preview-external-link-confirmation.test.ts": 1057, "src/renderer/src/components/browser-pane/workspace-doc/doc-preview-webview-attach.test.ts": 200, "src/renderer/src/components/browser-pane/workspace-doc/use-doc-preview-guest-tools.test.ts": 439, @@ -4804,7 +4790,6 @@ "src/renderer/src/components/dashboard-popout/dashboard-preview-link-composition.test.tsx": 8657, "src/renderer/src/components/dashboard-popout/preview-terminal-box-fit-lifecycle.test.ts": 192, "src/renderer/src/components/dashboard-popout/preview-terminal-ime-bridge-kitty-bytes.test.ts": 479, - "src/renderer/src/components/dashboard-popout/remote-runtime-terminal-preview-api.test.ts": 81, "src/renderer/src/components/dashboard-popout/useDashboardSnapshot.test.tsx": 432, "src/renderer/src/components/dashboard/AgentDashboardDrawer.focus.test.tsx": 2567, "src/renderer/src/components/dashboard/AgentDashboardDrawer.test.tsx": 1981, @@ -4836,7 +4821,6 @@ "src/renderer/src/components/editor/EditorFileLocationMenuItems.test.tsx": 846, "src/renderer/src/components/editor/EditorPanel.custom-editor-flush.test.tsx": 2478, "src/renderer/src/components/editor/EditorPanel.diff-rich-owner.test.tsx": 2823, - "src/renderer/src/components/editor/EditorPanelHeaderPath.test.tsx": 2664, "src/renderer/src/components/editor/notebook/cells/IpynbCellEditor.external-sync.test.tsx": 1660, "src/renderer/src/components/editor/notebook/kernel/IpynbKernelToolbar.test.tsx": 736, "src/renderer/src/components/editor/notebook/document/IpynbRendering.test.tsx": 2143, @@ -5102,7 +5086,6 @@ "src/renderer/src/components/mobile/WindowsFirewallNotice.test.tsx": 691, "src/renderer/src/components/mobile/paired-mobile-devices.test.ts": 192, "src/renderer/src/components/mobile/use-mobile-page-paired-devices.test.ts": 475, - "src/renderer/src/components/native-chat-recovery/integration/native-chat-resume-bulk-progress.test.tsx": 3261, "src/renderer/src/components/native-chat-recovery/offers/native-chat-resume-failed-chat-watch.test.ts": 1954, "src/renderer/src/components/native-chat-recovery/integration/native-chat-resume-finished-run.test.tsx": 4173, "src/renderer/src/components/native-chat/messages/rows/NativeChatAgentMessageCard.test.tsx": 3700, @@ -5116,7 +5099,6 @@ "src/renderer/src/components/native-chat/attachments/chips/NativeChatImageAttachmentPreview.test.tsx": 2818, "src/renderer/src/components/native-chat/media/visuals/NativeChatInlineVisual.link-placement.test.tsx": 2477, "src/renderer/src/components/native-chat/prompts/NativeChatInteractiveCard.test.tsx": 2881, - "src/renderer/src/components/native-chat/viewport/scroll/NativeChatJumpToLatest.test.tsx": 477, "src/renderer/src/components/native-chat/markdown/code/NativeChatMarkdown.code-wrap.test.tsx": 3123, "src/renderer/src/components/native-chat/media/images/NativeChatMarkdown.image-preview.test.tsx": 4346, @@ -5124,27 +5106,15 @@ "src/renderer/src/components/native-chat/media/visuals/NativeChatMarkdown.visual.test.tsx": 2860, "src/renderer/src/components/native-chat/messages/reasoning/NativeChatMessageList.live-reasoning.test.tsx": 20337, "src/renderer/src/components/native-chat/NativeChatMessageList.new-rows-marker.test.tsx": 4304, - "src/renderer/src/components/native-chat/viewport/history/NativeChatMessageList.older-history.test.tsx": 12659, - "src/renderer/src/components/native-chat/conversation/slots/NativeChatMessageList.opening-send.test.tsx": 3604, - "src/renderer/src/components/native-chat/conversation/slots/NativeChatMessageList.queued-turn-order.test.tsx": 2949, - "src/renderer/src/components/native-chat/viewport/navigation/NativeChatMessageList.rail-history-jump.test.tsx": 23851, "src/renderer/src/components/native-chat/viewport/scroll/NativeChatMessageList.scroll-behavior.test.tsx": 14260, - "src/renderer/src/components/native-chat/subagents/NativeChatMessageList.subagent-sections.test.tsx": 7517, - "src/renderer/src/components/native-chat/surfaces/integration/NativeChatMessageList.test.tsx": 4252, - "src/renderer/src/components/native-chat/conversation/turns/NativeChatMessageList.turn-indicator.test.tsx": 4070, - "src/renderer/src/components/native-chat/conversation/slots/NativeChatMessageList.turn-membership.test.tsx": 3527, - "src/renderer/src/components/native-chat/session/structured/delivery/NativeChatMessageList.unsent-message.test.tsx": 3069, "src/renderer/src/components/native-chat/viewport/scroll/NativeChatMessageList.visual-scroll.test.tsx": 6691, - "src/renderer/src/components/native-chat/viewport/virtualization/NativeChatMessageList.windowing.test.tsx": 20958, "src/renderer/src/components/native-chat/viewport/rail/NativeChatMessageRail.test.tsx": 1134, - "src/renderer/src/components/native-chat/messages/rows/NativeChatMessageRow.test.tsx": 3533, "src/renderer/src/components/native-chat/NativeChatNewRowsMarker.test.tsx": 3019, "src/renderer/src/components/native-chat/usage/NativeChatNoticeRow.test.tsx": 3399, "src/renderer/src/components/native-chat/pane/actions/NativeChatPaneHeader.test.tsx": 2736, "src/renderer/src/components/native-chat/composer/editor/NativeChatPromptEditor.paragraph-selection.test.tsx": 652, "src/renderer/src/components/native-chat/composer/editor/NativeChatPromptEditor.test.tsx": 1110, "src/renderer/src/components/native-chat/prompts/NativeChatQuestionCard.test.tsx": 762, - "src/renderer/src/components/native-chat/queue/NativeChatQueuedMessageList.in-flight.test.tsx": 1865, "src/renderer/src/components/native-chat/queue/NativeChatQueuedMessageRows.test.tsx": 2691, "src/renderer/src/components/native-chat/prompts/NativeChatResolutionReceipt.test.tsx": 912, "src/renderer/src/components/native-chat/media/images/NativeChatResolvedView.context-menu.test.tsx": 4025, @@ -5201,7 +5171,6 @@ "src/renderer/src/components/native-chat/drafts/native-chat-draft-retention.test.ts": 1415, "src/renderer/src/components/native-chat/attachments/intake/native-chat-external-attachments-destination.test.tsx": 951, "src/renderer/src/components/native-chat/links/actions/native-chat-file-link-existence.test.ts": 1937, - "src/renderer/src/components/native-chat/pane/actions/native-chat-header-ownership.test.tsx": 2796, "src/renderer/src/components/native-chat/links/actions/native-chat-host-file-open.test.ts": 895, "src/renderer/src/components/native-chat/links/previews/native-chat-hover-preview-cache.test.ts": 49, "src/renderer/src/components/native-chat/attachments/chips/native-chat-image-references.test.tsx": 2485, @@ -5245,8 +5214,6 @@ "src/renderer/src/components/native-chat/viewport/rail/structured-agent-session-rail-outline.test.ts": 48, "src/renderer/src/components/native-chat/session/structured/read/structured-agent-session-read-transport.test.ts": 243, "src/renderer/src/components/native-chat/session/status/structured-agent-session-status-bridge-clock.test.tsx": 2070, - "src/renderer/src/components/native-chat/session/status/structured-agent-session-status-bridge-failed-start.test.tsx": 2398, - "src/renderer/src/components/native-chat/session/status/structured-agent-session-status-bridge-unconfirmed-start.test.tsx": 2328, "src/renderer/src/components/native-chat/conversation/projection/structured-agent-session-transcript-order.test.ts": 294, "src/renderer/src/components/native-chat/session/attention/structured-attention-dispatch.test.ts": 1974, "src/renderer/src/components/native-chat/session/status/structured-chat-sleep-startup.test.tsx": 2285, @@ -5309,7 +5276,6 @@ "src/renderer/src/components/new-workspace/use-smart-workspace-name-field-foundation.source.test.tsx": 2290, "src/renderer/src/components/new-workspace/work-item-source-selection.test.ts": 1736, "src/renderer/src/components/onboarding/OnboardingLanguageLoading.test.tsx": 2167, - "src/renderer/src/components/onboarding/onboarding-feature-setup.test.ts": 76, "src/renderer/src/components/pet/pet-blob-cache.test.ts": 64, "src/renderer/src/components/plain-ssh-terminal/PlainSshTerminalPanels.test.tsx": 2510, "src/renderer/src/components/plugins/declarative/PluginDeclarativeView.test.tsx": 2804, @@ -5386,7 +5352,6 @@ "src/renderer/src/components/right-sidebar/checks-panel/gitlab-review-client.test.ts": 321, "src/renderer/src/components/right-sidebar/checks-panel/comments/review-comment-markdown.test.tsx": 2171, "src/renderer/src/components/right-sidebar/checks-panel/refresh/use-checks-panel-manual-refresh-recovery.test.tsx": 2909, - "src/renderer/src/lib/repository-refresh/coalesced-poll-runner.test.ts": 61, "src/renderer/src/components/right-sidebar/file-explorer/mutations/file-explorer-delete-undo-precondition.test.tsx": 2023, "src/renderer/src/components/right-sidebar/file-explorer/tree/file-explorer-dir-pages.test.ts": 1767, "src/renderer/src/components/right-sidebar/file-explorer/tree/file-explorer-directory-listing.test.ts": 2072, @@ -5400,7 +5365,6 @@ "src/renderer/src/components/right-sidebar/file-explorer/watching/file-explorer-watch-reconcile.test.ts": 1906, "src/renderer/src/components/right-sidebar/folder-workspace-attached-worktrees.test.ts": 70, "src/renderer/src/components/right-sidebar/source-control/sync/git-status-refresh.test.ts": 553, - "src/renderer/src/components/right-sidebar/source-control/sync/git-status-twin-copy.test.ts": 1841, "src/renderer/src/components/right-sidebar/hosted-review/folder-checks/parent-pr-checks-rows.test.ts": 374, "src/renderer/src/components/plugins/frames/plugin-frame-host-declarative.test.ts": 439, "src/renderer/src/components/right-sidebar/plugin-panels/health/plugin-panel-act-driver.test.ts": 293, @@ -5443,7 +5407,6 @@ "src/renderer/src/components/right-sidebar/hosted-review/provider-actions/useHostedReviewStackParent.test.tsx": 288, "src/renderer/src/components/right-sidebar/source-control/listing/useSourceControlSubmoduleStatus.test.tsx": 2076, "src/renderer/src/components/settings/accounts/AccountsPane.owner-scope.test.tsx": 4057, - "src/renderer/src/components/settings/agents/AgentsPane.test.tsx": 3230, "src/renderer/src/components/settings/accounts/providers/AntigravityAccountsSection.test.tsx": 2722, "src/renderer/src/components/settings/appearance/chat/AppearanceChatContrastControls.draft.test.tsx": 795, @@ -5470,7 +5433,6 @@ "src/renderer/src/components/settings/repository/worktrees/SparsePresetSettingsSection.test.tsx": 744, "src/renderer/src/components/settings/ssh/server-actions/SshHostDeltaMoveDialog.test.tsx": 438, "src/renderer/src/components/settings/ssh/server-actions/SshHostRecoverServerAction.test.tsx": 669, - "src/renderer/src/components/settings/ssh/SshPane.test.tsx": 1699, "src/renderer/src/components/settings/ssh/targets/SshTargetForm.test.tsx": 1014, "src/renderer/src/components/settings/ssh/targets/SshTargetList.test.tsx": 2093, "src/renderer/src/components/settings/tasks/TaskSourceSimpleSetup.test.tsx": 527, @@ -5573,7 +5535,6 @@ "src/renderer/src/components/sidebar/workspace-board/surface/use-workspace-kanban-drawer-lingering.test.tsx": 262, "src/renderer/src/components/sidebar/workspace-board/selection/use-workspace-kanban-selection.test.tsx": 243, "src/renderer/src/components/sidebar/workspace-card/review/use-workspace-reference-details.test.tsx": 1335, - "src/renderer/src/components/sidebar/worktree-list/navigation/use-workspace-reveal-body-redirect.test.tsx": 215, "src/renderer/src/components/sidebar/workspace-card/activity/use-worktree-activity-status.test.tsx": 565, "src/renderer/src/components/sidebar/workspace-card/activity/use-worktree-agent-rows-subscriptions.test.tsx": 3635, "src/renderer/src/components/sidebar/host-admission/wsl/use-wsl-distro-list.test.ts": 542, @@ -5609,7 +5570,6 @@ "src/renderer/src/components/sidebar/worktree-list/listing/use-sort-order.test.tsx": 2239, "src/renderer/src/components/sidebar/worktree-list/listing/use-visible-worktrees-retention.test.tsx": 2374, "src/renderer/src/components/sidebar/worktree-list/navigation/folder-reveal.test.ts": 97, - "src/renderer/src/components/sidebar/worktree-list/navigation/use-keyboard.focus.test.tsx": 691, "src/renderer/src/components/sidebar/worktree-list/navigation/use-keyboard.host-identity.test.tsx": 587, "src/renderer/src/components/sidebar/worktree-list/navigation/use-keyboard.reveal.test.tsx": 1691, "src/renderer/src/components/sidebar/worktree-list/navigation/use-selection-host-collision.test.tsx": 2217, @@ -5624,18 +5584,13 @@ "src/renderer/src/components/sidebar/workspace-actions/parenting/worktree-parent-eligibility.test.ts": 68, "src/renderer/src/components/sidebar/worktree-list/listing/worktree-sort-label-ordering.test.ts": 114, "src/renderer/src/components/sidebar/wsl-host-offer-move.test.ts": 227, - - "src/renderer/src/components/skills/installation/SkillInstallManagementDialog.test.tsx": 3300, "src/renderer/src/components/skills/sharing/SkillSharedLinkRow.test.tsx": 817, "src/renderer/src/components/skills/SkillsPage.test.tsx": 3822, "src/renderer/src/components/skills/catalog/skill-agent-filter.test.ts": 274, - "src/renderer/src/components/sparse/sparse-directory-entry-input.test.ts": 207, "src/renderer/src/components/stats/usage-daily-chart.test.tsx": 333, "src/renderer/src/components/stats/usage-overview-model.test.ts": 364, "src/renderer/src/components/status-bar/ClaudeSwitcherMenu.owner-lifetime.test.tsx": 2317, - - "src/renderer/src/components/status-bar/SshStatusSegment.large-host-list.test.tsx": 1838, "src/renderer/src/components/status-bar/StatusBarUsageChangeNotices.test.tsx": 785, "src/renderer/src/components/status-bar/UpdateStatusSegment.test.tsx": 2484, "src/renderer/src/components/status-bar/account-switch-row-keyboard.test.tsx": 2286, @@ -5656,20 +5611,17 @@ "src/renderer/src/components/status-bar/use-resource-usage-derived-model.test.tsx": 742, "src/renderer/src/components/tab-bar/CopyTabIdMenuItem.test.tsx": 428, "src/renderer/src/components/tab-bar/TabBarCreateEntry.search.test.tsx": 3224, - "src/renderer/src/components/tab-bar/TabBarItemRow.test.tsx": 2116, "src/renderer/src/components/tab-bar/TabBarQuickCommandItem.test.tsx": 384, "src/renderer/src/components/tab-bar/TabBarQuickCommandsMenu.virtualization.test.tsx": 1644, "src/renderer/src/components/tab-bar/TabStripScrollIndicator.test.tsx": 356, "src/renderer/src/components/tab-bar/cli-chat-resume-close-terminal.test.ts": 598, "src/renderer/src/components/tab-bar/cli-chat-resume-run-close.test.ts": 3079, - "src/renderer/src/components/tab-bar/cli-chat-resume-run.test.ts": 3848, "src/renderer/src/components/tab-bar/group-tab-order.test.ts": 2091, "src/renderer/src/components/tab-bar/host-agent-launch-preferences-source.test.tsx": 3154, "src/renderer/src/components/tab-bar/recent-tab-switching.test.ts": 1795, "src/renderer/src/components/tab-bar/tab-agent-launch-options.test.ts": 438, "src/renderer/src/components/tab-bar/tab-agent-types-by-tab-id.test.ts": 206, "src/renderer/src/components/tab-bar/tab-bar-layout-owner-props.test.ts": 174, - "src/renderer/src/components/tab-bar/tab-bar-quick-commands-shortcut.test.tsx": 273, "src/renderer/src/components/tab-bar/tab-context-menu.test.tsx": 5620, "src/renderer/src/components/tab-bar/tab-create-entry-classifier.test.ts": 510, "src/renderer/src/components/tab-bar/tab-create-entry-local-path.test.ts": 2614, @@ -5683,8 +5635,6 @@ "src/renderer/src/components/tab-bar/use-sortable-tab-context-menu.test.ts": 261, "src/renderer/src/components/tab-bar/use-tab-bar-quick-command-search-input.test.tsx": 536, "src/renderer/src/components/tab-group/RetainedPaneHost.test.tsx": 340, - "src/renderer/src/components/tab-group/TabGroupPanel.os-file-drop.test.tsx": 1711, - "src/renderer/src/components/tab-group/TabGroupPanel.pane-actions.test.tsx": 1419, "src/renderer/src/components/tab-group/tab-drag-pointer-sensor.test.ts": 187, "src/renderer/src/components/tab-group/tab-drag-preview-activation.test.ts": 1785, "src/renderer/src/components/tab-group/tab-drag-retained-guest-passthrough.test.tsx": 2104, @@ -5751,7 +5701,6 @@ "src/renderer/src/components/terminal-pane/provider-notices/codex-server-isolation/codex-shared-server-banner.test.tsx": 2766, "src/renderer/src/components/terminal-pane/pty-connection/output/deferred-reattach-live-data-queue.test.ts": 184, "src/renderer/src/components/terminal-pane/layout/split/deferred-split-pane-handoff.test.ts": 78, - "src/renderer/src/components/terminal-pane/viewport/desktop-fit-fallback.test.ts": 92, "src/renderer/src/components/terminal-pane/pty-connection/output-restore/direct-ssh-hidden-output-restore-unavailable-banner.test.ts": 1975, "src/renderer/src/components/terminal-pane/links/http/edge-wrapped-terminal-http-links.test.ts": 529, "src/renderer/src/components/terminal-pane/links/http/framed-overlay-terminal-http-links.test.ts": 508, @@ -5772,7 +5721,6 @@ "src/renderer/src/components/terminal-pane/pty-connection/agent-identity/foreground-process/pane-foreground-inspect-observation-identity.test.ts": 226, "src/renderer/src/components/terminal-pane/pty-connection/agent-identity/foreground-process/pane-foreground-process-exit-retire.test.ts": 329, "src/renderer/src/components/sidebar/workspace-card/activity/structured-chat-activity-status-live.test.tsx": 4146, - "src/renderer/src/components/terminal-pane/parking/output-watchers/parked-terminal-byte-watcher.test.ts": 2837, "src/renderer/src/components/terminal-pane/parking/output-watchers/parked-terminal-command-status.test.ts": 352, "src/renderer/src/components/terminal-pane/layout/close/pending-pane-close-confirmation.test.ts": 4695, "src/renderer/src/components/terminal-pane/layout/close/pending-runtime-pane-close.test.ts": 3487, @@ -5783,15 +5731,9 @@ "src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-foreground-agent.test.ts": 20118, "src/renderer/src/components/terminal-pane/pty-connection/lifecycle/pty-connection-git-bash-console-capacity.test.ts": 5784, "src/renderer/src/components/terminal-pane/pty-connection/lifecycle/pty-connection-hibernation-kill-shell-foreground.test.ts": 2205, - "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-runtime-snapshot.test.ts": 3129, - "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-backlog-snapshot.test.ts": 3129, "src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-hidden-replay.test.ts": 21687, - "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-restore-fit-overflow.test.ts": 3044, - "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-restore-flood-abandon.test.ts": 1756, - "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-restore-loss-disclosure.test.ts": 4220, "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-restore-marker-handoff.test.ts": 2170, "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-restore-unhide-coverage.test.ts": 4612, - "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-restore-unhide-repaint-fallback.test.ts": 3237, "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-hidden-restore-unhide-retired-task.test.ts": 1947, "src/renderer/src/components/terminal-pane/pty-connection/notifications/pty-connection-hook-idle-arbitration.test.ts": 2228, "src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-input-and-repaint.test.ts": 21974, @@ -5800,7 +5742,6 @@ "src/renderer/src/components/terminal-pane/pty-connection/output-restore/pty-connection-post-dispose-restore-termination.test.ts": 1215, "src/renderer/src/components/terminal-pane/pty-connection/agent-identity/pty-connection-process-exit-row-retire.test.ts": 10626, "src/renderer/src/components/terminal-pane/pty-connection/host-ownership/pty-connection-owner-hydration-backend-retention.test.ts": 4181, - "src/renderer/src/components/terminal-pane/pty-connection/reattach/pty-connection-reattach-binding.test.ts": 5240, "src/renderer/src/components/terminal-pane/pty-connection/input/pty-connection-remote-new-terminal-typeahead.test.ts": 1864, "src/renderer/src/components/terminal-pane/pty-connection/reattach/pty-connection-remote-snapshot-image-title.test.ts": 1754, "src/renderer/src/components/terminal-pane/pty-connection/tests/pty-connection-restore-and-resume.test.ts": 19401, @@ -5818,7 +5759,6 @@ "src/renderer/src/components/terminal-pane/pty-connection/startup/main-pane-resume-banner.test.ts": 59, "src/renderer/src/components/terminal-pane/pty-connection/spawn/main-pane-start-wait.test.ts": 76, "src/renderer/src/components/terminal-pane/pty-connection/serialization/pane-serializer-register.test.ts": 123, - "src/renderer/src/components/terminal-pane/pty-connection/host-ownership/pty-kitty-file-reader.test.ts": 297, "src/renderer/src/components/terminal-pane/pty-connection/output-restore/snapshot-covered-terminal-queries.test.ts": 150, "src/renderer/src/components/terminal-pane/pty-connection/output/terminal-input-echo-delay.test.ts": 132, "src/renderer/src/components/terminal-pane/pty-connection/host-ownership/unserved-ssh-pane-bridge.test.ts": 70, @@ -5845,66 +5785,45 @@ "src/renderer/src/components/terminal-pane/pty-transport/ipc/pty-transport-reattach-admission.test.ts": 1636, "src/renderer/src/components/terminal-pane/pty-transport/ipc/pty-transport-recycled-pty-incarnation.test.ts": 787, "src/renderer/src/components/terminal-pane/input/focus/regular-terminal-focus-ownership.test.ts": 208, - "src/renderer/src/components/terminal-pane/pty-connection/output-restore/remote-hidden-output-restore-outcomes.test.ts": 2794, "src/renderer/src/components/terminal-pane/pty-connection/output-restore/remote-hidden-output-restore-unavailable-banner.repro.test.ts": 2355, "src/renderer/src/components/terminal-pane/layout/persistence/remote-pane-layout-push.test.ts": 77, "src/renderer/src/components/terminal-pane/pty-connection/output-restore/remote-park-reveal-unverifiable-retry.test.ts": 1546, - "src/renderer/src/components/terminal-pane/pty-connection/geometry/remote-reconnect-unimaged-pane-redraw.test.ts": 3122, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-connect-failure-recovery.test.ts": 989, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-disconnected-input-grace-retry.test.ts": 1366, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/input/remote-runtime-input-journal.test.ts": 69, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-outage-toast-flood-and-stuck-reconnect.test.ts": 1269, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/output/remote-runtime-pty-batching.test.ts": 108, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-deadline-reattach.test.ts": 2117, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-latched-pane-retention.test.ts": 5267, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-query-reply-immediate.test.ts": 1556, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/recovery/remote-runtime-pty-recovery-state.test.ts": 85, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-activation-inventory-fallback.test.ts": 1311, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-handoff.test.ts": 14353, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-create-outcome-recovery.test.ts": 2041, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-empty-initial-snapshot.test.ts": 1491, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-end-verdict.test.ts": 942, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-expired-pane-recovery.test.ts": 1763, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-healthy-link-reattach.test.ts": 1595, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-exit-record.test.ts": 4078, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-session-launch.test.ts": 2248, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-host-surface-replacement.test.ts": 4276, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-input-coalescing.test.ts": 2777, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-input-fallback.test.ts": 1643, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-input-replay.test.ts": 7130, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-mirror-resolve-overlap.test.ts": 977, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-pairing-rotation.test.ts": 2480, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-pane-binding-ownership.test.ts": 4578, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-pane-handle-resolution.test.ts": 2860, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-pending-host-surface-attach.test.ts": 1768, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-prebind-discard-notice.test.ts": 889, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-reattach-type-ahead.test.ts": 3894, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-reveal-round-trips.test.ts": 1023, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-snapshot-replay.test.ts": 1717, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-spawn-intent.test.ts": 2215, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-split-leaf-activation.test.ts": 2034, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stale-handle-recovery.test.ts": 1882, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-sticky-replacement-policy.test.ts": 1801, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stopped-host-reopen.test.ts": 1083, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-stream-reconnect.test.ts": 4148, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-subscribe-ack-input.test.ts": 2565, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-unmounted-host-pane.test.ts": 626, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-unpublished-host-graph.test.ts": 1435, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-transport-web-mirror-recovery.test.ts": 1905, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/input/remote-runtime-recovery-input-hold.test.ts": 342, - "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-resubscribe-failure-recovery-routing.test.ts": 1896, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-saved-result-consumer.test.ts": 3650, "src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-ssh-sign-in-recovery.test.ts": 6038, "src/renderer/src/components/terminal-pane/snapshots/remote-snapshot-alt-screen-host-chain.test.ts": 31916, "src/renderer/src/components/terminal-pane/snapshots/remote-snapshot-alt-screen-replay.test.ts": 3010, "src/renderer/src/components/terminal-pane/snapshots/remote-snapshot-history-seam.test.ts": 2093, - "src/renderer/src/components/terminal-pane/snapshots/replay-guard.test.ts": 371, "src/renderer/src/components/terminal-pane/layout/split/resolve-split-cwd.test.ts": 56, "src/renderer/src/components/terminal-pane/viewport/split-right-white-screen.test.ts": 53, "src/renderer/src/components/terminal-pane/viewport/visibility/stale-document-visibility.test.ts": 88, "src/renderer/src/components/terminal-pane/input/paste/terminal-agent-paste-bracketing.test.ts": 329, - "src/renderer/src/components/terminal-pane/session-fork/terminal-agent-session-fork.test.ts": 1377, - "src/renderer/src/components/terminal-pane/appearance/terminal-appearance.test.ts": 339, "src/renderer/src/components/terminal-pane/input/paste/terminal-bracketed-paste.test.ts": 57, "src/renderer/src/components/terminal-pane/emulation/terminal-capability-replies.test.ts": 131, "src/renderer/src/components/terminal-pane/clipboard/terminal-clipboard-paste.test.ts": 76, @@ -5933,9 +5852,7 @@ "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-composition-deduplication.test.ts": 1643, "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-consumed-key-commit.test.ts": 751, "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-korean-enter-commit-order.test.ts": 328, - "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-midline-preedit-tail.test.ts": 980, "src/renderer/src/components/terminal-pane/input/ime/terminal-ime-xterm-resumed-preedit-visibility.test.ts": 498, - "src/renderer/src/components/terminal-pane/emulation/terminal-inline-image-da1.test.ts": 127, "src/renderer/src/components/terminal-pane/input/ime/terminal-ios-hangul-preedit-coexistence.test.ts": 621, "src/renderer/src/components/terminal-pane/input/ime/terminal-ios-hangul-preedit-device-trace.test.ts": 415, "src/renderer/src/components/terminal-pane/input/ime/terminal-ios-hangul-preedit.test.ts": 818, @@ -5960,13 +5877,11 @@ "src/renderer/src/components/terminal-pane/layout/reconciliation/terminal-pane-frame-reconciliation.test.ts": 903, "src/renderer/src/components/terminal-pane/host-state/terminal-pane-host-state-memo.test.ts": 4534, "src/renderer/src/components/terminal-pane/mounting/terminal-pane-mount-bootstrap.test.ts": 1723, - "src/renderer/src/components/terminal-pane/render-health/recovery/terminal-pane-recovery.test.ts": 949, "src/renderer/src/components/terminal-pane/layout/split/terminal-pane-split-request-routing.test.ts": 2015, "src/renderer/src/components/terminal-pane/layout/detach/terminal-pane-tab-detach-main-commit.test.ts": 2090, "src/renderer/src/components/terminal-pane/layout/detach/terminal-pane-tab-detach-main-move.test.ts": 2147, "src/renderer/src/components/terminal-pane/parking/verdict/terminal-park-verdict-flip-telemetry.test.ts": 123, "src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-tab-watchers.test.ts": 473, - "src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-reconciliation.test.ts": 243, "src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-registry.test.ts": 245, "src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-sleep-preserved-exit.test.ts": 399, "src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-sole-newborn-exit.test.ts": 402, @@ -5974,25 +5889,17 @@ "src/renderer/src/components/terminal-pane/input/paste/terminal-paste-coordinator.test.ts": 155, "src/renderer/src/components/terminal-pane/links/files/terminal-path-existence-batch.test.ts": 58, "src/renderer/src/components/terminal-pane/links/files/terminal-path-exists-cache.test.ts": 47, - "src/renderer/src/components/terminal-pane/render-health/terminal-render-desync-sentinel.test.ts": 468, "src/renderer/src/components/terminal-pane/snapshots/terminal-replay-application-continuity.test.ts": 372, "src/renderer/src/components/terminal-pane/snapshots/terminal-restore-sgr-latch.test.ts": 175, "src/shared/terminal/viewport/terminal-restored-viewport.test.ts": 46, "src/renderer/src/components/terminal-pane/terminal-resume-escape-gap.test.ts": 102, - "src/renderer/src/components/terminal-pane/snapshots/terminal-shutdown-layout-capture.test.ts": 197, "src/renderer/src/components/terminal-pane/pty-transport/output/terminal-side-effect-facts-handler.test.ts": 80, "src/renderer/src/components/terminal-pane/snapshots/terminal-snapshot-replay-paint.test.ts": 499, "src/renderer/src/components/terminal-pane/titles/terminal-title-evidence.test.ts": 184, "src/renderer/src/components/terminal-pane/links/http/terminal-url-link-click.test.ts": 2057, - "src/renderer/src/components/terminal-pane/viewport/visibility/terminal-visibility-resume.test.ts": 1669, "src/renderer/src/components/terminal-pane/links/files/terminal-worktree-path-link.test.ts": 1878, - "src/renderer/src/components/terminal-pane/mobile-driver/use-mobile-overlay-ticks-desktop-fit.test.tsx": 371, - "src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-pane-global-effects-visibility-resume.test.ts": 1951, - "src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-pane-global-effects-window-focus-recovery.test.ts": 1836, "src/renderer/src/components/terminal-pane/use-terminal-pane-lifecycle.test.ts": 1806, - "src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-scroll-visibility-memory.test.ts": 79, "src/renderer/src/components/terminal-pane/parking/lifecycle/use-terminal-tab-cold-parking.test.ts": 752, - "src/renderer/src/components/terminal-pane/viewport/visibility/use-terminal-window-wake-recovery.test.ts": 494, "src/renderer/src/components/terminal-pane/links/http/wrapped-terminal-http-link-limits.test.ts": 108, "src/renderer/src/components/terminal-pane/links/http/wrapped-terminal-http-link-provider.test.ts": 606, "src/renderer/src/components/terminal-parked-watcher-sync-entries.test.tsx": 1104, @@ -6006,7 +5913,6 @@ "src/renderer/src/components/terminal/active-terminal-repair-loop.react185.test.tsx": 1998, "src/renderer/src/components/terminal/background-terminal-worktree-mount.test.ts": 1707, "src/renderer/src/components/terminal/background-terminal-worktree-visibility.test.ts": 1790, - "src/renderer/src/components/terminal/initial-terminal-admission-wait.test.tsx": 2444, "src/renderer/src/components/terminal/initial-terminal-structured-launch.test.tsx": 786, "src/renderer/src/components/terminal/running-terminal-close-guard.test.ts": 99, "src/renderer/src/components/terminal/startup-terminal-tab-hold.test.ts": 2118, @@ -6030,8 +5936,6 @@ "src/renderer/src/components/use-quick-open-interaction.test.tsx": 1987, "src/renderer/src/components/use-task-creation-draft-retention.test.ts": 3185, "src/renderer/src/components/use-terminal-bulk-close-actions.frame-flush.test.tsx": 2300, - "src/renderer/src/components/use-terminal-create-actions.test.tsx": 302, - "src/renderer/src/components/use-terminal-editor-close-foundation.window-close.test.tsx": 2105, "src/renderer/src/components/use-terminal-parking-pass.test.tsx": 2142, "src/renderer/src/components/use-terminal-window-lifecycle.frame-flush.test.tsx": 2164, "src/renderer/src/components/virtualized-list.test.tsx": 446, @@ -6053,16 +5957,13 @@ "src/renderer/src/components/workspace-emoji/WorkspaceEmojiPickerPanel.test.tsx": 763, "src/renderer/src/components/workspace-emoji/useWorkspaceEmojiShortcodeInput.test.tsx": 365, "src/renderer/src/components/worktree-creation/PendingNativeChatCreation.test.tsx": 4075, - "src/renderer/src/components/worktree-jump/WorktreeJumpPalette.linear-url.test.tsx": 3372, "src/renderer/src/components/worktree-jump/WorktreeJumpPalette.recent-tabs.behavior.test.tsx": 4445, - "src/renderer/src/components/worktree-jump/WorktreeJumpPalette.recent-tabs.test.tsx": 9384, "src/renderer/src/components/worktree-jump/WorktreeJumpPalette.test.tsx": 4442, "src/renderer/src/components/worktree-jump/use-worktree-jump-palette-browser-ownership.test.ts": 2096, "src/renderer/src/components/worktree-jump/use-worktree-jump-palette-task-search.test.tsx": 2140, "src/renderer/src/components/worktree-jump/worktree-jump-palette-browser-navigation.test.tsx": 4470, "src/renderer/src/components/wsl-host-stopped/WslHostStoppedNotice.test.tsx": 491, "src/renderer/src/components/wsl-move/WslMoveDialog.test.tsx": 524, - "src/renderer/src/components/wsl-move/use-wsl-move-quit-guard.test.ts": 235, "src/renderer/src/components/wsl-move/wsl-move-dialog-store.test.ts": 2011, "src/renderer/src/components/wsl-move/wsl-move-orchestrator-status.test.tsx": 567, "src/renderer/src/components/wsl-move/wsl-move-scope-rows.test.ts": 156, @@ -6086,7 +5987,6 @@ "src/renderer/src/hooks/editor-external-watch-overflow.test.ts": 1023, "src/renderer/src/hooks/editor-external-watch-selected-host.test.ts": 1988, "src/renderer/src/hooks/editor-runtime-file-watch.test.ts": 58, - "src/renderer/src/hooks/ipc-events/agent-status-pane-routing-index-retention.test.ts": 4878, "src/renderer/src/hooks/ipc-events/agent-status-pending-retry-gate.test.ts": 466, "src/renderer/src/hooks/ipc-events/agent-status-terminal-title-tab-write.test.ts": 2247, @@ -6123,7 +6023,6 @@ "src/renderer/src/hooks/runtime-project-refresh-scheduler.test.ts": 65, "src/renderer/src/hooks/shortcut-label-cache.test.tsx": 2021, "src/renderer/src/hooks/unpaired-device-auth-notification.test.ts": 41, - "src/renderer/src/hooks/use-document-dark-theme.test.tsx": 350, "src/renderer/src/hooks/use-list-multi-selection.test.tsx": 545, "src/renderer/src/hooks/use-monaco-theme.test.tsx": 323, @@ -6153,15 +6052,11 @@ "src/renderer/src/hooks/useIpcEvents-agent-status-connection-attribution.test.ts": 5510, "src/renderer/src/hooks/useIpcEvents-agent-status-pane-teardown.test.ts": 5268, "src/renderer/src/hooks/useIpcEvents-agent-status-queue-ordering.test.ts": 3680, - "src/renderer/src/hooks/useIpcEvents-agent-status-snapshot-hydration.test.ts": 7403, "src/renderer/src/hooks/useIpcEvents-agent-status-snapshot-replay.test.ts": 4119, "src/renderer/src/hooks/useIpcEvents-agent-status-ssh-authority.test.ts": 3310, "src/renderer/src/hooks/useIpcEvents-browser-certificate-failure.test.ts": 2981, "src/renderer/src/hooks/useIpcEvents-browser-navigation.test.ts": 1511, - "src/renderer/src/hooks/useIpcEvents-client-hosted-browser-rows.test.ts": 1894, - "src/renderer/src/hooks/useIpcEvents-close-routing-active-browser-tab.test.ts": 4572, "src/renderer/src/hooks/useIpcEvents-close-routing-session-tabs.test.ts": 5812, - "src/renderer/src/hooks/useIpcEvents-cmd-j-digit-chord.test.ts": 2703, "src/renderer/src/hooks/useIpcEvents-lifecycle.test.ts": 2326, "src/renderer/src/hooks/useIpcEvents-new-workspace-shortcut.test.ts": 72, "src/renderer/src/hooks/useIpcEvents-runtime-environment-selectors.test.ts": 530, @@ -6178,8 +6073,6 @@ "src/renderer/src/hooks/useReadOnScreenAttention.mixed-workspace.test.ts": 1725, "src/renderer/src/hooks/useReadOnScreenAttention.test.ts": 1915, "src/renderer/src/hooks/useRetiredWorktreeNames.test.ts": 593, - - "src/renderer/src/hooks/useUnreadDockBadge.test.ts": 2126, "src/renderer/src/hooks/virtualized-hidden-row-measurement.test.ts": 199, "src/renderer/src/hooks/worktree-change-refresh-queue.test.ts": 59, "src/renderer/src/i18n/I18nProvider.test.tsx": 2101, @@ -6189,22 +6082,18 @@ "src/renderer/src/i18n/plugin-pack-plurals.test.ts": 191, "src/renderer/src/i18n/relative-time-format.test.ts": 53, "src/renderer/src/i18n/ui-intl-formatters.test.ts": 208, - "src/renderer/src/lib/activate-ai-vault-structured-session-host.test.ts": 589, - "src/renderer/src/lib/activate-ai-vault-structured-session-reveal.test.ts": 2099, "src/renderer/src/lib/workspace/tabs/activate-tab-and-focus-pane.test.ts": 54, "src/renderer/src/lib/agent-session/messaging/terminal/active-agent-note-send-explicit-target.test.ts": 980, "src/renderer/src/lib/agent-session/messaging/terminal/active-agent-note-send-focused-session.test.ts": 536, - "src/renderer/src/lib/activity-thread-display.test.ts": 134, + "src/renderer/src/lib/workspace/activity/activity-thread-display.test.ts": 134, "src/renderer/src/lib/agent-account-restart-startup.test.ts": 1780, "src/renderer/src/lib/agent-session/launch/background/agent-background-session-launch-host.test.ts": 1910, "src/renderer/src/lib/agent-draft-readiness.test.ts": 245, - "src/renderer/src/lib/agent-session/hibernation/agent-hibernation-coordinator.test.ts": 1880, "src/renderer/src/lib/agent-session/hibernation/agent-hibernation-pane-age.test.ts": 41, "src/renderer/src/lib/agent-session/hibernation/agent-hibernation-planner.test.ts": 341, "src/renderer/src/lib/agent-session/hibernation/agent-hibernation-runtime-liveness-race.test.ts": 1914, "src/renderer/src/lib/agent-session/launch/pane/agent-launch-pane-verdict-application.test.ts": 1869, "src/renderer/src/lib/agent-session/launch/routing/agent-launch-route-input.test.ts": 1659, - "src/renderer/src/lib/agent-session/launch/routing/agent-launch-route-registered-agents.test.ts": 1749, "src/renderer/src/lib/agent-session/launch/pane/agent-launch-tab-main-written.test.ts": 2084, "src/renderer/src/lib/agent-session/launch/pane/agent-launch-tab-publication.test.ts": 1855, "src/renderer/src/lib/agent-session/launch/pane/agent-launch-through-host.test.ts": 1975, @@ -6213,23 +6102,13 @@ "src/renderer/src/lib/agent-session/messaging/paste/agent-paste-draft.test.ts": 445, "src/renderer/src/lib/agent-session/resume/agent-resume-launch-target.test.ts": 3911, "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-after-failure.test.ts": 870, - "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-close-race.test.ts": 983, - "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-create-message.test.ts": 2521, - "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-different-request.test.ts": 885, "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-exited-owner.test.ts": 1289, "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-join-delivery.test.ts": 862, "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-options.test.ts": 991, "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-persistence.test.ts": 386, "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-probe-outage.test.ts": 1891, - "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-prompt.test.ts": 710, "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-record.test.ts": 151, "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-resume-identity.test.ts": 828, - "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-unconfirmed-or-retried.test.ts": 1085, - "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch.test.ts": 977, - "src/renderer/src/lib/agent-session/launch/structured-agent-session-new-chat-own-launch.test.ts": 2177, - "src/renderer/src/lib/agent-session/structured-agent-session-draft-position-lifetime.test.tsx": 3166, - "src/renderer/src/lib/agent-session/structured-agent-session-ordinary-draft.test.tsx": 9907, - "src/renderer/src/lib/agent-session/structured-agent-session-provisional-tab.test.ts": 3672, "src/renderer/src/lib/agent-session/launch/startup/agent-startup-delayed-delivery-perf.test.ts": 1708, "src/shared/agent-status/contracts/agent-status-evidence-clock.test.ts": 88, "src/shared/agent-status/title/agent-title-tracker.test.ts": 172, @@ -6250,7 +6129,6 @@ "src/renderer/src/lib/bounded-generation-map.test.ts": 35, "src/renderer/src/lib/browser/history/browser-history-match.test.ts": 328, "src/renderer/src/lib/browser/navigation/browser-link-destination.test.ts": 1839, - "src/renderer/src/lib/browser/navigation/browser-link-open-layout-owner.test.ts": 3133, "src/renderer/src/lib/browser/navigation/browser-link-open.test.ts": 2215, "src/renderer/src/lib/browser/navigation/browser-link-profile-isolation.test.ts": 2511, "src/renderer/src/lib/browser/palette/browser-page-palette-activation.test.ts": 1983, @@ -6261,37 +6139,28 @@ "src/renderer/src/lib/claude-account-switch-sessions.test.ts": 782, "src/renderer/src/lib/claude-session-account-move.test.ts": 1816, "src/renderer/src/lib/clipboard/images/clipboard-image-copy.test.ts": 243, - "src/renderer/src/lib/cmd-j-host-qualified-candidate-ownership.test.ts": 526, - "src/renderer/src/lib/cmd-j-linear-issue-intent.test.ts": 42, + "src/renderer/src/lib/workspace/search/palette/cmd-j-host-qualified-candidate-ownership.test.ts": 526, "src/renderer/src/lib/code-host-error-copy.test.ts": 297, - "src/renderer/src/lib/codex-pane-selection-lane.test.ts": 543, + "src/renderer/src/lib/agent-session/accounts/codex-pane-selection-lane.test.ts": 543, "src/renderer/src/lib/agent-session/accounts/codex/codex-session-restart-shell-flap.test.ts": 1745, "src/renderer/src/lib/agent-session/accounts/codex/codex-session-restart.test.ts": 2039, - "src/renderer/src/lib/codex-stale-pane-account-identity.test.ts": 1823, - "src/renderer/src/lib/codex-stale-pane-sweep.test.ts": 1817, + "src/renderer/src/lib/agent-session/accounts/codex/codex-stale-pane-account-identity.test.ts": 1823, + "src/renderer/src/lib/agent-session/accounts/codex/codex-stale-pane-sweep.test.ts": 1817, "src/renderer/src/lib/source-control/review/comments/comment-body-submit-state.test.ts": 55, "src/renderer/src/lib/composer-submit-cancellation.test.ts": 41, "src/renderer/src/lib/workspace/ownership/connection-context.test.ts": 1817, "src/renderer/src/lib/create-untitled-markdown.test.ts": 566, - "src/renderer/src/lib/desktop-created-server-tabs.test.ts": 1933, "src/renderer/src/lib/workspace/ownership/direct-ssh-target-scope.test.ts": 48, - "src/renderer/src/lib/workspace/creation/work-item/direct-work-item-setup-callers.test.tsx": 2436, "src/renderer/src/lib/workspace/creation/work-item/direct-work-item-setup.test.ts": 2072, "src/renderer/src/lib/browser/documents/doc-preview-grants.test.ts": 2094, "src/renderer/src/lib/editor/file-operations/editor-file-operation-owner.test.ts": 2848, "src/renderer/src/lib/emulator-error-copy.test.ts": 415, "src/renderer/src/runtime/repo-hooks/ensure-hooks-confirmed.test.ts": 799, - "src/renderer/src/lib/simulator/tabs/ensure-simulator-tab-behavior.test.ts": 3601, "src/renderer/src/runtime/hosts/platform/execution-host-facts.test.ts": 1796, "src/renderer/src/components/sidebar/sidebar-feedback/feedback-image-attachments.test.ts": 557, - "src/renderer/src/lib/files/search/file-search-selection.test.ts": 51, - "src/renderer/src/lib/finished-agent-resume-resurrection.test.ts": 1872, + "src/renderer/src/lib/agent-session/resume/finished-agent-resume-resurrection.test.ts": 1872, "src/renderer/src/components/terminal-pane/parking/retention/foreground-terminal-tabs.test.ts": 55, "src/renderer/src/lib/work-items/github/github-source-runtime-context.test.ts": 62, - "src/renderer/src/lib/host-mirror-handle-gap-drain.test.ts": 1706, - "src/renderer/src/lib/host-mirror-handle-gap-resume.test.ts": 1811, - "src/renderer/src/lib/host-mirrored-pane-resume-replay.test.ts": 1814, - "src/renderer/src/lib/browser/navigation/http-link-completion.test.ts": 1760, "src/renderer/src/lib/browser/navigation/http-link-routing-store.test.ts": 2211, "src/renderer/src/lib/text-input/ime/ime-composition-keyboard-event.test.ts": 274, "src/renderer/src/lib/text-input/ime/ime-text-field.test.tsx": 739, @@ -6305,14 +6174,12 @@ "src/renderer/src/lib/agent-session/launch/new-tab/launch-agent-new-tab-host-route-readiness.test.ts": 489, "src/renderer/src/lib/agent-session/launch/new-tab/launch-agent-picker-contract.test.ts": 3592, "src/renderer/src/lib/agent-session/launch/continuation/launch-agent-session-continuation-toast.test.tsx": 2347, - "src/renderer/src/lib/launch-cancel-tombstones-compat/structured-agent-session-launch-cancellation.test.ts": 2266, "src/renderer/src/lib/workspace/creation/work-item/launch-work-item-direct-accepted.test.tsx": 2754, "src/renderer/src/lib/workspace/creation/work-item/launch-work-item-direct-defaults.test.ts": 1594, "src/renderer/src/lib/workspace/creation/work-item/launch-work-item-direct-setup.test.tsx": 3435, "src/renderer/src/app-shell/startup/lazy-with-retry.never-landed-reload.test.ts": 194, "src/renderer/src/lib/work-items/linear/linear-board-drag-payload.test.ts": 58, "src/renderer/src/lib/work-items/linear/linear-issue-workspace-attachment.test.ts": 99, - "src/renderer/src/lib/link-source-local-open-owner.test.ts": 433, "src/renderer/src/lib/work-items/linked-work-item-context.test.ts": 64, "src/renderer/src/lib/editor/monaco/monaco-editor-gutter-disposal.test.ts": 295, "src/renderer/src/lib/monaco-languages/markdown-heading-outline.test.ts": 70, @@ -6329,80 +6196,34 @@ "src/renderer/src/lib/monaco-languages/textmate-token-provider.test.ts": 245, "src/renderer/src/lib/monaco-languages/zig-highlighting.test.ts": 7984, "src/renderer/src/lib/agent-session/resume/cli-fork/native-chat-cli-fork-preparation.test.ts": 2773, - "src/renderer/src/lib/open-agent-message-sender.test.ts": 1497, "src/renderer/src/lib/simulator/launch/open-mobile-emulator-tab.test.ts": 545, - "src/renderer/src/lib/order-empty-query-worktrees.test.ts": 62, "src/renderer/src/lib/files/drop/os-file-drop-cancellation-guard.test.ts": 204, - "src/renderer/src/lib/paired-runtime-closed-tab-resume.test.ts": 2008, + "src/renderer/src/lib/agent-session/resume/paired-runtime-closed-tab-resume.test.ts": 2008, "src/renderer/src/lib/pane-manager/pane-close-focus-successor.test.ts": 1123, - "src/renderer/src/lib/pane-manager/pane-container-listener-lifecycle.test.ts": 312, - "src/renderer/src/lib/pane-manager/pane-cursor-blink-suspension.test.ts": 429, "src/renderer/src/lib/pane-manager/pane-drag-window-blur.test.ts": 618, - "src/renderer/src/lib/pane-manager/pane-fit-resize-observer.test.ts": 94, - "src/renderer/src/lib/pane-manager/pane-inline-image-recovery.test.ts": 61, - "src/renderer/src/lib/pane-manager/pane-inline-images.test.ts": 74, "src/renderer/src/lib/pane-manager/pane-layout-geometry-apply.test.ts": 897, "src/renderer/src/lib/pane-manager/pane-manager-registry.test.ts": 69, "src/renderer/src/lib/pane-manager/pane-manager-spawn-placement.test.ts": 766, - "src/renderer/src/lib/pane-manager/pane-scroll.test.ts": 153, - "src/renderer/src/lib/pane-manager/pane-terminal-foreground-render-settle.test.ts": 43, - "src/renderer/src/lib/pane-manager/pane-terminal-mouse-wheel.test.ts": 88, - "src/renderer/src/lib/pane-manager/pane-terminal-output-queue-chunks.test.ts": 44, - "src/renderer/src/lib/pane-manager/pane-tree-equalization-parity.test.ts": 182, - "src/renderer/src/lib/pane-manager/pane-tree-equalization-scaling.test.ts": 239, + "src/renderer/src/lib/pane-manager/terminal-output/pane-terminal-output-queue-chunks.test.ts": 44, "src/renderer/src/lib/pane-manager/pane-tree-match-moves.test.ts": 662, - "src/renderer/src/lib/pane-manager/pane-viewport-present-lifetime.test.ts": 1466, - "src/renderer/src/lib/pane-manager/pane-viewport-present-synchronized-output.test.ts": 316, - "src/renderer/src/lib/pane-manager/pane-webgl-renderer.test.ts": 390, - "src/renderer/src/lib/pane-manager/terminal-arabic-shaping-joiner.test.ts": 84, - "src/renderer/src/lib/pane-manager/terminal-delivery-credit.test.ts": 40, + "src/renderer/src/lib/pane-manager/terminal-rendering/terminal-arabic-shaping-joiner.test.ts": 84, "src/renderer/src/lib/pane-manager/terminal-foreground-repair-convergence.test.ts": 247, - "src/renderer/src/lib/pane-manager/terminal-grid-size-for-box.test.ts": 195, - "src/renderer/src/lib/pane-manager/terminal-image-added-repaint.test.ts": 50, - "src/renderer/src/lib/pane-manager/terminal-ime-anchor.test.ts": 51, - "src/renderer/src/lib/pane-manager/terminal-ime-candidate-anchor.test.ts": 232, - "src/renderer/src/lib/pane-manager/terminal-indic-cluster-ranges.test.ts": 50, - "src/renderer/src/lib/pane-manager/terminal-kitty-file-reader.test.ts": 83, - "src/renderer/src/lib/pane-manager/terminal-ligatures-addon.test.ts": 59, - "src/renderer/src/lib/pane-manager/terminal-linkifier-hover-reset-on-write.test.ts": 59, - "src/renderer/src/lib/pane-manager/terminal-mouse-encoding-tracker.test.ts": 95, + "src/renderer/src/lib/pane-manager/terminal-rendering/terminal-indic-cluster-ranges.test.ts": 50, "src/renderer/src/lib/pane-manager/terminal-mouse-report-finite-coordinates.test.ts": 272, - "src/renderer/src/lib/pane-manager/terminal-scroll-intent-anchor.test.ts": 234, - "src/renderer/src/lib/pane-manager/terminal-scroll-intent-input-resync.test.ts": 72, - "src/renderer/src/lib/pane-manager/terminal-scroll-intent.test.ts": 118, - "src/renderer/src/lib/pane-manager/terminal-stable-cell-fit-addon.test.ts": 198, - "src/renderer/src/lib/pane-manager/terminal-structural-replay-coordinator.test.ts": 68, - "src/renderer/src/lib/pane-manager/terminal-structural-replay-presentation.test.ts": 360, - "src/renderer/src/lib/pane-manager/terminal-webgl-hidden-canvas-release.test.ts": 177, - "src/renderer/src/lib/pane-manager/terminal-windows-ctrl-alt-chord-classification.test.ts": 213, - "src/renderer/src/lib/pane-manager/terminal-write-pipeline-health.test.ts": 66, - "src/renderer/src/lib/pane-manager/windows-pty-compatibility.test.ts": 68, "src/renderer/src/lib/pane-manager/xterm-alternate-buffer-resize.test.ts": 89, - "src/renderer/src/lib/pane-manager/xterm-instance-disposed.test.ts": 57, - "src/renderer/src/lib/pane-manager/xterm-parse-barrier.test.ts": 154, - "src/renderer/src/lib/pane-manager/xterm-user-scrolling-contract.test.ts": 1266, - "src/renderer/src/components/terminal-pane/session-restore/spawn-deferral/pane-spawn-deferral-drain.test.ts": 61, "src/renderer/src/components/terminal-pane/mounting/parked-terminal-host-hydration.test.ts": 274, "src/renderer/src/lib/text-input/paste/paste-payload-metadata.test.ts": 53, "src/renderer/src/lib/path-display/path-head-elision.test.ts": 53, "src/renderer/src/lib/path.test.ts": 55, - "src/renderer/src/lib/plugin-command-keybindings.test.ts": 1909, - "src/renderer/src/lib/plugin-command-replacements.test.ts": 95, + "src/renderer/src/lib/plugins/commands/plugin-command-keybindings.test.ts": 1909, "src/renderer/src/lib/plugin-icons/plugin-icon-svg.test.ts": 231, "src/renderer/src/lib/editor/appearance/plugin-monaco-token-rules.test.ts": 51, "src/renderer/src/lib/source-control/review/pr-bot-author-overrides.test.ts": 349, "src/renderer/src/lib/source-control/review/comments/pr-comment-thread-resolution.test.ts": 48, - "src/renderer/src/lib/workspace/creation/project-clone-url-prefill.test.ts": 61, "src/renderer/src/lib/workspace/creation/project-host-workspace-target.jira-mapping.test.ts": 76, "src/renderer/src/lib/workspace/creation/project-host-workspace-target.test.ts": 92, "src/renderer/src/lib/editor/file-operations/remap-open-editor-tabs-for-path-change.test.ts": 2178, - "src/renderer/src/lib/rename-user-named-tab-access.test.ts": 2804, "src/renderer/src/lib/renderer-agent-status-observation-ingress.test.ts": 81, - "src/renderer/src/diagnostics/memory/renderer-memory-profile.test.ts": 70, - "src/renderer/src/lib/repo-search.test.ts": 54, - "src/renderer/src/lib/repo-slug-cache.test.ts": 52, - "src/renderer/src/lib/repo-slug-index.test.ts": 2240, - "src/renderer/src/lib/resolved-worktree-execution-host.test.ts": 300, "src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session-deferred-pane.test.ts": 1747, "src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session-direct-ssh-hydration-gap.test.ts": 1654, "src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session-execution-host-scope.test.ts": 1924, @@ -6412,57 +6233,37 @@ "src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session-slept-pane-recovery.test.ts": 1855, "src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session-stranded-sleep.test.ts": 1962, "src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session-suppress-navigation.test.ts": 1919, - "src/renderer/src/lib/agent-session/resume/resume-sleeping-agent-session.test.ts": 2140, "src/renderer/src/lib/resume-stale-structured-agent-session.test.ts": 1774, - "src/renderer/src/lib/retracted-host-pane-resume.test.ts": 2009, "src/renderer/src/lib/review-owner.test.ts": 238, - "src/renderer/src/lib/run-quick-command-in-new-tab.test.ts": 82, "src/renderer/src/lib/runtime-host-copy.test.ts": 317, - "src/renderer/src/lib/script-textarea-rows.test.ts": 93, - "src/renderer/src/lib/session-write-subscriber-acknowledgment.test.ts": 1823, - "src/renderer/src/lib/session-write-subscriber.test.ts": 1882, - "src/renderer/src/lib/sidebar-ended-creations.test.ts": 1889, - "src/renderer/src/lib/sidebar-pending-layer.test.ts": 338, - "src/renderer/src/lib/sidebar-shadow/workspace-activity-shadow.test.ts": 1728, + "src/renderer/src/components/sidebar/sidebar-feed/sidebar-pending-layer.test.ts": 338, "src/renderer/src/lib/simulator/launch/simulator-launch-coordination.test.ts": 43, "src/renderer/src/lib/simulator/search/simulator-palette-search.test.ts": 515, "src/renderer/src/lib/simulator/tabs/simulator-pane-shutdown-scheduler.test.ts": 1679, "src/renderer/src/lib/simulator/tabs/simulator-tab-layout-owner.test.ts": 2398, "src/renderer/src/lib/simulator/tabs/simulator-tab-palette-activation.test.ts": 1903, "src/renderer/src/lib/source-control/remote/source-control-remote-error.test.ts": 340, - "src/renderer/src/lib/ssh-config-passive-sync.test.ts": 1513, "src/renderer/src/diagnostics/memory/state-collection-byte-estimate.test.ts": 86, "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-draft.test.ts": 1042, - "src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-prerequisites.test.ts": 2427, - "src/renderer/src/lib/agent-session/options/structured-agent-session-selection-lifetime.test.tsx": 2947, - "src/renderer/src/lib/structured-chat-tab-index.test.ts": 45, - "src/renderer/src/lib/structured-session-open-consumers.test.tsx": 2643, "src/renderer/src/lib/syntax-highlighting/incremental-syntax-tokenizer.test.ts": 665, "src/renderer/src/lib/syntax-highlighting/syntax-highlight-scheduler.test.ts": 149, "src/renderer/src/lib/syntax-highlighting/syntax-highlighter.test.ts": 539, "src/renderer/src/lib/syntax-highlighting/textmate-core.test.ts": 60, - "src/renderer/src/lib/tab-agent-status-index.test.ts": 210, "src/renderer/src/lib/task-provider-error-copy.test.ts": 363, "src/renderer/src/app-shell/appearance/terminal-app-theme.test.ts": 301, - "src/renderer/src/lib/terminal-input-activity-coalescing.test.ts": 43, "src/renderer/src/lib/text-input/paste/text-control-paste-ownership.test.ts": 217, "src/renderer/src/lib/text-input/paste/text-control-paste.test.ts": 222, "src/renderer/src/lib/text-generation-error-copy.test.ts": 466, - "src/renderer/src/lib/typing-latency/echo-instrumentation.test.ts": 145, - "src/renderer/src/lib/typing-latency/renderer-long-tasks.test.ts": 75, - "src/renderer/src/lib/typing-latency/sample-window.test.ts": 77, - "src/renderer/src/lib/unread-badge-count-selector.test.ts": 1930, - "src/renderer/src/lib/use-tab-agent-observed-signal-dispatch.test.tsx": 1971, - "src/renderer/src/lib/use-tab-agent-opencode-native-title.test.ts": 2093, - "src/renderer/src/lib/use-tab-agent.test.ts": 1961, - "src/renderer/src/lib/wake-sleeping-agents-live-unmounted-pane.test.ts": 2432, + "src/renderer/src/diagnostics/typing-latency/echo-instrumentation.test.ts": 145, + "src/renderer/src/diagnostics/typing-latency/renderer-long-tasks.test.ts": 75, + "src/renderer/src/attention/unread/unread-badge-count-selector.test.ts": 1930, + "src/renderer/src/lib/agent-session/tab-identity/use-tab-agent-observed-signal-dispatch.test.tsx": 1971, + "src/renderer/src/lib/agent-session/tab-identity/use-tab-agent.test.ts": 1961, "src/renderer/src/runtime/hosts/capabilities/windows-terminal-capabilities-race.test.ts": 450, "src/renderer/src/lib/workspace/activation/workspace-activation-path-gate.test.ts": 2107, "src/renderer/src/lib/browser/workspace/workspace-browser-tab-open-placement.test.ts": 1996, "src/renderer/src/lib/workspace-ports/workspace-port-scan-debounce.test.ts": 57, - "src/renderer/src/lib/workspace/persistence/workspace-session-host-contention.test.ts": 265, "src/renderer/src/lib/workspace/persistence/workspace-session-host-emptied-fields.test.ts": 279, - "src/renderer/src/lib/workspace/persistence/workspace-session-host-persistence.test.ts": 313, "src/renderer/src/lib/workspace/persistence/workspace-session-ssh-partition-ownership.test.ts": 309, "src/renderer/src/lib/workspace/persistence/workspace-session-ssh-partition-round-trip.test.ts": 1775, "src/renderer/src/lib/workspace/search/tabs/workspace-tab-palette-activation.store.test.ts": 1994, @@ -6474,23 +6275,18 @@ "src/renderer/src/lib/workspace/activation/worktree-activation-structured-chat-surface.test.ts": 2043, "src/renderer/src/lib/workspace/activation/worktree-activation-web-runtime.test.ts": 2768, "src/renderer/src/lib/workspace/activation/worktree-agent-activation-seam.test.ts": 3440, - "src/renderer/src/lib/workspace/creation/worktree-creation-backend-startup-focus.test.ts": 2267, "src/renderer/src/lib/workspace/creation/worktree-creation-initial-surface.test.ts": 5258, - "src/renderer/src/lib/workspace/creation/worktree-creation-structured-session-lifecycle.test.ts": 2633, "src/renderer/src/lib/workspace/creation/worktree-creation-structured-session-prompts.test.tsx": 4554, "src/renderer/src/lib/workspace/ownership/worktree-live-terminal-surface-owners.test.ts": 266, "src/renderer/src/lib/workspace/ownership/worktree-operation-route-index.test.ts": 262, "src/renderer/src/lib/workspace/ownership/worktree-operation-route.test.ts": 342, "src/renderer/src/lib/workspace/search/worktrees/worktree-palette-comment-snippet.test.ts": 53, "src/renderer/src/lib/workspace/search/worktrees/worktree-palette-titleless-review.test.ts": 198, - "src/renderer/src/lib/workspace/search/worktrees/worktree-palette-search.test.ts": 206, "src/renderer/src/lib/workspace/search/worktrees/worktree-palette-task-url-match.test.ts": 165, "src/renderer/src/lib/workspace/activation/worktree-reactivation-preserved-pane-replacement.test.ts": 2268, "src/renderer/src/lib/workspace/activation/worktree-reactivation-tab-forkbomb.test.ts": 4131, "src/renderer/src/lib/workspace/ownership/worktree-runtime-owner-index.detected.test.ts": 121, "src/renderer/src/lib/workspace/ownership/worktree-runtime-owner.test.ts": 380, - "src/renderer/src/lib/worktree-status-spinner-launch-agent.test.ts": 271, - "src/renderer/src/lib/worktree-status.test.ts": 306, "src/renderer/src/lib/workspace/persistence/wsl-move-renderer-store-rewrites.test.ts": 1072, "src/renderer/src/runtime/rpc/calls/abortable-runtime-environment-call.test.ts": 189, "src/renderer/src/runtime/provider-accounts/observations/claude-agent-view-observations.test.ts": 105, @@ -6505,20 +6301,15 @@ "src/renderer/src/runtime/workspace-layout/frames/layout-changes-during-stream-outage.test.ts": 1948, "src/renderer/src/runtime/workspace-layout/commands/layout-owner-command.test.ts": 549, "src/renderer/src/runtime/native-chat/naming/legacy-chat-rename-migration.test.tsx": 3834, - "src/renderer/src/runtime/local-structured-session-tabs-sync/local-structured-session-tabs-sync.test.ts": 2643, "src/renderer/src/runtime/web-session-tabs-sync/agent-status/mirrored-agent-status-clock-skew.test.ts": 1839, - "src/renderer/src/runtime/web-session-tabs-sync/agent-status/paired-reconnect-sidebar-agent-count.test.ts": 1905, "src/renderer/src/runtime/web-session-tabs-sync/closing/paired-terminal-tab-close-environment-removal.test.ts": 1897, "src/renderer/src/runtime/web-session-tabs-sync/closing/paired-terminal-tab-close-reload.test.ts": 1943, "src/renderer/src/runtime/workspace-layout/frames/pane-titles-drawn-from-frames.test.ts": 1988, - "src/renderer/src/runtime/web-session-tabs-sync/agent-status/remote-agent-row-last-assistant-message.test.ts": 1776, - "src/renderer/src/runtime/files/mutations/remote-host-file-delete-repro.test.ts": 1890, "src/renderer/src/runtime/web-session-tabs-sync/inventory/remote-runtime-session-tabs-inflight.test.ts": 55, "src/renderer/src/runtime/hosted-terminals/snapshots/remote-runtime-snapshot-outcome.test.ts": 233, "src/renderer/src/runtime/hosted-terminals/streams/remote-runtime-terminal-frame-drop-resync.test.ts": 266, "src/renderer/src/runtime/hosted-terminals/streams/remote-runtime-terminal-paused-output-drop.test.ts": 248, "src/renderer/src/runtime/hosted-terminals/streams/remote-runtime-terminal-stale-stream-frames.test.ts": 234, - "src/renderer/src/runtime/hosted-terminals/streams/remote-runtime-terminal-stall-recovery.test.ts": 826, "src/renderer/src/runtime/hosts/updates/remote-server-restart-wait.test.ts": 49, "src/renderer/src/runtime/rpc/subscriptions/runtime-client-events.test.ts": 64, "src/renderer/src/runtime/files/reads/runtime-directory-page-client.test.ts": 268, @@ -6544,17 +6335,13 @@ "src/renderer/src/runtime/workspace-layout/server/server-layout-apply.test.ts": 2222, "src/renderer/src/runtime/workspace-layout/server/server-layout-editor-handover.test.ts": 5075, "src/renderer/src/runtime/workspace-layout/server/server-layout-frames-handover.test.ts": 1991, - "src/renderer/src/runtime/workspace-layout/server/server-layout-frames-held-tabs.test.ts": 2302, "src/renderer/src/runtime/workspace-layout/server/server-layout-frames.test.ts": 2053, "src/renderer/src/runtime/native-chat/status/structured-agent-session-status-feed-lifecycle.test.ts": 62, "src/renderer/src/runtime/native-chat/status/structured-agent-session-status-feed.test.ts": 82, - "src/renderer/src/runtime/native-chat/status/structured-agent-session-turn-completion-feed.test.ts": 118, "src/renderer/src/runtime/native-chat/host-capabilities/structured-chat-host-permission.test.ts": 523, "src/renderer/src/runtime/web-session-tabs-sync/placement/structured-conversation-tab-replacement.test.ts": 2029, - "src/renderer/src/runtime/native-chat/tab-retirement/structured-launch-cancel-layout-owner.test.ts": 1985, "src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-chat-tab-order.test.ts": 529, "src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-conversion-publish.test.ts": 1608, - "src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-editor-diff-tabs.test.ts": 526, "src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-parked-leaf.test.ts": 641, "src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-payload-partition.test.ts": 583, "src/renderer/src/runtime/sync-runtime-graph/sync-runtime-graph-publication-cost.test.ts": 549, @@ -6563,28 +6350,21 @@ "src/renderer/src/runtime/sync-runtime-graph/terminal-group-grid-sizes.test.ts": 194, "src/renderer/src/runtime/browser/creation/web-runtime-browser-creation-placement.test.ts": 1927, "src/renderer/src/runtime/browser/creation/web-runtime-browser-link-open.test.ts": 2217, - "src/renderer/src/runtime/browser/creation/web-runtime-browser-link-session.test.ts": 1964, "src/renderer/src/runtime/web-session-tabs-sync/closing/web-session-close-replay.test.ts": 1119, - "src/renderer/src/runtime/web-session-tabs-sync/placement/web-session-open-files-batch-equivalence.test.ts": 1478, "src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-restored-placeholder-identity.test.ts": 985, "src/renderer/src/runtime/web-session-tabs-sync/agent-status/web-session-tabs-agent-completion-notifications.test.ts": 1953, "src/renderer/src/runtime/web-session-tabs-sync/tracking/web-session-tabs-removed-frame-retires-live-publisher.test.ts": 854, "src/renderer/src/runtime/web-session-tabs-sync/subscriptions/web-session-tabs-stream-end-resubscribe.test.tsx": 2282, - "src/renderer/src/runtime/web-session-tabs-sync/agent-status/web-session-tabs-sync-agent-status.test.ts": 987, - "src/renderer/src/runtime/web-session-tabs-sync/placement/web-session-tabs-sync-browser-tabs.test.ts": 925, "src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-tabs-sync-cross-runtime-worktree.test.ts": 964, "src/renderer/src/runtime/web-session-tabs-sync/placement/web-session-tabs-sync-editor-ownership.test.ts": 1902, "src/renderer/src/runtime/web-session-tabs-sync/placement/web-session-tabs-sync-editor-tabs.test.ts": 1073, "src/renderer/src/runtime/web-session-tabs-sync/navigation/web-session-tabs-sync-focus-intent.test.ts": 892, "src/renderer/src/runtime/web-session-tabs-sync/agent-status/web-session-tabs-sync-host-tab-retraction-ghost-rows.test.ts": 1956, - "src/renderer/src/runtime/web-session-tabs-sync/subscriptions/web-session-tabs-sync-initial-terminal-relaunch.test.tsx": 2248, "src/renderer/src/runtime/web-session-tabs-sync/identity/web-session-tabs-sync-mirror-identity.test.ts": 2524, "src/renderer/src/runtime/web-session-tabs-sync/placement/web-session-tabs-sync-mirrored-draft-close.test.ts": 1833, "src/renderer/src/runtime/web-session-tabs-sync/agent-status/web-session-tabs-sync-remote-status-title-flap.test.ts": 1715, - "src/renderer/src/runtime/web-session-tabs-sync/agent-status/web-session-tabs-sync-sleep-activity.test.ts": 1010, "src/renderer/src/runtime/web-session-tabs-sync/agent-status/web-session-tabs-sync-stale-spinner.test.ts": 921, "src/renderer/src/runtime/web-session-tabs-sync/tracking/web-session-tabs-sync-tracking-teardown.test.ts": 940, - "src/renderer/src/runtime/web-session-tabs-sync/subscriptions/web-session-tabs-sync-unverifiable-host.test.tsx": 2424, "src/renderer/src/runtime/web-session-tabs-sync/subscriptions/web-session-tabs-sync-visibility-collision.test.tsx": 2699, "src/renderer/src/runtime/web-session-tabs-sync/subscriptions/web-session-tabs-sync-window-visibility.test.tsx": 2589, "src/renderer/src/runtime/web-session-tabs-sync/subscriptions/web-session-tabs-sync-worktree-switch.test.tsx": 2625, @@ -6592,7 +6372,6 @@ "src/renderer/src/runtime/web-session-tabs-sync/frame-drawn-server-workspaces.test.ts": 956, "src/renderer/src/runtime/hosted-terminals/recovery/inventory/web-session-terminal-orphan-absence-across-republication.test.ts": 678, "src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-mixed-version.test.ts": 923, - "src/renderer/src/runtime/hosted-terminals/recovery/adoption/web-session-terminal-orphan-recovery-adoption-regressions.test.ts": 1214, "src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-recovery-regressions.test.ts": 1029, "src/renderer/src/runtime/hosted-terminals/recovery/web-session-terminal-orphan-recovery-sleep.test.ts": 1066, "src/renderer/src/runtime/hosted-terminals/recovery/surfaces/web-session-terminal-orphan-recovery-topology-fence.test.ts": 868, @@ -6601,10 +6380,8 @@ "src/renderer/src/runtime/hosted-terminals/recovery/evidence/web-session-terminal-retirement-proof-ledger.test.ts": 685, "src/renderer/src/runtime/rpc/subscriptions/window-visibility-subscription-parking-stream-end.test.ts": 225, "src/renderer/src/runtime/workspace-layout/frames/workspace-layout-frame-binding.test.ts": 2155, - "src/renderer/src/runtime/workspace-layout/frames/workspace-layout-frame-editor-views.test.ts": 2098, "src/renderer/src/runtime/workspace-layout/frames/workspace-layout-frame-held-tabs.test.ts": 2519, "src/renderer/src/runtime/workspace-layout/frames/workspace-layout-frame-sync.test.ts": 2282, - "src/renderer/src/runtime/workspace-layout/frames/workspace-layout-frame-tab-props.test.ts": 2852, "src/renderer/src/ssh/node-dist-mirror-recovery.test.ts": 1770, "src/renderer/src/ssh/ssh-connect-in-flight.test.ts": 62, "src/renderer/src/startup/startup-degraded-recovery.test.ts": 574, @@ -6616,8 +6393,6 @@ "src/renderer/src/store/github/requests/provider-request-coalescing.test.ts": 969, "src/renderer/src/store/slices/hosted-review/refresh/visible-hosted-review-refresh-scheduler.test.ts": 97, "src/renderer/src/store/github/repositories/wsl-stopped-distro-poll-refusal.test.ts": 696, - "src/renderer/src/store/workspaces/host-isolation/host-twin-isolation.test.ts": 1889, - "src/renderer/src/store/workspaces/host-isolation/host-twin-worktree-purge.test.ts": 1945, "src/renderer/src/store/plugins/localization/plugin-language-packs-startup.test.ts": 435, "src/renderer/src/store/plugins/localization/plugin-language-packs.test.ts": 377, "src/renderer/src/store/plugins/catalog/plugin-panel-retry-timer-cleanup.test.ts": 5216, @@ -6653,18 +6428,15 @@ "src/renderer/src/store/slices/agent-status/agent-status-worktree-purge-leak.test.ts": 1744, "src/renderer/src/store/slices/agent-status/agent-status.test.ts": 2129, "src/renderer/src/store/repos/all-host-catalog-settlement.test.ts": 1955, - "src/renderer/src/store/slices/worktrees/teardown/ambiguous-owner-warning-worktree-removal-leak.test.ts": 2101, "src/renderer/src/store/slices/browser/annotations/browser-annotation-retention.test.ts": 8178, "src/renderer/src/store/slices/browser/cleanup/browser-cleanup-close.test.ts": 1911, "src/renderer/src/store/slices/browser/cleanup/browser-mount-admission-removal.test.ts": 1982, "src/renderer/src/store/slices/browser/pages/browser-page-conversion.test.ts": 1777, - "src/renderer/src/store/slices/browser/hosts/browser-remote-tab-creation.test.ts": 2119, "src/renderer/src/store/slices/browser/hosts/browser-session-host-selection.test.ts": 988, "src/renderer/src/store/slices/browser/profiles/browser-session-profiles.test.ts": 792, "src/renderer/src/store/slices/browser/tabs/browser-tab-creation-placement.test.ts": 1886, "src/renderer/src/store/slices/browser/pages/browser-workspace-doc-location.test.ts": 2007, "src/renderer/src/store/slices/browser/browser.test.ts": 2001, - "src/renderer/src/store/slices/worktrees/teardown/bulk-worktree-purge-terminal-maps-leak.test.ts": 1727, "src/renderer/src/store/terminals/codex-restart-notice-lifecycle.test.ts": 1685, "src/renderer/src/store/slices/tabs/content-tabs-from-main-frames.test.ts": 2025, "src/renderer/src/store/slices/tabs/content-tabs-paired-server-workspace.test.ts": 1923, @@ -6674,12 +6446,9 @@ "src/renderer/src/store/slices/diff-comments/diffComments.test.ts": 1896, "src/renderer/src/store/slices/editor/git/editor-branch-line-total.test.ts": 892, "src/renderer/src/store/slices/editor/checks/editor-check-details-reading.test.ts": 945, - "src/renderer/src/store/slices/editor/checks/editor-check-details-reconstructed-owner.test.ts": 2056, "src/renderer/src/store/slices/editor/checks/editor-check-details-tab-owner.test.ts": 1103, - "src/renderer/src/store/slices/editor/checks/editor-check-details-tabs.test.ts": 1814, "src/renderer/src/store/slices/editor/closing/editor-close-background-file.test.ts": 893, "src/renderer/src/store/slices/editor/closing/editor-close-document-siblings.test.ts": 1317, - "src/renderer/src/store/slices/editor/closing/editor-close-file-cleanup.test.ts": 2000, "src/renderer/src/store/slices/editor/closing/editor-close-file-stale-active.test.ts": 1806, "src/renderer/src/store/slices/editor/closing/editor-close-pinned-sibling.test.ts": 924, "src/renderer/src/store/slices/editor/closing/editor-close-workspace-selection.test.ts": 1850, @@ -6687,16 +6456,13 @@ "src/renderer/src/store/slices/editor/git/editor-git-status-reconciliation.test.ts": 870, "src/renderer/src/store/slices/editor/tabs/editor-layout-owner-records.test.ts": 2006, "src/renderer/src/store/slices/editor/markdown/editor-markdown-link-activation.test.ts": 953, - "src/renderer/src/store/slices/editor/git/editor-open-diff.test.ts": 1987, "src/renderer/src/store/slices/editor/tabs/editor-open-link-placement.test.ts": 1987, "src/renderer/src/store/slices/editor/tabs/editor-preview-tab-setting.test.ts": 1952, "src/renderer/src/store/slices/editor/opening/editor-read-only-tabs.test.ts": 901, "src/renderer/src/store/slices/editor/closing/editor-recently-closed-tabs.test.ts": 1948, "src/renderer/src/store/slices/editor/git/editor-remote-branch-actions.test.ts": 935, - "src/renderer/src/store/slices/editor/hydration/editor-session-duplicate-restore.test.ts": 1931, "src/renderer/src/store/slices/editor/focus/editor-set-active-file-guard.test.ts": 895, "src/renderer/src/store/slices/editor/tabs/editor-tab-layout-owner.test.ts": 1883, - "src/renderer/src/store/slices/editor/tabs/editor-tab-placement.test.ts": 1837, "src/renderer/src/store/slices/editor/tabs/editor-tab-shared-project-owner.test.ts": 954, "src/renderer/src/store/slices/editor/buffers/editor-buffer-reconcile-identity.test.ts": 1775, "src/renderer/src/store/slices/editor/buffers/editor-buffer-reconcile-joins.test.ts": 1766, @@ -6711,15 +6477,12 @@ "src/renderer/src/store/github/pull-requests/github-linked-review-clear-ownership.test.ts": 891, "src/renderer/src/store/slices/editor/git/github-post-operation-owner.test.ts": 2062, "src/renderer/src/store/github/pull-requests/github-pr-branch-direct-refresh-scope.test.ts": 667, - "src/renderer/src/store/github/pull-requests/github-pr-branch-fallback-results.test.ts": 658, "src/renderer/src/store/github/pull-requests/github-pr-branch-linked-pr-divergence.test.ts": 662, "src/renderer/src/store/github/comments/github-pr-comment-read-order.test.ts": 570, "src/renderer/src/store/github/comments/github-pr-comments.test.ts": 746, - "src/renderer/src/store/github/pull-requests/github-pr-host-scope.test.ts": 1030, "src/renderer/src/store/github/refresh/github-pr-manual-refresh-broadcast.test.ts": 693, "src/renderer/src/store/github/refresh/github-pr-refresh-states-leak.test.ts": 1327, "src/renderer/src/store/github/pull-requests/github-pr-request-lifetime.test.ts": 1458, - "src/renderer/src/store/github/projects/github-project-view-tables.test.ts": 656, "src/renderer/src/store/github/repositories/github-repo-lookup-index.test.ts": 51, "src/renderer/src/store/github/review-threads/github-review-thread-rollback.test.ts": 663, "src/renderer/src/store/github/task-records/github-task-record-retries.test.ts": 758, @@ -6738,17 +6501,14 @@ "src/renderer/src/store/slices/worktrees/teardown/native-chat-launch-draft-teardown.test.ts": 1854, "src/renderer/src/store/slices/orca-profiles/orca-profiles-auth-actions-connect-overlap.test.ts": 1685, "src/renderer/src/store/slices/tabs/pinned-tab-close-confirm.test.ts": 44, - "src/renderer/src/store/slices/preflight/preflight.test.ts": 1858, "src/renderer/src/store/repos/project-removal-host-twin-state.test.ts": 1972, "src/renderer/src/store/repos/project-removal-owner-host.test.ts": 1880, "src/renderer/src/store/repos/project-removal-runtime-terminal-order.test.ts": 1769, "src/renderer/src/store/repos/project-removal-unreachable-server.test.ts": 2292, "src/renderer/src/store/slices/worktrees/teardown/purge-stale-runtime-host-ownership.test.ts": 1767, - "src/renderer/src/store/slices/worktrees/teardown/purge-stale-runtime-host-state.test.ts": 1719, "src/renderer/src/store/slices/worktrees/teardown/removed-worktree-diff-memory.test.ts": 2981, "src/renderer/src/store/repos/repos-add-races.test.ts": 1731, "src/renderer/src/store/repos/repos-all-hosts-generation.test.ts": 1908, - "src/renderer/src/store/repos/repos-all-hosts.test.ts": 1971, "src/renderer/src/store/repos/repos-catalog-connection-fence.test.ts": 1821, "src/renderer/src/store/repos/repos-catalog-request-coordination.test.ts": 1602, "src/renderer/src/store/repos/repos-ephemeral-vm-cleanup-retention.test.ts": 2459, @@ -6777,23 +6537,14 @@ "src/renderer/src/store/slices/runtime-status/set-runtime-environments-purge-wiring.test.ts": 1683, "src/renderer/src/store/slices/settings/settings-owner-hydration-write-fence.test.ts": 1860, "src/renderer/src/store/slices/settings/settings-terminal-quick-commands.test.ts": 1734, - "src/renderer/src/store/slices/settings/settings.test.ts": 1938, "src/renderer/src/store/slices/worktrees/create/sparse-presets.test.ts": 217, - "src/renderer/src/store/slices/ssh/ssh.test.ts": 1843, "src/renderer/src/lib/workspace/activation/active-worktree-removal-successor.test.ts": 1867, - "src/renderer/src/store/slices/worktrees/session/store-active-worktree-selection.test.ts": 2039, "src/renderer/src/store/terminals/store-create-tab-start-in-main.test.ts": 1801, "src/renderer/src/store/slices/tabs/store-open-to-side-layout-owner.test.ts": 1919, - "src/renderer/src/store/slices/browser/hydration/store-session-browser-hydration.test.ts": 1906, "src/renderer/src/store/repos/store-session-cascades.test.ts": 1775, - "src/renderer/src/store/slices/editor/hydration/store-session-editor-hydration.test.ts": 1719, - "src/renderer/src/store/terminals/store-session-terminal-reconnect.test.ts": 2279, - "src/renderer/src/store/terminals/store-session-workspace-hydration.test.ts": 1733, - "src/renderer/src/store/terminals/store-sleep-agent-status-retention.test.ts": 7641, "src/renderer/src/store/terminals/store-sleep-exact-runtime-stop.test.ts": 1842, "src/renderer/src/store/terminals/store-sleep-pane-hibernation.test.ts": 1932, "src/renderer/src/store/terminals/store-sleep-runtime-convergence.test.ts": 1767, - "src/renderer/src/store/terminals/store-sleep-twin-host-owner.test.ts": 1706, "src/renderer/src/store/slices/worktrees/teardown/store-worktree-removal-cascade.test.ts": 1786, "src/renderer/src/store/slices/worktrees/teardown/tab-worktree-orphan-map-purge-leak.test.ts": 1936, "src/renderer/src/store/slices/tabs/tabs-close-dangling-group.test.ts": 1849, @@ -6803,22 +6554,18 @@ "src/renderer/src/store/slices/tabs/tabs-model-reconciliation.test.ts": 1800, "src/renderer/src/store/slices/tabs/tabs-open-close-lifecycle.test.ts": 2140, "src/renderer/src/store/slices/tabs/tabs-pane-layout-operations.test.ts": 1652, - "src/renderer/src/store/slices/tabs/tabs-split-create.test.ts": 1733, "src/renderer/src/store/slices/tabs/tabs-unread-and-focus.test.ts": 1801, "src/renderer/src/store/slices/tabs/structured-chat-close-owner.test.ts": 1866, "src/renderer/src/store/slices/tabs/tabs-reconciliation-empty-groups.test.ts": 1703, "src/renderer/src/store/terminals/terminal-layout-pty-ownership.test.ts": 1734, "src/renderer/src/store/terminals/terminal-pane-detach-agent-identity.test.ts": 1627, - "src/renderer/src/store/terminals/terminal-pane-detach-agent-retention.test.ts": 2846, "src/renderer/src/store/terminals/terminal-pty-identity-replacement.test.ts": 1751, "src/renderer/src/store/terminals/terminal-quick-command-hosts.test.ts": 1759, "src/renderer/src/store/terminals/terminal-tab-owner-index.test.ts": 50, "src/renderer/src/store/terminals/terminal-tab-recovery-remount.test.ts": 1791, "src/renderer/src/store/terminals/terminal-tab-retirement-store.test.ts": 1955, - "src/renderer/src/store/terminals/terminal-tab-title-batch.test.ts": 1749, "src/renderer/src/store/terminals/terminals-hydration-canonical-pty-overlap.test.ts": 1946, "src/renderer/src/store/terminals/terminals-hydration-canonical-rows.test.ts": 1680, - "src/renderer/src/store/slices/ui/ui-agent-send-target.test.ts": 760, "src/renderer/src/store/slices/ui/ui-host-filter-sync.test.ts": 597, "src/renderer/src/store/slices/ui/ui-host-workspace-statuses.test.ts": 1695, "src/renderer/src/store/slices/ui/ui-modal-slot-dismissal.test.ts": 662, @@ -6855,13 +6602,9 @@ "src/renderer/src/store/slices/worktrees/metadata/worktrees-git-identity-twin-host.test.ts": 1342, "src/renderer/src/store/slices/worktrees/listing/worktrees-hydration-purge.test.ts": 1274, "src/renderer/src/store/slices/worktrees/session/worktrees-identity-migration.test.ts": 1412, - "src/renderer/src/store/slices/worktrees/metadata/worktrees-lineage-state.test.ts": 1133, "src/renderer/src/store/slices/worktrees/metadata/worktrees-linked-review-push-target.test.ts": 1186, "src/renderer/src/store/slices/worktrees/metadata/worktrees-multiple-attachments.test.ts": 1132, "src/renderer/src/store/slices/worktrees/create/worktrees-pending-creation-state.test.ts": 1132, - "src/renderer/src/store/slices/worktrees/teardown/worktrees-purge-terminal-state.test.ts": 1133, - "src/renderer/src/store/slices/worktrees/create/worktrees-remote-runtime-create.test.ts": 1244, - "src/renderer/src/store/slices/worktrees/teardown/worktrees-remote-runtime-removal.test.ts": 1227, "src/renderer/src/store/slices/worktrees/teardown/worktrees-removal-state-cleanup.test.ts": 1229, "src/renderer/src/store/slices/worktrees/listing/worktrees-runtime-connection-generation-fence.test.ts": 1240, "src/renderer/src/store/slices/worktrees/session/worktrees-terminal-pr-exact-observation.test.ts": 1201, @@ -6889,7 +6632,6 @@ "src/renderer/src/store/terminals/workspace-terminal-placeholders.test.ts": 302, "src/renderer/src/store/slices/runtime-status/views/use-runtime-status-view.test.tsx": 1979, "src/renderer/src/store/workspace-layout/workspace-layout-cache.test.ts": 63, - "src/renderer/src/store/workspace-layout/frames/workspace-layout-frame-store-patch.test.ts": 2284, "src/renderer/src/store/slices/worktrees/listing/worktree-host-collision-index.test.ts": 1875, "src/renderer/src/web/preload-api/web-agent-session-attachment-upload.test.ts": 1588, "src/renderer/src/web/preload-api/web-chat-permission-normalization.test.ts": 293, @@ -7852,10 +7594,8 @@ "tests/e2e/agent-launch-cli.unit.test.ts": 2379, "tests/e2e/agent-launch-setup-choice.unit.test.ts": 2657, "tests/e2e/agent-model-catalog-renderer-cache.unit.test.ts": 2029, - "tests/e2e/ai-vault-account-stream.unit.test.ts": 4506, "tests/e2e/ai-vault-manual-name-clear.unit.test.ts": 21206, "tests/e2e/automation-chat-reopen.unit.test.ts": 6262, - "tests/e2e/claude-agent-row-view.unit.test.ts": 1491, "tests/e2e/codex-child-approval-activity-row.unit.test.ts": 14886, "tests/e2e/completed-worker-retirement-resume.unit.test.ts": 38857, @@ -7891,20 +7631,16 @@ "tests/e2e/host-agent-launch-preferences-work.unit.test.ts": 3882, "tests/e2e/host-agent-launch-settings-hook-bookkeeping.unit.test.ts": 21972, "tests/e2e/host-cold-park-remote-subscriber.unit.test.ts": 5314, - "tests/e2e/launch-agent-background-session-remote.unit.test.ts": 1016, "tests/e2e/launch-agent-in-new-tab-web-runtime.unit.test.ts": 14288, "tests/e2e/linear-cli-recovery.unit.test.ts": 7592, "tests/e2e/linear-store.unit.test.ts": 519, "tests/e2e/linear-write-lifetime.unit.test.ts": 5214, "tests/e2e/multi-workspace-typing-bench.unit.test.ts": 550, - "tests/e2e/native-chat-image-runtime-context.unit.test.ts": 2124, "tests/e2e/native-chat-live-history.unit.test.ts": 3258, "tests/e2e/native-chat-rewind-boundary.unit.test.ts": 2977, "tests/e2e/native-chat-ssh-transcript.unit.test.ts": 1166, "tests/e2e/native-chat-startup-option-pickers.unit.test.ts": 9377, - - "tests/e2e/native-chat-transcript-reasoning.unit.test.ts": 3341, "tests/e2e/nested-agent-idle-owner.unit.test.ts": 2469, "tests/e2e/omp-child-session-recovery.unit.test.ts": 2205, "tests/e2e/omp-retired-host-renderer.unit.test.ts": 2546, @@ -7928,7 +7664,6 @@ "tests/e2e/source-control-action-phone-launch.unit.test.ts": 746, "tests/e2e/ssh-browser-network-execution-route.docker.unit.test.ts": 413, "tests/e2e/structured-agent-session-launch-admission.unit.test.ts": 4762, - "tests/e2e/structured-agent-session-launch-continuation.unit.test.ts": 23572, "tests/e2e/structured-agent-session-read-owner.unit.test.ts": 6912, "tests/e2e/structured-attention-headless-delivery.unit.test.ts": 328, "tests/e2e/structured-attention-prompt-relay.unit.test.ts": 14045, @@ -8018,7 +7753,14 @@ "src/main/skills/skill-delete/skill-wsl-delete.integration.test.ts": 85, "src/main/skills/filesystem/skill-wsl-install-filesystem.test.ts": 60, "src/main/skills/install/skill-wsl-install-transaction.integration.test.ts": 250, - "src/main/skills/filesystem/skill-wsl-posix-semantics.integration.test.ts": 254 + "src/main/skills/filesystem/skill-wsl-posix-semantics.integration.test.ts": 254, + "src/renderer/src/lib/pane-manager/terminal-scroll/pane-scroll.test.ts": 153, + "src/renderer/src/lib/pane-manager/terminal-input/pane-terminal-mouse-wheel.test.ts": 88, + "src/renderer/src/lib/pane-manager/pane-layout/pane-tree-equalization-parity.test.ts": 182, + "src/renderer/src/lib/pane-manager/terminal-input/terminal-ime-anchor.test.ts": 51, + "src/renderer/src/lib/pane-manager/terminal-scroll/terminal-scroll-intent.test.ts": 118, + "src/renderer/src/lib/pane-manager/terminal-replay/terminal-structural-replay-coordinator.test.ts": 68, + "src/renderer/src/lib/pane-manager/terminal-protocol/windows-pty-compatibility.test.ts": 68 } }, "e2e": { diff --git a/config/scripts/locale-catalog/locale-cjk-latin-spaced-terms.mjs b/config/scripts/locale-catalog/locale-cjk-latin-spaced-terms.mjs index dce911f0a4c..f93d7b5ed70 100644 --- a/config/scripts/locale-catalog/locale-cjk-latin-spaced-terms.mjs +++ b/config/scripts/locale-catalog/locale-cjk-latin-spaced-terms.mjs @@ -32,6 +32,9 @@ export const CJK_LATIN_SPACED_TERMS = [ 'Kimi', 'OpenCode', 'Orca', + 'Artifacts', + 'Artifact', + 'Relay', 'Cursor', 'Bitbucket', 'Tailscale', diff --git a/config/scripts/locale-catalog/locale-ja-unified-values.mjs b/config/scripts/locale-catalog/locale-ja-unified-values.mjs index bd099f9be7b..c85b2d93793 100644 --- a/config/scripts/locale-catalog/locale-ja-unified-values.mjs +++ b/config/scripts/locale-catalog/locale-ja-unified-values.mjs @@ -152,7 +152,7 @@ export const JA_UNIFIED_VALUES = { 'The GitLab CLI is installed but not authenticated. Run this command in a terminal:': 'GitLab CLI はインストールされていますが、認証されていません。ターミナルで次のコマンドを実行してください:', 'Install GitLab CLI': 'GitLab CLI をインストール', - 'CLI.': 'CLI。', + 'CLI.': 'CLI', 'The GitHub CLI is installed but not authenticated. Run this command in a terminal:': 'GitHub CLI はインストールされていますが、認証されていません。ターミナルで次のコマンドを実行してください:', 'Install GitHub CLI': 'GitHub CLI をインストール', diff --git a/config/scripts/locale-catalog/locale-key-overrides.mjs b/config/scripts/locale-catalog/locale-key-overrides.mjs index 625c59ae173..8947fb2fee8 100644 --- a/config/scripts/locale-catalog/locale-key-overrides.mjs +++ b/config/scripts/locale-catalog/locale-key-overrides.mjs @@ -116,7 +116,7 @@ const BASE_LOCALE_KEY_OVERRIDES = { }, 'auto.components.settings.SettingsSidebar.82db1b7de4': { ko: '온보딩 체크리스트, {{value0}}/{{value1}} 완료. 설정 가이드 보기.', - zh: '入门清单,已完成 {{value0}}/{{value1}}。显示设置指南。', + zh: '入门清单,已完成 {{value0}}/{{value1}}。显示设置指南', ja: 'オンボーディングチェックリスト、{{value0}}/{{value1}} 完了。セットアップガイドを表示。' }, 'auto.components.settings.ShortcutFilterRail.02dc7d4251': { @@ -307,12 +307,12 @@ const BASE_LOCALE_KEY_OVERRIDES = { }, 'settings.appearance.statusBar.kimiToggleDescription': { ko: '활성 워크스페이스의 Kimi 구독 사용량을 표시합니다.', - zh: '显示当前工作区的 Kimi 订阅使用情况。', + zh: '显示当前工作区的 Kimi 订阅使用情况', ja: 'アクティブなワークスペースの Kimi サブスクリプション使用状況を表示します。' }, 'auto.components.mobile.MobileHero.cd4e5e816f': { ko: '주머니 속의 워크스페이스.', - zh: '您的工作区就在您的口袋里。', + zh: '您的工作区就在您的口袋里', ja: 'ワークスペースをポケットに。' }, 'auto.components.GitHubItemDialog.dbe5e2448e': { @@ -332,12 +332,12 @@ const BASE_LOCALE_KEY_OVERRIDES = { }, 'auto.components.JiraIssueWorkspace.857bd2f88f': { ko: '선택한 이슈를 미리보기하고, 편집하고, 작업을 시작하세요.', - zh: '预览、编辑并从选定的议题开始工作。', + zh: '预览、编辑并从选定的议题开始工作', ja: '選択したイシューをプレビュー・編集し、そこから作業を開始します。' }, 'auto.components.LinearIssueWorkspace.ad5dec37b7': { ko: '선택한 이슈를 미리보기하고, 편집하고, 작업을 시작하세요.', - zh: '预览、编辑并从选定的议题开始工作。', + zh: '预览、编辑并从选定的议题开始工作', ja: '選択したイシューをプレビュー・編集し、そこから作業を開始します。' }, 'auto.components.TaskPage.67662ade50': { @@ -352,12 +352,12 @@ const BASE_LOCALE_KEY_OVERRIDES = { }, 'auto.components.TaskPage.1e1b2ad8f2': { ko: '이 이슈를 등록하기 전에 프로젝트 워크스페이스에서 팀을 선택하세요.', - zh: '在提交此议题之前,请从项目工作区选择一个团队。', + zh: '在提交此议题之前,请从项目工作区选择一个团队', ja: 'このイシューを登録する前に、プロジェクトワークスペースからチームを選択してください。' }, 'auto.components.TaskPage.94d900518d': { ko: '선택한 프리셋과 일치하는 이슈가 없습니다.', - zh: '没有与所选预设匹配的议题。', + zh: '没有与所选预设匹配的议题', ja: '選択したプリセットに一致するイシューはありません。' }, 'auto.components.linear.project.view.surfaces.3ad562bdf4': { @@ -392,7 +392,7 @@ const BASE_LOCALE_KEY_OVERRIDES = { }, 'auto.components.onboarding.OnboardingFlow.04ae28d8ca': { ko: '몇 시간 내내 보고 싶은 테마를 선택하세요.', - zh: '选择你想盯着看几个小时的主题。', + zh: '选择你想盯着看几个小时的主题', ja: '何時間も眺めていたくなるテーマを選んでください。' }, 'auto.components.GitLabItemDialog.e089f62594': { @@ -402,12 +402,12 @@ const BASE_LOCALE_KEY_OVERRIDES = { }, 'auto.components.right.sidebar.source.control.primary.action.3d5dccef0b': { ko: '커밋할 것이 없습니다. PR은 이미 병합되었습니다.', - zh: '没有可提交的内容。PR 已合并。', + zh: '没有可提交的内容。PR 已合并', ja: 'コミットするものはありません。PR はすでにマージされています。' }, 'auto.components.settings.integrations.search.16a486a49d': { ko: 'Linear에 연결해 이슈를 탐색하고 연결합니다.', - zh: '连接 Linear 以浏览和链接议题。', + zh: '连接 Linear 以浏览和链接议题', ja: 'Linear に接続してイシューを参照し、リンクします。' }, 'menu.showTitlebarAppName': { @@ -422,7 +422,7 @@ const BASE_LOCALE_KEY_OVERRIDES = { }, 'auto.lib.fix.checks.agent.launch.9f00d7df0c': { ko: '검사 프롬프트가 비어 있습니다. 소스 제어 AI 설정을 업데이트하세요.', - zh: '检查提示为空。请更新源代码管理 AI 设置。', + zh: '检查提示为空。请更新源代码管理 AI 设置', ja: 'チェック プロンプトが空です。ソース管理 AI 設定を更新してください。' }, 'auto.components.TaskPage.2af3ab5c58': { @@ -442,7 +442,7 @@ const BASE_LOCALE_KEY_OVERRIDES = { }, 'auto.components.TaskPage.25ff84769a': { ko: '이 Linear 컨텍스트와 일치하는 이슈가 없습니다.', - zh: '没有议题与此 Linear 上下文匹配。', + zh: '没有议题与此 Linear 上下文匹配', ja: 'この Linear コンテキストに一致するイシューはありません。' }, 'auto.components.GitHubItemDialog.8c45901789': { @@ -512,7 +512,7 @@ const BASE_LOCALE_KEY_OVERRIDES = { }, 'auto.components.GitHubItemDialog.a341343303': { ko: '리뷰 댓글이 추가되었습니다.', - zh: '已添加评审评论。', + zh: '已添加评审评论', ja: 'レビューコメントを追加しました。' }, // Port forwarding "Forward" is 転送, not the browser-navigation 進む. diff --git a/config/scripts/locale-catalog/locale-macos-tcc-key-overrides.mjs b/config/scripts/locale-catalog/locale-macos-tcc-key-overrides.mjs index d094fb6c249..375e3335e6e 100644 --- a/config/scripts/locale-catalog/locale-macos-tcc-key-overrides.mjs +++ b/config/scripts/locale-catalog/locale-macos-tcc-key-overrides.mjs @@ -9,13 +9,13 @@ export const MACOS_TCC_KEY_OVERRIDES = { es: 'Los mensajes de permisos de macOS pueden aparecer cuando un agente o una herramienta de terminal que se ejecuta en Orca intenta acceder a archivos protegidos. Concede acceso total al disco en Ajustes para reducir estos avisos.', ja: 'Orca で実行中のエージェントやターミナルツールが保護されたファイルにアクセスしようとすると、macOS の権限メッセージが表示されることがあります。これらの確認を減らすには、設定でフルディスクアクセスを許可してください。', ko: 'Orca에서 실행 중인 에이전트나 터미널 도구가 보호된 파일에 접근하려고 하면 macOS 권한 메시지가 표시될 수 있습니다. 이러한 요청을 줄이려면 설정에서 전체 디스크 접근 권한을 허용하세요.', - zh: '当 Orca 中运行的智能体或终端工具尝试访问受保护的文件时,macOS 可能会显示权限信息。请在“设置”中授予“完全磁盘访问权限”,以减少此类提示。' + zh: '当 Orca 中运行的智能体或终端工具尝试访问受保护的文件时,macOS 可能会显示权限信息。请在“设置”中授予“完全磁盘访问权限”,以减少此类提示' }, 'auto.components.settings.DeveloperPermissionsPane.7ca17b62c8': { es: 'Cuando los agentes que ejecuta Orca leen datos de otras apps, macOS muestra el nombre de Orca porque es el proceso responsable de los comandos de terminal. Concede este permiso a Orca para reducir esos avisos. Después, cierra y vuelve a abrir Orca.', ja: 'Orca が実行するエージェントがほかのアプリのデータを読み取ると、ターミナルコマンドの実行元プロセスである Orca の名前が macOS に表示されます。これらの確認を減らすには、Orca にこの権限を許可してください。その後、Orca を終了して再度開いてください。', ko: 'Orca가 실행하는 에이전트가 다른 앱의 데이터를 읽으면, macOS는 터미널 명령을 실행하는 프로세스인 Orca를 표시합니다. 이러한 요청을 줄이려면 Orca에 이 권한을 허용하세요. 그런 다음 Orca를 종료했다가 다시 여세요.', - zh: '当 Orca 运行的智能体读取其他应用的数据时,macOS 会显示 Orca,因为 Orca 是执行终端命令的进程。请为 Orca 授予此权限,以减少此类提示。然后退出并重新打开 Orca。' + zh: '当 Orca 运行的智能体读取其他应用的数据时,macOS 会显示 Orca,因为 Orca 是执行终端命令的进程。请为 Orca 授予此权限,以减少此类提示。然后退出并重新打开 Orca' }, 'auto.components.settings.DeveloperPermissionsPane.c566bca278': { ko: '전체 디스크 접근 권한', diff --git a/config/scripts/locale-catalog/locale-value-overrides.mjs b/config/scripts/locale-catalog/locale-value-overrides.mjs index 6b08bcc811e..025a1833d7d 100644 --- a/config/scripts/locale-catalog/locale-value-overrides.mjs +++ b/config/scripts/locale-catalog/locale-value-overrides.mjs @@ -197,8 +197,8 @@ export const LOCALE_VALUE_OVERRIDES = { Next: '下一步', Beta: '测试版', Dismiss: '关闭', - Artifacts: '工件', - artifacts: '工件', + Artifacts: '产物', + artifacts: '产物', Native: '原生', Bundled: '内置', Quarter: '季度', diff --git a/config/scripts/locale-catalog/locale-zh-value-overrides.mjs b/config/scripts/locale-catalog/locale-zh-value-overrides.mjs index 82c499edec5..dd816f66b0f 100644 --- a/config/scripts/locale-catalog/locale-zh-value-overrides.mjs +++ b/config/scripts/locale-catalog/locale-zh-value-overrides.mjs @@ -22,7 +22,7 @@ export const ZH_VALUE_OVERRIDES = { reviewer: '评审人', review: '评审', Review: '评审', - 'No matching reviewers.': '没有匹配的评审人。', + 'No matching reviewers.': '没有匹配的评审人', 'Request up to 15 reviewers': '最多请求 15 名评审人', 'No reviewers requested.': '未请求评审人', 'Remove reviewer {{value0}}': '移除评审人 {{value0}}', @@ -39,8 +39,8 @@ export const ZH_VALUE_OVERRIDES = { 'Enter a reviewer': '输入评审人', 'Add reviewer': '添加评审人', 'No reviewers.': '没有评审人', - 'Open the PR details to view current reviewers.': '打开 PR 详情以查看当前评审人。', - 'Review comment added.': '已添加评审评论。', + 'Open the PR details to view current reviewers.': '打开 PR 详情以查看当前评审人', + 'Review comment added.': '已添加评审评论', 'Loading labels': '加载标签', // Why: MT rendered the "Pin Tab" action as "引脚标签" (noun reading of "pin"); pair it with 取消固定标签. 'Pin Tab': '固定标签', @@ -57,12 +57,12 @@ export const ZH_VALUE_OVERRIDES = { 'Markdown Review Notes': 'Markdown 评审笔记', 'Reviewed by': '评审人', 'Review from': '评审来自', - 'Reviewer id is unavailable for this GitLab user.': '此 GitLab 用户无法获取评审人 ID。', - 'Create a {{value0}} to start checks and review.': '创建 {{value0}} 以开始检查和评审。', + 'Reviewer id is unavailable for this GitLab user.': '此 GitLab 用户无法获取评审人 ID', + 'Create a {{value0}} to start checks and review.': '创建 {{value0}} 以开始检查和评审', 'Conflicted files are reviewed separately': '冲突文件单独评审', 'This review snapshot no longer has any live unresolved conflicts.': - '此评审快照不再有任何未解决的实时冲突。', - 'Skill command copied and inserted below for review.': '技能命令已复制并插入到下方以供评审。', + '此评审快照不再有任何未解决的实时冲突', + 'Skill command copied and inserted below for review.': '技能命令已复制并插入到下方以供评审', 'Release readiness review': '发布就绪评审', 'Recurring review': '定期评审', Completed: '已完成', @@ -91,9 +91,9 @@ export const ZH_VALUE_OVERRIDES = { 'Quick actions': '快捷操作', 'action recipes': '操作方案', 'Repository action recipes. Global settings are used until this repository customizes them.': - '仓库操作方案。在此仓库自定义之前,将使用全局设置。', + '仓库操作方案。在此仓库自定义之前,将使用全局设置', 'Adds action recipes for Source Control commit, pull request, branch-name, and fix actions.': - '为源代码管理的提交、拉取请求、分支命名和修复操作添加操作方案。', + '为源代码管理的提交、拉取请求、分支命名和修复操作添加操作方案', // Picker siblings are translated; English pins here would regenerate half-Chinese UI. Play: '播放', Flag: '标记', @@ -121,39 +121,39 @@ export const ZH_VALUE_OVERRIDES = { 'floating terminal': '浮动终端', 'New Issue': '新建议题', 'No issues match the selected filters. Clear a filter or try different criteria.': - '没有议题符合所选筛选条件。请清除筛选条件或尝试其他条件。', + '没有议题符合所选筛选条件。请清除筛选条件或尝试其他条件', 'No issues in this workspace scope. Try searching or adjusting teams.': - '此工作区范围内没有议题。请尝试搜索或调整团队。', + '此工作区范围内没有议题。请尝试搜索或调整团队', 'Close as duplicate': '作为重复议题关闭', 'Reply in this review thread': '在此评审线程中回复', - 'Failed to add review comment.': '添加评审评论失败。', + 'Failed to add review comment.': '添加评审评论失败', 'Localhost Worktree Labels': 'localhost 工作树标签', 'Open workspace ports as worktree-specific Orca localhost URLs so browser tabs are easier to tell apart.': - '将工作区端口作为工作树专属的 Orca localhost URL 打开,便于区分浏览器标签页。', + '将工作区端口作为工作树专属的 Orca localhost URL 打开,便于区分浏览器标签页', 'Permanently deletes the remote Git worktrees and their branches. Cannot be undone.': - '永久删除远程 Git 工作树及其分支。此操作不可撤销。', + '永久删除远程 Git 工作树及其分支。此操作不可撤销', 'Clears them from Orca only. Remote files, worktrees, and branches are left untouched.': - '仅从 Orca 中清除。远程文件、工作树和分支均不受影响。', + '仅从 Orca 中清除。远程文件、工作树和分支均不受影响', 'GitHub reports this pull request is blocked': 'GitHub 报告此拉取请求已被阻塞', 'GitHub requires review approval before this pull request can merge': 'GitHub 需要评审批准才能合并此拉取请求', 'Used by repositories that inherit global hosted-review defaults.': - '由继承全局托管评审默认值的仓库使用。', + '由继承全局托管评审默认值的仓库使用', 'Use review template when available': '可用时使用评审模板', 'Create hosted reviews as drafts unless changed in the composer.': - '除非在编辑器中更改,否则将托管评审创建为草稿。', - 'Start an agent from failed hosted-review checks.': '从失败的托管评审检查中启动智能体。', + '除非在编辑器中更改,否则将托管评审创建为草稿', + 'Start an agent from failed hosted-review checks.': '从失败的托管评审检查中启动智能体', 'Checks require a Git branch and hosted review context': '检查需要 Git 分支和托管评审上下文', 'Resolve Review Conflicts With AI': '使用 AI 解决评审冲突', 'Hosted review operation in progress…': '托管评审操作进行中…', 'Hosted review creation defaults': '托管评审创建默认值', 'Open hosted review after creation': '创建后打开托管评审', 'Hosted review creation defaults used when the hosted review editor opens.': - '打开托管评审编辑器时使用的托管评审创建默认值。', + '打开托管评审编辑器时使用的托管评审创建默认值', 'Run hosted review detail generation once when the editor opens.': - '编辑器打开时运行一次托管评审详情生成。', + '编辑器打开时运行一次托管评审详情生成', 'Show local Markdown review notes controls in rich editor mode.': - '在富文本编辑器模式下显示本地 Markdown 评审笔记控件。', + '在富文本编辑器模式下显示本地 Markdown 评审笔记控件', 'Orca IDE': 'Orca IDE', 'Orca first': 'Orca 优先', 'Orca Mobile': 'Orca Mobile', @@ -169,57 +169,57 @@ export const ZH_VALUE_OVERRIDES = { 'Active Codex Account': '活跃 Codex 账户', 'Claude Accounts': 'Claude 账户', 'Remove Claude Account?': '删除 Claude 账户?', - 'Claude account updated.': 'Claude 账户已更新。', - 'Claude account update failed.': 'Claude 账户更新失败。', - 'Could not load Claude accounts.': '无法加载 Claude 账户。', - 'Claude sign-in failed.': 'Claude 登录失败。', - 'Claude account added.': '已添加 Claude 账户。', + 'Claude account updated.': 'Claude 账户已更新', + 'Claude account update failed.': 'Claude 账户更新失败', + 'Could not load Claude accounts.': '无法加载 Claude 账户', + 'Claude sign-in failed.': 'Claude 登录失败', + 'Claude account added.': '已添加 Claude 账户', 'Claude Code session started': 'Claude Code 会话已开始', 'Codex session started': 'Codex 会话已开始', 'Enable Codex': '启用 Codex', - 'Most recent local Codex sessions in this scope.': '此范围内最近的本地 Codex 会话。', + 'Most recent local Codex sessions in this scope.': '此范围内最近的本地 Codex 会话', 'Hosted-review creation defaults': '托管评审创建默认值', - 'Defaults used when the hosted-review composer opens.': '打开托管评审编辑器时使用的默认值。', + 'Defaults used when the hosted-review composer opens.': '打开托管评审编辑器时使用的默认值', 'Run hosted-review detail generation once when the composer opens.': - '编辑器打开时运行一次托管评审详情生成。', + '编辑器打开时运行一次托管评审详情生成', 'Show local markdown review note controls in rich editor mode.': - '在富文本编辑器模式下显示本地 Markdown 评审笔记控件。', + '在富文本编辑器模式下显示本地 Markdown 评审笔记控件', 'Start an agent for local or hosted-review merge conflicts.': - '启动用于解决本地或托管评审合并冲突的智能体。', + '启动用于解决本地或托管评审合并冲突的智能体', 'changed since you last approved. Re-review before it runs': '自您上次批准以来已发生变化。运行前请重新评审', 'Run the weekly dependency audit and summarize risky changes.': - '每周运行依赖项审计并总结有风险的更改。', + '每周运行依赖项审计并总结有风险的更改', 'This turns on a process-wide Electron networking switch after restart. Use it for corporate VPNs or proxies that reject HTTP/2 update downloads.': - '这将在重启后启用进程级 Electron 网络开关。适用于拒绝 HTTP/2 更新下载的企业 VPN 或代理。', + '这将在重启后启用进程级 Electron 网络开关。适用于拒绝 HTTP/2 更新下载的企业 VPN 或代理', 'Use only when a corporate VPN or proxy breaks update downloads with HTTP/2 protocol errors. It affects all Electron networking after restart.': - '仅当企业 VPN 或代理因 HTTP/2 协议错误而中断更新下载时使用。重启后会影响所有 Electron 网络。', + '仅当企业 VPN 或代理因 HTTP/2 协议错误而中断更新下载时使用。重启后会影响所有 Electron 网络', 'Use HTTP/1.1 for Electron networking when HTTP/2 fails behind a proxy.': - '当 HTTP/2 在代理后面失败时,使用 HTTP/1.1 进行 Electron 网络。', + '当 HTTP/2 在代理后面失败时,使用 HTTP/1.1 进行 Electron 网络', 'Proxy Bypass Rules': '代理绕过规则', - 'Hosts that should bypass the configured HTTP proxy.': '应绕过配置的 HTTP 代理的主机。', + 'Hosts that should bypass the configured HTTP proxy.': '应绕过配置的 HTTP 代理的主机', 'Leave empty to use system proxy settings and inherited proxy environment variables.': - '留空以使用系统代理设置和继承的代理环境变量。', + '留空以使用系统代理设置和继承的代理环境变量', 'Proxy Command': '代理命令', "Give agents direct access to Orca's browser so they can test pages, capture screenshots, and act on what they see.": - '让智能体直接访问 Orca 的浏览器,以便测试页面、捕获屏幕截图并根据所见内容执行操作。', + '让智能体直接访问 Orca 的浏览器,以便测试页面、捕获屏幕截图并根据所见内容执行操作', 'X finishes, send it the review task.”': 'X 完成后,把评审任务发给它。”', - 'Branch naming, base refs, and Git AI Author.': '分支命名、基础引用和 Git AI Author。', + 'Branch naming, base refs, and Git AI Author.': '分支命名、基础引用和 Git AI Author', 'You have unsaved Git AI Author changes. Leaving will discard them.': - '您有未保存的 Git AI Author 更改。离开将丢弃它们。', + '您有未保存的 Git AI Author 更改。离开将丢弃它们', 'Discard unsaved Git AI Author changes?': '放弃未保存的 Git AI Author 更改?', - 'Create a Linear project for the selected team.': '为所选团队创建 Linear 项目。', + 'Create a Linear project for the selected team.': '为所选团队创建 Linear 项目', 'Linear task mode': 'Linear 任务模式', - 'Failed to switch Linear workspace.': '无法切换 Linear 工作区。', - 'Linear project is missing workspace context.': 'Linear 项目缺少工作区上下文。', + 'Failed to switch Linear workspace.': '无法切换 Linear 工作区', + 'Linear project is missing workspace context.': 'Linear 项目缺少工作区上下文', 'No Linear projects found': '未找到 Linear 项目', 'Unable to load Linear projects': '无法加载 Linear 项目', 'Change Linear state from {{value0}}': '将 Linear 状态从 {{value0}} 更改为', 'GitHub & Linear tasks': 'GitHub 和 Linear 任务', 'Each connected Linear workspace has one key stored by the active runtime. Full-access keys can cover all teams the key owner can access; restricted keys can be replaced any time.': - '每个已连接的 Linear 工作区都有一个由活动运行时存储的密钥。全权限密钥可覆盖密钥所有者可访问的所有团队;受限密钥可随时更换。', + '每个已连接的 Linear 工作区都有一个由活动运行时存储的密钥。全权限密钥可覆盖密钥所有者可访问的所有团队;受限密钥可随时更换', 'Show Linear in the Tasks source picker and sidebar shortcuts.': - '在任务源选择器和侧边栏快捷方式中显示 Linear。', + '在任务源选择器和侧边栏快捷方式中显示 Linear', 'Local project, Git repo, or folder with many repos': '本地项目、Git 仓库或包含多个仓库的文件夹', 'Staged Changes': '已暂存的更改', Changes: '更改', @@ -231,12 +231,12 @@ export const ZH_VALUE_OVERRIDES = { 'Split Terminal Down': '向下拆分终端', 'Split Terminal Right': '向右拆分终端', 'Optional account switching for Claude while preserving shared chat context.': - 'Claude 的可选账户切换,同时保留共享聊天上下文。', + 'Claude 的可选账户切换,同时保留共享聊天上下文', 'Countdown timer showing time until prompt cache expires (Claude agents).': - '显示提示词缓存到期倒计时的计时器(Claude 智能体)。', + '显示提示词缓存到期倒计时的计时器(Claude 智能体)', 'Claude caches your conversation to reduce costs. When idle too long the cache expires and the next message resends full context at higher cost. This shows a countdown so you know when to resume.': - 'Claude 会缓存对话以降低成本。空闲过久后缓存会过期,下一条消息将以更高成本重新发送完整上下文。此倒计时可帮助您了解何时继续。', - 'from Orca. It is still on your disk.': '来自 Orca。它仍保留在您的磁盘上。', + 'Claude 会缓存对话以降低成本。空闲过久后缓存会过期,下一条消息将以更高成本重新发送完整上下文。此倒计时可帮助您了解何时继续', + 'from Orca. It is still on your disk.': '来自 Orca。它仍保留在您的磁盘上', 'Pull request reopened': '拉取请求已重新打开', 'Reopen PR': '重新打开 PR', 'Reopened MR !{{value0}}': '已重新打开 MR !{{value0}}', diff --git a/config/scripts/localization/source-extraction/audit-localization-coverage.mjs b/config/scripts/localization/source-extraction/audit-localization-coverage.mjs index cd7cf997a7b..2fd052728b5 100644 --- a/config/scripts/localization/source-extraction/audit-localization-coverage.mjs +++ b/config/scripts/localization/source-extraction/audit-localization-coverage.mjs @@ -41,7 +41,8 @@ const USER_VISIBLE_FUNCTION_NAMES = new Set([ 'confirm', 'prompt', 'showError', - 'showToast' + 'showToast', + 'toast' ]) const USER_VISIBLE_OBJECT_METHODS = new Set([ 'error', diff --git a/config/scripts/performance/native-chat/native-chat-4a-comparison-arm.ts b/config/scripts/performance/native-chat/native-chat-4a-comparison-arm.ts index 49b71987ed3..de4d1e1a6de 100644 --- a/config/scripts/performance/native-chat/native-chat-4a-comparison-arm.ts +++ b/config/scripts/performance/native-chat/native-chat-4a-comparison-arm.ts @@ -3,6 +3,7 @@ import type { Arm } from './native-chat-4a-arm' import type { Manifest } from './native-chat-4a-fixture' import { profileRunner } from './native-chat-4a-run-context' import * as memory from './native-chat-4a-ops-memory' +import { convertedMemoryRows } from './native-chat-4a-memory-profile' import type { ArmResult, Row } from './native-chat-4a-report' import { seededDbFiles } from './native-chat-4a-sqlite-observer' import type { Workload } from './native-chat-4a-workloads' @@ -146,7 +147,7 @@ export async function runArm(input: { source.seedDir, source.manifest, 'memory', - memory.convertedMemoryRows, + convertedMemoryRows, memory.memoryWorkload(workload) ) }) diff --git a/config/scripts/performance/native-chat/native-chat-4a-comparison.ts b/config/scripts/performance/native-chat/native-chat-4a-comparison.ts index 5dc732d720e..eb0bb8e425e 100644 --- a/config/scripts/performance/native-chat/native-chat-4a-comparison.ts +++ b/config/scripts/performance/native-chat/native-chat-4a-comparison.ts @@ -10,6 +10,7 @@ import type { Arm } from './native-chat-4a-arm' import { assertOneRun, parseArmSpec, seededBy } from './native-chat-4a-arm-provenance' import { FAMILIES, runArm, type Family } from './native-chat-4a-comparison-arm' import * as memory from './native-chat-4a-ops-memory' +import { seedMemoryProfile } from './native-chat-4a-memory-profile' import { armMarkdown, writeComparison, type ArmResult } from './native-chat-4a-report' import { conversionToolOutputBytes, @@ -104,7 +105,7 @@ async function main(): Promise { ? seededBy(seedArm, await seed(workload.history.toolOutputBytes, workload)) : null const { memoryProfile, memorySeedFailure } = families.has('memory') - ? await memory.seedMemoryProfile( + ? await seedMemoryProfile( out, workload, async (seeded, runDir) => diff --git a/config/scripts/performance/native-chat/native-chat-4a-memory-report.ts b/config/scripts/performance/native-chat/native-chat-4a-memory-report.ts index 2c29a1d5c31..42941120d6d 100644 --- a/config/scripts/performance/native-chat/native-chat-4a-memory-report.ts +++ b/config/scripts/performance/native-chat/native-chat-4a-memory-report.ts @@ -120,15 +120,15 @@ export function memoryMarkdown(base: ArmResult, next?: ArmResult): string[] { const heaps = workers .map((worker) => { const memory = object(worker.memory) - return `${memory.threadId ?? worker.sessionId}: ${memory.heapUsed ?? 'unavailable'}` + return `${String(memory.threadId ?? worker.sessionId)}: ${String(memory.heapUsed ?? 'unavailable')}` }) .join(', ') const status = inventory.complete === true ? JSON.stringify(inventory.roleCounts) - : `unexercised: ${sample?.evidence?.workerError ?? JSON.stringify(inventory.errors) ?? 'inventory unavailable'}` + : `unexercised: ${String(sample?.evidence?.workerError ?? JSON.stringify(inventory.errors) ?? 'inventory unavailable')}` lines.push( - `| ${result.arm} | ${row.variant} | ${status} | ${heaps} | ${inventory.processRssBytes ?? 'unavailable'} |` + `| ${result.arm} | ${row.variant} | ${status} | ${heaps} | ${String(inventory.processRssBytes ?? 'unavailable')} |` ) } } diff --git a/config/scripts/performance/native-chat/native-chat-4a-ops-memory.ts b/config/scripts/performance/native-chat/native-chat-4a-ops-memory.ts index e61f0916374..7ce57fa6327 100644 --- a/config/scripts/performance/native-chat/native-chat-4a-ops-memory.ts +++ b/config/scripts/performance/native-chat/native-chat-4a-ops-memory.ts @@ -284,5 +284,3 @@ export async function memoryRows(ctx: RunContext): Promise { delta('before activation post-GC', 'after activation post-GC', 'activation delta post-GC') } } - -export { seedMemoryProfile, convertedMemoryRows } from './native-chat-4a-memory-profile' diff --git a/config/scripts/performance/terminal-stream/terminal-shutdown-byte-limit-benchmark.mjs b/config/scripts/performance/terminal-stream/terminal-shutdown-byte-limit-benchmark.mjs index 402ec2fa290..874600c3049 100644 --- a/config/scripts/performance/terminal-stream/terminal-shutdown-byte-limit-benchmark.mjs +++ b/config/scripts/performance/terminal-stream/terminal-shutdown-byte-limit-benchmark.mjs @@ -43,7 +43,7 @@ const layoutFunctions = layoutAst.statements.filter( ) assert.equal(layoutFunctions.length, layoutNames.length) const layoutSubset = `import { isTerminalLeafId } from ${JSON.stringify(path.resolve('src/shared/workspace-layout/stable-pane-id.ts'))}; -import { readSplitRatio } from '@/lib/pane-manager/pane-split-ratio'; +import { readSplitRatio } from '@/lib/pane-manager/pane-layout/pane-split-ratio'; import { SPLIT_RATIO_TOLERANCE } from ${JSON.stringify(path.resolve('src/shared/workspace-layout/terminal-pane-tree.ts'))}; ${layoutFunctions.map((node) => node.getText(layoutAst)).join('\n')}` diff --git a/config/scripts/static-analysis/ratchets/renderer-state/check-terminal-parking-ownership-ratchet.mjs b/config/scripts/static-analysis/ratchets/renderer-state/check-terminal-parking-ownership-ratchet.mjs index 112b837bbb7..8d823b050a9 100644 --- a/config/scripts/static-analysis/ratchets/renderer-state/check-terminal-parking-ownership-ratchet.mjs +++ b/config/scripts/static-analysis/ratchets/renderer-state/check-terminal-parking-ownership-ratchet.mjs @@ -125,7 +125,7 @@ const EFFECT_BOUNDARIES = new Set([ `${WATCHERS}terminal-parked-pty-watcher.ts#startParkedPtyWatcher`, `${RENDERER}components/terminal-pane/parking/capture/parked-terminal-buffer-capture.ts#captureParkedTerminalBuffers`, `${RENDERER}lib/agent-session/resume/sleeping-agent-session-launch.ts#launchSleepingAgentSession`, - `${RENDERER}lib/host-mirror-handle-gap-wait.ts#parkUntilHostMirrorHandleLands`, + `${RENDERER}lib/agent-session/resume/host-mirror-handle-gap-wait.ts#parkUntilHostMirrorHandleLands`, `${RENDERER}runtime/web-session-tabs-sync/hydration/host-session-mirror-hydration.ts#parkUntilHostSessionMirrorHydrates` ]) const ENUMERATORS = new Set(['entries', 'values', 'keys', 'assign']) diff --git a/config/scripts/workflow/source-routing/pr-feature-area-e2e-source-routes.mjs b/config/scripts/workflow/source-routing/pr-feature-area-e2e-source-routes.mjs index beb16f2a13c..1e6977f9dd9 100644 --- a/config/scripts/workflow/source-routing/pr-feature-area-e2e-source-routes.mjs +++ b/config/scripts/workflow/source-routing/pr-feature-area-e2e-source-routes.mjs @@ -92,9 +92,9 @@ export const PR_FEATURE_AREA_E2E_SOURCE_ROUTES = [ ['issue-12656-terminal-link-tooltip', 'terminal-pane-padding-edges'], [ 'src/renderer/src/assets/terminal.css', - 'src/renderer/src/lib/pane-manager/pane-divider.ts', + 'src/renderer/src/lib/pane-manager/pane-layout/pane-divider.ts', 'src/renderer/src/lib/pane-manager/pane-dom-creation.ts', - 'src/renderer/src/lib/pane-manager/terminal-linkifier-hover-reset-on-mouseleave.ts' + 'src/renderer/src/lib/pane-manager/terminal-input/terminal-linkifier-hover-reset-on-mouseleave.ts' ] ), featureRoute( diff --git a/config/workspace-record-read-baseline.txt b/config/workspace-record-read-baseline.txt index 8734401d303..b6e4e4e16f9 100644 --- a/config/workspace-record-read-baseline.txt +++ b/config/workspace-record-read-baseline.txt @@ -8,7 +8,6 @@ 4 src/renderer/src/components/dashboard/build-dashboard-bucket-counts.ts # P5b-2 must clear: optional state fields; memo compare goes stale when absent 3 src/renderer/src/components/dashboard/dashboard-card-terminal-input.ts # P5b-2 must clear: optional state fields default to empty 1 src/renderer/src/components/dashboard/dashboard-snapshot-workspaces.ts # P5b-2 must clear: optional state field defaults to empty -1 src/renderer/src/components/dashboard/dashboard-worktree-launch-options.ts # P5b-2 must clear: optional state field defaults to empty 4 src/renderer/src/components/dashboard/useDashboardPopoutBridge.ts # P5b-2 must clear: change detection on optional fields never fires when absent 2 src/renderer/src/components/dashboard/useRetainedAgents.ts # reads a passed-in copy 1 src/renderer/src/components/editor/markdown/documents/markdown-document-worktree-path-selector.ts # P5b-2 must clear: optional state field @@ -31,14 +30,14 @@ 1 src/renderer/src/lib/browser/navigation/http-link-localhost-route.ts # P5b-2 must clear: optional state field defaults to empty; extracted from http-link-routing.ts 1 src/renderer/src/lib/workspace/ownership/connection-owner-resolution.ts # P5b-2 must clear: optional-chain compare of a previous slice 2 src/renderer/src/lib/workspace/ownership/direct-ssh-target-scope.ts # P5b-2 must clear: optional input fields default to empty -3 src/renderer/src/lib/duplicate-paired-servers.ts # P5b-2 must clear: optional state fields default to empty +3 src/renderer/src/lib/workspace/ownership/duplicate-paired-servers.ts # P5b-2 must clear: optional state fields default to empty 1 src/renderer/src/lib/workspace/ownership/folder-workspace-runtime-owner.ts # P5b-2 must clear: loosely typed state param 1 src/renderer/src/runtime/hosts/wsl/local-project-runtime-workspace.ts # P5b-2 must clear: optional state field defaults to empty -1 src/renderer/src/lib/resolved-worktree-execution-host.ts # P5b-2 must clear: loosely typed state param +1 src/renderer/src/lib/workspace/ownership/resolved-worktree-execution-host.ts # P5b-2 must clear: loosely typed state param 2 src/renderer/src/lib/workspace/ownership/runtime-session-mirror-owners.ts # P5b-2 must clear: optional state fields default to empty 2 src/renderer/src/lib/workspace/ownership/terminal-worktree-route.ts # P5b-2 must clear: the unattributed-twin check reads both catalogs directly -3 src/renderer/src/lib/typing-latency/diagnostic-summary.ts # P5b-2 must clear: optional state field -2 src/renderer/src/lib/unread-badge-count.ts # reads a passed-in copy +3 src/renderer/src/diagnostics/typing-latency/diagnostic-summary.ts # P5b-2 must clear: optional state field +2 src/renderer/src/attention/unread/unread-badge-count.ts # reads a passed-in copy 1 src/renderer/src/lib/workspace/paths/workspace-directory.ts # P5b-2 must clear: optional state field defaults to empty 2 src/renderer/src/lib/workspace/ownership/workspace-terminal-host-authority.ts # P5b-2 must clear: optional state fields 1 src/renderer/src/lib/workspace/activation/initial-surface/worktree-initial-terminal-seeding.ts # P5b-2 must clear: treats an undefined field as a narrow adapter diff --git a/docs/assets/readme-downloads.svg b/docs/assets/readme-downloads.svg index 25b9a04169b..2892989fee1 100644 --- a/docs/assets/readme-downloads.svg +++ b/docs/assets/readme-downloads.svg @@ -1,5 +1,5 @@ - - downloads: 168m + + downloads: 169m @@ -15,7 +15,7 @@ downloads downloads - 168m - 168m + 169m + 169m diff --git a/docs/site/content/docs/cli/reference.mdx b/docs/site/content/docs/cli/reference.mdx index 12cfa96f2b0..bff53fb760b 100644 --- a/docs/site/content/docs/cli/reference.mdx +++ b/docs/site/content/docs/cli/reference.mdx @@ -233,6 +233,21 @@ orca chat rename --name "Migrate auth" Renames a chat tab, the same as renaming it by hand. `--session` takes the `sessionId` that `orca agent launch` prints. Run inside a chat, it defaults to that chat; with `--environment` it is required. +Agents that run as chats are read and messaged with `chat` commands. `--session` takes the session id from `chat list` or the handle `agent launch` returns. + +```bash +orca chat list --json +orca chat list --state working --json +orca chat read --session --limit 10 --json +orca chat send --session --text "Run the tests, then summarize failures" --json +orca chat send --session --text "" --wait --timeout-ms 600000 --json +orca chat wait --session --timeout-ms 600000 --json +``` + +`chat read` returns the newest messages, tool calls, errors, approvals and questions; an approval or question waiting for an answer has `pending: true`. `chat send` sends the text as your message. While the agent is working, hosts with a message queue hold it until the turn ends and report `delivery: "queued"`. A chat that restarted since it was read refuses the send. `--text-file -` reads the message from stdin. + +`chat send --wait` and `chat wait` return once the chat's own turn settles, in the words `chat list` uses: `settled: "done"`, or `settled: "blocked"` when an approval or question needs an answer. Background agents the chat started can still show as `working` or `waiting` in `chat list`. They print the entries since the last user message. A wait past `--timeout-ms` returns `settled: "timeout"`, and a message held in a stopped or failed queue returns `settled: "held"`; both exit 1. `chat read --json` returns a `cursor` for the newest row read, and `truncated: true` when older rows it needed were past the 200-row read. `chat list --state` takes `working`, `blocked`, `waiting` or `done`. Paired hosts (`--environment`, `--pairing-code`) can list chats but not read, send or wait yet. + ## Files ```bash @@ -412,7 +427,7 @@ A selection applies to every agent of that provider launched on the host after i ## Artifacts -Publish HTML or Markdown through the signed-in Orca account. Viewing a public link does not require sign-in; create/list/update/delete do. **Publishing is off by default** — a human must enable **Settings → Artifacts → Allow publishing public artifact links** on the device. There is no CLI flag that grants the gate. `list`, `unshare`, and `delete` stay available so you can audit or revoke links after turning publishing off. +Publish HTML or Markdown through the signed-in Orca account. Viewing a public link does not require sign-in; create/list/update/delete do. Publishing follows **Settings → Artifacts → Allow publishing public artifact links** on the device: on by default for new profiles, while profiles created before this default keep their previous setting. Only a human can change it; there is no CLI flag that grants the gate. `list`, `unshare`, and `delete` stay available so you can audit or revoke links after turning publishing off. ```bash orca artifacts share ./report.html --json diff --git a/docs/site/content/docs/editing/markdown.mdx b/docs/site/content/docs/editing/markdown.mdx index a84c3991611..32869df4e07 100644 --- a/docs/site/content/docs/editing/markdown.mdx +++ b/docs/site/content/docs/editing/markdown.mdx @@ -51,4 +51,4 @@ For long documents, click the **Table of Contents** button (tree icon) in the ed ## Share as artifact -From the editor header, **Share as artifact** publishes the open Markdown file as a public view link through your signed-in Orca account. Requires **Settings → Artifacts → Allow publishing public artifact links** (off by default). Republish updates the same link when Orca still has the mapping; manage or delete links from the sidebar **Artifacts** page. Agents and scripts can use `orca artifacts share|update|list|delete` — see [CLI reference → Artifacts](/docs/cli/reference#artifacts). +From the editor header, **Share as artifact** publishes the open Markdown file as a public view link through your signed-in Orca account. Requires **Settings → Artifacts → Allow publishing public artifact links** (on by default for new profiles). Republish updates the same link when Orca still has the mapping; manage or delete links from the sidebar **Artifacts** page. Agents and scripts can use `orca artifacts share|update|list|delete` — see [CLI reference → Artifacts](/docs/cli/reference#artifacts). diff --git a/docs/site/content/docs/settings.mdx b/docs/site/content/docs/settings.mdx index 7d71631f1c5..eb489b00875 100644 --- a/docs/site/content/docs/settings.mdx +++ b/docs/site/content/docs/settings.mdx @@ -91,7 +91,7 @@ Settings are grouped into panes. Everything here is searchable with `Cmd-,` then ## Artifacts - **Orca account** — sign in (same account family as Orca Relay) to publish and manage shared files. -- **Allow publishing public artifact links** — **off by default**. Device-wide gate: when on, you, agents, and the `orca` CLI on this machine can upload HTML/Markdown and mint public view links. Turning it off does not delete existing links. +- **Allow publishing public artifact links** — **on by default for new profiles**; profiles created before this default keep their previous setting. Device-wide gate: when on, you, agents, and the `orca` CLI on this machine can upload HTML/Markdown and mint public view links. Turning it off does not delete existing links. - **Show Artifacts** / sidebar shortcut — open the Artifacts list to search, preview, copy, or delete account-owned links. - **Ask Before Deleting Artifacts** — optional confirmation before breaking a public link. - Share from an open local HTML page or Markdown editor with **Share as artifact**, or via `orca artifacts …`. See [CLI reference → Artifacts](/docs/cli/reference#artifacts). diff --git a/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/MobileWebShellBridge.kt b/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/MobileWebShellBridge.kt index 045cce54908..99f8bfc2713 100644 --- a/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/MobileWebShellBridge.kt +++ b/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/MobileWebShellBridge.kt @@ -38,7 +38,7 @@ internal enum class MobileWebShellBridgeInstall { /** The prop is false, so nothing is registered and Phase B behaviour is byte-identical. */ SKIP, INSTALL, - /** The WebView provider is older than `WEB_MESSAGE_LISTENER` (Chromium 88). Terminal. */ + /** The WebView provider is older than `WEB_MESSAGE_LISTENER` (Chromium 83). Terminal. */ UNAVAILABLE } diff --git a/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/MobileWebShellDocument.kt b/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/MobileWebShellDocument.kt index af1aff6a343..0d8f77c5fc5 100644 --- a/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/MobileWebShellDocument.kt +++ b/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/MobileWebShellDocument.kt @@ -201,7 +201,7 @@ internal class MobileWebShellDocument(private val context: Context) { view.destroy() } - // Keep explicit settings for the Chromium 83 floor, even where newer WebViews ignore deprecated options. + // Keep explicit settings even where newer WebViews ignore deprecated options; the floor is Chromium 101. // B4 requires device proofs: no network, persistent state, file/content access, cleartext or navigation escape. @Suppress("DEPRECATION") private fun createWebView(): WebView { diff --git a/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/MobileWebShellNetworkApiBlocker.kt b/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/MobileWebShellNetworkApiBlocker.kt index 4c0397fdd0a..0b94103df6e 100644 --- a/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/MobileWebShellNetworkApiBlocker.kt +++ b/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/MobileWebShellNetworkApiBlocker.kt @@ -17,7 +17,7 @@ internal val MOBILE_WEB_SHELL_NETWORK_API_BLOCKER = """ })(); """.trimIndent() -/** Query document-start-script capability (Chromium 83 floor), not version strings. */ +/** Query capability, not version strings; stable WebView has it from Chromium 101. */ internal fun installMobileWebShellNetworkApiBlocker( webView: WebView, allowedOrigin: String diff --git a/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/OrcaMobileWebShellModule.kt b/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/OrcaMobileWebShellModule.kt index abba9fd7675..e08436bd126 100644 --- a/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/OrcaMobileWebShellModule.kt +++ b/mobile/modules/orca-mobile-web-shell/android/src/main/java/expo/modules/orcamobilewebshell/OrcaMobileWebShellModule.kt @@ -8,6 +8,8 @@ import android.content.res.Configuration import android.net.Uri import android.os.Handler import android.os.Looper +import androidx.webkit.WebViewCompat +import androidx.webkit.WebViewFeature import expo.modules.kotlin.exception.CodedException import expo.modules.kotlin.exception.Exceptions import expo.modules.kotlin.functions.Queues @@ -68,6 +70,17 @@ class OrcaMobileWebShellModule : Module() { Uri.fromFile(directory).toString() } + // Lets isolation-unavailable name the WebView to update. + Function("currentWebViewProvider") { + val context = appContext.reactContext ?: return@Function null + val info = WebViewCompat.getCurrentWebViewPackage(context) ?: return@Function null + val version = info.versionName ?: return@Function null + val name = info.applicationInfo?.loadLabel(context.packageManager)?.toString() ?: info.packageName + val hasShellFeatures = WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT) && + WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) + mapOf("name" to name, "version" to version, "hasShellFeatures" to hasShellFeatures) + } + AsyncFunction("prepareSpareDocument") { directory: String, sessionId: String -> val activity = appContext.currentActivity ?: return@AsyncFunction false MobileWebShellSparePool.prepare(activity, directory, sessionId) diff --git a/mobile/modules/orca-mobile-web-shell/src/index.ts b/mobile/modules/orca-mobile-web-shell/src/index.ts index 97979cd7019..4e072e2efb2 100644 --- a/mobile/modules/orca-mobile-web-shell/src/index.ts +++ b/mobile/modules/orca-mobile-web-shell/src/index.ts @@ -18,7 +18,7 @@ export type OrcaMobileWebShellViewProps = ViewProps & { generationDirectory: string /** `[A-Za-z0-9_-]{1,128}`. Scopes the private origin, so every mount must mint a fresh one. */ sessionId: string - // Bridge is off by default with nothing registered. Opt-in on Android below WEB_MESSAGE_LISTENER/Chromium 88 fails isolation-unavailable instead of loading unfenced. + // Bridge is off by default with nothing registered. Opt-in on Android below WEB_MESSAGE_LISTENER/Chromium 83 fails isolation-unavailable instead of loading unfenced. bridgeEnabled?: boolean onLoadState?: (event: NativeSyntheticEvent) => void // Raw JSON from window.orcaBridge; native silently rejects other origins/frames/WebViews and envelopes above 640 KiB (MobileWebShellBridge.maxMessageByteCount). @@ -82,6 +82,23 @@ export function warmUpWebShell(): void { } } +export type WebViewProvider = { name: string; version: string; hasShellFeatures: boolean } + +// Android only: the WebView provider and whether it has the shell's fences. Null when unknown. +export function currentWebViewProvider(): WebViewProvider | null { + if (Platform.OS !== 'android') { + return null + } + const shell = requireOptionalNativeModule<{ + currentWebViewProvider?: () => WebViewProvider | null + }>('OrcaMobileWebShell') + try { + return shell?.currentWebViewProvider?.() ?? null + } catch { + return null + } +} + export { MOBILE_WEB_SHELL_FAILURE_REASONS, parseMobileWebShellLoadState, diff --git a/mobile/rpc-foundation/pilot-scenarios.json b/mobile/rpc-foundation/pilot-scenarios.json index dfd3079e39d..688d2a86b98 100644 --- a/mobile/rpc-foundation/pilot-scenarios.json +++ b/mobile/rpc-foundation/pilot-scenarios.json @@ -21045,7 +21045,7 @@ "id": "codex-reset-credit-consumed", "operation": "accounts.codex-reset-credit", "family": "components.codex-reset-credit", - "sites": ["mobile/src/components/codex-reset-credit.ts"], + "sites": ["mobile/src/accounts/usage/codex-reset-credit.ts"], "schedules": [], "deviceStore": {}, "steps": [ diff --git a/mobile/src/accounts/MobileAccountsScreen.tsx b/mobile/src/accounts/MobileAccountsScreen.tsx index a76da2ffa62..2cdb378d4b3 100644 --- a/mobile/src/accounts/MobileAccountsScreen.tsx +++ b/mobile/src/accounts/MobileAccountsScreen.tsx @@ -16,22 +16,23 @@ import { useMobileTranslation } from '../i18n/use-mobile-translation' import { styles } from './mobile-accounts-screen-styles' import { useNow } from '../hooks/use-now' import { ClaudeIcon, OpenAIIcon } from '../components/AgentIcons' +import './usage/UsageBar' import { type ProviderKey, getActiveProviderRateLimits, getInactiveProviderUsage, getOtherUsageProviders, hasActiveProviderUsage -} from '../components/AccountUsage' +} from './usage/usage-selectors' import { MobileAgentIcon } from '../components/MobileAgentIcon' import { getProviderDisplayName } from '../../../src/shared/usage-provider-windows' import { ProviderUsageWindows } from './ProviderUsageWindows' import { getActiveCodexAccountIdForRateLimitTarget, getCodexResetCreditSummary -} from '../components/codex-reset-credit' -import { CodexResetCreditAction } from '../components/CodexResetCreditAction' -import { useCodexResetCreditAction } from '../components/use-codex-reset-credit-action' +} from './usage/codex-reset-credit' +import { CodexResetCreditAction } from './usage/CodexResetCreditAction' +import { useCodexResetCreditAction } from './usage/use-codex-reset-credit-action' import { ConfirmModal } from '../components/ConfirmModal' import { NavBar } from '../components/nav-bar/NavBar' import { NavBarButton } from '../components/nav-bar/NavBarButton' diff --git a/mobile/src/accounts/ProviderUsageWindows.tsx b/mobile/src/accounts/ProviderUsageWindows.tsx index 8f9dd1e9e30..43f8b9a5be3 100644 --- a/mobile/src/accounts/ProviderUsageWindows.tsx +++ b/mobile/src/accounts/ProviderUsageWindows.tsx @@ -4,12 +4,9 @@ import { getUsageWindowSections, type UsageWindowSection } from '../../../src/shared/usage-provider-windows' -import { - getUsageBarState, - getWindowResetLabel, - UsageBar, - type ProviderRateLimits -} from '../components/AccountUsage' +import { UsageBar } from './usage/UsageBar' +import { getUsageBarState, getWindowResetLabel } from './usage/usage-selectors' +import type { ProviderRateLimits } from './accounts-snapshot' import type { Translate } from '../i18n/mobile-i18n' import { useMobileTranslation } from '../i18n/use-mobile-translation' import { spacing } from '../theme/mobile-theme' diff --git a/mobile/src/accounts/accounts-snapshot-stream.ts b/mobile/src/accounts/accounts-snapshot-stream.ts index 09ca407fead..64ed6066c1b 100644 --- a/mobile/src/accounts/accounts-snapshot-stream.ts +++ b/mobile/src/accounts/accounts-snapshot-stream.ts @@ -1,6 +1,6 @@ import { queryOptions, skipToken } from '@tanstack/react-query' -import { AccountsSnapshotSchema, decodeAccountsSnapshot } from '../components/accounts-snapshot' -import type { AccountsSnapshot } from '../components/AccountUsage' +import { AccountsSnapshotSchema, decodeAccountsSnapshot } from './accounts-snapshot' +import type { AccountsSnapshot } from './accounts-snapshot' import { hostQueryKey, type HostQueryKey } from '../query/host-query-key' import type { PersistedHostFamily } from '../query/host-query-persistence' import type { RpcClient } from '../transport/rpc/rpc-client-contract' diff --git a/mobile/src/components/accounts-snapshot.ts b/mobile/src/accounts/accounts-snapshot.ts similarity index 100% rename from mobile/src/components/accounts-snapshot.ts rename to mobile/src/accounts/accounts-snapshot.ts diff --git a/mobile/src/components/CodexResetCreditAction.tsx b/mobile/src/accounts/usage/CodexResetCreditAction.tsx similarity index 91% rename from mobile/src/components/CodexResetCreditAction.tsx rename to mobile/src/accounts/usage/CodexResetCreditAction.tsx index 0c273fa6d19..0ba5841b6c0 100644 --- a/mobile/src/components/CodexResetCreditAction.tsx +++ b/mobile/src/accounts/usage/CodexResetCreditAction.tsx @@ -1,11 +1,11 @@ import { ActivityIndicator, Pressable, StyleSheet, Text } from 'react-native' import { RotateCcw } from 'lucide-react-native' -import { useMobileTranslation } from '../i18n/use-mobile-translation' -import { colors, feedback, radii, spacing, typography } from '../theme/mobile-theme' -import { themedStyleSheet } from '../theme/themed-styles' -import { useMobileColorScheme } from '../theme/use-mobile-color-scheme' +import { useMobileTranslation } from '../../i18n/use-mobile-translation' +import { colors, feedback, radii, spacing, typography } from '../../theme/mobile-theme' +import { themedStyleSheet } from '../../theme/themed-styles' +import { useMobileColorScheme } from '../../theme/use-mobile-color-scheme' import type { CodexResetCreditSummary } from './codex-reset-credit' -import { ListRow } from './list/ListGroup' +import { ListRow } from '../../components/list/ListGroup' export function CodexResetCreditAction({ summary, diff --git a/mobile/src/components/AccountUsage.tsx b/mobile/src/accounts/usage/UsageBar.tsx similarity index 81% rename from mobile/src/components/AccountUsage.tsx rename to mobile/src/accounts/usage/UsageBar.tsx index 83253a3c04b..7fdcd674347 100644 --- a/mobile/src/components/AccountUsage.tsx +++ b/mobile/src/accounts/usage/UsageBar.tsx @@ -1,29 +1,9 @@ import { View, Text, ActivityIndicator, type StyleProp, type ViewStyle } from 'react-native' -import { colors, spacing, typography } from '../theme/mobile-theme' -import { themedStyleSheet } from '../theme/themed-styles' -import { useMobileColorScheme } from '../theme/use-mobile-color-scheme' +import { colors, spacing, typography } from '../../theme/mobile-theme' +import { themedStyleSheet } from '../../theme/themed-styles' +import { useMobileColorScheme } from '../../theme/use-mobile-color-scheme' -// Re-export pure account-usage-state selectors/types to keep imports stable and tests free of RN. -export type { - RateLimitWindow, - ProviderRateLimits, - InactiveAccountUsage, - ClaudeAccountSummary, - CodexAccountSummary, - AccountsSnapshot, - ProviderKey, - UsageBarState -} from './account-usage-state' -export { - decodeAccountsSnapshot, - getActiveProviderRateLimits, - getInactiveProviderUsage, - getOtherUsageProviders, - getUsageBarState, - getWindowResetLabel, - hasActiveProviderUsage, - hasRenderableUsage -} from './account-usage-state' +import './usage-selectors' /** A meter's fill: the rounded, clamped percent and its consumption colour, shared by every usage meter. */ export function usageBarFill( diff --git a/mobile/src/components/codex-reset-credit-capability.ts b/mobile/src/accounts/usage/codex-reset-credit-capability.ts similarity index 51% rename from mobile/src/components/codex-reset-credit-capability.ts rename to mobile/src/accounts/usage/codex-reset-credit-capability.ts index 1000e16013e..f8e184c0aa9 100644 --- a/mobile/src/components/codex-reset-credit-capability.ts +++ b/mobile/src/accounts/usage/codex-reset-credit-capability.ts @@ -1,10 +1,7 @@ import { useEffect, useState } from 'react' -import { CODEX_RESET_CREDIT_RUNTIME_CAPABILITY } from '../../../src/shared/account-runtime-capabilities' -import type { RpcClient } from '../transport/rpc/rpc-client-contract' -import { startRuntimeCapabilityProbe } from '../transport/connection/runtime-capability-probe' - -// Use shared capability constant so host/mobile versions cannot silently drift. -export const MOBILE_CODEX_RESET_CREDIT_CAPABILITY = CODEX_RESET_CREDIT_RUNTIME_CAPABILITY +import { CODEX_RESET_CREDIT_RUNTIME_CAPABILITY } from '../../../../src/shared/account-runtime-capabilities' +import type { RpcClient } from '../../transport/rpc/rpc-client-contract' +import { startRuntimeCapabilityProbe } from '../../transport/connection/runtime-capability-probe' export function useCodexResetCreditCapability( client: RpcClient | null, @@ -18,7 +15,7 @@ export function useCodexResetCreditCapability( return } return startRuntimeCapabilityProbe(client, (capabilities) => { - setSupported(capabilities.includes(MOBILE_CODEX_RESET_CREDIT_CAPABILITY)) + setSupported(capabilities.includes(CODEX_RESET_CREDIT_RUNTIME_CAPABILITY)) }) }, [client, connected]) diff --git a/mobile/src/components/codex-reset-credit-consume-operations.ts b/mobile/src/accounts/usage/codex-reset-credit-consume-operations.ts similarity index 91% rename from mobile/src/components/codex-reset-credit-consume-operations.ts rename to mobile/src/accounts/usage/codex-reset-credit-consume-operations.ts index ef3c719fd7b..2f7c685034d 100644 --- a/mobile/src/components/codex-reset-credit-consume-operations.ts +++ b/mobile/src/accounts/usage/codex-reset-credit-consume-operations.ts @@ -1,5 +1,5 @@ -import { bindDeferredRpcOperation, defineRpcOperation } from '../transport/rpc/rpc-operation' -import { rpcResultVariant } from '../transport/rpc/rpc-operation-result-reader' +import { bindDeferredRpcOperation, defineRpcOperation } from '../../transport/rpc/rpc-operation' +import { rpcResultVariant } from '../../transport/rpc/rpc-operation-result-reader' import { codexResetCreditReplySchema } from './codex-reset-credit-reply-schema' // Use require-result-or-throw-message so confirm shows host sentence. Keep payload opaque: call-site decodeResetResult alone checks attempt scope/snapshot. diff --git a/mobile/src/components/codex-reset-credit-reply-schema.ts b/mobile/src/accounts/usage/codex-reset-credit-reply-schema.ts similarity index 100% rename from mobile/src/components/codex-reset-credit-reply-schema.ts rename to mobile/src/accounts/usage/codex-reset-credit-reply-schema.ts diff --git a/mobile/src/components/codex-reset-credit.ts b/mobile/src/accounts/usage/codex-reset-credit.ts similarity index 98% rename from mobile/src/components/codex-reset-credit.ts rename to mobile/src/accounts/usage/codex-reset-credit.ts index 47bf70bfcad..fced6e3117c 100644 --- a/mobile/src/components/codex-reset-credit.ts +++ b/mobile/src/accounts/usage/codex-reset-credit.ts @@ -1,20 +1,20 @@ import { buildCodexResetCreditExpectedScope, type CodexResetCreditExpectedScope -} from '../../../src/shared/codex-reset-credit-scope' +} from '../../../../src/shared/codex-reset-credit-scope' import { codexResetCreditConsume, type MobileCodexResetCreditRpcSender, type MobileCodexResetCreditSendScope } from './codex-reset-credit-consume-operations' import { CodexResetCreditExpectedScopeSchema } from './codex-reset-credit-reply-schema' -import { randomV4Uuid } from '../platform/random-v4-uuid' -import { translate } from '../i18n/mobile-i18n' +import { randomV4Uuid } from '../../platform/random-v4-uuid' +import { translate } from '../../i18n/mobile-i18n' import { decodeAccountsSnapshot, type AccountsSnapshot, type ProviderRateLimits -} from './accounts-snapshot' +} from '../accounts-snapshot' export type CodexResetCreditOutcome = 'reset' | 'nothingToReset' | 'noCredit' | 'alreadyRedeemed' diff --git a/mobile/src/components/account-usage-state.ts b/mobile/src/accounts/usage/usage-selectors.ts similarity index 83% rename from mobile/src/components/account-usage-state.ts rename to mobile/src/accounts/usage/usage-selectors.ts index 23d4c02485c..f0f3b6d3311 100644 --- a/mobile/src/components/account-usage-state.ts +++ b/mobile/src/accounts/usage/usage-selectors.ts @@ -1,29 +1,13 @@ // Keep shapes aligned with shared types/rate-limit-types without pulling Electron-coupled desktop graph into mobile. -// Pure RN-free selectors stay directly testable; AccountUsage re-exports them with UsageBar. -import { formatResetCountdown } from '../../../src/shared/rate-limit-reset-format' -import { hasUsageData } from '../../../src/shared/usage-provider-windows' +import { formatResetCountdown } from '../../../../src/shared/rate-limit-reset-format' +import { hasUsageData } from '../../../../src/shared/usage-provider-windows' import { ProviderRateLimitsSchema, type AccountsSnapshot, type InactiveAccountUsage, type ProviderRateLimits, type RateLimitWindow -} from './accounts-snapshot' - -export { - AccountsSnapshotSchema, - decodeAccountsSnapshot, - ProviderRateLimitsSchema, - RateLimitRuntimeTargetSchema, - type AccountProviderRateLimits, - type AccountsSnapshot, - type ClaudeAccountSummary, - type CodexAccountSummary, - type InactiveAccountUsage, - type ProviderRateLimits, - type RateLimitRuntimeTarget, - type RateLimitWindow -} from './accounts-snapshot' +} from '../accounts-snapshot' export type ProviderKey = 'claude' | 'codex' diff --git a/mobile/src/components/use-codex-reset-credit-action.ts b/mobile/src/accounts/usage/use-codex-reset-credit-action.ts similarity index 93% rename from mobile/src/components/use-codex-reset-credit-action.ts rename to mobile/src/accounts/usage/use-codex-reset-credit-action.ts index cb0dbcda7f8..4e33f0e9afc 100644 --- a/mobile/src/components/use-codex-reset-credit-action.ts +++ b/mobile/src/accounts/usage/use-codex-reset-credit-action.ts @@ -1,10 +1,10 @@ import { useCallback, useMemo, useRef, useState } from 'react' -import type { CodexResetCreditExpectedScope } from '../../../src/shared/codex-reset-credit-scope' -import type { RpcClient } from '../transport/rpc/rpc-client-contract' -import { translate } from '../i18n/mobile-i18n' -import type { Translate } from '../i18n/mobile-i18n' -import { useMobileTranslation } from '../i18n/use-mobile-translation' -import type { AccountsSnapshot } from './account-usage-state' +import type { CodexResetCreditExpectedScope } from '../../../../src/shared/codex-reset-credit-scope' +import type { RpcClient } from '../../transport/rpc/rpc-client-contract' +import { translate } from '../../i18n/mobile-i18n' +import type { Translate } from '../../i18n/mobile-i18n' +import { useMobileTranslation } from '../../i18n/use-mobile-translation' +import type { AccountsSnapshot } from '../accounts-snapshot' import { getCodexResetCreditOutcomeCopy, getCodexResetCreditScope, diff --git a/mobile/src/accounts/use-mobile-accounts-snapshot.ts b/mobile/src/accounts/use-mobile-accounts-snapshot.ts index d4370bb5310..d14fb47b4b9 100644 --- a/mobile/src/accounts/use-mobile-accounts-snapshot.ts +++ b/mobile/src/accounts/use-mobile-accounts-snapshot.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react' import { hashKey, useQuery, useQueryClient } from '@tanstack/react-query' -import { AccountsSnapshotError, decodeAccountsSnapshot } from '../components/accounts-snapshot' -import type { AccountsSnapshot } from '../components/AccountUsage' +import { AccountsSnapshotError, decodeAccountsSnapshot } from './accounts-snapshot' +import type { AccountsSnapshot } from './accounts-snapshot' import { useMobileTranslation } from '../i18n/use-mobile-translation' import { holdsRestoredHostQueryData } from '../query/host-query-persistence' import type { ConnectionState } from '../transport/connection/connection-state' diff --git a/mobile/src/agents/agent-list-row-text.ts b/mobile/src/agents/agent-list-row-text.ts index 194a77e7616..c3e9d8ef8b7 100644 --- a/mobile/src/agents/agent-list-row-text.ts +++ b/mobile/src/agents/agent-list-row-text.ts @@ -21,14 +21,7 @@ function oneLine(text: string | null | undefined): string { return text?.replace(/\s+/g, ' ').trim() ?? '' } -// A worktree agent row or a session tab's AgentStatusEntry, which leaves these optional. -type AgentPreviewSource = Pick & { - lastAssistantMessage?: string | null - toolName?: string | null - toolInput?: string | null -} - -function lastMessage(agent: AgentPreviewSource): string { +function lastMessage(agent: RuntimeWorktreeAgentRow): string { const message = agent.lastAssistantMessage return message ? oneLine(withoutNativeChatVisualDirectiveLines(message)) : '' } @@ -38,7 +31,7 @@ function lastMessage(agent: AgentPreviewSource): string { * (`group` null) shows no tool, since the tool call is long over. */ export function agentListPreview( - agent: AgentPreviewSource, + agent: RuntimeWorktreeAgentRow, group: AgentStatusGroup | null, title: string ): string { diff --git a/mobile/src/components/ActionSheetModal.tsx b/mobile/src/components/ActionSheetModal.tsx index 774adcc3c40..49a25ebbc78 100644 --- a/mobile/src/components/ActionSheetModal.tsx +++ b/mobile/src/components/ActionSheetModal.tsx @@ -15,6 +15,8 @@ export type ActionSheetAction = { destructive?: boolean disabled?: boolean hint?: string + /** Short trailing state, e.g. "↑2" or "Up to date". */ + status?: string /** Marks the choice that is current, as a trailing check. */ checked?: boolean loading?: boolean @@ -77,6 +79,7 @@ export function ActionSheetContent({ title, message, children, actions, onClose key={action.id ?? action.label} title={action.label} subtitle={action.hint} + value={action.status} leading={ action.renderIcon?.() ?? ( /** Part of the lines picked for a note. */ selected?: boolean + /** Fits the file's longest line number, so every row's gutter lines up. */ + numberWidth: number /** Absent where lines take no notes, e.g. a past commit's files. */ onAddNote?: (lineNumber: number) => void onEditNote: (comment: DiffComment) => void @@ -52,6 +54,7 @@ export const MobileDiffReviewLine = memo(function MobileDiffReviewLine({ comments, staleCommentIds, selected = false, + numberWidth, onAddNote, onEditNote }: Props) { @@ -59,23 +62,45 @@ export const MobileDiffReviewLine = memo(function MobileDiffReviewLine({ useMobileColorScheme() const lineNumber = mobileDiffLineNumber(line) const canComment = onAddNote !== undefined && canCommentOnLine(line) + const ground = [ + line.kind === 'add' && styles.addedRow, + line.kind === 'delete' && styles.deletedRow, + selected && styles.selectedRow + ] return ( - {mobileDiffLinePrefix(line.kind)} - {lineNumber ? String(lineNumber) : ''} + {/* Pinned while the file scrolls sideways, so it repaints the row's tint over an opaque ground. */} + + + + {lineNumber ? String(lineNumber) : ''} + + + {mobileDiffLinePrefix(line.kind)} + + + [styles.code, pressed && canComment && styles.codePressed]} disabled={!canComment} @@ -98,41 +123,83 @@ export const MobileDiffReviewLine = memo(function MobileDiffReviewLine({ {comments.length > 0 ? ( - - {comments.map((comment) => ( - [styles.noteButton, pressed && styles.noteButtonPressed]} - onPress={() => onEditNote(comment)} - accessibilityRole="button" - accessibilityLabel={t( - 'components.diffReviewLine.editNoteOnLine', - 'Edit note on line {{number}}', - { - number: comment.lineNumber - } - )} - > - - - ))} + + + {comments.map((comment) => ( + [styles.noteButton, pressed && styles.noteButtonPressed]} + onPress={() => onEditNote(comment)} + accessibilityRole="button" + accessibilityLabel={t( + 'components.diffReviewLine.editNoteOnLine', + 'Edit note on line {{number}}', + { + number: comment.lineNumber + } + )} + > + + + ))} + ) : null} ) }) +/** Renders one code line's worth of a known string, so the list can size its columns to the code font. */ +export function MobileDiffReviewCharWidthProbe({ + onCharWidth +}: { + onCharWidth: (width: number) => void +}) { + return ( + onCharWidth(event.nativeEvent.layout.width / PROBE_TEXT.length)} + > + {PROBE_TEXT} + + ) +} + +const PROBE_TEXT = '0'.repeat(100) +const SIGN_WIDTH = 14 +// Room either side of the line number. +const NUMBER_PADDING = 12 + +export function mobileDiffReviewGutterWidth(numberWidth: number): number { + return numberWidth + SIGN_WIDTH +} + +export function mobileDiffReviewNumberWidth(digits: number, charWidth: number): number { + return Math.ceil(digits * charWidth + NUMBER_PADDING) +} + +// The page lets long lines run and the file scroll sideways under pinned cells (Kelvin's choice over wrapping). +const webPinned: ViewStyle = + Platform.OS === 'web' + ? { + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: RN Web renders CSS sticky; this branch never reaches native. + position: 'sticky' as ViewStyle['position'], + zIndex: 1 + } + : {} + // Use 18px lineHeight alone without padding/minHeight to match desktop diff density (STA-1239). const styles = themedStyleSheet(() => ({ row: { flexDirection: 'row', - alignItems: 'stretch', - borderBottomWidth: StyleSheet.hairlineWidth, - borderBottomColor: colors.borderSubtle + alignItems: 'stretch' }, addedRow: { backgroundColor: colors.diffAddedBg @@ -144,38 +211,71 @@ const styles = themedStyleSheet(() => ({ selectedRow: { backgroundColor: colors.skillTokenSurface }, - prefix: { - width: 18, - textAlign: 'center', - color: colors.textMuted, + pinned: { + ...webPinned, + backgroundColor: colors.bgBase + }, + pinnedLeft: { + left: 0 + }, + pinnedRight: { + right: 0 + }, + gutter: { + flex: 1, + flexDirection: 'row' + }, + lineNumber: { + paddingRight: 6, + textAlign: 'right', + color: colors.diffLineNumber, fontFamily: typography.monoFamily, fontSize: typography.metaSize, lineHeight: 18 }, - lineNumber: { - width: 44, - paddingRight: spacing.xs, - textAlign: 'right', - color: colors.textMuted, + addedNumber: { + color: colors.textPrimary, + backgroundColor: colors.diffAddedGutter + }, + deletedNumber: { + color: colors.textPrimary, + backgroundColor: colors.diffDeletedGutter + }, + sign: { + width: SIGN_WIDTH, + textAlign: 'center', + color: colors.diffLineNumber, fontFamily: typography.monoFamily, fontSize: typography.metaSize, lineHeight: 18 }, + addedSign: { + color: colors.diffAddedSign + }, + deletedSign: { + color: colors.diffDeletedSign + }, code: { flex: 1, minWidth: 0, - paddingHorizontal: spacing.sm + paddingRight: 10 }, codePressed: { backgroundColor: colors.bgRaised }, codeText: { + ...(Platform.OS === 'web' ? { whiteSpace: 'pre' as const } : {}), color: colors.textPrimary, fontFamily: typography.monoFamily, fontSize: 12, lineHeight: 18 }, + probe: { + position: 'absolute', + opacity: 0 + }, notes: { + flex: 1, width: 40, alignItems: 'center', justifyContent: 'center', diff --git a/mobile/src/components/MobileDiffReviewLines.tsx b/mobile/src/components/MobileDiffReviewLines.tsx index 04ddb7398eb..09fb1e9d3f3 100644 --- a/mobile/src/components/MobileDiffReviewLines.tsx +++ b/mobile/src/components/MobileDiffReviewLines.tsx @@ -1,11 +1,17 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { FlatList, Platform, Pressable, Text, View } from 'react-native' +import { FlatList, Platform, Pressable, Text, View, type ViewStyle } from 'react-native' import { Gesture, GestureDetector } from 'react-native-gesture-handler' -import { ChevronsUpDown } from 'lucide-react-native' +import { UnfoldVertical } from 'lucide-react-native' import type { DiffComment } from '../../../src/shared/diff-comment-types' import { useMobileColorScheme } from '../theme/use-mobile-color-scheme' import { useMobileTranslation } from '../i18n/use-mobile-translation' -import { DIFF_LINE_ID_PREFIX, MobileDiffReviewLine } from './MobileDiffReviewLine' +import { + DIFF_LINE_ID_PREFIX, + MobileDiffReviewCharWidthProbe, + MobileDiffReviewLine, + mobileDiffReviewGutterWidth, + mobileDiffReviewNumberWidth +} from './MobileDiffReviewLine' import type { ReviewDiffLine } from '../source-control/review/mobile-diff-review-screen-model' import { buildMobileDiffReviewRows, @@ -25,6 +31,18 @@ const RANGE_PICK_LONG_PRESS_MS = 350 const MAX_SCROLL_ATTEMPTS = 10 const NO_LINE_NOTES: readonly DiffComment[] = [] const SCROLL_RETRY_MS = 100 +// The page's default tab-size, so a tabbed line's width matches what it draws. +const TAB_COLUMNS = 8 +const CODE_END_PADDING = 10 +const NOTES_WIDTH = 40 + +function lineColumns(text: string): number { + let columns = 0 + for (const char of text) { + columns = char === '\t' ? (Math.floor(columns / TAB_COLUMNS) + 1) * TAB_COLUMNS : columns + 1 + } + return columns +} export type LineRange = { startLine: number; line: number } @@ -77,6 +95,44 @@ export function MobileDiffReviewLines({ setOpened({ lines, indexes: next }) } + // Long lines run on one line and the whole file scrolls sideways, so every row is as wide as the longest. + const [charWidth, setCharWidth] = useState(0) + const [viewportWidth, setViewportWidth] = useState(0) + const { numberWidth, codeColumns } = useMemo(() => { + let digits = 1 + let columns = 0 + for (const line of lines) { + digits = Math.max(digits, String(line.newLineNumber ?? line.oldLineNumber ?? '').length) + columns = Math.max(columns, lineColumns(line.text)) + } + return { numberWidth: mobileDiffReviewNumberWidth(digits, charWidth), codeColumns: columns } + }, [charWidth, lines]) + const gutterWidth = mobileDiffReviewGutterWidth(numberWidth) + const rowFrame: ViewStyle = + Platform.OS === 'web' && charWidth > 0 + ? { + width: Math.max( + viewportWidth, + Math.ceil( + gutterWidth + + codeColumns * charWidth + + CODE_END_PADDING + + (commentsByLine.size > 0 ? NOTES_WIDTH : 0) + ) + ) + } + : {} + // Folds, threads and the footer hold still in the viewport while the code slides under them. + const viewportRow: ViewStyle = + Platform.OS === 'web' && viewportWidth > 0 + ? { + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: RN Web renders CSS sticky; this branch never reaches native. + position: 'sticky' as ViewStyle['position'], + left: 0, + width: viewportWidth + } + : {} + const listRef = useRef>>(null) const scrollFailedRef = useRef(false) const [scrollAttempt, setScrollAttempt] = useState(0) @@ -204,10 +260,16 @@ export function MobileDiffReviewLines({ return ( - + setViewportWidth(event.nativeEvent.layout.width)} + > + > ref={listRef} data={rows} + style={styles.diffList} // The list holds still while lines are being picked, so the drag selects instead of scrolling. scrollEnabled={dragRange === null} onScrollToIndexFailed={(info) => { @@ -218,60 +280,77 @@ export function MobileDiffReviewLines({ }) }} keyExtractor={(row) => row.key} - renderItem={({ item: row }) => - row.kind === 'fold' ? ( - [styles.foldRow, pressed && styles.buttonPressed]} - onPress={() => openFold(row.startIndex, row.endIndex)} - accessibilityRole="button" - accessibilityLabel={t( - 'components.diffReviewBody.showUnchangedLines', - 'Show {{count}} unchanged lines', - { count: row.hiddenCount } - )} - > - - - {row.hiddenCount === 1 - ? t( - 'components.diffReviewBody.unchangedLines_one', - '{{count}} unchanged line', - { - count: row.hiddenCount - } - ) - : t( - 'components.diffReviewBody.unchangedLines_other', - '{{count}} unchanged lines', - { count: row.hiddenCount } - )} - - - ) : row.kind === 'thread' ? ( - - - - ) : ( - = highlighted.startLine && - row.line.newLineNumber <= highlighted.line - } - {...(onPickLines ? { onAddNote: pickOneLine } : {})} - onEditNote={onEditNote} - /> - ) - } - contentContainerStyle={styles.diffList} + renderItem={({ item: row }) => ( + + {row.kind === 'fold' ? ( + [ + styles.foldRow, + viewportRow, + pressed && styles.buttonPressed + ]} + onPress={() => openFold(row.startIndex, row.endIndex)} + accessibilityRole="button" + accessibilityLabel={t( + 'components.diffReviewBody.showUnchangedLines', + 'Show {{count}} unchanged lines', + { count: row.hiddenCount } + )} + > + + + + + + {row.hiddenCount === 1 + ? t( + 'components.diffReviewBody.unchangedLines_one', + '{{count}} unchanged line', + { + count: row.hiddenCount + } + ) + : t( + 'components.diffReviewBody.unchangedLines_other', + '{{count}} unchanged lines', + { count: row.hiddenCount } + )} + + {row.enclosingLine ? ( + + {row.enclosingLine} + + ) : null} + + + ) : row.kind === 'thread' ? ( + + + + ) : ( + = highlighted.startLine && + row.line.newLineNumber <= highlighted.line + } + {...(onPickLines ? { onAddNote: pickOneLine } : {})} + onEditNote={onEditNote} + /> + )} + + )} + contentContainerStyle={styles.diffListContent} + ListFooterComponentStyle={rowFrame} ListFooterComponent={ truncated ? ( - + {t('components.diffReviewBody.diffTruncated', 'Diff truncated for mobile preview.')} ) : null diff --git a/mobile/src/components/MobilePRSidebar.tsx b/mobile/src/components/MobilePRSidebar.tsx index 433f909e6f3..c264d0281e4 100644 --- a/mobile/src/components/MobilePRSidebar.tsx +++ b/mobile/src/components/MobilePRSidebar.tsx @@ -24,6 +24,7 @@ import { useNow } from '../hooks/use-now' import { commentRelativeTime } from './pr-sidebar/pr-comment-relative-time' import { prStateBadge } from './pr-sidebar/pr-checks-presentation' import { statusColor } from './pr-sidebar/pr-sidebar-status-color' +import { PrStateIcon } from './PrStateIcon' import { PrTabEmptyState } from './pr-sidebar/PrTabEmptyState' import { PrChangesCard, PrDescription } from './pr-sidebar/PrTabOverviewCards' import { PrTabBottomAction } from './pr-sidebar/PrTabBottomAction' @@ -231,6 +232,7 @@ function PrTabHeader({ data }: { data: PrSidebarData }) { + {badge.label} #{pr.number} diff --git a/mobile/src/components/MobileSyntaxSegments.tsx b/mobile/src/components/MobileSyntaxSegments.tsx index b768a2be8e7..9f06e26fa39 100644 --- a/mobile/src/components/MobileSyntaxSegments.tsx +++ b/mobile/src/components/MobileSyntaxSegments.tsx @@ -47,5 +47,8 @@ const syntaxTokenStyles: Record = themedStyleS }, meta: { color: colors.syntaxMeta + }, + tag: { + color: colors.syntaxTag } })) diff --git a/mobile/src/components/PrStateIcon.tsx b/mobile/src/components/PrStateIcon.tsx new file mode 100644 index 00000000000..3eb44c4d943 --- /dev/null +++ b/mobile/src/components/PrStateIcon.tsx @@ -0,0 +1,7 @@ +import { createElement } from 'react' +import type { LucideProps } from 'lucide-react-native' +import { prStateIcon } from './pr-state-token' + +export function PrStateIcon({ state, ...props }: { state: string } & LucideProps) { + return createElement(prStateIcon(state), props) +} diff --git a/mobile/src/components/SwipeRowActions.tsx b/mobile/src/components/SwipeRowActions.tsx index b070de4ff38..704077f636d 100644 --- a/mobile/src/components/SwipeRowActions.tsx +++ b/mobile/src/components/SwipeRowActions.tsx @@ -84,8 +84,6 @@ export function SwipeRowActions({ }) // Web has no worklet plugin; mapper hooks need this explicit dependency list. const rowStyle = useAnimatedStyle(() => ({ transform: [{ translateX: offset.value }] }), [offset]) - // Hidden at rest, so the action can't show through a rounded group's antialiased corners. - const actionsStyle = useAnimatedStyle(() => ({ opacity: offset.value === 0 ? 0 : 1 }), [offset]) // A tap on an open row closes it rather than pressing the row. const guardPress = (onPress: () => void) => () => { // The click a drag release produces belongs to the drag, not to the row. @@ -126,10 +124,8 @@ export function SwipeRowActions({ } return ( - - {leading ? renderAction(leading, 'leading') : null} - {trailing ? renderAction(trailing, 'trailing') : null} - + {leading ? renderAction(leading, 'leading') : null} + {trailing ? renderAction(trailing, 'trailing') : null} {/* pan-y keeps the page scrolling vertically over the row on the web. */} {children(guardPress)} @@ -148,7 +144,6 @@ const styles = themedStyleSheet(() => ({ justifyContent: 'center', gap: 2 }, - actions: { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0 }, leading: { left: 0 }, trailing: { right: 0 }, actionPressed: { opacity: feedback.pressedOpacity }, diff --git a/mobile/src/components/WorktreeListRow.tsx b/mobile/src/components/WorktreeListRow.tsx index 73627d48a4b..10207f88ba5 100644 --- a/mobile/src/components/WorktreeListRow.tsx +++ b/mobile/src/components/WorktreeListRow.tsx @@ -1,5 +1,5 @@ import { memo } from 'react' -import { Bell, ChevronDown, ChevronRight, GitBranch, GitPullRequest } from 'lucide-react-native' +import { Bell, ChevronDown, ChevronRight, GitBranch } from 'lucide-react-native' import { Pressable, StyleSheet, Text, View } from 'react-native' import type { MobileRenderableRepoIcon } from '../host-screen/host-screen-reply-schema' import { triggerMediumImpact } from '../platform/haptics' @@ -20,6 +20,7 @@ import { HostKindIcon } from './HostKindIcon' import { MobileRepoIcon } from './MobileRepoIcon' import { WorktreeAgentList } from './WorktreeAgentList' import { WorktreeMetaGlyphs, prStateColor } from './WorktreeMetaGlyphs' +import { PrStateIcon } from './PrStateIcon' import { WorktreeUnsavedName } from './WorktreeUnsavedName' import { WORKTREE_ROW_LAYOUT } from './worktree-list-row-layout' @@ -76,6 +77,8 @@ function WorktreeListRowComponent({ const showRepoChip = cardDetails.repoInTitle && !shouldHideRepo && !isFolderWorkspace const showRepoInMetaRow = !cardDetails.repoInTitle && !shouldHideRepo const hostId = view.hostContextHostId ?? item.hostId + const prState = item.linkedPR?.state ?? '' + const prColor = prStateColor(prState) const hostAccessibilityLabel = [view.hostContextLabel, view.hostContextHealthLabel] .filter(Boolean) .join(', ') @@ -153,10 +156,8 @@ function WorktreeListRowComponent({ {cardDetails.pr && item.linkedPR && ( - - - #{item.linkedPR.number} - + + #{item.linkedPR.number} )} {isFolderWorkspace && ( diff --git a/mobile/src/components/accounts-snapshot.test.ts b/mobile/src/components/accounts-snapshot.test.ts deleted file mode 100644 index 89e0bf84934..00000000000 --- a/mobile/src/components/accounts-snapshot.test.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { describe, expect, it } from 'vitest' - -import { decodeAccountsSnapshot } from './accounts-snapshot' - -function makeSnapshot(): unknown { - return { - extensionField: { retained: true }, - claude: { - accounts: [], - activeAccountId: null, - activeAccountIdsByRuntime: { host: null, wsl: {} } - }, - codex: { - accounts: [ - { - id: 'codex-host', - email: 'host@example.com', - managedHomeRuntime: 'host', - wslDistro: null, - updatedAt: 100, - extensionField: 'account-extra' - } - ], - activeAccountId: 'codex-host', - activeAccountIdsByRuntime: { - host: 'codex-host', - wsl: { Ubuntu: 'codex-wsl' } - } - }, - rateLimits: { - extensionField: 'limits-extra', - claude: null, - codex: { - provider: 'codex', - session: { - usedPercent: 100, - windowMinutes: 300, - resetsAt: 200, - resetDescription: 'soon' - }, - weekly: null, - rateLimitResetCredits: { - availableCount: 1, - totalEarnedCount: 2, - nextExpiresAt: 300, - credits: [{ status: 'available', expiresAt: 300, grantedAt: 50 }] - }, - updatedAt: 100, - error: null, - status: 'ok', - extensionField: 'provider-extra' - }, - claudeTarget: { runtime: 'host', wslDistro: null }, - codexTarget: { runtime: 'host', wslDistro: null }, - inactiveClaudeAccounts: [], - inactiveCodexAccounts: [ - { - accountId: 'codex-inactive', - rateLimits: null, - updatedAt: 99, - isFetching: false - } - ] - } - } -} - -function setPath(root: unknown, path: string[], value: unknown): void { - let current: unknown = root - for (const segment of path.slice(0, -1)) { - if (!current || typeof current !== 'object' || Array.isArray(current)) { - throw new Error(`Invalid fixture path: ${path.join('.')}`) - } - current = (current as Record)[segment] - } - if (!current || typeof current !== 'object' || Array.isArray(current)) { - throw new Error(`Invalid fixture path: ${path.join('.')}`) - } - const record = current as Record - record[path.at(-1)!] = value -} - -describe('decodeAccountsSnapshot', () => { - it('validates nested account/rate-limit state and preserves forward-compatible fields', () => { - const snapshot = decodeAccountsSnapshot(makeSnapshot()) - - expect(snapshot.extensionField).toEqual({ retained: true }) - expect(snapshot.codex.accounts[0]?.extensionField).toBe('account-extra') - expect(snapshot.rateLimits.extensionField).toBe('limits-extra') - expect(snapshot.rateLimits.codex?.extensionField).toBe('provider-extra') - }) - - it('defaults missing runtime targets for older host-only snapshots', () => { - const raw = makeSnapshot() as { - rateLimits: { claudeTarget?: unknown; codexTarget?: unknown } - } - delete raw.rateLimits.claudeTarget - delete raw.rateLimits.codexTarget - - const snapshot = decodeAccountsSnapshot(raw) - - expect(snapshot.rateLimits.claudeTarget).toEqual({ runtime: 'host', wslDistro: null }) - expect(snapshot.rateLimits.codexTarget).toEqual({ runtime: 'host', wslDistro: null }) - }) - - it.each([ - ['account arrays', ['codex', 'accounts'], {}], - ['active account IDs', ['codex', 'activeAccountId'], 42], - ['runtime selections', ['codex', 'activeAccountIdsByRuntime', 'wsl'], []], - ['targets', ['rateLimits', 'codexTarget', 'runtime'], 'remote'], - ['provider identity', ['rateLimits', 'codex', 'provider'], 'claude'], - ['inactive account arrays', ['rateLimits', 'inactiveCodexAccounts'], {}], - ['window percentages', ['rateLimits', 'codex', 'session', 'usedPercent'], 101], - ['credit counts', ['rateLimits', 'codex', 'rateLimitResetCredits', 'availableCount'], -1], - [ - 'credit status', - ['rateLimits', 'codex', 'rateLimitResetCredits', 'credits'], - [{ status: '', expiresAt: 300, grantedAt: 50 }] - ], - ['credit expiry', ['rateLimits', 'codex', 'rateLimitResetCredits', 'nextExpiresAt'], 'soon'] - ] satisfies Array<[string, string[], unknown]>)('rejects malformed %s', (_name, path, value) => { - const snapshot = makeSnapshot() - setPath(snapshot, path, value) - - expect(() => decodeAccountsSnapshot(snapshot)).toThrow('Invalid accounts snapshot from host') - }) - - it('rejects a host target that smuggles a WSL distro', () => { - const snapshot = makeSnapshot() - setPath(snapshot, ['rateLimits', 'codexTarget', 'wslDistro'], 'Ubuntu') - - expect(() => decodeAccountsSnapshot(snapshot)).toThrow('Invalid accounts snapshot from host') - }) -}) diff --git a/mobile/src/components/mobile-diff-review-layout-styles.ts b/mobile/src/components/mobile-diff-review-layout-styles.ts index 8204ed0f69a..c9ac1229ed9 100644 --- a/mobile/src/components/mobile-diff-review-layout-styles.ts +++ b/mobile/src/components/mobile-diff-review-layout-styles.ts @@ -1,4 +1,4 @@ -import { StyleSheet } from 'react-native' +import { Platform, StyleSheet } from 'react-native' import { colors, radii, spacing, typography } from '../theme/mobile-theme' import { themedStyleSheet } from '../theme/themed-styles' @@ -59,13 +59,31 @@ export const mobileDiffReviewLayoutStyles = themedStyleSheet(() => ({ foldRow: { minHeight: 32, flexDirection: 'row', + alignItems: 'stretch', + backgroundColor: colors.diffFoldBg + }, + foldIcon: { alignItems: 'center', justifyContent: 'center', - gap: spacing.xs, - backgroundColor: colors.bgPanel + backgroundColor: colors.diffFoldGutter + }, + foldBody: { + flex: 1, + minWidth: 0, + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + paddingHorizontal: spacing.sm }, foldText: { + flexShrink: 0, + color: colors.diffFoldText, + fontSize: typography.metaSize + }, + foldContext: { + flexShrink: 1, color: colors.textMuted, + fontFamily: typography.monoFamily, fontSize: typography.metaSize }, diffListFrame: { @@ -77,8 +95,14 @@ export const mobileDiffReviewLayoutStyles = themedStyleSheet(() => ({ backgroundColor: colors.bgBase }, diffList: { - paddingBottom: 140, - backgroundColor: colors.editorSurface + flex: 1, + backgroundColor: colors.bgBase + }, + // On the page the rows run as wide as the longest line and scroll sideways together. A sideways scroller inside + // the vertical list keeps each swipe on one axis, as nested scrollers do in WebKit. + diffListContent: { + ...(Platform.OS === 'web' ? { overflowX: 'auto' as const } : {}), + paddingBottom: 140 }, truncatedText: { color: colors.textMuted, diff --git a/mobile/src/components/nav-bar/NavBarButton.tsx b/mobile/src/components/nav-bar/NavBarButton.tsx index 697704fa9e4..6cd4fbbedb6 100644 --- a/mobile/src/components/nav-bar/NavBarButton.tsx +++ b/mobile/src/components/nav-bar/NavBarButton.tsx @@ -16,6 +16,8 @@ type NavBarButtonProps = { /** The screen or panel this button opens is showing. */ active?: boolean disabled?: boolean + /** The icon's colour while not active, e.g. a PR state's. */ + iconColor?: string } // A round top-bar button; the bar floats over content like the composer, so its buttons are round too. @@ -25,7 +27,8 @@ export function NavBarButton({ accessibilityLabel, onPress, active = false, - disabled = false + disabled = false, + iconColor }: NavBarButtonProps) { useMobileColorScheme() return ( @@ -44,7 +47,11 @@ export function NavBarButton({ accessibilityLabel={accessibilityLabel} accessibilityState={{ disabled, selected: active }} > - + ) } diff --git a/mobile/src/components/nav-bar/PullDownMenu.tsx b/mobile/src/components/nav-bar/PullDownMenu.tsx index 029dc1aadc6..3bd53702855 100644 --- a/mobile/src/components/nav-bar/PullDownMenu.tsx +++ b/mobile/src/components/nav-bar/PullDownMenu.tsx @@ -196,7 +196,9 @@ export function PullDownMenu({ visible, anchorRef, groups, onClose }: PullDownMe disabled={action.disabled || action.loading} onPress={() => press(action)} accessibilityRole="menuitem" - accessibilityLabel={action.label} + accessibilityLabel={ + action.status ? `${action.label}, ${action.status}` : action.label + } accessibilityHint={action.hint} accessibilityState={ action.checked === undefined ? undefined : { checked: action.checked } @@ -213,6 +215,11 @@ export function PullDownMenu({ visible, anchorRef, groups, onClose }: PullDownMe ) : null} + {action.status ? ( + + {action.status} + + ) : null} {action.checked ? ( ) : action.renderIcon ? ( @@ -280,5 +287,12 @@ const styles = themedStyleSheet(() => ({ hint: { color: colors.textSecondary, fontSize: typography.metaSize + }, + status: { + marginLeft: 'auto', + flexShrink: 0, + color: colors.textSecondary, + fontSize: typography.metaSize, + fontVariant: ['tabular-nums'] } })) diff --git a/mobile/src/components/pr-sidebar/pr-tab-styles.ts b/mobile/src/components/pr-sidebar/pr-tab-styles.ts index 7f385b7ab5b..15336f306ab 100644 --- a/mobile/src/components/pr-sidebar/pr-tab-styles.ts +++ b/mobile/src/components/pr-sidebar/pr-tab-styles.ts @@ -17,6 +17,9 @@ export const prTabStyles = themedStyleSheet(() => ({ header: { gap: spacing.xs }, metaRow: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, flexWrap: 'wrap' }, badge: { + flexDirection: 'row', + alignItems: 'center', + gap: 4, paddingHorizontal: spacing.sm, paddingVertical: 1, borderRadius: radii.pill, diff --git a/mobile/src/components/pr-state-token.ts b/mobile/src/components/pr-state-token.ts index 469c483aeda..fe8968a1729 100644 --- a/mobile/src/components/pr-state-token.ts +++ b/mobile/src/components/pr-state-token.ts @@ -1,3 +1,10 @@ +import { + GitMerge, + GitPullRequest, + GitPullRequestClosed, + GitPullRequestDraft, + type LucideIcon +} from 'lucide-react-native' import type { MobileStatusToken } from './pr-sidebar/pr-checks-presentation' // Share status tokens between workspace PR badge and sidebar to prevent color drift, matching desktop ReviewIcon. @@ -14,3 +21,17 @@ export function prStateToken(state: string): MobileStatusToken { return 'textSecondary' } } + +// Glyph per state, like GitHub and desktop's getReviewStateIcon; open and unknown keep the plain PR glyph. +export function prStateIcon(state: string): LucideIcon { + switch (state.toLowerCase()) { + case 'merged': + return GitMerge + case 'closed': + return GitPullRequestClosed + case 'draft': + return GitPullRequestDraft + default: + return GitPullRequest + } +} diff --git a/mobile/src/device-store/device-store-contract.ts b/mobile/src/device-store/device-store-contract.ts index be677c45372..ee3683b62d4 100644 --- a/mobile/src/device-store/device-store-contract.ts +++ b/mobile/src/device-store/device-store-contract.ts @@ -1,4 +1,4 @@ -import type { GenerationFileSystem } from '../mobile-web-shell/generation-store-file-system' +import type { GenerationFileSystem } from '../mobile-web-shell/generations/generation-store-file-system' import type { DeviceStoreRoots } from './device-store-files' import type { DeviceStoreKeychain } from './device-store-key' import type { DeviceStoreTable } from './device-store-seal' diff --git a/mobile/src/device-store/device-store-eviction.ts b/mobile/src/device-store/device-store-eviction.ts index 42a2c719764..dc385540b6e 100644 --- a/mobile/src/device-store/device-store-eviction.ts +++ b/mobile/src/device-store/device-store-eviction.ts @@ -1,10 +1,10 @@ -import { joinUri } from '../mobile-web-shell/generation-cache-uri' +import { joinUri } from '../mobile-web-shell/generations/generation-cache-uri' import type { GenerationDirectoryEntry, GenerationFileListing, GenerationFileSystem -} from '../mobile-web-shell/generation-store-file-system' -import { deriveHostCacheKey } from '../mobile-web-shell/host-cache-key' +} from '../mobile-web-shell/generations/generation-store-file-system' +import { deriveHostCacheKey } from '../mobile-web-shell/generations/host-cache-key' import { DEVICE_STORE_BUCKETS, DRAFT_TMP_SUFFIX, promoteLoneDraftTmp } from './device-store-files' import type { DeviceStoreTable } from './device-store-seal' diff --git a/mobile/src/device-store/device-store-files.ts b/mobile/src/device-store/device-store-files.ts index a7b65f057c5..51ee84f7132 100644 --- a/mobile/src/device-store/device-store-files.ts +++ b/mobile/src/device-store/device-store-files.ts @@ -1,9 +1,9 @@ import { sha256 } from '@noble/hashes/sha256' import { bytesToHex } from '@noble/hashes/utils' import type { AESEncryptionKey } from 'expo-crypto' -import { joinUri } from '../mobile-web-shell/generation-cache-uri' -import type { GenerationFileSystem } from '../mobile-web-shell/generation-store-file-system' -import { deriveHostCacheKey } from '../mobile-web-shell/host-cache-key' +import { joinUri } from '../mobile-web-shell/generations/generation-cache-uri' +import type { GenerationFileSystem } from '../mobile-web-shell/generations/generation-store-file-system' +import { deriveHostCacheKey } from '../mobile-web-shell/generations/host-cache-key' import { openDeviceStoreValue, type DeviceStoreTable, diff --git a/mobile/src/device-store/device-store.ts b/mobile/src/device-store/device-store.ts index adbb20ff677..849871cef76 100644 --- a/mobile/src/device-store/device-store.ts +++ b/mobile/src/device-store/device-store.ts @@ -6,7 +6,7 @@ import type { import type { AESEncryptionKey } from 'expo-crypto' import { Directory, Paths } from 'expo-file-system' import { AppState } from 'react-native' -import { createExpoGenerationFileSystem } from '../mobile-web-shell/generation-store-file-system' +import { createExpoGenerationFileSystem } from '../mobile-web-shell/generations/generation-store-file-system' import { loadStoredHostProfiles } from '../host-catalog/host-metadata-store' import { readPairingKeychainItem, diff --git a/mobile/src/diagnostics/mobile-web-shell-update-failure-row.tsx b/mobile/src/diagnostics/mobile-web-shell-update-failure-row.tsx index 78889ea5e51..b11d739e5ac 100644 --- a/mobile/src/diagnostics/mobile-web-shell-update-failure-row.tsx +++ b/mobile/src/diagnostics/mobile-web-shell-update-failure-row.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react' import { Text, View } from 'react-native' import type { MobileWebShellUpdateFailure } from '../mobile-web-shell/mobile-web-shell-update-failure' -import { processGenerationStore } from '../mobile-web-shell/process-generation-store' +import { processGenerationStore } from '../mobile-web-shell/generations/process-generation-store' import { loadHosts } from '../host-catalog/host-store' import { formatUpdateFailure } from './mobile-web-shell-update-failure-copy' import { useMobileColorScheme } from '../theme/use-mobile-color-scheme' diff --git a/mobile/src/files/session-documents/mobile-file-syntax.ts b/mobile/src/files/session-documents/mobile-file-syntax.ts index 3bc9bc7a35a..ad87f3f1ff3 100644 --- a/mobile/src/files/session-documents/mobile-file-syntax.ts +++ b/mobile/src/files/session-documents/mobile-file-syntax.ts @@ -11,6 +11,7 @@ export type MobileSyntaxTokenKind = | 'function' | 'variable' | 'meta' + | 'tag' export type MobileSyntaxSegment = { text: string @@ -184,28 +185,35 @@ function tokenKindForClasses(className: unknown): MobileSyntaxTokenKind | null { : [] const tokens = new Set(classes.map((value) => value.replace(/^hljs-/, ''))) + // Buckets follow highlight.js's GitHub theme, except `attr` (JSON/YAML keys) is green as on github.com. + if (tokens.has('subst')) { + return 'plain' + } if (hasAny(tokens, ['comment', 'quote'])) { return 'comment' } - if (hasAny(tokens, ['keyword', 'selector-tag', 'tag', 'name'])) { + if (hasAny(tokens, ['keyword', 'doctag', 'template-tag', 'language_'])) { return 'keyword' } + if (hasAny(tokens, ['name', 'selector-tag', 'selector-pseudo', 'attr'])) { + return 'tag' + } if (hasAny(tokens, ['string', 'regexp', 'symbol', 'bullet'])) { return 'string' } - if (hasAny(tokens, ['number', 'literal'])) { + if (hasAny(tokens, ['number', 'literal', 'attribute', 'selector-class', 'selector-id'])) { return 'number' } - if (hasAny(tokens, ['type', 'built_in', 'class', 'title.class'])) { + if (hasAny(tokens, ['type', 'built_in'])) { return 'type' } - if (hasAny(tokens, ['title.function', 'function', 'title'])) { + if (hasAny(tokens, ['title', 'function'])) { return 'function' } - if (hasAny(tokens, ['attr', 'attribute', 'property', 'variable', 'params'])) { + if (hasAny(tokens, ['variable', 'template-variable'])) { return 'variable' } - if (hasAny(tokens, ['meta', 'doctag', 'subst', 'section'])) { + if (hasAny(tokens, ['meta', 'section'])) { return 'meta' } return null diff --git a/mobile/src/files/session-documents/mobile-session-reader-styles.ts b/mobile/src/files/session-documents/mobile-session-reader-styles.ts index bc5d1519e1a..ebc74564da4 100644 --- a/mobile/src/files/session-documents/mobile-session-reader-styles.ts +++ b/mobile/src/files/session-documents/mobile-session-reader-styles.ts @@ -1,4 +1,4 @@ -import { Platform, StyleSheet } from 'react-native' +import { StyleSheet } from 'react-native' import { colors, spacing, radii, typography } from '../../theme/mobile-theme' import { themedStyleSheet } from '../../theme/themed-styles' @@ -14,7 +14,7 @@ export const mobileSessionReaderStyles = themedStyleSheet(() => ({ paddingBottom: spacing.xl * 3, fontSize: typography.bodySize, lineHeight: 22, - fontFamily: Platform.select({ ios: 'Menlo', android: 'monospace', default: 'monospace' }) + fontFamily: typography.monoFamily }, filePreviewScroll: { flex: 1, @@ -30,7 +30,7 @@ export const mobileSessionReaderStyles = themedStyleSheet(() => ({ color: colors.textPrimary, fontSize: typography.bodySize, lineHeight: 22, - fontFamily: Platform.select({ ios: 'Menlo', android: 'monospace', default: 'monospace' }) + fontFamily: typography.monoFamily }, imagePreviewContainer: { flex: 1, @@ -106,14 +106,14 @@ export const mobileSessionReaderStyles = themedStyleSheet(() => ({ color: colors.textMuted, fontSize: typography.metaSize, lineHeight: 22, - fontFamily: Platform.select({ ios: 'Menlo', android: 'monospace', default: 'monospace' }) + fontFamily: typography.monoFamily }, diffText: { flex: 1, color: colors.textPrimary, fontSize: typography.bodySize, lineHeight: 22, - fontFamily: Platform.select({ ios: 'Menlo', android: 'monospace', default: 'monospace' }) + fontFamily: typography.monoFamily }, diffPrefix: { color: colors.textMuted diff --git a/mobile/src/home/tabs/MobileHomeUsageTab.tsx b/mobile/src/home/tabs/MobileHomeUsageTab.tsx index 3aebd0acebb..0f97179ff0c 100644 --- a/mobile/src/home/tabs/MobileHomeUsageTab.tsx +++ b/mobile/src/home/tabs/MobileHomeUsageTab.tsx @@ -7,13 +7,13 @@ import Animated, { useSharedValue, withTiming } from 'react-native-reanimated' +import { usageBarFill } from '../../accounts/usage/UsageBar' import { getUsageBarState, getWindowResetLabel, - usageBarFill, - type AccountsSnapshot, type ProviderKey -} from '../../components/AccountUsage' +} from '../../accounts/usage/usage-selectors' +import type { AccountsSnapshot } from '../../accounts/accounts-snapshot' import { ClaudeIcon, OpenAIIcon } from '../../components/AgentIcons' import { useNow } from '../../hooks/use-now' import { useMobileTranslation } from '../../i18n/use-mobile-translation' diff --git a/mobile/src/home/tabs/home-usage-cards.test.ts b/mobile/src/home/tabs/home-usage-cards.test.ts index b8757f26084..2c5d9145d90 100644 --- a/mobile/src/home/tabs/home-usage-cards.test.ts +++ b/mobile/src/home/tabs/home-usage-cards.test.ts @@ -1,8 +1,5 @@ import { describe, expect, it } from 'vitest' -import type { - AccountProviderRateLimits, - AccountsSnapshot -} from '../../components/account-usage-state' +import type { AccountProviderRateLimits, AccountsSnapshot } from '../../accounts/accounts-snapshot' import { selectHomeUsageCards } from './home-usage-cards' function limits( diff --git a/mobile/src/home/tabs/home-usage-cards.ts b/mobile/src/home/tabs/home-usage-cards.ts index df89a46d8cb..a10f916c5fd 100644 --- a/mobile/src/home/tabs/home-usage-cards.ts +++ b/mobile/src/home/tabs/home-usage-cards.ts @@ -3,11 +3,10 @@ import { getInactiveProviderUsage, hasActiveProviderUsage, hasRenderableUsage, - type AccountsSnapshot, - type ProviderKey, - type ProviderRateLimits -} from '../../components/account-usage-state' -import { getActiveCodexAccountIdForRateLimitTarget } from '../../components/codex-reset-credit' + type ProviderKey +} from '../../accounts/usage/usage-selectors' +import type { AccountsSnapshot, ProviderRateLimits } from '../../accounts/accounts-snapshot' +import { getActiveCodexAccountIdForRateLimitTarget } from '../../accounts/usage/codex-reset-credit' export type HomeUsageCard = { /** The managed account's id, or null for the agent's own login (System default). */ diff --git a/mobile/src/home/use-home-spare-page.ts b/mobile/src/home/use-home-spare-page.ts index 14a883477e1..2a8227e88c9 100644 --- a/mobile/src/home/use-home-spare-page.ts +++ b/mobile/src/home/use-home-spare-page.ts @@ -8,7 +8,7 @@ import { leaveHomeSparePage, prepareHomeSparePage } from '../mobile-web-shell/home-spare-page' -import { processGenerationStore } from '../mobile-web-shell/process-generation-store' +import { processGenerationStore } from '../mobile-web-shell/generations/process-generation-store' // Past Home's first paint and its first reads, so the boot never competes with them. const HOME_SPARE_IDLE_MS = 1000 diff --git a/mobile/src/home/use-mobile-home-data.ts b/mobile/src/home/use-mobile-home-data.ts index a0500640fed..86db717735c 100644 --- a/mobile/src/home/use-mobile-home-data.ts +++ b/mobile/src/home/use-mobile-home-data.ts @@ -16,7 +16,7 @@ import { } from '../agents/agent-list-rows' import { useAgentActivityWrites } from '../agents/use-agent-activity-writes' import { accountsSnapshotOptions } from '../accounts/accounts-snapshot-stream' -import type { AccountsSnapshot } from '../components/AccountUsage' +import type { AccountsSnapshot } from '../accounts/accounts-snapshot' import { HOST_LIST_TARGET, homeWorktreeCountsKey, diff --git a/mobile/src/host-catalog/host-removal-lifecycle.ts b/mobile/src/host-catalog/host-removal-lifecycle.ts index 65ff0eff370..29e05398f23 100644 --- a/mobile/src/host-catalog/host-removal-lifecycle.ts +++ b/mobile/src/host-catalog/host-removal-lifecycle.ts @@ -3,7 +3,7 @@ import { wipeHostStore } from '../device-store/device-store' import { deleteHostPageCache, forgetHostUpdateFailures -} from '../mobile-web-shell/removed-host-shell-cache' +} from '../mobile-web-shell/generations/removed-host-shell-cache' import { unregisterPushForRemovedHost } from '../notifications/push-registration' import { forgetNativeHostQueries } from '../query/native-query-persistence' import { forgetHostDescriptor } from '../host-descriptors/host-descriptor-store' diff --git a/mobile/src/host-catalog/mobile-relay-host-overlay-store.test.ts b/mobile/src/host-catalog/mobile-relay-host-overlay-store.test.ts deleted file mode 100644 index fd4e8f54f2f..00000000000 --- a/mobile/src/host-catalog/mobile-relay-host-overlay-store.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' - -const asyncStorage = vi.hoisted(() => ({ - getItem: vi.fn(), - setItem: vi.fn() -})) - -vi.mock('@react-native-async-storage/async-storage', () => ({ default: asyncStorage })) - -import { - loadMobileRelayHostRoutingState, - resetMobileRelayHostOverlayStoreForTests, - saveMobileRelayHostRouting -} from './mobile-relay-host-overlay-store' -import type { MobileRelayHostOverlay } from './mobile-relay-host-overlay' - -const STORAGE_KEY = 'orca:mobile-relay:host-overlays:v2' -const RELAY = { - v: 1 as const, - directorUrl: 'https://relay.onorca.dev', - cellUrl: 'https://relay-c1.onorca.dev', - assignmentEpoch: 7, - relayHostId: 'AbCdEf0123_-xyZ9', - e2eeFraming: 2 as const -} -const RELAY_ONLY_OVERLAY: MobileRelayHostOverlay = { - v: 2, - hostId: 'host-1', - endpoints: [ - { - id: 'relay-primary', - kind: 'relay', - url: 'wss://relay-c1.onorca.dev/v1/connect/AbCdEf0123_-xyZ9' - } - ], - relayHostId: RELAY.relayHostId, - relay: RELAY -} -// What builds before the relay-routing split wrote: a copy of the row's address beside the relay. -const LEGACY_OVERLAY: MobileRelayHostOverlay = { - ...RELAY_ONLY_OVERLAY, - endpoints: [ - { id: 'direct-primary', kind: 'lan', url: 'ws://192.168.1.10:6768' }, - ...RELAY_ONLY_OVERLAY.endpoints - ] -} - -// Freeze the shipped overlay schema to prove older builds still accept written records. - -describe('mobile relay host overlay store', () => { - let stored: string | null - - beforeEach(() => { - vi.clearAllMocks() - resetMobileRelayHostOverlayStoreForTests() - stored = null - asyncStorage.getItem.mockImplementation(async (key: string) => - key === STORAGE_KEY ? stored : null - ) - asyncStorage.setItem.mockImplementation(async (key: string, value: string) => { - if (key === STORAGE_KEY) { - stored = value - } - }) - }) - - it('ignores a direct address an older build stored and drops it on the next routing write', async () => { - stored = JSON.stringify([LEGACY_OVERLAY]) - - await expect(loadMobileRelayHostRoutingState(new Set(['host-1']))).resolves.toEqual({ - relays: new Map([['host-1', RELAY]]), - orphanHostIds: [] - }) - await expect(saveMobileRelayHostRouting('host-1', RELAY)).resolves.toBe(true) - expect(JSON.parse(stored!)).toEqual([RELAY_ONLY_OVERLAY]) - }) -}) diff --git a/mobile/src/host-credentials/mobile-relay-credential-bundle.test.ts b/mobile/src/host-credentials/mobile-relay-credential-bundle.test.ts deleted file mode 100644 index 37e2f71cbd9..00000000000 --- a/mobile/src/host-credentials/mobile-relay-credential-bundle.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' - -const asyncStorage = vi.hoisted(() => ({ - getItem: vi.fn(), - setItem: vi.fn() -})) -const secureStore = vi.hoisted(() => ({ - getItemAsync: vi.fn(), - setItemAsync: vi.fn(), - deleteItemAsync: vi.fn() -})) -const platform = vi.hoisted(() => ({ OS: 'ios' })) - -vi.mock('@react-native-async-storage/async-storage', () => ({ default: asyncStorage })) -vi.mock('expo-secure-store', () => ({ - WHEN_UNLOCKED_THIS_DEVICE_ONLY: 'WHEN_UNLOCKED_THIS_DEVICE_ONLY', - ...secureStore -})) -vi.mock('react-native', () => ({ Platform: platform })) - -import { promotePairingJournalCredential } from './mobile-relay-credential-bundle' -import type { MobileRelayPairingJournal } from '../pairing/mobile-relay-pairing-journal' -import { resetPairingKeychainForTests } from './pairing-keychain' - -const journal = { - metadata: { - v: 1, - journalId: 'pair-1', - offerFingerprint: 'A'.repeat(43), - host: { - id: 'host-1', - name: 'Blue Whale', - endpoint: 'ws://192.168.1.10:6768', - publicKeyB64: 'A'.repeat(44), - lastConnected: 1 - }, - relay: { - v: 1, - directorUrl: 'https://relay.onorca.dev', - cellUrl: 'https://relay-c1.onorca.dev', - assignmentEpoch: 7, - relayHostId: 'AbCdEf0123_-xyZ9', - inviteExpiresAt: 10_000, - e2eeFraming: 2 - }, - installReqId: 'install-1', - resumeConfirmReqId: 'confirm-1', - pendingResumeTokenHash: 'B'.repeat(43), - winner: 'direct', - authorizationMode: 'authenticated-direct' - }, - secrets: { - v: 1, - journalId: 'pair-1', - deviceToken: 'device-token', - inviteToken: 'C'.repeat(43), - pendingResumeToken: 'D'.repeat(43) - } -} satisfies MobileRelayPairingJournal - -describe('mobile relay credential bundle', () => { - const stored = new Map() - - beforeEach(() => { - vi.clearAllMocks() - resetPairingKeychainForTests() - platform.OS = 'ios' - stored.clear() - asyncStorage.getItem.mockResolvedValue(null) - asyncStorage.setItem.mockResolvedValue(undefined) - secureStore.getItemAsync.mockImplementation(async (key: string) => stored.get(key) ?? null) - secureStore.setItemAsync.mockImplementation(async (key: string, value: string) => { - stored.set(key, value) - }) - secureStore.deleteItemAsync.mockImplementation(async (key: string) => { - stored.delete(key) - }) - }) - - it('rejects a result from another request or authorization mode', () => { - const installed = { - v: 1 as const, - reqId: 'install-1', - authorizationMode: 'authenticated-direct' as const, - currentVersion: 1, - resumeExpiresAt: 50_000 - } - expect(() => - promotePairingJournalCredential({ - journal, - installed: { ...installed, reqId: 'other-request' } - }) - ).toThrow(/does not match/) - expect(() => - promotePairingJournalCredential({ - journal, - installed: { ...installed, authorizationMode: 'relay-basis' } - }) - ).toThrow(/does not match/) - }) -}) diff --git a/mobile/src/host-screen/workspace-details-sheet.tsx b/mobile/src/host-screen/workspace-details-sheet.tsx index cdeab528d5e..e285c5b6480 100644 --- a/mobile/src/host-screen/workspace-details-sheet.tsx +++ b/mobile/src/host-screen/workspace-details-sheet.tsx @@ -5,9 +5,6 @@ import { CircleDot, ExternalLink, GitMerge, - GitPullRequest, - GitPullRequestClosed, - GitPullRequestDraft, SquareTerminal, StickyNote } from 'lucide-react-native' @@ -15,6 +12,7 @@ import { colors, spacing, typography } from '../theme/mobile-theme' import { themedStyleSheet } from '../theme/themed-styles' import { useMobileColorScheme } from '../theme/use-mobile-color-scheme' import { prStateColor } from '../components/WorktreeMetaGlyphs' +import { PrStateIcon } from '../components/PrStateIcon' import { LIST_LEADING_INSET, LIST_LEADING_SLOT, @@ -135,20 +133,13 @@ function originLabel(origin: WorkspaceOrigin, t: Translate): string { function ReviewIcon({ item }: { item: WorkspaceDetailLink }) { useMobileColorScheme() - const color = prStateColor(item.state ?? '') - if ( - item.state === 'merged' || - (item.type === 'mr' && item.state !== 'closed' && item.state !== 'draft') - ) { + const state = item.state ?? '' + const color = prStateColor(state) + // GitLab draws every open MR with the merge glyph. + if (item.type === 'mr' && state !== 'closed' && state !== 'draft') { return } - if (item.state === 'closed') { - return - } - if (item.state === 'draft') { - return - } - return + return } function LinkIcon({ item }: { item: WorkspaceDetailLink }) { diff --git a/mobile/src/i18n/locales/de.json b/mobile/src/i18n/locales/de.json index c8c64c2cf93..0d48e6ab72e 100644 --- a/mobile/src/i18n/locales/de.json +++ b/mobile/src/i18n/locales/de.json @@ -2454,7 +2454,8 @@ "tabStrip": { "checkingCapabilities": "Desktop-Funktionen werden geprüft – gleich erneut versuchen", "newTab": "Neuen Tab erstellen", - "quickCommandsUpdateRequired": "Desktop-Update für Schnellbefehle erforderlich" + "quickCommandsUpdateRequired": "Desktop-Update für Schnellbefehle erforderlich", + "tabStatus": "{{title}}, {{status}}" }, "terminalActionSheetActions": { "clearTerminal": "Terminal leeren", @@ -3364,6 +3365,12 @@ }, "tasks": { "hostedMerge": { + "confirmGitHubMerge": "PR #{{number}} zusammenführen?", + "confirmGitHubSquash": "PR #{{number}} mit Squash zusammenführen?", + "confirmGitHubRebase": "PR #{{number}} mit Rebase zusammenführen?", + "confirmGitLabMerge": "Merge Request #{{number}} zusammenführen?", + "confirmGitLabSquash": "Merge Request #{{number}} mit Squash zusammenführen?", + "confirmGitLabRebase": "Merge Request #{{number}} mit Rebase zusammenführen?", "merged": "Zusammengeführt", "closed": "Geschlossen", "conflicts": "Konflikte", diff --git a/mobile/src/i18n/locales/en.json b/mobile/src/i18n/locales/en.json index f14faed6778..e3be23f7526 100644 --- a/mobile/src/i18n/locales/en.json +++ b/mobile/src/i18n/locales/en.json @@ -820,6 +820,8 @@ "webShell": { "shellStateScreen": { "isolationUnavailable": "This device's WebView is too old to open the workspace safely.", + "isolationUnavailableAndroid": "Orca needs Android System WebView or Chrome 101 or newer. Update it from the Play Store, or pick a newer one in Developer options > WebView implementation.", + "webViewInUse": "This device has {{name}} {{version}}.", "downloadFailed": "The latest app could not be downloaded from this host.", "hostProfileUnreadable": "Could not read this host on your device. Try again.", "statusUnreadable": "Could not read this host's status. Go back and reopen it.", @@ -2182,10 +2184,10 @@ "renameTerminal": "Rename Terminal", "renameTerminalFailed": "Couldn't rename the terminal. {{reason}}", "terminalName": "Terminal name", - "allowAutoClose": "Allow Auto-Close", - "agents": "Agents" + "allowAutoClose": "Allow Auto-Close" }, "tabStrip": { + "tabStatus": "{{title}}, {{status}}", "newTab": "New tab", "quickCommandsUpdateRequired": "Desktop update required for quick commands", "checkingCapabilities": "Checking desktop capabilities — try again in a moment" @@ -2887,6 +2889,8 @@ }, "presentation": { "loadingTabs": "Loading tabs", + "oneTab": "1 tab", + "tabCount": "{{tabCount}} tabs", "tapToRetry": "{{status}} — tap to retry" }, "documentReaders": { @@ -2924,29 +2928,6 @@ "skip": "Skip", "stop": "Stop", "yes": "Yes" - }, - "tabsSheet": { - "needsYou": "Needs you", - "working": "Working", - "everythingElse": "Everything else", - "open": "Open", - "closeTab": "Close {{title}}" - }, - "tabRows": { - "browser": "Browser", - "markdown": "Markdown note", - "file": "File", - "chat": "Chat", - "terminal": "Terminal" - }, - "tabBar": { - "oneTab": "1 tab", - "tabCount": "{{count}} tabs", - "anotherNeedsYou": "another tab needs you", - "actionsHint": "Shows actions for this tab", - "next": "Next tab", - "previous": "Previous tab", - "hint": "Shows all tabs" } }, "chat": { @@ -3482,7 +3463,12 @@ "commitThenPullPush": "Commit, then pull and push", "resolveConflicts": "Resolve conflicts before committing", "stageFile": "Stage at least one file to commit", - "enterMessage": "Enter a commit message to commit" + "enterMessage": "Enter a commit message to commit", + "statusConflicts": "Conflicts", + "statusNothingStaged": "Nothing staged", + "statusNeedsMessage": "Needs message", + "statusNotPublished": "Not published", + "statusNoBranch": "No branch" }, "createPrAction": { "createReview": "Create {{titleLabel}}", @@ -3559,7 +3545,15 @@ "nothingToPushTo": "Nothing to push to {{upstreamName}}", "nothingToForcePushTo": "Nothing to force push to {{upstreamName}}", "rebaseFromNamedBase": "Rebase from {{baseRef}}", - "rebaseWithLatestFrom": "Rebase current branch with latest commits from {{baseRef}}" + "rebaseWithLatestFrom": "Rebase current branch with latest commits from {{baseRef}}", + "statusUpToDate": "Up to date", + "statusSetsUpstream": "Sets upstream", + "statusNotPublished": "Not published", + "statusNoBranch": "No branch", + "statusMayFail": "May fail", + "statusPublished": "Published", + "statusStashFirst": "Stash first", + "statusReplaces": "Replaces ↓{{behind}}" }, "actions": { "createPr": "Create PR", @@ -4559,6 +4553,12 @@ "createFailed": "Failed to create workspace" }, "hostedMerge": { + "confirmGitHubMerge": "Merge PR #{{number}}?", + "confirmGitHubSquash": "Squash and merge PR #{{number}}?", + "confirmGitHubRebase": "Rebase and merge PR #{{number}}?", + "confirmGitLabMerge": "Merge merge request #{{number}}?", + "confirmGitLabSquash": "Squash and merge merge request #{{number}}?", + "confirmGitLabRebase": "Rebase and merge merge request #{{number}}?", "merged": "Merged", "closed": "Closed", "conflicts": "Conflicts", diff --git a/mobile/src/i18n/locales/es.json b/mobile/src/i18n/locales/es.json index 78f372f2264..3c85874971d 100644 --- a/mobile/src/i18n/locales/es.json +++ b/mobile/src/i18n/locales/es.json @@ -2524,7 +2524,8 @@ "tabStrip": { "checkingCapabilities": "Comprobando las funciones del escritorio. Inténtalo de nuevo en un momento.", "newTab": "Nueva pestaña", - "quickCommandsUpdateRequired": "Actualiza el escritorio para usar los comandos rápidos." + "quickCommandsUpdateRequired": "Actualiza el escritorio para usar los comandos rápidos.", + "tabStatus": "{{title}}, {{status}}" }, "terminalActionSheetActions": { "clearTerminal": "Limpiar terminal", @@ -3452,6 +3453,12 @@ }, "tasks": { "hostedMerge": { + "confirmGitHubMerge": "¿Fusionar el PR #{{number}}?", + "confirmGitHubSquash": "¿Compactar y fusionar el PR #{{number}}?", + "confirmGitHubRebase": "¿Hacer rebase y fusionar el PR #{{number}}?", + "confirmGitLabMerge": "¿Fusionar la solicitud de merge #{{number}}?", + "confirmGitLabSquash": "¿Compactar y fusionar la solicitud de merge #{{number}}?", + "confirmGitLabRebase": "¿Hacer rebase y fusionar la solicitud de merge #{{number}}?", "merged": "Fusionado", "closed": "Cerrado", "conflicts": "Conflictos", diff --git a/mobile/src/i18n/locales/fr.json b/mobile/src/i18n/locales/fr.json index 20d2d3b5828..bcac91b25ec 100644 --- a/mobile/src/i18n/locales/fr.json +++ b/mobile/src/i18n/locales/fr.json @@ -2524,7 +2524,8 @@ "tabStrip": { "checkingCapabilities": "Vérification des fonctionnalités de l'ordinateur — réessayez dans un instant", "newTab": "Nouvel onglet", - "quickCommandsUpdateRequired": "Mettez à jour Orca sur l'ordinateur pour utiliser les commandes rapides" + "quickCommandsUpdateRequired": "Mettez à jour Orca sur l'ordinateur pour utiliser les commandes rapides", + "tabStatus": "{{title}}, {{status}}" }, "terminalActionSheetActions": { "clearTerminal": "Effacer le terminal", @@ -3452,6 +3453,12 @@ }, "tasks": { "hostedMerge": { + "confirmGitHubMerge": "Fusionner la PR nº {{number}} ?", + "confirmGitHubSquash": "Compresser les commits et fusionner la PR nº {{number}} ?", + "confirmGitHubRebase": "Rebaser et fusionner la PR nº {{number}} ?", + "confirmGitLabMerge": "Fusionner la demande de fusion nº {{number}} ?", + "confirmGitLabSquash": "Compresser les commits et fusionner la demande de fusion nº {{number}} ?", + "confirmGitLabRebase": "Rebaser et fusionner la demande de fusion nº {{number}} ?", "merged": "Fusionné", "closed": "Fermé", "conflicts": "Conflits", diff --git a/mobile/src/i18n/locales/ja.json b/mobile/src/i18n/locales/ja.json index c6ee2e0fa4f..1d47e857681 100644 --- a/mobile/src/i18n/locales/ja.json +++ b/mobile/src/i18n/locales/ja.json @@ -2450,7 +2450,8 @@ "tabStrip": { "checkingCapabilities": "デスクトップの対応機能を確認中です。少し待ってから再試行してください。", "newTab": "新規タブ", - "quickCommandsUpdateRequired": "クイックコマンドの利用にはデスクトップの更新が必要です。" + "quickCommandsUpdateRequired": "クイックコマンドの利用にはデスクトップの更新が必要です。", + "tabStatus": "{{title}}、{{status}}" }, "terminalActionSheetActions": { "clearTerminal": "ターミナルをクリア", @@ -3440,6 +3441,12 @@ "openView": "GitHub でビューを開く" }, "hostedMerge": { + "confirmGitHubMerge": "PR #{{number}} をマージしますか?", + "confirmGitHubSquash": "PR #{{number}} のコミットをまとめてマージしますか?", + "confirmGitHubRebase": "PR #{{number}} をリベースしてマージしますか?", + "confirmGitLabMerge": "マージリクエスト #{{number}} をマージしますか?", + "confirmGitLabSquash": "マージリクエスト #{{number}} のコミットをまとめてマージしますか?", + "confirmGitLabRebase": "マージリクエスト #{{number}} をリベースしてマージしますか?", "merged": "マージ済み", "closed": "クローズ済み", "conflicts": "競合あり", diff --git a/mobile/src/i18n/locales/ko.json b/mobile/src/i18n/locales/ko.json index 2b51f3ce5ae..0d561688f68 100644 --- a/mobile/src/i18n/locales/ko.json +++ b/mobile/src/i18n/locales/ko.json @@ -2450,7 +2450,8 @@ "tabStrip": { "checkingCapabilities": "데스크톱에서 지원하는 기능을 확인 중입니다. 잠시 후 다시 시도하세요.", "newTab": "새 탭", - "quickCommandsUpdateRequired": "빠른 명령을 사용하려면 데스크톱 업데이트가 필요합니다." + "quickCommandsUpdateRequired": "빠른 명령을 사용하려면 데스크톱 업데이트가 필요합니다.", + "tabStatus": "{{title}}, {{status}}" }, "terminalActionSheetActions": { "clearTerminal": "터미널 지우기", @@ -3360,6 +3361,12 @@ }, "tasks": { "hostedMerge": { + "confirmGitHubMerge": "PR #{{number}}을(를) 병합하시겠습니까?", + "confirmGitHubSquash": "PR #{{number}}의 커밋을 합쳐서 병합하시겠습니까?", + "confirmGitHubRebase": "PR #{{number}}을(를) 리베이스한 후 병합하시겠습니까?", + "confirmGitLabMerge": "병합 요청 #{{number}}을(를) 병합하시겠습니까?", + "confirmGitLabSquash": "병합 요청 #{{number}}의 커밋을 합쳐서 병합하시겠습니까?", + "confirmGitLabRebase": "병합 요청 #{{number}}을(를) 리베이스한 후 병합하시겠습니까?", "merged": "병합됨", "closed": "닫힘", "conflicts": "충돌", diff --git a/mobile/src/i18n/locales/pt.json b/mobile/src/i18n/locales/pt.json index 0d4a2150210..a771d8fb340 100644 --- a/mobile/src/i18n/locales/pt.json +++ b/mobile/src/i18n/locales/pt.json @@ -17,7 +17,8 @@ "switchFailed": "Não foi possível trocar de conta", "title": "Contas", "useReset": "Redefinir agora", - "weeklyWindow": "7d" + "weeklyWindow": "7d", + "pairingInvalidMessage": "Emparelhe novamente este telefone com seu desktop para ver suas contas." } }, "agentHistory": { @@ -40,7 +41,11 @@ "unknownHostPlatform": "Não foi possível determinar a plataforma do host.", "updateHost": "Atualize o Orca neste host para consultar o histórico de sessões de agente.", "waitingForHost": "Aguardando host…", - "workspace": "Espaço de Trabalho" + "workspace": "Espaço de Trabalho", + "hideDetails": "Ocultar detalhes", + "showDetails": "Mostrar detalhes", + "dismissNotice": "Descartar", + "loading": "Carregando sessões do agente…" }, "resumeTarget": { "differentHost": "Esta sessão pertence a um host diferente. Abra um espaço de trabalho no mesmo host para retomá-la.", @@ -55,7 +60,10 @@ "messages_many": "{{count}} mensagens", "messages_one": "{{count}} mensagem", "messages_other": "{{count}} mensagens", - "resumeSession": "Retomar sessão de agente" + "resumeSession": "Retomar sessão de agente", + "hidePreview": "Oculta as mensagens recentes.", + "showPreview": "Mostra as mensagens recentes.", + "you": "Você" }, "useAgentHistoryState": { "hostUnreachable": "Não foi possível acessar o host", @@ -65,6 +73,9 @@ "worktreeNavigationActions": { "agentSessionHistory": "Histórico de Sessões de Agente", "sourceControl": "Controle de Código-Fonte" + }, + "resume": { + "hostConnectionChanged": "A conexão com o host mudou. Tente retomar a sessão." } }, "app": { @@ -165,6 +176,13 @@ "viewModeSwitch": { "mobileView": "Mostrar versão do site para celular", "webView": "Mostrar versão do site para computador" + }, + "stream": { + "updateApp": "Atualize o aplicativo Orca para transmitir as guias do navegador aqui.", + "updateDesktop": "Atualize o Orca para desktop para transmitir as guias do navegador no celular.", + "checking": "Verificando o suporte de streaming do navegador de desktop.", + "pageUnavailable": "A página do navegador ainda não está disponível.", + "timedOut": "A transmissão do navegador expirou." } }, "chat": { @@ -407,7 +425,8 @@ "toggleOption": "Alternar {{value0}}", "ultra": "Ultra", "xhigh": "Extra alto", - "xhighShort": "Extra alto" + "xhighShort": "Extra alto", + "ultracode": "Ultracode" }, "sessionOptionPickers": { "agentWorking": "O agente está trabalhando", @@ -418,7 +437,9 @@ "permissions": "Permissões", "permissionsLabel": "Permissões, {{value}}", "settingsLocked": "As configurações do modelo serão desbloqueadas quando este turno terminar.", - "workingAnnouncement": "O agente está trabalhando. As configurações do modelo serão desbloqueadas quando este turno terminar." + "workingAnnouncement": "O agente está trabalhando. As configurações do modelo serão desbloqueadas quando este turno terminar.", + "applying": "Aplicando…", + "optionsSection": "Opções" }, "sessionOptionRows": { "defaultMarker": "Padrão", @@ -617,7 +638,12 @@ }, "agentMessage": { "handedOffToAgent": "Entregue a um agente", - "startedAgent": "Agente iniciado" + "startedAgent": "Agente iniciado", + "startedWorker": "Worker iniciado", + "taskFromCoordinator": "Tarefa do coordenador", + "messageFromCoordinator": "Mensagem do coordenador", + "updateFromWorker": "Atualização do worker", + "messageFrom": "Mensagem de" }, "textAttachmentPreview": { "unreadableReply": "A resposta do anexo não pode ser lida. Tente novamente.", @@ -706,7 +732,22 @@ "retry": "Tentar novamente", "save": "Salvar", "settings": "Configurações", - "unknown": "Desconhecido" + "unknown": "Desconhecido", + "loadError": { + "title": "Não foi possível carregar", + "generic": "Algo deu errado. Tente novamente.", + "unreachable": "Não foi possível conectar ao computador. Tente novamente." + }, + "offline": { + "waitingFor": "Esperando por {{host}}", + "waiting": "Aguardando o computador", + "message": "Verifique se o seu computador está ativado e se o Orca está em execução.", + "reconnect": "Reconectar" + }, + "noMatch": { + "title": "Nenhuma correspondência", + "clearSearch": "Limpar busca" + } }, "components": { "accountsSnapshot": { @@ -821,7 +862,12 @@ "noReviewableChanges": "Nenhuma alteração para revisar", "reviewUnavailable": "Revisão indisponível", "selectFile": "Selecione um arquivo para revisar.", - "tooLargeMessage": "Este diff é grande demais para a prévia no celular." + "tooLargeMessage": "Este diff é grande demais para a prévia no celular.", + "showUnchangedLines": "Mostrar {{count}} linhas inalteradas", + "unchangedLines_one": "{{count}} linha inalterada", + "unchangedLines_other": "{{count}} linhas inalteradas", + "allStaged": "Tudo foi preparado para commit", + "unchangedLines_many": "{{count}} linhas inalteradas" }, "diffReviewDrawers": { "addNote": "Adicionar nota", @@ -849,20 +895,48 @@ "unsentNotes_many": "{{count}} notas não enviadas", "unsentNotes_one": "{{count}} nota não enviada", "unsentNotes_other": "{{count}} notas não enviadas", - "updateRequired": "Atualize o Orca no seu computador" + "updateRequired": "Atualize o Orca no seu computador", + "viewedFiles_one": "{{count}} arquivo visualizado", + "viewedFiles_other": "{{count}} arquivos visualizados", + "notes_one": "{{count}} nota", + "notes_other": "{{count}} notas", + "allViewedTitle": "Todos os arquivos visualizados", + "unstageFile": "Remover do stage", + "addFileNote": "Adicionar nota de arquivo", + "pullRequest": "Pull request", + "discardChanges": "Descartar alterações", + "rangeLine": "Linha {{line}}", + "rangeLines": "Linhas {{startLine}}–{{line}}", + "sendToAnAgent": "Enviar para agente", + "rangePlaceholder": "O que deve mudar aqui?", + "commentOnGitHub": "Comente no GitHub", + "sendToAgent": "Enviar para {{agent}}", + "viewedFiles_many": "{{count}} arquivos visualizados", + "notes_many": "{{count}} notas" }, "diffReviewFileSummary": { "changed": "Alterado", "editFileNote": "Editar nota do arquivo", - "stale": "Desatualizada" + "stale": "Desatualizada", + "untracked": "Não rastreado", + "notStaged": "Não preparado", + "viewed": "Visualizado", + "renamedFrom": "Renomeado de {{oldPath}}", + "threadsWhenInSync_one": "O comentário no GitHub aparecerá aqui quando esta branch corresponder ao pull request.", + "threadsWhenInSync_other": "Os {{count}} comentários no GitHub aparecerão aqui quando esta branch corresponder ao pull request.", + "threadsWhenInSync_many": "Os {{count}} comentários no GitHub aparecerão aqui quando esta branch corresponder ao pull request." }, "diffReviewFooter": { "nextFile": "Próximo arquivo", - "previousFile": "Arquivo anterior" + "previousFile": "Arquivo anterior", + "stageNext": "Preparar · próximo arquivo", + "viewedNext": "Visualizado · próximo arquivo", + "nextFileButton": "Próximo arquivo" }, "diffReviewHeader": { "openReviewActions": "Abrir ações de revisão", - "title": "Alterações" + "title": "Alterações", + "jumpToFile": "{{fileName}}, pule para outro arquivo" }, "diffReviewLine": { "addNoteOnLine": "Adicionar nota na linha {{number}}", @@ -956,7 +1030,11 @@ "noProjectsFound": "Nenhum projeto encontrado", "note": "Nota", "notePlaceholder": "Escreva uma nota", - "workspaceName": "Nome do espaço de trabalho" + "workspaceName": "Nome do espaço de trabalho", + "options": "Opções", + "createWorkspace": "Criar espaço de trabalho", + "startFrom": "Iniciar a partir de", + "loadingProjects": "Carregando projetos…" }, "newWorktreeModal": { "remoteRepository": "Repositório remoto" @@ -970,7 +1048,8 @@ "project": "Projeto", "runOn": "Executar em", "selectProject": "Selecione um projeto", - "selectRunTarget": "Selecione um destino de execução" + "selectRunTarget": "Selecione um destino de execução", + "where": "Onde" }, "prSidebar": { "loading": "Carregando pull request…", @@ -1027,7 +1106,12 @@ "runHooks": "Executar hooks", "runSetupTitle": "Executar a configuração de {{repoName}}?", "scriptChangedTitle": "O script de configuração de {{repoName}} foi alterado", - "scriptLabel": "Script de configuração" + "scriptLabel": "Script de configuração", + "runArchiveTitle": "Executar o script de arquivamento de {{repoName}}?", + "archiveScriptChangedTitle": "O script de arquivamento de {{repoName}} foi alterado", + "archiveDescription": "O orca.yaml deste repositório é executado antes que o espaço de trabalho seja excluído. Execute-o apenas se você confiar neste repositório.", + "archiveScriptLabel": "Script de arquivamento", + "newArchiveScriptLabel": "Novo script de arquivamento" }, "smartWorkspaceAdvancedFields": { "branchName": "Nome da branch", @@ -1042,11 +1126,15 @@ "noResults": "Nenhum resultado encontrado.", "searchPlaceholder": "Digite um nome ou busque uma origem", "switchRepo": "Mudar para {{repoName}}", - "typeWorkspaceName": "Digite um nome para o espaço de trabalho no campo abaixo." + "typeWorkspaceName": "Digite um nome para o espaço de trabalho no campo abaixo.", + "workspaceName": "Nome do espaço de trabalho", + "startFrom": "Iniciar a partir de" }, "smartWorkspaceSourceField": { "openSelectedSource": "Abrir origem selecionada", - "searchPlaceholder": "Digite um nome ou busque uma origem" + "searchPlaceholder": "Digite um nome ou busque uma origem", + "optionalLabel": "Opcional", + "clearSelectedSource": "Limpar origem selecionada" }, "smartWorkspaceSourceRow": { "createBranch": "Criar branch \"{{name}}\"", @@ -1140,7 +1228,41 @@ "composer": { "planMode": "Plano", "exitPlanMode": "Sair do modo de planejamento" + }, + "turnDiff": { + "changedFiles_one": "{{count}} arquivo alterado", + "changedFiles_other": "{{count}} arquivos alterados", + "partial": "Diff parcial", + "showMoreFiles": "Mostrar mais {{count}}", + "changedFiles_many": "{{count}} arquivos alterados" } + }, + "pullDownMenu": { + "close": "Fechar menu" + }, + "bottomSearchBar": { + "closeSearch": "Fechar busca" + }, + "sheetHeader": { + "close": "Fechar" + }, + "worktreeAgentList": { + "hideChildAgents_one": "Ocultar {{count}} agente filho", + "hideChildAgents_other": "Ocultar {{count}} agentes filhos", + "showChildAgents_one": "Mostrar {{count}} agente filho", + "showChildAgents_other": "Mostrar {{count}} agentes filhos", + "hideIdleChildren": "Ocultar {{count}} agentes filhos inativos", + "showIdleChildren": "Mostrar {{count}} agentes filhos ociosos", + "idleChildCount": "{{count}} ocioso", + "hideChildAgents_many": "Ocultar {{count}} agentes filhos", + "showChildAgents_many": "Mostrar {{count}} agentes filhos" + }, + "diffReviewFilesSheet": { + "title": "Arquivos", + "search": "Ir para o arquivo", + "noMatches": "Nenhum arquivo corresponde", + "current": "atual", + "viewedFile": "{{path}} visualizado" } }, "connection": { @@ -1412,7 +1534,11 @@ "loadFailed": "Não foi possível carregar os arquivos", "title": "Arquivos", "truncatedList": "{{worktreeLabel}} - Mostrando os primeiros 5000", - "waiting": "Aguardando o desktop…" + "waiting": "Aguardando o desktop…", + "filterPlaceholder": "Filtrar arquivos", + "noMatchesHint": "Somente as pastas que você abriu serão pesquisadas.", + "clearFilter": "Limpar filtro", + "loading": "Carregando arquivos…" }, "fileExplorerRow": { "fileUnavailable": "{{name}} indisponível no celular", @@ -1437,7 +1563,9 @@ "copyLoadedSource": "Copiar código-fonte Markdown carregado", "copySource": "Copiar código-fonte Markdown", "viewPreview": "Ver pré-visualização renderizada do Markdown", - "viewSource": "Ver código-fonte Markdown" + "viewSource": "Ver código-fonte Markdown", + "previewMode": "Pré-visualizar", + "sourceMode": "Origem" }, "fileMediaPreview": { "downloading": "Baixando {{bytes}} de {{total}}", @@ -1513,7 +1641,8 @@ "appUpdateCard": { "dismissAccessibilityLabel": "Descartar atualização do Orca {{version}}", "title": "Orca {{version}} está disponível", - "updateAccessibilityLabel": "Orca {{version}} está disponível, toque para atualizar" + "updateAccessibilityLabel": "Orca {{version}} está disponível, toque para atualizar", + "update": "Atualizar" }, "automationsTab": { "connectDesktop": "Conecte {{desktop}} para ver e executar automações.", @@ -1536,7 +1665,9 @@ "openDesktopDescription": "Vá para Configurações → Mobile e gere um código QR de pareamento.", "openDesktopTitle": "Abra o Orca no desktop", "scanCodeTitle": "Escaneie o código", - "title": "Conecte seu desktop" + "title": "Conecte seu desktop", + "pairDesktopButton": "Emparelhar computador", + "scanCodeBelowDescription": "Toque em Emparelhar computador abaixo e aponte a câmera para o código QR na tela." }, "listFooter": { "hostPickerTitle": "Abrir tarefas em" @@ -1577,6 +1708,18 @@ "showUsageFor": "Mostrar uso de", "updatedAgo": "Atualizado há {{time}}", "updatedJustNow": "Atualizado agora mesmo" + }, + "bottomBar": { + "connectFirst": "Conecte um computador para iniciar um novo trabalho.", + "newWorkspace": "Novo espaço de trabalho" + }, + "desktops": { + "pairDesktop": "Emparelhe um computador" + }, + "jumpBackIn": {}, + "sections": { + "tasks": "Tarefas", + "tasksSubtitle": "Explore suas issues e revisões" } }, "hooks": { @@ -1608,7 +1751,8 @@ "name": "Nome", "saveFailed": "Falha ao salvar o host.", "saveHost": "Salvar host", - "title": "Editar host" + "title": "Editar host", + "removeHost": "Remover host" } }, "hostScreen": { @@ -1629,7 +1773,8 @@ "hideSidebar": "Ocultar barra lateral", "reconnect": "Reconectar", "tasks": "Tarefas", - "automations": "Automações" + "automations": "Automações", + "moreActions": "Mais ações" }, "hostScreenOverlays": { "deleteConfirmMessage": "Excluir \"{{name}}\" ({{branch}})?", @@ -1642,7 +1787,9 @@ "removeHostMessage": "Remover \"{{name}}\"? Você pode parear novamente mais tarde.", "sleep": "Suspender", "unpin": "Desafixar", - "rename": "Renomear" + "rename": "Renomear", + "deleteFailed": "Falha ao excluir \"{{name}}\"", + "deleteAnyway": "Excluir Mesmo Assim" }, "workspaceDetailsSheet": { "checksFailing": "Verificações: com falha", @@ -1723,13 +1870,26 @@ "syncedAcrossDevices": "Sincronizadas entre seus dispositivos", "thisComputer": "Este computador", "waitingForDesktop": "Ainda aguardando o desktop", - "workspaceOptions": "Opções do espaço de trabalho" + "workspaceOptions": "Opções do espaço de trabalho", + "done": "Concluído", + "reset": "Restaurar" }, "workspaceRenameSheet": { "title": "Renomear espaço de trabalho", "emptyUsesBranch": "Deixe em branco para usar o nome da branch.", "emptyUsesFolder": "Deixe em branco para usar o nome da pasta.", "failed": "Não foi possível renomear o espaço de trabalho. {{reason}}" + }, + "hostBottomBar": { + "workspaceOptions": "Opções do espaço de trabalho", + "activeFilters_one": "Opções do espaço de trabalho ({{count}} filtro ativo)", + "activeFilters_other": "Opções do espaço de trabalho ({{count}} filtros ativos)", + "searchWorkspaces": "Buscar espaços de trabalho", + "newWorkspace": "Novo espaço de trabalho", + "activeFilters_many": "Opções do espaço de trabalho ({{count}} filtros ativos)" + }, + "identity": { + "hostNotFound": "Host não encontrado" } }, "navigation": { @@ -1768,7 +1928,9 @@ "onlyWhenAwayHint": "Após 3 minutos sem atividade do teclado ou mouse, ou quando o desktop estiver bloqueado.", "sound": "Som de notificação", "suppressWhileFocused": "Suprimir enquanto em foco", - "suppressWhileFocusedHint": "Não enviar alertas do espaço de trabalho aberto neste celular." + "suppressWhileFocusedHint": "Não enviar alertas do espaço de trabalho aberto neste celular.", + "onlyWhenAgentNeedsInput": "Somente quando um agente precisa de mim", + "onlyWhenAgentNeedsInputHint": "Solicitações de permissão e perguntas. Ignora agentes finalizados." } }, "onboarding": { @@ -1825,7 +1987,15 @@ "unresolve": "Reabrir", "yearsAgo_many": "há {{count}} anos", "yearsAgo_one": "há {{count}} ano", - "yearsAgo_other": "há {{count}} anos" + "yearsAgo_other": "há {{count}} anos", + "resolved": "resolvido", + "openOnGitHub": "Abrir comentário no GitHub", + "replyToComment": "Responder ao comentário", + "editComment": "Editar comentário", + "deleteComment": "Excluir comentário", + "unresolveThread": "Reabrir discussão", + "resolveThread": "Resolver thread", + "replyPlaceholder": "Escreva uma resposta…" }, "commentsSection": { "comment": "Comentar", @@ -1834,7 +2004,20 @@ "noComments": "Ainda não há comentários.", "noDescription": "Nenhuma descrição fornecida.", "showMore": "Mostrar mais {{count}}", - "title": "Comentários" + "title": "Comentários", + "all": "Todos", + "humans": "Humanos", + "bots": "Robôs", + "noBotComments": "Nenhum comentário de bot.", + "noHumanComments": "Nenhum comentário humano.", + "commentsLoadFailed": "Não foi possível carregar os comentários. Toque em atualizar para tentar novamente.", + "showMoreOf": "Mostrar {{count}} mais de {{remaining}}", + "addCommentPlaceholder": "Adicione um comentário…", + "resolvedThreadSingle": "Thread resolvida de {{author}}", + "resolvedThreadCount": "Tópico resolvido por {{author}} ({{count}})", + "resolvedCommentSingle": "Comentário resolvido de {{author}}", + "resolvedCommentCount": "Comentário resolvido por {{author}} ({{count}})", + "commentsLoadFailedRetry": "Não foi possível carregar os comentários." }, "linkPrForm": { "linkButton": "Vincular pull request", @@ -1854,7 +2037,10 @@ "reopenButton": "Reabrir", "reopenConfirmMessage": "#{{number}} será reaberto.", "reopenConfirmTitle": "Reabrir pull request?", - "unlinkButton": "Desvincular" + "unlinkButton": "Desvincular", + "unlinkFailed": "Falha ao desvincular o pull request.", + "mergeConfirmTitle": "Mesclar pull request?", + "mergeButton": "Mesclar" }, "prActionsState": { "behindHint": "Atualize a branch antes de fazer o merge", @@ -1956,7 +2142,8 @@ "currentBranchNotLinked": "A branch atual não está vinculada a um PR aberto.", "linkExistingPullRequest": "Vincular um pull request existente", "linkedPrUnavailable": "PR vinculado #{{number}} indisponível", - "refreshOrCreate": "Atualize para verificar novamente ou crie um novo PR para esta branch." + "refreshOrCreate": "Atualize para verificar novamente ou crie um novo PR para esta branch.", + "branchRequired": "Faça checkout de uma branch antes de criar um pull request." }, "prViewPanel": { "branchUnavailable": "Branch atual indisponível.", @@ -1976,7 +2163,172 @@ "removeReviewer": "Remover {{login}}", "requested": "Solicitado", "reviewed": "Revisado", - "title": "Revisores" + "title": "Revisores", + "loadFailed": "Não foi possível carregar os revisores. Toque em atualizar para tentar novamente." + }, + "tab": { + "updated": "atualizado {{time}}", + "moreActions": "Mais ações de pull request", + "unlinkConfirmTitle": "Desvincular pull request?", + "unlinkConfirmMessage": "#{{number}} permanece aberto no GitHub; este espaço de trabalho para de rastreá-lo.", + "createPullRequest": "Criar pull request", + "mergedInto": "Mesclado em {{base}}", + "merged": "Mesclado", + "cantMergeYet": "Ainda não é possível mesclar:", + "willMergeWhenReady": "Irá mesclar quando estiver pronto", + "mergeWhenReady": "Mesclar quando estiver pronto", + "commentsOnFiles": "{{comments}} comentários em {{files}} arquivos", + "filesChanged_one": "{{count}} arquivo alterado", + "filesChanged_other": "{{count}} arquivos alterados", + "editDescription": "Editar descrição", + "edit": "Editar", + "showLess": "Mostrar menos", + "showMore": "Mostrar mais", + "viewedOf": "{{viewed}} de {{total}} visualizados", + "filesChanged_many": "{{count}} arquivos alterados" + }, + "menu": { + "refresh": "Atualizar", + "openOnGitHub": "Abrir no GitHub", + "copied": "Copiado", + "copyLink": "Copiar link", + "editTitle": "Editar título", + "autoMerge": "Mesclar automaticamente", + "markDraft": "Marcar como rascunho", + "unlink": "Desvincular do espaço de trabalho", + "close": "Fechar pull request" + }, + "mergeSheet": { + "squashDetail": "Um commit em {{base}}", + "mergeDetail": "Mantém cada commit", + "rebaseDetail": "Reproduz cada commit em {{base}}", + "subtitle": "Em {{base}}", + "title": "Mesclar #{{number}}" + }, + "editSheet": { + "title": "Editar título", + "description": "Editar descrição" + }, + "createSheet": { + "base": "Base", + "searchBranches": "Buscar branches", + "branchSearchFailed": "Falha ao buscar branches", + "noBranches": "Nenhuma ramificação correspondente", + "title": "Crie {{reviewLabel}}", + "titleLabel": "Título", + "descriptionLabel": "Descrição", + "writeWithAi": "Escreva com IA", + "descriptionPlaceholder": "Opcional", + "draft": "Criar como rascunho" + }, + "screens": { + "hideLog": "Ocultar registro", + "viewLog": "Ver registro", + "copyError": "Copiar erro", + "openOnGitHub": "Abrir no GitHub", + "failedAfter": "Falha após {{duration}}", + "failed": "Falhou", + "rerun": "Executar novamente", + "copyErrorFailed": "Não foi possível copiar o erro.", + "durationMinutes": "{{minutes}}min {{seconds}}s", + "failing": "Com falha", + "fixWithAi": "Corrigir com IA", + "runningSection": "Em execução", + "queued": "Na fila", + "inProgress": "Em andamento", + "passedSection": "Aprovado", + "neutralSection": "Neutro", + "filterComments": "Filtrar comentários", + "unresolvedCount": "Não resolvido {{count}}", + "noUnresolved": "Não há tópicos não resolvidos.", + "hideBots": "Ocultar bots", + "bot": "robô", + "commentActions": "Mais para este comentário", + "replyAndMore": "{{body}} (+{{count}} mais)", + "severityCritical": "Crítico", + "severityMajor": "Alta", + "severityMinor": "Baixa", + "severityTrivial": "Trivial", + "thread": "Discussão", + "backToComments": "Voltar aos comentários", + "threadGone": "Esta discussão não está mais no pull request.", + "replyPlaceholder": "Responder…", + "back": "Voltar ao pull request", + "noPullRequest": "Esta branch não tem um pull request no momento.", + "live": "Ao vivo", + "askToFix": "Peça ao {{agent}} para corrigir", + "askAiToFix": "Peça à IA para consertar", + "checkActions": "Mais para {{name}}", + "durationSeconds": "{{seconds}}s", + "durationHours": "{{hours}}h {{minutes}}m", + "namesAndMore": "{{names}} e {{count}} mais", + "running": "{{count}} em execução", + "commentOnPr": "Comente em #{{number}}…", + "allCount": "Todos {{count}}", + "resolvedCount": "Resolvido {{count}}", + "threadSubtitle_one": "{{author}} · {{count}} mensagem", + "threadSubtitle_other": "{{author}} · {{count}} mensagens", + "fixWith": "Corrigir com {{agent}}", + "threadSubtitle_many": "{{author}} · {{count}} mensagens" + }, + "reviewersSheet": { + "approvals_one": "{{count}} aprovação", + "approvals_other": "{{count}} aprovações", + "addReviewer": "Adicionar um revisor", + "approvals_many": "{{count}} aprovações" + }, + "emptyState": { + "commitsReady_one": "{{count}} commit em {{branch}} está pronto para entrar em {{base}}.", + "commitsReady_other": "{{count}} commits em {{branch}} estão prontos para entrar em {{base}}.", + "title": "Ainda não há pull request", + "commitsReady_many": "{{count}} commits em {{branch}} estão prontos para entrar em {{base}}." + }, + "gates": { + "checksUnavailable": "Verificações indisponíveis", + "checksFailing_one": "{{count}} verificação falhando", + "checksFailing_other": "{{count}} verificações falhando", + "checksRunning_one": "{{count}} verificação em execução", + "checksRunning_other": "{{count}} verificações em execução", + "checksPassedSoFar": "Verificações aprovadas até agora: {{count}}", + "noChecks": "Nenhuma verificação", + "checksFinished": "Verificações concluídas", + "checksPassed_one": "{{count}} verificação aprovada", + "checksPassed_other": "{{count}} verificações aprovadas", + "checksNeutral": "Verificações neutras: {{count}}", + "threads": "Discussões da revisão", + "commentsUnavailable": "Comentários indisponíveis", + "allThreadsResolved": "Todos os tópicos resolvidos", + "noThreads": "Nenhum tópico de revisão", + "fromBots_one": "{{count}} de um bot", + "fromBots_other": "{{count}} de bots", + "unresolvedThreads_one": "{{count}} tópico não resolvido", + "unresolvedThreads_other": "{{count}} tópicos não resolvidos", + "changesRequested": "Alterações solicitadas", + "requestedChangesBy": "Alterações solicitadas por {{logins}}", + "approvedBy": "Aprovado por {{logins}}", + "reviewRequestedFrom": "Revisão solicitada a {{logins}}", + "reviewRequired": "Revisão necessária", + "noApprovals": "Ainda não há aprovações", + "approvals_one": "{{count}} aprovação", + "approvals_other": "{{count}} aprovações", + "conflictsWithBase": "Conflitos com {{base}}", + "conflicts": "Conflitos de merge", + "conflictFiles_one": "{{count}} arquivo", + "conflictFiles_other": "{{count}} arquivos", + "conflictsChecking": "Verificando conflitos", + "noConflictsWithBase": "Sem conflitos com {{base}}", + "noConflicts": "Sem conflitos", + "threadAuthorOnFile": "{{author}} em {{file}}", + "checksFailing_many": "{{count}} verificações falhando", + "checksRunning_many": "{{count}} verificações em execução", + "checksPassed_many": "{{count}} verificações aprovadas", + "fromBots_many": "{{count}} de bots", + "unresolvedThreads_many": "{{count}} tópicos não resolvidos", + "approvals_many": "{{count}} aprovações", + "conflictFiles_many": "{{count}} arquivos" + }, + "checkStatus": { + "cancelled": "Cancelado" } }, "session": { @@ -1994,7 +2346,10 @@ "switchToPhoneMode": "Mudar para o modo celular", "pasteFromClipboard": "Colar da área de transferência", "paste": "Colar", - "addCustomShortcut": "Adicionar atalho personalizado" + "addCustomShortcut": "Adicionar atalho personalizado", + "control": "Ctrl", + "alt": "Alt", + "shift": "Shift" }, "activeContent": { "createTab": "Criar Aba", @@ -2117,7 +2472,8 @@ }, "commandDock": { "liveInputHint": "O texto digitado é enviado diretamente ao terminal ativo.", - "liveInputLabel": "Entrada em tempo real no terminal" + "liveInputLabel": "Entrada em tempo real no terminal", + "tapToShowKeyboard": "Toque para mostrar o teclado" }, "contentRow": { "dismissCreationWarning": "Dispensar aviso de criação do espaço de trabalho" @@ -2136,17 +2492,30 @@ "committedDiffUnavailable": "Diff de alterações commitadas indisponível", "desktopUpdateRequired": "Atualize o Orca no desktop para revisar alterações no celular.", "diffLoadFailed": "Não foi possível carregar o diff", - "reviewNotesLoadFailed": "Não foi possível carregar as notas de revisão" + "reviewNotesLoadFailed": "Não foi possível carregar as notas de revisão", + "commitLoadFailed": "Não foi possível carregar este commit", + "commitDiffUnavailable": "O diff do commit não está disponível." }, "diffReviewQueue": { "committedOnBranch": "Commitado na branch", "staged": "Preparado", - "unstaged": "Não preparado" + "unstaged": "Não preparado", + "inCommit": "Neste commit" }, "diffReviewScreenModel": { "branch": "Branch", "staged": "Preparado", - "unstaged": "Não preparado" + "unstaged": "Não preparado", + "positionUncommitted": "{{position}} de {{count}} não confirmado", + "positionInCommit": "{{position}} de {{count}} neste commit", + "positionViewed": "{{position}} de {{count}} · {{viewedCount}} visualizados", + "commitFiles_one": "{{count}} arquivo", + "commitFiles_other": "{{count}} arquivos", + "uncommittedFiles_one": "{{count}} não confirmado", + "uncommittedFiles_other": "{{count}} não confirmado", + "viewedOfCount": "{{viewedCount}} de {{count}} visualizados", + "commitFiles_many": "{{count}} arquivos", + "uncommittedFiles_many": "{{count}} não confirmado" }, "failure": { "accountSwitchInProgress": "A configuração de {{agent}} está sendo alterada neste host. Tente novamente quando terminar.", @@ -2275,7 +2644,8 @@ "waitForBackgroundTasks": "Aguarde a conclusão das tarefas em segundo plano.", "waitForStart": "Aguarde o agente terminar de iniciar.", "writeFailed": "O Orca não conseguiu repassar esta mensagem ao agente, por isso ela não foi enviada.", - "pluginInputRequired": "{{agent}} parou porque o plugin \"{{plugin}}\" está aguardando uma entrada em um painel de terminal. Desative o plugin para sessões de chat ou execute a tarefa em um terminal {{agent}}." + "pluginInputRequired": "{{agent}} parou porque o plugin \"{{plugin}}\" está aguardando uma entrada em um painel de terminal. Desative o plugin para sessões de chat ou execute a tarefa em um terminal {{agent}}.", + "unconfirmed": "Não foi possível confirmar se isto foi enviado. Não foi reenviado." }, "fileReader": { "copyReviewNotes": "Copiar notas de revisão", @@ -2286,14 +2656,16 @@ "reviewNotes_one": "{{count}} nota de revisão", "reviewNotes_other": "{{count}} notas de revisão", "send": "Enviar", - "sendReviewNotes": "Enviar notas de revisão à IA" + "sendReviewNotes": "Enviar notas de revisão à IA", + "loading": "Carregando arquivo…" }, "floatingWorkspace": { "title": "Espaço de Trabalho Flutuante" }, "githubPrMutations": { "reviewThreadUpdateFailed": "Falha ao atualizar a thread de revisão.", - "titleUpdateFailed": "Falha ao atualizar o título." + "titleUpdateFailed": "Falha ao atualizar o título.", + "fileViewedFailed": "Falha ao atualizar o estado visualizado." }, "githubPrRpc": { "requestFailed": "Falha na solicitação: {{method}}" @@ -2327,7 +2699,8 @@ "copySource": "Copiar código-fonte Markdown", "discard": "Descartar", "previewTruncated": "Pré-visualização truncada.", - "readOnly": "Somente leitura" + "readOnly": "Somente leitura", + "loading": "Carregando documento…" }, "nativeChatAttachActions": { "availableSkills": "Disponíveis: {{count}}", @@ -2524,7 +2897,8 @@ "tabStrip": { "checkingCapabilities": "Verificando os recursos do desktop — tente novamente em instantes", "newTab": "Nova aba", - "quickCommandsUpdateRequired": "Atualize o desktop para usar comandos rápidos" + "quickCommandsUpdateRequired": "Atualize o desktop para usar comandos rápidos", + "tabStatus": "{{title}}, {{status}}" }, "terminalActionSheetActions": { "clearTerminal": "Limpar Terminal", @@ -2594,7 +2968,8 @@ "useDiffReviewController": { "loadFailed": "Não foi possível carregar a revisão", "missingWorktree": "Worktree ausente", - "waitingForDesktop": "Aguardando o desktop…" + "waitingForDesktop": "Aguardando o desktop…", + "commitMissing": "Atualize o aplicativo Orca para abrir arquivos de commit aqui." }, "useDiffReviewDiffLoading": { "loadFailed": "Não foi possível carregar o diff", @@ -2777,7 +3152,8 @@ "waitForCommand": "Aguarde a conclusão do /compact ou /clear.", "waitForStart": "Aguarde o agente terminar de iniciar.", "waitForTurn": "Aguarde o agente terminar de responder ou interrompa-o.", - "waitMoment": "Aguarde um momento." + "waitMoment": "Aguarde um momento.", + "mailOwnerUnconfirmed": "Orca não conseguiu confirmar se esta mensagem ainda se destina a este chat." }, "workerAutoClose": { "running": "Agente de orquestração temporário · Fecha 2 minutos após terminar", @@ -2823,7 +3199,47 @@ }, "structuredOpen": { "worktreeDeleted": "A worktree foi excluída.", - "folderWorkspaceRemoved": "O espaço de trabalho de pasta foi removido." + "folderWorkspaceRemoved": "O espaço de trabalho de pasta foi removido.", + "goneGeneric": "O chat do agente não está mais neste host, portanto não pode ser reaberto aqui.", + "unknownGeneric": "Não foi possível encontrar o bate-papo do agente neste host. Reconecte-se ao computador e tente novamente.", + "unsupportedGeneric": "O chat do agente não pode ser reaberto até que o Orca seja atualizado.", + "unreachableGeneric": "O chat do agente ainda não está disponível. Tente novamente em alguns instantes.", + "gone": "O bate-papo de {{agent}} não está mais neste host, portanto não pode ser reaberto aqui.", + "unknown": "O bate-papo de {{agent}} não foi encontrado neste host. Reconecte-se ao computador e tente novamente.", + "unsupported": "O bate-papo de {{agent}} não pode ser reaberto até que o Orca seja atualizado.", + "unreachable": "O bate-papo de {{agent}} ainda não está disponível. Tente novamente em alguns instantes.", + "paneUnavailable": "O painel do agente não está mais disponível." + }, + "nativeChatView": { + "loading": "Carregando conversa…" + }, + "contentState": { + "connectingTo": "Conectando-se a {{host}}…", + "connecting": "Conectando…", + "tabsStalled": "As guias estão demorando mais que o esperado" + }, + "presentation": { + "loadingTabs": "Carregando guias", + "oneTab": "1 guia", + "tabCount": "{{tabCount}} guias", + "tapToRetry": "{{status}} — toque para tentar novamente" + }, + "documentReaders": { + "markdownFailed": "Não foi possível carregar o Markdown.", + "diffFailed": "Não foi possível carregar a visualização das diferenças", + "fileFailed": "Não foi possível carregar a visualização do arquivo", + "outsideWorkspace": "Este arquivo está fora do espaço de trabalho. Abra-o no computador para visualizá-lo." + }, + "linkActionSheet": { + "openInOrca": "Abrir no navegador do Orca", + "openInBrowser": "Abrir no navegador do sistema", + "copyLink": "Copiar link" + }, + "useDiffReviewGitHub": { + "waitingForDesktop": "Aguardando o desktop…" + }, + "usePrTextAction": { + "updateFailed": "Falha ao atualizar o pull request." } }, "settings": { @@ -2976,7 +3392,8 @@ "speechModelHeading": "MODELO DE VOZ", "title": "Voz", "toggleMode": "Alternar", - "updateFailed": "Não foi possível atualizar" + "updateFailed": "Não foi possível atualizar", + "loading": "Carregando configurações de voz…" }, "agents": { "permissionOwnAll": "Configurações próprias dos agentes" @@ -3028,7 +3445,8 @@ "switchBranch": "Trocar de branch", "syncCounts": "Faça pull de {{behind}} e push de {{ahead}}.", "upToDate": "Nada para fazer commit. A branch está atualizada.", - "waitForRemoteOperation": "Tente novamente quando a operação remota terminar." + "waitForRemoteOperation": "Tente novamente quando a operação remota terminar.", + "openCommits": "Abrir commits" }, "branchBaseRef": { "resolveFailed": "Não foi possível determinar a branch base" @@ -3149,7 +3567,9 @@ "renamedFrom": "de {{path}}", "stageFile": "Adicionar {{path}} ao stage", "unresolvedConflict": "Conflito não resolvido", - "unstageFile": "Remover {{path}} do stage" + "unstageFile": "Remover {{path}} do stage", + "discard": "Descartar", + "discardFile": "Descartar {{path}}" }, "gitHistory": { "days_many": "{{count}}d", @@ -3177,10 +3597,13 @@ "noCommits": "Nenhum commit.", "noFileChanges": "Nenhuma alteração em arquivos", "retryFiles": "Tentar carregar os arquivos do commit novamente", - "waitingForDesktop": "Aguardando o desktop…" + "waitingForDesktop": "Aguardando o desktop…", + "loading": "Carregando commits…" }, "gitStatus": { - "conflicts": "Conflitos" + "conflicts": "Conflitos", + "uncommitted": "Sem commit", + "staged": "Preparado" }, "header": { "backToSession": "Voltar à sessão", @@ -3239,7 +3662,8 @@ "pushBeforeCreateFailed": "O push falhou. Resolva o erro de push e tente novamente." }, "hubTab": { - "changes": "Alterações" + "changes": "Alterações", + "pullRequest": "Pull request" }, "loaders": { "connectingToDesktop": "Conectando ao desktop…", @@ -3258,7 +3682,8 @@ "switchBranchTitle": "Trocar Branch" }, "panel": { - "unavailableTitle": "Controle de Código-Fonte Indisponível" + "unavailableTitle": "Controle de Código-Fonte Indisponível", + "loading": "Carregando alterações…" }, "prCreate": { "authRequired": "Autentique-se antes de criar um {{reviewLabel}}.", @@ -3289,7 +3714,17 @@ "publishBranch": "Publicar Branch", "pull": "Pull", "push": "Push", - "sync": "Sincronizar" + "sync": "Sincronizar", + "commitFiles_one": "Criar commit com {{count}} arquivo", + "commitFiles_other": "Criar commit com {{count}} arquivos", + "pushCommits_one": "Fazer push de {{count}} commit", + "pushCommits_other": "Fazer push de {{count}} commits", + "pullCommits_one": "Fazer pull de {{count}} commit", + "pullCommits_other": "Fazer pull de {{count}} commits", + "stageAll": "Adicionar tudo ao stage", + "commitFiles_many": "Criar commit com {{count}} arquivos", + "pushCommits_many": "Fazer push de {{count}} commits", + "pullCommits_many": "Fazer pull de {{count}} commits" }, "remoteDropdown": { "branchAlreadyPublished": "A branch já está publicada", @@ -3447,25 +3882,100 @@ "markResolved": "Marcar como resolvido", "keepFile": "Manter arquivo", "keepDeletion": "Manter exclusão", - "completeMergeFailed": "Não foi possível concluir a mesclagem" + "completeMergeFailed": "Não foi possível concluir a mesclagem", + "resolveFile": "{{action}}: {{path}}" + }, + "useMobileCreatePrRunner": { + "branchRequired": "Faça checkout de uma branch antes de criar um pull request." + }, + "commitDetail": { + "copySha": "Copiar SHA", + "openOnGitHub": "Abrir no GitHub", + "openOnWeb": "Abrir na web", + "back": "Voltar para commits", + "title": "Commit", + "more": "Mais ações de commit", + "author": "Autor", + "date": "Data", + "status": "Status", + "onOrigin": "Na origem", + "notPushed": "Não enviado", + "files_one": "{{count}} arquivo", + "files_other": "{{count}} arquivos", + "filesHeader": "Arquivos", + "authorWithCoAuthors": "{{author}}, com {{coAuthors}}", + "files_many": "{{count}} arquivos" + }, + "commits": { + "branchedFrom": "Ramificado de {{baseRef}}", + "baseUpToDate": "Atualizada", + "baseNewer_one": "1 commit mais recente", + "baseNewer_other": "{{count}} commits mais recentes", + "updateBranch": "Atualizar branch", + "back": "Voltar ao controle de versão", + "title": "Commits", + "loadMoreFailed": "Não foi possível carregar mais commits. Tentar novamente", + "notPushed": "Commits não enviados: {{count}}", + "onOrigin": "Na origem {{count}}", + "baseNewer_many": "{{count}} commits mais recentes" + }, + "nextStep": { + "willMergeWhenReady": "Irá mesclar quando estiver pronto", + "cancelAutoMerge": "Cancelar", + "cancelAutoMergeLabel": "Cancelar mesclagem automática", + "mergedInto": "Mesclado em {{base}}", + "merged": "Mesclado", + "genericAgent": "AI", + "cantMergeYet": "Ainda não é possível mesclar:", + "checksFailing_one": "{{count}} verificação falhando", + "checksFailing_other": "{{count}} verificações falhando", + "mergeWhenReady": "Mesclar quando estiver pronto", + "merge": "Mesclar", + "checksRunning_one": "{{count}} verificação ainda em execução", + "checksRunning_other": "{{count}} verificações ainda em execução", + "waitingOnReviewer": "Aguardando revisão de {{login}}", + "waitingOnReview": "Aguardando revisão", + "resolveWithAgent": "Resolva com {{agent}}", + "fixWithAgent": "Corrigir com {{agent}}", + "pushAndCreateReview": "Envie e crie {{review}}", + "createReview": "Criar {{review}}", + "checksFailing_many": "{{count}} verificações falhando", + "checksRunning_many": "{{count}} verificações ainda em execução" + }, + "prCreateDraft": { + "generateFailed": "Falha ao escrever uma descrição" + }, + "changesHeader": { + "merging": "Fazendo merge", + "rebasing": "Fazendo rebase", + "cherryPicking": "Aplicando cherry-pick", + "notPublished": "Não publicado", + "notPushed": "{{count}} não enviado", + "behind": "{{count}} atrás", + "upToDate": "Atualizada", + "switchBranch": "Mudar branch de {{branch}}", + "mergeInProgress": "Merge em andamento", + "rebaseInProgress": "Rebase em andamento", + "cherryPickInProgress": "Cherry-pick em andamento", + "filesNeedDecision_one": "{{count}} arquivo precisa de uma decisão antes de você concluir.", + "filesNeedDecision_other": "{{count}} arquivos precisam de uma decisão antes de você terminar.", + "conflictsResolved": "Todos os conflitos foram resolvidos. Conclua na barra abaixo.", + "continueOnComputer": "Todo conflito é resolvido. Continue no seu computador para terminar.", + "commits_one": "{{count}} commit", + "commits_other": "{{count}} commits", + "conflictsMayRemain": "Nem todos os arquivos estão listados, portanto, os conflitos podem permanecer. Verifique no seu computador.", + "filesNeedDecision_many": "{{count}} arquivos precisam de uma decisão antes de você terminar.", + "commits_many": "{{count}} commits" + }, + "fileList": { + "stageAll": "Adicionar tudo ao stage", + "mergedCleanly": "Mesclado de forma limpa", + "unstageAll": "Remover tudo do stage", + "onThisBranch": "Nesta branch: {{count}}", + "versusBase": "versus {{base}}" } }, "tasks": { - "hostedMerge": { - "merged": "Mesclado", - "closed": "Fechado", - "conflicts": "Conflitos", - "behind": "Desatualizado", - "blocked": "Bloqueado", - "checksPending": "Verificações pendentes", - "ableToMerge": "Pode ser mesclado", - "unknown": "Desconhecido" - }, - "pagination": { - "pageUnreachable": "A página {{page}} está além do que a pesquisa do GitHub pode retornar.", - "loadPageFailed": "A página {{page}} não pôde ser carregada do GitHub.", - "noMoreResults": "Não há mais resultados na página {{page}}." - }, "composerSource": { "baseFailed": "Falha ao determinar a branch base.", "forkPushWarning": "Este PR está com \"Permitir edições de mantenedores\" desativado; o GitHub pode rejeitar o push para o fork." @@ -3505,7 +4015,8 @@ "teamsTitle": "Equipes do Linear", "teams_many": "{{count}} equipes", "teams_one": "{{count}} equipe", - "teams_other": "{{count}} equipes" + "teams_other": "{{count}} equipes", + "statesFailed": "Não foi possível carregar os estados. Reabra para tentar novamente." }, "githubProjectList": { "browseProjects": "Navegar pelos projetos", @@ -3519,7 +4030,9 @@ "moreFields_other": "+{{count}} campos", "noItems": "Nenhum item no projeto", "pullRequestSubtitle": "Pull request · {{repository}}{{number}}", - "linkedPullRequestsOverflow": "+{{count}} mais" + "linkedPullRequestsOverflow": "+{{count}} mais", + "loading": "Carregando projeto…", + "noMatches": "Nenhum item do projeto corresponde." }, "githubProjectPickers": { "add": "Adicionar", @@ -3556,7 +4069,10 @@ "creating": "Criando…", "mergeConflicts": "O GitHub informa conflitos de merge.", "mergeMergeRequest": "Fazer merge do merge request", - "mergePullRequest": "Fazer merge do pull request" + "mergePullRequest": "Fazer merge do pull request", + "copyLink": "Copiar link", + "startWorkspace": "Iniciar espaço de trabalho", + "moreActions": "Mais ações" }, "itemDetailContent": { "addSubIssue": "Adicionar sub-issue", @@ -3574,7 +4090,15 @@ "pipelineJobs_other": "{{count}} jobs", "rerunAll": "Reexecutar todas", "subIssueTitle": "Título da sub-issue", - "subIssues": "Sub-issues" + "subIssues": "Sub-issues", + "details": "Detalhes", + "type": "Tipo", + "status": "Status", + "assignee": "Responsável", + "project": "Projeto", + "priority": "Prioridade", + "assignees": "Responsáveis", + "loading": "Carregando detalhes…" }, "itemDetailDrawer": { "refreshDetails": "Atualizar detalhes" @@ -3811,7 +4335,11 @@ }, "providerControls": { "myTodos": "Minhas pendências", - "projectMergeRequests": "MRs do projeto" + "projectMergeRequests": "MRs do projeto", + "reposLabel": "Repositórios: {{repos}}", + "filter": "Filtro", + "filterLabel": "Filtrar e exibir", + "filterCount": "Filtro · {{count}}" }, "providerItemList": { "intoBranch": "para {{base}}", @@ -3820,7 +4348,8 @@ "pageOfTotal": "Página {{page}} de {{total}}", "previousPage": "Página anterior", "selectPage": "Selecionar página, página {{page}}", - "selectPageOfTotal": "Selecionar página, página {{page}} de {{total}}" + "selectPageOfTotal": "Selecionar página, página {{page}} de {{total}}", + "kindAndStatus": "{{kind}}, {{status}}" }, "providerPickers": { "allRepositories": "Todos os repositórios", @@ -3940,7 +4469,8 @@ "selectRepository": "Selecione um repositório", "startFrom": "Iniciar a partir de", "title": "Criar Espaço de Trabalho", - "workspaceName": "Nome do Espaço de Trabalho" + "workspaceName": "Nome do Espaço de Trabalho", + "optionalLabel": "Opcional" }, "workspaceCreateProjection": { "nameAlreadyExists": "\"{{name}}\" já existe.", @@ -3998,7 +4528,69 @@ }, "worktreeCreateRetry": { "createFailed": "Falha ao criar espaço de trabalho" - } + }, + "hostedMerge": { + "confirmGitHubMerge": "Mesclar PR #{{number}}?", + "confirmGitHubSquash": "Fazer squash e mesclar o PR #{{number}}?", + "confirmGitHubRebase": "Fazer rebase e mesclar PR #{{number}}?", + "confirmGitLabMerge": "Mesclar o merge request #{{number}}?", + "confirmGitLabSquash": "Fazer squash e mesclar o merge request #{{number}}?", + "confirmGitLabRebase": "Fazer rebase e mesclar o merge request #{{number}}?", + "merged": "Mesclado", + "closed": "Fechado", + "conflicts": "Conflitos", + "behind": "Desatualizado", + "blocked": "Bloqueado", + "checksPending": "Verificações pendentes", + "ableToMerge": "Pode ser mesclado", + "unknown": "Desconhecido" + }, + "pagination": { + "pageUnreachable": "A página {{page}} está além do que a pesquisa do GitHub pode retornar.", + "loadPageFailed": "A página {{page}} não pôde ser carregada do GitHub.", + "noMoreResults": "Não há mais resultados na página {{page}}." + }, + "filterSheet": { + "sortBy": "Ordenar por", + "issueSource": "Origem da issue", + "issueSourceRow": "Upstream ou origem", + "view": "Exibir", + "projectView": "Visualização do projeto", + "chooseView": "Escolher", + "showOnRows": "Mostrar em linhas", + "projectFields": "Campos do projeto", + "workspace": "Espaço de Trabalho", + "linearWorkspace": "Espaço de trabalho do Linear", + "layout": "Disposição", + "groupBy": "Agrupar por", + "orderBy": "Ordenar por", + "displayProperties": "Propriedades de exibição", + "title": "Filtrar e exibir", + "done": "Concluído", + "jqlReplacesPreset": "Sua pesquisa JQL substitui a predefinição Mostrar. Limpe a pesquisa para escolher uma novamente.", + "projectItems_one": "{{count}} item", + "projectItems_other": "{{count}} itens", + "projectItems_many": "{{count}} itens" + }, + "jiraViewControls": { + "jqlSearch": "Pesquisa JQL" + }, + "itemComments": { + "noComments": "Ainda não há comentários", + "oneComment": "1 comentário", + "commentCount": "{{commentCount}} comentários" + }, + "listState": { + "loading": "Carregando tarefas…" + }, + "connectionPresentation": { + "connectToHost": "Conecte-se a um host para carregar tarefas", + "noMatchingTasks": "Nenhuma tarefa correspondente" + }, + "runtimeHydration": { + "loadFailed": "Falha ao carregar as configurações de Tarefas" + }, + "rerunUnsuccessful": "Repetir verificações" }, "terminal": { "keyDefinitions": { @@ -4097,7 +4689,9 @@ "noFilterMatches": "Nenhum espaço de trabalho corresponde aos filtros", "noMatches": "Nenhum espaço de trabalho encontrado", "reopen": "Reabrir para atualizar", - "reopenDetail": "Este host lista os espaços de trabalho em um formato que esta página ainda não reconhece." + "reopenDetail": "Este host lista os espaços de trabalho em um formato que esta página ainda não reconhece.", + "loading": "Carregando espaços…", + "retryingAutomatically": "Tentando novamente automaticamente." }, "workspaceListSections": { "all": "Todos", @@ -4115,6 +4709,9 @@ "right": "Direcional para a direita", "down": "Direcional para baixo", "hint": "Envia uma tecla de direção. Mantenha pressionado para repetir." + }, + "terminalKeyRail": { + "ctrlC": "Ctrl+C" } }, "automations": { @@ -4266,7 +4863,8 @@ "discardChangesTitle": "Descartar alterações?", "discardChangesMessage": "As edições não salvas nesta automação serão perdidas.", "discard": "Descartar", - "keepEditing": "Continuar editando" + "keepEditing": "Continuar editando", + "chooseHost": "Automações em {{host}}, escolha outro host" }, "orphanIssues": { "hostReselection": "Edite esta automação e selecione novamente seu host antes de executá-la.", @@ -4309,7 +4907,8 @@ "error": "A configuração do projeto falhou no host selecionado para a automação.", "unsupported": "O host selecionado para a automação não oferece suporte a este projeto." }, - "wslDistroStopped": "A distribuição WSL {{distro}} está parada, então esta execução agendada não a iniciou. Inicie a distribuição ou use Executar agora; as próximas execuções acontecem enquanto ela estiver em execução." + "wslDistroStopped": "A distribuição WSL {{distro}} está parada, então esta execução agendada não a iniciou. Inicie a distribuição ou use Executar agora; as próximas execuções acontecem enquanto ela estiver em execução.", + "agentInterrupted": "O agente foi interrompido antes de terminar esta execução." } }, "auto": { diff --git a/mobile/src/i18n/locales/ru.json b/mobile/src/i18n/locales/ru.json index cec7d8ced57..d76fa238c1a 100644 --- a/mobile/src/i18n/locales/ru.json +++ b/mobile/src/i18n/locales/ru.json @@ -2594,7 +2594,8 @@ "tabStrip": { "checkingCapabilities": "Проверяем возможности Orca на компьютере — повторите попытку чуть позже", "newTab": "Новая вкладка", - "quickCommandsUpdateRequired": "Для быстрых команд обновите Orca на компьютере" + "quickCommandsUpdateRequired": "Для быстрых команд обновите Orca на компьютере", + "tabStatus": "{{title}}, {{status}}" }, "terminalActionSheetActions": { "clearTerminal": "Очистить терминал", @@ -3540,6 +3541,12 @@ }, "tasks": { "hostedMerge": { + "confirmGitHubMerge": "Слить PR #{{number}}?", + "confirmGitHubSquash": "Объединить коммиты и слить PR #{{number}}?", + "confirmGitHubRebase": "Выполнить rebase и слить PR #{{number}}?", + "confirmGitLabMerge": "Слить запрос на слияние #{{number}}?", + "confirmGitLabSquash": "Объединить коммиты и слить запрос на слияние #{{number}}?", + "confirmGitLabRebase": "Выполнить rebase и слить запрос на слияние #{{number}}?", "merged": "Слито", "closed": "Закрыто", "conflicts": "Конфликты", diff --git a/mobile/src/i18n/locales/tr.json b/mobile/src/i18n/locales/tr.json index 81be23db055..b66fe29a454 100644 --- a/mobile/src/i18n/locales/tr.json +++ b/mobile/src/i18n/locales/tr.json @@ -2454,7 +2454,8 @@ "tabStrip": { "checkingCapabilities": "Masaüstü özellikleri kontrol ediliyor — birazdan tekrar deneyin", "newTab": "Yeni sekme", - "quickCommandsUpdateRequired": "Hızlı komutlar için masaüstü uygulaması güncellenmeli" + "quickCommandsUpdateRequired": "Hızlı komutlar için masaüstü uygulaması güncellenmeli", + "tabStatus": "{{title}}, {{status}}" }, "terminalActionSheetActions": { "clearTerminal": "Terminali Temizle", @@ -3364,6 +3365,12 @@ }, "tasks": { "hostedMerge": { + "confirmGitHubMerge": "PR #{{number}} birleştirilsin mi?", + "confirmGitHubSquash": "PR #{{number}} commit’leri squash edilerek birleştirilsin mi?", + "confirmGitHubRebase": "PR #{{number}} yeniden temellendirilip birleştirilsin mi?", + "confirmGitLabMerge": "Birleştirme isteği #{{number}} birleştirilsin mi?", + "confirmGitLabSquash": "Birleştirme isteği #{{number}} commit’leri squash edilerek birleştirilsin mi?", + "confirmGitLabRebase": "Birleştirme isteği #{{number}} yeniden temellendirilip birleştirilsin mi?", "merged": "Birleştirildi", "closed": "Kapatıldı", "conflicts": "Çakışmalar", diff --git a/mobile/src/i18n/locales/zh-Hant.json b/mobile/src/i18n/locales/zh-Hant.json index 535fb5d378a..f6cdeed4645 100644 --- a/mobile/src/i18n/locales/zh-Hant.json +++ b/mobile/src/i18n/locales/zh-Hant.json @@ -2450,7 +2450,8 @@ "tabStrip": { "checkingCapabilities": "正在檢查桌面版支援的功能,請稍後再試", "newTab": "新分頁", - "quickCommandsUpdateRequired": "需更新桌面版才能使用快速命令" + "quickCommandsUpdateRequired": "需更新桌面版才能使用快速命令", + "tabStatus": "{{title}},{{status}}" }, "terminalActionSheetActions": { "clearTerminal": "清除終端機", @@ -3360,6 +3361,12 @@ }, "tasks": { "hostedMerge": { + "confirmGitHubMerge": "要合併 PR #{{number}} 嗎?", + "confirmGitHubSquash": "要將 PR #{{number}} 的提交壓縮後合併嗎?", + "confirmGitHubRebase": "要將 PR #{{number}} 變基後合併嗎?", + "confirmGitLabMerge": "要合併合併請求 #{{number}} 嗎?", + "confirmGitLabSquash": "要將合併請求 #{{number}} 的提交壓縮後合併嗎?", + "confirmGitLabRebase": "要將合併請求 #{{number}} 變基後合併嗎?", "merged": "已合併", "closed": "已關閉", "conflicts": "有衝突", diff --git a/mobile/src/i18n/locales/zh.json b/mobile/src/i18n/locales/zh.json index f845b0e146d..97e4440ed9d 100644 --- a/mobile/src/i18n/locales/zh.json +++ b/mobile/src/i18n/locales/zh.json @@ -9,7 +9,7 @@ "hostNotFound": "未找到主机", "invalidSnapshot": "主机返回的账户快照无效", "loadingAccounts": "正在加载账户…", - "manageAccountsHint": "请在桌面的“设置 → 账户”中添加账户或重新进行账户身份验证。", + "manageAccountsHint": "请在桌面的“设置 → 账户”中添加账户或重新进行账户身份验证", "mcpWindow": "MCP", "otherAgents": "其他智能体", "refreshAccounts": "刷新账户", @@ -23,28 +23,28 @@ "agentHistory": { "panel": { "all": "全部", - "emptyScope": "此范围内暂无历史智能体会话。", - "missingResumeId": "此会话缺少恢复 ID。", - "noSearchResults": "没有符合搜索条件的会话。", + "emptyScope": "此范围内暂无历史智能体会话", + "missingResumeId": "此会话缺少恢复 ID", + "noSearchResults": "没有符合搜索条件的会话", "noSessions": "暂无智能体会话", "placeholder": "搜索会话,repo:、path:", "project": "项目", "refreshSessions": "刷新智能体会话", - "resumeFailed": "恢复会话失败。", - "sessionQueued": "智能体会话已加入队列。", + "resumeFailed": "恢复会话失败", + "sessionQueued": "智能体会话已加入队列", "skipped_one": "跳过了 {{count}} 个记录", "skipped_other": "跳过了 {{count}} 个记录", "title": "智能体会话历史", "unavailable": "智能体会话历史不可用", - "unknownHostPlatform": "无法确定主机平台。", - "updateHost": "请更新此主机上的 Orca,以浏览智能体会话历史。", + "unknownHostPlatform": "无法确定主机平台", + "updateHost": "请更新此主机上的 Orca,以浏览智能体会话历史", "waitingForHost": "正在等待主机…", "workspace": "工作区" }, "resumeTarget": { - "differentHost": "此会话属于其他主机。请打开同一主机上的工作区以恢复它。", - "openWorkspace": "恢复会话前请先打开一个工作区。", - "runtimeUnavailable": "由运行时托管的工作区不支持从历史记录恢复会话。" + "differentHost": "此会话属于其他主机。请打开同一主机上的工作区以恢复它", + "openWorkspace": "恢复会话前请先打开一个工作区", + "runtimeUnavailable": "由运行时托管的工作区不支持从历史记录恢复会话" }, "sessionCard": { "untitledSession": "无标题会话" @@ -67,13 +67,13 @@ }, "app": { "mobileOnboarding": { - "notificationSettingsFailed": "无法更新通知设置。请重试。", + "notificationSettingsFailed": "无法更新通知设置。请重试", "progress": "入门引导进度", - "saveChoiceFailed": "无法保存选择。请重试。", + "saveChoiceFailed": "无法保存选择。请重试", "stepProgress": "第 {{step}} 步,共 {{total}} 步" }, "notifications": { - "description": "即使应用已关闭,也能收到智能体提醒。提醒通过 Orca 的推送服务及 Apple 或 Google 送达。" + "description": "即使应用已关闭,也能收到智能体提醒。提醒通过 Orca 的推送服务及 Apple 或 Google 送达" }, "pair": { "backToHome": "返回首页", @@ -83,27 +83,27 @@ "backToHome": "返回首页", "connectTimedOut": "未能在 {{seconds}} 秒内连接,请查看下方日志,了解连接停在哪一步", "connecting": "正在连接…", - "description": "已打开来自桌面的配对链接。确认后将此桌面添加到主机列表。", + "description": "已打开来自桌面的配对链接。确认后将此桌面添加到主机列表", "pairButton": "配对", "pairingFailed": "配对失败:{{error}}", "pairingLog": "配对日志", "title": "要与此桌面配对吗?" }, "pairScan": { - "cameraDisabledDescription": "请在“设置”中启用相机访问权限,或粘贴配对码。", + "cameraDisabledDescription": "请在“设置”中启用相机访问权限,或粘贴配对码", "cameraDisabledTitle": "相机访问已禁用", - "cameraPermissionDescription": "扫描桌面上 Orca 显示的二维码,或粘贴配对码。", + "cameraPermissionDescription": "扫描桌面上 Orca 显示的二维码,或粘贴配对码", "connectTimedOut": "未能在 {{seconds}} 秒内连接,请查看下方日志,了解连接停在哪一步", "connecting": "正在连接…", "invalidPairingCode": "配对码无效,请从电脑上复制后重新粘贴", "invalidQrCode": "无效的 Orca 二维码", - "downloadQrCode": "这是下载码。请扫描桌面端第 2 步中的配对码。", + "downloadQrCode": "这是下载码。请扫描桌面端第 2 步中的配对码", "openDesktopStep": "在电脑上打开 Orca", "openMobileSettingsStep": "前往“设置” → “移动端”", "openSettings": "打开设置", "pairingFailed": "配对失败:{{error}}", "pairingLog": "配对日志", - "pasteCodeMessage": "复制电脑上二维码下方显示的配对码。", + "pasteCodeMessage": "复制电脑上二维码下方显示的配对码", "pasteCodePlaceholder": "orca://pair?code=... 或粘贴配对码", "pasteCodeTitle": "粘贴配对码", "pasteInstead": "改为粘贴配对码", @@ -119,9 +119,9 @@ "largeText": "大(125%)", "largerText": "更大(150%)", "largestText": "最大(200%)", - "leaveAppDescription": "在手机上使用终端时,Orca 会缩小终端尺寸以适应屏幕。关闭应用或切换到其他应用时,此设置决定终端是保持手机尺寸(避免交互式 CLI 工具的界面重新排版),还是恢复为桌面尺寸。您随时可以点击桌面横幅中的“恢复”手动调整尺寸。", + "leaveAppDescription": "在手机上使用终端时,Orca 会缩小终端尺寸以适应屏幕。关闭应用或切换到其他应用时,此设置决定终端是保持手机尺寸(避免交互式 CLI 工具的界面重新排版),还是恢复为桌面尺寸。您随时可以点击桌面横幅中的“恢复”手动调整尺寸", "leaveAppHeading": "离开应用时", - "noPairedDesktops": "尚未配对桌面。配对后即可设置终端行为。", + "noPairedDesktops": "尚未配对桌面。配对后即可设置终端行为", "restoreAfterMinutes_one": "{{count}} 分钟后", "restoreAfterMinutes_other": "{{count}} 分钟后", "restoreAfterSeconds_one": "{{count}} 秒后", @@ -130,7 +130,7 @@ "smallerText": "较小(75%)", "smallestText": "最小(50%)", "textSize": "文字大小", - "textSizeDescription": "调整终端文字大小。文字较小时可显示更多列,两侧留有边距;文字较大时显示的列数较少,可横向拖动查看。也可以直接在终端中双指缩放,此设置会随之更新。仅影响当前设备的显示,不会改变桌面终端。", + "textSizeDescription": "调整终端文字大小。文字较小时可显示更多列,两侧留有边距;文字较大时显示的列数较少,可横向拖动查看。也可以直接在终端中双指缩放,此设置会随之更新。仅影响当前设备的显示,不会改变桌面终端", "textSizeHeading": "文字大小", "textSizePickerTitle": "终端文字大小", "title": "终端" @@ -141,7 +141,7 @@ "urlPlaceholder": "URL" }, "pane": { - "invalidUrl": "请输入有效的 URL。" + "invalidUrl": "请输入有效的 URL" }, "paneView": { "dialogTitle": "浏览器对话框", @@ -155,7 +155,7 @@ }, "useBrowserCommands": { "deliveryUnconfirmed": "尚未确认是否送达,请先检查页面再重试", - "dialogAnswerFailed": "未能将回答发送到网页。", + "dialogAnswerFailed": "未能将回答发送到网页", "sent": "已发送" }, "viewModeSwitch": { @@ -214,10 +214,10 @@ "diffTruncated": "差异被截断" }, "hostStatus": { - "continuedOutside": "已在此聊天之外继续。", - "continuedOutsideRewound": "已在此聊天之外继续。上方较早的回复已不在此对话的历史记录中。", - "historyItemTooLarge": "聊天的这一部分过大,无法显示。", - "historyRepaired": "此聊天的部分历史记录无法加载。" + "continuedOutside": "已在此聊天之外继续", + "continuedOutsideRewound": "已在此聊天之外继续。上方较早的回复已不在此对话的历史记录中", + "historyItemTooLarge": "聊天的这一部分过大,无法显示", + "historyRepaired": "此聊天的部分历史记录无法加载" }, "message": { "copyMessage": "复制消息", @@ -225,7 +225,7 @@ "forkFromResponseHint": "新聊天将包含本轮结束前的完整回复" }, "messageActionsSheet": { - "clipboardRejected": "剪贴板拒绝接收该文本。", + "clipboardRejected": "剪贴板拒绝接收该文本", "copyFailed": "复制失败", "copyMessage": "复制消息", "selectText": "选择文本", @@ -314,12 +314,12 @@ "at": "提交" }, "orcaStop": { - "canContinue": "您可以在此对话中继续。", - "crash": "此回复进行期间,{{machine}} 上的 Orca 意外停止。", - "quit": "此回复进行期间,{{machine}} 上的 Orca 已关闭。", - "remote": "此回复进行期间,{{machine}} 上的 Orca 已停止。", + "canContinue": "您可以在此对话中继续", + "crash": "此回复进行期间,{{machine}} 上的 Orca 意外停止", + "quit": "此回复进行期间,{{machine}} 上的 Orca 已关闭", + "remote": "此回复进行期间,{{machine}} 上的 Orca 已停止", "unnamedServer": "远程服务器", - "update": "此回复进行期间,{{machine}} 上的 Orca 为更新而重新启动。" + "update": "此回复进行期间,{{machine}} 上的 Orca 为更新而重新启动" }, "interruptedContinue": { "failed": "无法继续此聊天。请重试,或发送一条消息。", @@ -330,13 +330,13 @@ }, "permission": { "needsAccessTo": "需要访问: ", - "newerVersionRequired": "此请求需要更新版本的 Orca。", + "newerVersionRequired": "此请求需要更新版本的 Orca", "planFile": "计划文件:{{filePath}}", "reason": "原因: " }, "promptCard": { "answerInTerminal": "在终端中回答", - "terminalExplanation": "在终端中回答这个 OMP 问题。" + "terminalExplanation": "在终端中回答这个 OMP 问题" }, "promptStrip": { "expand": "展开" @@ -378,7 +378,7 @@ "otherDevice": "其他设备" }, "sessionOptionCopy": { - "availableAfterSessionStarts": "会话开始后可用。", + "availableAfterSessionStarts": "会话开始后可用", "chooseInAgentPicker": "在智能体选择器中选择…", "effort": "推理强度", "fast": "快速", @@ -396,7 +396,7 @@ "on": "开启", "permissions": "权限", "sessionOptions": "会话选项", - "setWhenSessionStarts": "请在会话开始时设置。", + "setWhenSessionStarts": "请在会话开始时设置", "speed": "速度", "standard": "标准", "thinking": "思考", @@ -413,8 +413,8 @@ "modelLabel": "模型,{{value}}", "permissions": "权限", "permissionsLabel": "权限,{{value}}", - "settingsLocked": "本轮结束后将解锁模型设置。", - "workingAnnouncement": "智能体正在工作。本轮结束后将解锁模型设置。" + "settingsLocked": "本轮结束后将解锁模型设置", + "workingAnnouncement": "智能体正在工作。本轮结束后将解锁模型设置" }, "sessionOptionRows": { "defaultMarker": "默认", @@ -554,8 +554,8 @@ "workingFor": "已工作 {{value0}}" }, "usageLimit": { - "reached": "{{agent}} 已达到使用上限。", - "reachedNamed": "{{agent}} 已达到{{window}}上限。", + "reached": "{{agent}} 已达到使用上限", + "reachedNamed": "{{agent}} 已达到{{window}}上限", "theAgent": "智能体", "windowCredits": "额外用量", "windowSession": "会话", @@ -677,7 +677,7 @@ "copyFailed": "无法复制", "copyPrompt": "复制提示", "statusUnreadable": "无法读取此主机的状态。正在重试…", - "updateRequired": "请先更新电脑上的 Orca,才能从手机启动智能体。" + "updateRequired": "请先更新电脑上的 Orca,才能从手机启动智能体" }, "agentSpinner": { "monitoring": "监控后台任务", @@ -688,11 +688,11 @@ "unverifiable": "暂无近期更新" }, "authFailedBanner": { - "message": "身份验证失败。请先尝试重新连接;若仍失败,请在桌面端重新配对。" + "message": "身份验证失败。请先尝试重新连接;若仍失败,请在桌面端重新配对" }, "authFailedBannerActions": { "repair": "重新配对", - "webNote": "请在 Orca 应用中重新连接或移除此主机。" + "webNote": "请在 Orca 应用中重新连接或移除此主机" }, "codexResetCredit": { "alreadyAppliedTitle": "已执行重置", @@ -711,11 +711,11 @@ "expiryNowMultiple": "下一个现在过期", "expiryNowSingle": "现在过期", "invalidResponse": "主机返回的重置响应无效", - "noResetMessage": "此账户没有已获得的可用重置额度。", + "noResetMessage": "此账户没有已获得的可用重置额度", "noResetTitle": "无可用重置次数", - "nothingToResetMessage": "符合重置条件的 Codex 用量窗口均未耗尽额度。", + "nothingToResetMessage": "符合重置条件的 Codex 用量窗口均未耗尽额度", "nothingToResetTitle": "无需重置", - "refresh": "Codex 用量已刷新。", + "refresh": "Codex 用量已刷新", "resetTitle": "速率限制已重置" }, "codexResetCreditAction": { @@ -750,7 +750,7 @@ "textMacroHint": "发送自定义文本命令" }, "dictationSetupSheet": { - "description": "在此即可下载或选择模型,并在已配对的电脑上启用听写。", + "description": "在此即可下载或选择模型,并在已配对的电脑上启用听写", "download": "下载", "downloadFailed": "下载失败", "downloadModel": "下载 {{model}}", @@ -769,19 +769,19 @@ }, "diffReviewBody": { "binaryDiff": "二进制差异", - "binaryMessage": "无法在移动端将此文件显示为文本。", + "binaryMessage": "无法在移动端将此文件显示为文本", "deletedFile": "文件已删除", - "deletedMessage": "此文件已删除。可添加文件备注或将其标记为已评审。", + "deletedMessage": "此文件已删除。可添加文件备注或将其标记为已评审", "diffTooLarge": "差异过大", - "diffTruncated": "差异已截断,以便在移动端预览。", + "diffTruncated": "差异已截断,以便在移动端预览", "diffUnavailable": "差异不可用", "loadFailed": "无法加载评审", "loadingDiff": "加载差异…", "loadingReview": "正在加载评审…", "noReviewableChanges": "没有可评审的更改", "reviewUnavailable": "评审不可用", - "selectFile": "请选择要评审的文件。", - "tooLargeMessage": "此差异过大,无法在移动端预览。" + "selectFile": "请选择要评审的文件", + "tooLargeMessage": "此差异过大,无法在移动端预览" }, "diffReviewDrawers": { "addNote": "添加备注", @@ -790,7 +790,7 @@ "copyNotes": "复制备注", "deleteNote": "删除注释", "discard": "放弃", - "discardMessage": "要放弃对“{{filePath}}”的更改吗?此操作无法撤销。", + "discardMessage": "要放弃对“{{filePath}}”的更改吗?此操作无法撤销", "discardTitle": "放弃文件更改", "editNote": "编辑备注", "fileNote": "文件备注", @@ -869,7 +869,7 @@ }, "jiraConnectPrompt": { "checkAgain": "再次检查", - "connectHint": "请在 Orca 桌面端的“设置 → 集成”中添加 Jira 站点,然后再次检查。", + "connectHint": "请在 Orca 桌面端的“设置 → 集成”中添加 Jira 站点,然后再次检查", "connectOnDesktop": "在桌面端连接 Jira", "credentialUnreadable": "Jira 凭据已保存,但无法读取:{{credentialError}}", "updateDesktop": "更新 Orca 桌面端" @@ -901,7 +901,7 @@ "connect": "连接", "connecting": "连接中…", "label": "SSH 连接", - "serverRecovery": "需要在桌面端恢复其服务器:设置 → SSH 主机 → 恢复服务器。" + "serverRecovery": "需要在桌面端恢复其服务器:设置 → SSH 主机 → 恢复服务器" }, "newWorktreeAgentSelection": { "blankTerminal": "空白终端" @@ -932,25 +932,25 @@ }, "prSidebar": { "loading": "正在加载 PR…", - "notPermitted": "无权访问:您的 GitHub 账户尚未连接。", + "notPermitted": "无权访问:您的 GitHub 账户尚未连接", "retryLoading": "重试加载 PR" }, "protocolBlockScreen": { "backToHosts": "返回主机列表", - "desktopTooOldBody": "已配对的桌面应用版本过旧,无法与当前的 Orca Mobile 兼容。请更新电脑上的 Orca,然后重新连接此主机。", + "desktopTooOldBody": "已配对的桌面应用版本过旧,无法与当前的 Orca Mobile 兼容。请更新电脑上的 Orca,然后重新连接此主机", "getVersion": "获取 Orca {{version}}", - "mobileTooOldAppStore": "此桌面需要更新版本的 Orca Mobile。请从 App Store 更新 Orca Mobile,然后重新连接此主机。", - "mobileTooOldGitHubReleases": "此桌面需要更新版本的 Orca Mobile。请从 GitHub Releases 更新 Orca Mobile,然后重新连接此主机。", + "mobileTooOldAppStore": "此桌面需要更新版本的 Orca Mobile。请从 App Store 更新 Orca Mobile,然后重新连接此主机", + "mobileTooOldGitHubReleases": "此桌面需要更新版本的 Orca Mobile。请从 GitHub Releases 更新 Orca Mobile,然后重新连接此主机", "openAppStore": "打开 App Store", "openGitHubReleases": "打开 GitHub Releases", - "refreshRecoveryNote": "如果仍显示此消息,请移除此主机并重新配对。", - "refreshWorkspaceBody": "此主机的工作区缓存版本低于桌面要求。请重新连接此主机,下载当前版本。", + "refreshRecoveryNote": "如果仍显示此消息,请移除此主机并重新配对", + "refreshWorkspaceBody": "此主机的工作区缓存版本低于桌面要求。请重新连接此主机,下载当前版本", "refreshWorkspaceTitle": "刷新移动端工作区", "updateDesktopTitle": "更新电脑上的 Orca", "updateMobileTitle": "更新 Orca Mobile", - "updateRecoveryNote": "已经更新?请返回“主机”并刷新连接。如果仍显示此消息,请移除此主机并重新配对。", - "workspaceNeedsUpdateAppStore": "此桌面的移动端工作区需要更新版本的 Orca Mobile。请从 App Store 更新 Orca Mobile,然后重新连接此主机。", - "workspaceNeedsUpdateGitHubReleases": "此桌面的移动端工作区需要更新版本的 Orca Mobile。请从 GitHub Releases 更新 Orca Mobile,然后重新连接此主机。" + "updateRecoveryNote": "已经更新?请返回“主机”并刷新连接。如果仍显示此消息,请移除此主机并重新配对", + "workspaceNeedsUpdateAppStore": "此桌面的移动端工作区需要更新版本的 Orca Mobile。请从 App Store 更新 Orca Mobile,然后重新连接此主机", + "workspaceNeedsUpdateGitHubReleases": "此桌面的移动端工作区需要更新版本的 Orca Mobile。请从 GitHub Releases 更新 Orca Mobile,然后重新连接此主机" }, "richMarkdownEditor": { "imageUrl": "图像 URL", @@ -979,7 +979,7 @@ }, "setupHookTrustDrawer": { "alwaysTrustAndRun": "始终信任并运行", - "description": "此仓库的 orca.yaml 会在工作区启动前运行。请仅在信任此仓库时运行。", + "description": "此仓库的 orca.yaml 会在工作区启动前运行。请仅在信任此仓库时运行", "dontRun": "不运行", "newScriptLabel": "新设置脚本", "runHooks": "运行钩子", @@ -994,13 +994,13 @@ "workspaceName": "工作区名称" }, "smartWorkspaceSourceDrawer": { - "connectRepository": "连接仓库以搜索来源。", - "crossRepoMessage": "此条目位于 {{owner}}/{{repo}}。", - "gitHubRemoteRequired": "此 SSH 仓库需要配置 GitHub 远程仓库,才能列出议题和 PR。", - "noResults": "未找到结果。", + "connectRepository": "连接仓库以搜索来源", + "crossRepoMessage": "此条目位于 {{owner}}/{{repo}}", + "gitHubRemoteRequired": "此 SSH 仓库需要配置 GitHub 远程仓库,才能列出议题和 PR", + "noResults": "未找到结果", "searchPlaceholder": "输入名称或搜索来源", "switchRepo": "切换到 {{repoName}}", - "typeWorkspaceName": "请在下方输入框中输入工作区名称。" + "typeWorkspaceName": "请在下方输入框中输入工作区名称" }, "smartWorkspaceSourceField": { "openSelectedSource": "打开所选来源", @@ -1016,7 +1016,7 @@ "useName": "使用“{{name}}”" }, "sourceCopyButton": { - "clipboardRejected": "剪贴板拒绝接收该文本。", + "clipboardRejected": "剪贴板拒绝接收该文本", "copiedLoaded": "已复制已加载内容", "copyFailed": "复制失败", "copyLoaded": "复制已加载内容", @@ -1027,7 +1027,7 @@ "addDescription": "创建组合键或文本宏", "addShortcut": "添加自定义快捷键…", "customShortcuts": "自定义快捷键", - "empty": "尚未设置自定义快捷键。", + "empty": "尚未设置自定义快捷键", "removeShortcut": "移除 {{label}}", "resetDefaults": "恢复默认设置", "resetDescription": "按原始顺序显示所有内置快捷键", @@ -1041,16 +1041,16 @@ "useCodexResetCreditAction": { "confirmTitle": "使用一次速率限制重置额度?", "detailsChanged": "重置详情已变更", - "detailsChangedMessage": "主机联系 Codex 前,账户或重置额度信息已发生变化。请查看更新后的详情,然后再次确认。", + "detailsChangedMessage": "主机联系 Codex 前,账户或重置额度信息已发生变化。请查看更新后的详情,然后再次确认", "hostAccount": "主机上的 {{identity}}", - "hostAccountConfirmMessage": "这会为主机上的 {{identity}} 消耗一次已获得的重置额度,并立即重置符合条件的用量窗口。", + "hostAccountConfirmMessage": "这会为主机上的 {{identity}} 消耗一次已获得的重置额度,并立即重置符合条件的用量窗口", "hostSelectedAccount": "主机上选定的托管账户", - "hostSelectedAccountConfirmMessage": "这会为主机上选定的托管账户消耗一次已获得的重置额度,并立即重置符合条件的用量窗口。", + "hostSelectedAccountConfirmMessage": "这会为主机上选定的托管账户消耗一次已获得的重置额度,并立即重置符合条件的用量窗口", "resetFailed": "无法重置速率限制", "wslAccount": "WSL {{distro}} 上的 {{identity}}", - "wslAccountConfirmMessage": "这会为 WSL {{distro}} 上的 {{identity}} 消耗一次已获得的重置额度,并立即重置符合条件的用量窗口。", + "wslAccountConfirmMessage": "这会为 WSL {{distro}} 上的 {{identity}} 消耗一次已获得的重置额度,并立即重置符合条件的用量窗口", "wslSelectedAccount": "WSL {{distro}} 上选定的托管账户", - "wslSelectedAccountConfirmMessage": "这会为 WSL {{distro}} 上选定的托管账户消耗一次已获得的重置额度,并立即重置符合条件的用量窗口。" + "wslSelectedAccountConfirmMessage": "这会为 WSL {{distro}} 上选定的托管账户消耗一次已获得的重置额度,并立即重置符合条件的用量窗口" }, "voiceModelList": { "deleteModel": "删除 {{label}}", @@ -1064,7 +1064,7 @@ "useModel": "使用 {{label}}" }, "workspaceDetailPlaceholder": { - "description": "从侧边栏选择一个工作区,即可在此处打开其终端。", + "description": "从侧边栏选择一个工作区,即可在此处打开其终端", "title": "未打开工作区" }, "workspaceNameInput": { @@ -1130,24 +1130,24 @@ "directViaTailscale": "通过 Tailscale 直连" }, "hostEndpoint": { - "addressRequired": "请输入主机地址。", - "hostnameRequired": "缺少主机名。", - "invalidAddress": "地址无效。", - "invalidHostname": "主机名无效。", - "invalidPort": "端口号必须为 1–65535。", - "invalidScheme": "请使用 ws:// 或 wss://(或 host:port)。", - "pathOrQueryNotAllowed": "主机地址不得包含路径或查询参数。" + "addressRequired": "请输入主机地址", + "hostnameRequired": "缺少主机名", + "invalidAddress": "地址无效", + "invalidHostname": "主机名无效", + "invalidPort": "端口号必须为 1–65535", + "invalidScheme": "请使用 ws:// 或 wss://(或 host:port)", + "pathOrQueryNotAllowed": "主机地址不得包含路径或查询参数" }, "pairConfirmState": { "invalidCode": "配对码无效", "missingCode": "缺少配对码" }, "rpcClientStreamRegistry": { - "endedBeforeReady": "流式请求尚未就绪便已结束。", + "endedBeforeReady": "流式请求尚未就绪便已结束", "interrupted": "连接中断" }, "rpcClientTerminalBinaryFrame": { - "unsupportedFrame": "不支持的终端流帧(操作码 {{opcode}})。" + "unsupportedFrame": "不支持的终端流帧(操作码 {{opcode}})" } }, "diagnostics": { @@ -1159,9 +1159,9 @@ "diagnosisHeading": "可能的原因", "disconnected": "已断开连接", "handshaking": "握手中", - "noEvents": "暂无连接事件。应用尝试连接此主机时,会显示相关事件。", - "noHosts": "没有已配对的主机。", - "privacyHint": "发送一份经过脱敏且大小受限的报告,包含主机名、端点、版本、连接状态和事件,绝不包含终端内容或凭据。", + "noEvents": "暂无连接事件。应用尝试连接此主机时,会显示相关事件", + "noHosts": "没有已配对的主机", + "privacyHint": "发送一份经过脱敏且大小受限的报告,包含主机名、端点、版本、连接状态和事件,绝不包含终端内容或凭据", "reconnecting": "重新连接中", "retrySending": "重试发送", "sendDiagnostics": "向 Orca 发送诊断信息", @@ -1187,34 +1187,34 @@ "title": "工作区更新" }, "troubleshootCommonIssues": { - "allowNotifications": "检查系统设置是否允许 Orca 发送通知,并确认专注模式或勿扰模式已关闭。", - "checkTailnet": "确认桌面未休眠,并在 tailnet 中显示为已连接。", + "allowNotifications": "检查系统设置是否允许 Orca 发送通知,并确认专注模式或勿扰模式已关闭", + "checkTailnet": "确认桌面未休眠,并在 tailnet 中显示为已连接", "desktopTitle": "桌面应用未运行", - "disableVpn": "关闭该 VPN,或启用分流功能/“允许 LAN”选项。", + "disableVpn": "关闭该 VPN,或启用分流功能/“允许 LAN”选项", "firewallTitle": "防火墙拦截端口 {{port}}", "linuxFirewall": "Linux: sudo ufw allow {{port}}", - "keepTailscaleOn": "100.x.x.x 或 *.ts.net 等主机地址通过 Tailscale 连接,请保持 Tailscale 开启。", - "macosFirewall": "macOS:系统设置 → 网络 → 防火墙,允许 Orca 通过。", - "notificationNetwork": "尝试切换到蜂窝网络或其他 Wi-Fi 网络。如果切换后能收到通知,则原网络可能导致通知延迟。", + "keepTailscaleOn": "100.x.x.x 或 *.ts.net 等主机地址通过 Tailscale 连接,请保持 Tailscale 开启", + "macosFirewall": "macOS:系统设置 → 网络 → 防火墙,允许 Orca 通过", + "notificationNetwork": "尝试切换到蜂窝网络或其他 Wi-Fi 网络。如果切换后能收到通知,则原网络可能导致通知延迟", "notificationsTitle": "推送通知", - "openDesktop": "桌面上的 Orca 必须保持运行才能接受连接。", - "pairAfterUpdate": "更新后可能需要重新扫描二维码配对。", - "reconnectWifi": "尝试在两台设备上重新连接 WiFi。", - "restartBothApps": "如果持续超时,请重启手机端和桌面端应用。", - "restartDesktop": "尝试重启 Orca,移动端连接服务会随应用启动。", - "restartTailscale": "iOS/Android 可能在无提示的情况下导致隧道卡住:请在 Tailscale 应用中关闭 Tailscale 后再重新开启。", - "restrictedNetwork": "公司或学校网络可能阻止 P2P 连接,请尝试使用个人热点。", - "retryHost": "返回主机列表,点按要连接的主机以重试。", - "sameNetwork": "两台设备必须处于同一 LAN(通过 Tailscale 连接时除外)。", - "sameSubnet": "以太网和 WiFi 必须位于同一子网。", + "openDesktop": "桌面上的 Orca 必须保持运行才能接受连接", + "pairAfterUpdate": "更新后可能需要重新扫描二维码配对", + "reconnectWifi": "尝试在两台设备上重新连接 WiFi", + "restartBothApps": "如果持续超时,请重启手机端和桌面端应用", + "restartDesktop": "尝试重启 Orca,移动端连接服务会随应用启动", + "restartTailscale": "iOS/Android 可能在无提示的情况下导致隧道卡住:请在 Tailscale 应用中关闭 Tailscale 后再重新开启", + "restrictedNetwork": "公司或学校网络可能阻止 P2P 连接,请尝试使用个人热点", + "retryHost": "返回主机列表,点按要连接的主机以重试", + "sameNetwork": "两台设备必须处于同一 LAN(通过 Tailscale 连接时除外)", + "sameSubnet": "以太网和 WiFi 必须位于同一子网", "tailscaleTitle": "无法访问 Tailscale 主机", "timeoutTitle": "连接超时", - "updateTailscale": "请更新 Tailscale 应用,近期版本修复了重新连接时的问题。", - "vpnRouting": "Tailscale 以外的 VPN 可能会将本地流量经由远程服务器转发。", + "updateTailscale": "请更新 Tailscale 应用,近期版本修复了重新连接时的问题", + "vpnRouting": "Tailscale 以外的 VPN 可能会将本地流量经由远程服务器转发", "vpnTitle": "其他 VPN 干扰", - "wifiSignal": "检查手机的 WiFi 信号强度。", + "wifiSignal": "检查手机的 WiFi 信号强度", "wifiTitle": "WiFi 网络不同", - "windowsFirewall": "Windows:Defender 防火墙 → 允许应用,允许 Orca 通过专用网络。" + "windowsFirewall": "Windows:Defender 防火墙 → 允许应用,允许 Orca 通过专用网络" }, "troubleshootView": { "commonIssues": "常见问题", @@ -1239,9 +1239,9 @@ "unexpectedResponse": "响应异常" }, "webShellUpdateFailureCopy": { - "blockedReason": "已阻止:{{reason}}。", - "blockedWorkspace": "已阻止打开工作区。", - "failed": "已显示失败界面。", + "blockedReason": "已阻止:{{reason}}", + "blockedWorkspace": "已阻止打开工作区", + "failed": "已显示失败界面", "failedAgo": "来自 {{hostName}} 的上次更新于 {{time}} 前失败:{{reason}}{{offered}}。{{outcome}}", "failedJustNow": "来自 {{hostName}} 的上次更新刚刚失败:{{reason}}{{offered}}。{{outcome}}", "hostCodeCopy": { @@ -1252,10 +1252,10 @@ "readLimited": "主机限制了并发读取数量", "unavailable": "主机上没有工作区资源包" }, - "nativeRoute": "已显示原生界面。", + "nativeRoute": "已显示原生界面", "offeredGeneration": " (构建标识 {{generation}})", - "openedCached": "已回退到保存的版本。", - "openedCachedGeneration": "已回退到保存的版本(构建标识 {{generation}})。", + "openedCached": "已回退到保存的版本", + "openedCachedGeneration": "已回退到保存的版本(构建标识 {{generation}})", "reasonCopy": { "assetChecksumMismatch": "资源校验和不匹配", "assetEntryChanged": "资源与清单不再匹配", @@ -1274,8 +1274,8 @@ "replyUnreadable": "此应用无法解析主机返回的响应", "unrecognisedError": "无法识别的错误" }, - "routeUnavailable": "已显示界面不可用的提示。", - "waiting": "已进入等待主机状态。", + "routeUnavailable": "已显示界面不可用的提示", + "waiting": "已进入等待主机状态", "wallCopy": { "bundleShellTooOld": "此应用版本过旧,无法使用保存的资源包", "bundleTooOldForHost": "保存的资源包版本过旧,无法用于此主机", @@ -1291,14 +1291,14 @@ "alreadyActive": "电脑或另一部手机正在使用听写。请更新电脑上的 Orca,以便在多台设备上同时听写。", "cloudModelNeedsKey": "需要 OpenAI 密钥", "deleteFailed": "删除模型失败", - "desktopUpdateRequired": "请更新已配对的 Orca 桌面应用,以使用移动端语音设置。", + "desktopUpdateRequired": "请更新已配对的 Orca 桌面应用,以使用移动端语音设置", "downloadFailed": "启动下载失败", "loadFailed": "加载听写模型失败", "modelBusy": "另一台设备正在使用不同的语音模型听写。请等它结束后再试。", - "repairRequired": "请将此手机与电脑重新配对,以使用听写。", - "serverUpdateRequired": "请更新此服务器上的 Orca,以使用语音听写。", + "repairRequired": "请将此手机与电脑重新配对,以使用听写", + "serverUpdateRequired": "请更新此服务器上的 Orca,以使用语音听写", "sessionLimit": "这台电脑上正在听写的设备过多。请等其中一台结束后再试。", - "sessionLost": "听写与电脑的连接已断开。请重试。", + "sessionLost": "听写与电脑的连接已断开。请重试", "updateFailed": "更新听写设置失败" }, "controls": { @@ -1401,7 +1401,7 @@ "waiting": "等待桌面…" }, "fileMutationOwnership": { - "sshOwnerChanged": "无法验证 SSH 连接。请重新连接主机后重试。" + "sshOwnerChanged": "无法验证 SSH 连接。请重新连接主机后重试" }, "filePreviewBody": { "emptyFile": "空文件", @@ -1425,16 +1425,16 @@ }, "filePreviewScreen": { "backToFiles": "返回文件列表", - "chooseWorkspaceFile": "请选择此工作区内的文件。", + "chooseWorkspaceFile": "请选择此工作区内的文件", "discard": "放弃", - "discardMessage": "未保存的更改将丢失。", - "discardMessageSaving": "正在进行的保存可能无法完成。未保存的编辑将会丢失。", + "discardMessage": "未保存的更改将丢失", + "discardMessageSaving": "正在进行的保存可能无法完成。未保存的编辑将会丢失", "discardTitle": "放弃更改?", "fileTitle": "文件", "loadFailed": "无法加载预览", "loading": "正在加载预览…", "openFailed": "无法打开文件", - "saveArtifact": "保存终端工件", + "saveArtifact": "保存终端产物", "saveFailed": "无法保存文件", "stay": "留在此页", "title": "预览", @@ -1442,7 +1442,7 @@ }, "filePreviewSourceText": { "previewLabel": "文件预览", - "truncatedNote": "预览已截断。文件大小:{{size}}。" + "truncatedNote": "预览已截断。文件大小:{{size}}" }, "markdownPreviewImage": { "expandFallback": "放大图片", @@ -1485,10 +1485,10 @@ "updateDesktop": "请更新 {{desktop}} 上的 Orca,以使用自动化。" }, "emptyState": { - "connectedDescription": "桌面将显示在这里。所有数据均采用端到端加密。", + "connectedDescription": "桌面将显示在这里。所有数据均采用端到端加密", "connectedTitle": "已连接", - "description": "与电脑上的 Orca 配对,即可在手机上查看智能体、进入任意终端并推进工作。", - "openDesktopDescription": "前往“设置” → “移动端”,生成配对二维码。", + "description": "与电脑上的 Orca 配对,即可在手机上查看智能体、进入任意终端并推进工作", + "openDesktopDescription": "前往“设置” → “移动端”,生成配对二维码", "openDesktopTitle": "打开 Orca 桌面应用", "scanCodeTitle": "扫描二维码", "title": "连接桌面" @@ -1502,9 +1502,9 @@ "screen": { "pairingCheckFailed": "无法检查配对状态", "removeHostFailed": "无法移除主机", - "removeHostMessage": "要移除“{{name}}”吗?之后可重新配对。", + "removeHostMessage": "要移除“{{name}}”吗?之后可重新配对", "removeHostTitle": "移除主机", - "tryAgain": "请重试。" + "tryAgain": "请重试" }, "stats": { "agentTime": "智能体时间", @@ -1539,11 +1539,11 @@ "recordingFailed": "麦克风录音启动失败" }, "useMobileDictation": { - "inputClosed": "此会话已不再接受输入,语音听写已停止。请重试。", + "inputClosed": "此会话已不再接受输入,语音听写已停止。请重试", "microphoneInitFailed": "麦克风初始化失败", - "microphoneInterrupted": "麦克风录音中断,语音听写已停止。请重试。", + "microphoneInterrupted": "麦克风录音中断,语音听写已停止。请重试", "microphonePermissionDenied": "麦克风权限被拒绝", - "noSpeech": "未检测到语音。", + "noSpeech": "未检测到语音", "phoneUnavailable": "此手机上的听写尚未就绪。请在语音设置中下载,或选择“自动”。", "phoneFailed": "此手机上的听写已停止工作。请重试。", "phoneBusy": "此手机上的听写仍在启动。请稍后再试。" @@ -1552,16 +1552,16 @@ "host": { "edit": { "address": "地址", - "addressHint": "支持 IP、host:port 或 ws:// / wss://。wss:// URL 未指定端口时使用 443。仅输入地址时保留当前端口(或使用 6768)。", + "addressHint": "支持 IP、host:port 或 ws:// / wss://。wss:// URL 未指定端口时使用 443。仅输入地址时保留当前端口(或使用 6768)", "connectionPreview": "连接到 {{endpoint}}", "goBack": "返回", - "help": "更改显示名称或连接地址。名称留空时,将使用桌面提供的名称。更改地址只会切换此手机的连接地址,不会重新配对。当同一桌面可通过不同 IP 访问时(例如家庭局域网与 Tailscale),可使用此功能。", + "help": "更改显示名称或连接地址。名称留空时,将使用桌面提供的名称。更改地址只会切换此手机的连接地址,不会重新配对。当同一桌面可通过不同 IP 访问时(例如家庭局域网与 Tailscale),可使用此功能", "hostNamePlaceholder": "主机名", - "hostRemoved": "此主机已从这部手机上移除。", - "loadFailed": "加载主机失败。", - "missingHost": "缺少主机信息。", + "hostRemoved": "此主机已从这部手机上移除", + "loadFailed": "加载主机失败", + "missingHost": "缺少主机信息", "name": "名称", - "saveFailed": "保存主机失败。", + "saveFailed": "保存主机失败", "saveHost": "保存主机", "title": "编辑主机" } @@ -1592,9 +1592,9 @@ "deleteKeepsEnvironment": "Orca 为其创建的环境“{{environment}}”会继续运行:其配方没有销毁步骤。", "deleteWorktree": "删除工作树", "pin": "固定", - "primaryWorktreeDeleteHint": "主工作树不能删除。请改为移除项目。", + "primaryWorktreeDeleteHint": "主工作树不能删除。请改为移除项目", "removeHost": "移除主机", - "removeHostMessage": "要移除“{{name}}”吗?之后可重新配对。", + "removeHostMessage": "要移除“{{name}}”吗?之后可重新配对", "sleep": "休眠", "unpin": "取消固定", "rename": "重命名" @@ -1617,7 +1617,7 @@ "agentActivity": "智能体活动", "agentActivityLayout": "智能体活动布局", "agentActivitySort": "智能体活动", - "agentActivitySortDescription": "需要关注的智能体,然后是最近的活动。", + "agentActivitySortDescription": "需要关注的智能体,然后是最近的活动", "agentStatuses": "智能体状态", "allHosts": "所有主机", "allProjects": "所有项目", @@ -1637,7 +1637,7 @@ "linearIssues": "Linear 议题", "manual": "手动的", "manualProjectOrderDescription": "拖动项目进行排列", - "manualWorkspaceOrderDescription": "拖动工作区以将它们排列在每个组中。", + "manualWorkspaceOrderDescription": "拖动工作区以将它们排列在每个组中", "name": "名称", "none": "无", "notes": "笔记", @@ -1718,12 +1718,12 @@ "silentName": "Orca 静默通知" }, "notificationDeliverySection": { - "footer": "提醒类型遵循各个已配对桌面的通知设置。连续 7 天未使用此应用后,通知将暂停;打开应用并重新连接即可恢复。", + "footer": "提醒类型遵循各个已配对桌面的通知设置。连续 7 天未使用此应用后,通知将暂停;打开应用并重新连接即可恢复", "onlyWhenAway": "仅在离开桌面时", - "onlyWhenAwayHint": "键盘和鼠标均无操作达 3 分钟后,或锁屏时。", + "onlyWhenAwayHint": "键盘和鼠标均无操作达 3 分钟后,或锁屏时", "sound": "通知声音", "suppressWhileFocused": "查看时不提醒", - "suppressWhileFocusedHint": "不发送此手机上当前打开的工作区的提醒。" + "suppressWhileFocusedHint": "不发送此手机上当前打开的工作区的提醒" } }, "onboarding": { @@ -1731,16 +1731,16 @@ "claudeNeedsInput": "Claude 需要输入", "codexFinished": "Codex 已完成", "now": "现在", - "testsPassing": "测试已通过。", - "waitingOnYou": "等待您的回应。" + "testsPassing": "测试已通过", + "waitingOnYou": "等待您的回应" }, "onboardingPage": { "enableAgentNotifications": "启用智能体通知", "enableNotifications": "启用通知", "keepTerminal": "继续使用终端", "notNow": "暂不", - "notificationsDescription": "智能体完成任务或等待响应时,即使未使用应用,此手机也会收到通知。", - "notificationsDisclosure": "桌面空闲 3 分钟后,通过 Orca 的推送服务发送通知。可随时在“设置”中更改。", + "notificationsDescription": "智能体完成任务或等待响应时,即使未使用应用,此手机也会收到通知", + "notificationsDisclosure": "桌面空闲 3 分钟后,通过 Orca 的推送服务发送通知。可随时在“设置”中更改", "notificationsTitle": "智能体需要您时,及时收到提醒", "openInChatUi": "在聊天界面中打开会话", "openInTerminal": "在终端中打开会话", @@ -1761,7 +1761,7 @@ "commentCard": { "daysAgo_one": "{{count}} 天前", "daysAgo_other": "{{count}} 天前", - "deleteConfirmMessage": "这将永久删除 GitHub 上的这条评论。", + "deleteConfirmMessage": "这将永久删除 GitHub 上的这条评论", "deleteConfirmTitle": "删除评论?", "editPlaceholder": "编辑评论…", "hoursAgo_one": "{{count}} 小时前", @@ -1779,10 +1779,13 @@ }, "commentsSection": { "comment": "评论", + "commentsLoadFailed": "无法加载评论。请点按刷新重试", "description": "描述", - "descriptionLoadFailed": "无法加载描述。请点按刷新重试。", - "noComments": "还没有评论。", - "noDescription": "没有提供描述。", + "descriptionLoadFailed": "无法加载描述。请点按刷新重试", + "noBotComments": "没有机器人评论", + "noComments": "还没有评论", + "noDescription": "没有提供描述", + "noHumanComments": "没有人类评论", "showMore": "再显示 {{count}} 条", "title": "评论" }, @@ -1797,14 +1800,15 @@ "details": "详情" }, "prActionsSection": { - "closeConfirmMessage": "#{{number}} 将被关闭,不会合并。", + "closeConfirmMessage": "#{{number}} 将被关闭,不会合并", "closeConfirmTitle": "关闭 PR?", "markReadyButton": "标记为可评审", "reopenAccessibilityLabel": "重新开启 PR", "reopenButton": "重新开启", - "reopenConfirmMessage": "#{{number}} 将被重新开启。", + "reopenConfirmMessage": "#{{number}} 将被重新开启", "reopenConfirmTitle": "重新开启 PR?", - "unlinkButton": "取消关联" + "unlinkButton": "取消关联", + "unlinkFailed": "取消 PR 关联失败" }, "prActionsState": { "behindHint": "合并前更新分支", @@ -1815,7 +1819,7 @@ "changesRequestedLabel": "要求更改", "checkingHint": "GitHub 仍在计算此PR合并状态", "checkingLabel": "检查中", - "checksPassedHint": "检查已通过。合并资格将在合并前再次验证。", + "checksPassedHint": "检查已通过。合并资格将在合并前再次验证", "checksPassedLabel": "检查已通过", "closedHint": "此PR已关闭", "closedLabel": "已关闭", @@ -1823,12 +1827,12 @@ "conflictsLabel": "冲突", "draftHint": "这个PR仍然是一个草稿", "draftLabel": "草稿", - "mergeConfirmMessage": "这将把 #{{number}} 合并到其基础分支。", + "mergeConfirmMessage": "这将把 #{{number}} 合并到其基础分支", "mergeQueueAutoMergeOnHint": "该基础分支使用 GitHub 合并队列", "mergeQueueAutoMergeOnLabel": "自动合并已开启", "mergeQueueHint": "该基础分支使用 GitHub 合并队列", "mergeQueueLabel": "准备好后合并", - "mergeStackMessage": "GitHub 将合并此拉取请求以及堆栈中其下方的每个拉取请求。", + "mergeStackMessage": "GitHub 将合并此拉取请求以及堆栈中其下方的每个拉取请求", "mergeStatusUnavailableHint": "此 PR 的合并状态不可用", "mergeStatusUnavailableLabel": "合并", "mergeThrough_one": "合并 #{{number}} 及下方 PR · 共 {{count}} 个", @@ -1846,24 +1850,24 @@ "methodMerge": "创建合并提交", "methodRebase": "变基合并", "methodSquash": "压缩合并", - "queueStackMessage": "GitHub 会将此拉取请求及其下面的每个拉取请求添加到合并队列中。", + "queueStackMessage": "GitHub 会将此拉取请求及其下面的每个拉取请求添加到合并队列中", "queueThrough_one": "将 #{{number}} 及下方 PR 入队 · 共 {{count}} 个", "queueThrough_other": "将 #{{number}} 及下方 PR 入队 · 共 {{count}} 个", "reviewRequiredHint": "GitHub 需要评审批准才能合并此拉取请求", "reviewRequiredLabel": "需要批准", - "stackBehind": "#{{number}} 必须更新。", - "stackBlocked": "#{{number}} 已阻塞。", - "stackChangesRequested": "#{{number}} 被要求更改。", - "stackClosed": "#{{number}} 已关闭。", - "stackConflicts": "#{{number}} 存在合并冲突。", - "stackDraft": "#{{number}} 仍为草稿。", - "stackReviewRequired": "#{{number}} 仍需评审批准。" + "stackBehind": "#{{number}} 必须更新", + "stackBlocked": "#{{number}} 已阻塞", + "stackChangesRequested": "#{{number}} 被要求更改", + "stackClosed": "#{{number}} 已关闭", + "stackConflicts": "#{{number}} 存在合并冲突", + "stackDraft": "#{{number}} 仍为草稿", + "stackReviewRequired": "#{{number}} 仍需评审批准" }, "prCheckDetail": { "annotations": "注释", "annotationsTruncated": "显示前 20 个注释", "jobsTruncated": "显示前 100 个作业", - "noDetails": "暂无详细信息。" + "noDetails": "暂无详细信息" }, "prCheckDetailContent": { "annotation": "批注", @@ -1891,19 +1895,20 @@ "all": "全部", "bots": "机器人", "humans": "人类", - "noBotComments": "没有机器人评论。", - "noComments": "还没有评论。", - "noHumanComments": "没有人类评论。" + "noBotComments": "没有机器人评论", + "noComments": "还没有评论", + "noHumanComments": "没有人类评论" }, "prSidebarCreateEmptyState": { - "branchNotLinked": "{{branch}} 未关联到开放的 PR。", - "currentBranchNotLinked": "当前分支未关联到开放的 PR。", + "branchNotLinked": "{{branch}} 未关联到开放的 PR", + "branchRequired": "创建 PR 前,请先检出分支", + "currentBranchNotLinked": "当前分支未关联到开放的 PR", "linkExistingPullRequest": "关联现有 PR", "linkedPrUnavailable": "关联的 PR #{{number}} 不可用", - "refreshOrCreate": "刷新以重新检查,或为此分支创建新的 PR。" + "refreshOrCreate": "刷新以重新检查,或为此分支创建新的 PR" }, "prViewPanel": { - "branchUnavailable": "当前分支不可用。", + "branchUnavailable": "当前分支不可用", "githubRemoteRequired": "此标签页需要 GitHub 远程仓库才能显示拉取请求详情。对于其他受支持的平台,请在“更改”中创建审查,然后在浏览器中打开。" }, "reviewerPickerDrawer": { @@ -1915,6 +1920,7 @@ "changesRequested": "要求更改", "commented": "已评论", "dismissed": "已撤销", + "loadFailed": "无法加载评审人。请点按刷新重试", "noReviewers": "尚未请求评审", "pending": "待处理", "removeReviewer": "移除 {{login}}", @@ -1933,7 +1939,7 @@ "messageModeLabel": "消息模式:输入后发送。切换到按键模式", "moreKeys": "更多按键和操作", "showKeyboard": "显示键盘", - "dismissKeyboardHint": "隐藏软键盘,并保持当前终端会话打开。", + "dismissKeyboardHint": "隐藏软键盘,并保持当前终端会话打开", "switchToDesktopMode": "切换到桌面模式", "switchToPhoneMode": "切换到手机模式", "pasteFromClipboard": "从剪贴板粘贴", @@ -1971,7 +1977,7 @@ "sendFailed": "发送恢复命令失败" }, "aiVaultResumePreparation": { - "prepareFailed": "无法准备此旧版 Codex 会话。请重试恢复。" + "prepareFailed": "无法准备此旧版 Codex 会话。请重试恢复" }, "backgroundTask": { "agent": "后台智能体", @@ -1987,7 +1993,7 @@ "countTasks_other": "{{count}} 个任务", "countWorkflows_one": "{{count}} 个工作流程", "countWorkflows_other": "{{count}} 个工作流程", - "detailsUnavailable": "此会话的任务详细信息不可用。", + "detailsUnavailable": "此会话的任务详细信息不可用", "outputFile": "输出:{{value0}}", "groupAgents": "智能体", "groupMonitors": "监控", @@ -2037,7 +2043,7 @@ }, "bulkTabClose": { "confirm": "关闭标签页", - "description": "选中的标签页将关闭。固定的标签页将保持打开。", + "description": "选中的标签页将关闭。固定的标签页将保持打开", "titleEditors": "关闭所有编辑器标签页?", "titleLeft": "关闭左侧标签页?", "titleOthers": "关闭其他标签页?", @@ -2062,7 +2068,7 @@ "committedChangesFailed": "加载已提交的更改失败", "committedChangesUnavailable": "已提交的更改不可用", "committedDiffUnavailable": "已提交的差异不可用", - "desktopUpdateRequired": "请更新 Orca 桌面端,以便在手机上评审更改。", + "desktopUpdateRequired": "请更新 Orca 桌面端,以便在手机上评审更改", "diffLoadFailed": "无法加载差异", "reviewNotesLoadFailed": "无法加载评审笔记" }, @@ -2077,133 +2083,133 @@ "unstaged": "未暂存" }, "failure": { - "accountSwitchInProgress": "正在此主机上更改 {{agent}} 的设置。请在完成后重试。", - "agentCommandNotRunnable": "{{agent}} 在设置 → 智能体中的命令必须是 Orca 能找到的程序路径或名称,且不能包含参数或变量。请修改或重置。", - "agentCommandNotSignedIn": "请在运行此聊天的电脑上使用 `{{loginCommand}}` 登录 {{agent}}。", - "agentNotSignedIn": "请登录 {{agent}}。", - "agentStarting": "智能体仍在启动。", - "agentStillWorking": "智能体仍在工作。", - "answerUnconfirmed": "您的回答已记录,但智能体未确认。", - "antigravityNotSignedIn": "尚未登录 Antigravity。请在设置 → 账户 → Antigravity中登录,然后重新发送消息。", - "argumentsMissingValue": "已保存的参数需要为 {{option}} 指定一个值。", - "argumentsMultipleValues": "已保存的参数为 {{option}} 指定了多个值。", - "argumentsPositionalPrompt": "已保存的参数中包含提示词。", - "argumentsUnsupportedOption": "已保存的参数包含不支持的选项({{option}})。", - "attachmentAtMost": "{{agent}} 每条消息最多接受 {{limit}} 张图片,因此此消息未发送。", - "attachmentEmpty": "此消息中的一张图片为空,因此消息未发送。", - "attachmentInvalid": "此消息中的附件无法发送给智能体。", + "accountSwitchInProgress": "正在此主机上更改 {{agent}} 的设置。请在完成后重试", + "agentCommandNotRunnable": "{{agent}} 在设置 → 智能体中的命令必须是 Orca 能找到的程序路径或名称,且不能包含参数或变量。请修改或重置", + "agentCommandNotSignedIn": "请在运行此聊天的电脑上使用 `{{loginCommand}}` 登录 {{agent}}", + "agentNotSignedIn": "请登录 {{agent}}", + "agentStarting": "智能体仍在启动", + "agentStillWorking": "智能体仍在工作", + "answerUnconfirmed": "您的回答已记录,但智能体未确认", + "antigravityNotSignedIn": "尚未登录 Antigravity。请在设置 → 账户 → Antigravity中登录,然后重新发送消息", + "argumentsMissingValue": "已保存的参数需要为 {{option}} 指定一个值", + "argumentsMultipleValues": "已保存的参数为 {{option}} 指定了多个值", + "argumentsPositionalPrompt": "已保存的参数中包含提示词", + "argumentsUnsupportedOption": "已保存的参数包含不支持的选项({{option}})", + "attachmentAtMost": "{{agent}} 每条消息最多接受 {{limit}} 张图片,因此此消息未发送", + "attachmentEmpty": "此消息中的一张图片为空,因此消息未发送", + "attachmentInvalid": "此消息中的附件无法发送给智能体", "attachmentsExpired": "{{names}} 已过期。", - "attachmentLargerThan": "此消息中的一张图片超过 {{size}} MB,因此消息未发送。", - "attachmentNoSource": "此消息中的一张图片没有可发送的文件,因此消息未发送。", - "attachmentNotAFile": "此消息中的一张图片不是文件,因此消息未发送。", - "attachmentTooLarge": "此消息中的一张图片过大,因此消息未发送。", - "attachmentTooMany": "此消息包含的图片过多,因此未发送。", - "attachmentTotalMoreThan": "此消息中的图片总计超过 {{size}} MB,因此消息未发送。", - "attachmentTotalTooLarge": "此消息中的图片总大小过大,因此消息未发送。", - "attachmentUnreadable": "无法读取此消息中的附件,因此消息未发送。", - "attachmentUnsupportedType": "{{agent}} 仅接受 PNG、JPEG、GIF 和 WebP 图片,因此此消息未发送。", - "backgroundTaskNotStopped": "后台任务未停止。", - "backgroundTasksNotStopped": "后台任务未停止。", - "backgroundTasksRunning": "后台任务仍在运行。", - "cancelUnconfirmed": "未能确认是否已取消。", - "cancelled": "此消息在智能体开始处理前已撤回。", - "chatClosed": "此消息发送前聊天已关闭。", - "chooseClaudeAccount": "请在 Claude 账户设置中选择或添加一个。", - "chooseClaudeAccountThenRunCommand": "请在 Claude 账户设置中选择或添加一个,然后重新运行 /{{command}}。", - "chooseClaudeAccountThenSend": "请在 Claude 账户设置中选择或添加一个,然后重新发送您的消息。", - "claudeAccountFolderMissing": "所选 Claude 账户的文件夹不存在。请重新登录该账户或选择其他账户。", - "claudeAccountSetupFailed": "无法设置所选 Claude 账户。请重试或选择其他账户。", - "claudeEffortInvalid": "Claude 的推理强度无效;请选择 low、medium、high、xhigh 或 max,然后重新发送。", - "claudeManagedNotSignedIn": "此 Claude 账户尚未登录。请在 Claude 账户设置中重新登录。", - "claudeSystemNotSignedIn": "Claude 尚未登录。请运行 `{{loginCommand}}`,或在 Claude 账户设置中选择账户。", - "cliMissing": "在运行此聊天的计算机上找不到 {{agent}}。请安装它,或检查设置 → 智能体中的命令。", - "cliMissingInWslDistro": "WSL 发行版 {{distro}} 中未安装 {{agent}}。请在 {{distro}} 中安装它,或检查设置 → 智能体中的命令。", - "cliTooOld": "{{agent}} {{installedVersion}} 版本过旧,无法用于聊天。请更新到 {{minimumVersion}} 或更高版本。", - "codexManagedNotSignedIn": "此 Codex 账户尚未登录。请在 Codex 账户设置中重新登录。", - "codexSystemNotSignedIn": "Codex 尚未登录。请运行 `{{loginCommand}}`。", - "commandAfterAnswer": "请先回答智能体的问题或处理审批请求,然后再运行 /{{command}}。", - "commandRefused": "此命令未运行。", - "commandRefusedTryAgain": "此命令未运行。请重试。", - "commandUnavailable": "此命令在 {{agent}} 聊天中不可用,因此未发送。", - "compactionFailed": "压缩失败。", - "compactionFailedQuoted": "压缩失败:{{detail}}。", - "compactionUnconfirmed": "未确认压缩是否完成。", - "conversationOpenElsewhere": "Codex 仍占用此对话。请稍后重试,或关闭其他 Codex 终端。", - "conversationOpenInTerminal": "{{agent}} 已在另一个终端中运行此对话。请退出那里的 {{agent}} 或关闭该终端,然后在这里继续。", - "couldNotRestart": "{{agent}} 无法重新启动。", - "couldNotStart": "{{agent}} 无法启动。", - "couldNotStop": "无法停止 {{agent}}。", - "couldNotStopTheAgent": "无法停止智能体。", - "editSavedArguments": "请在设置 > 智能体 > 参数中编辑。", - "emptyMessage": "此消息为空,因此未发送。", - "fullAccessAsRoot": "{{agent}} 以 root 身份运行时不会使用完全访问。请在运行此聊天的计算机的“设置”→“智能体”中为 {{agent}} 选择其他权限,然后开始新的聊天。", - "historyInOtherAccount": "此聊天的历史记录位于另一个 Claude 账户中。请切换回该账户以继续此聊天。", - "historyTooLarge": "此对话的历史记录过大,无法在此恢复。", - "hostFault": "Orca 遇到问题,因此此操作未完成。", - "hostFaultTryAgain": "Orca 遇到问题,因此此操作未完成。请重试。", - "hostRestarted": "此消息发送前 Orca 已重新启动。", - "hostStopped": "{{agent}} 始终未完成启动,因此 Orca 已将其停止。", - "interactiveAgentNotSignedIn": "请在运行此聊天的电脑上启动 `{{loginCommand}}` 并使用 `{{slashCommand}}` 登录 {{agent}}。", - "launchFolderMissing": "此聊天运行所在的文件夹已不存在。请恢复该文件夹以继续此聊天。", - "launchPreparationFailed": "Orca 无法在运行此聊天的计算机上准备启动 {{agent}}。", - "managedAccountEnvOverride": "此次 Claude 启动设置了自己的 Anthropic 登录变量。请移除这些变量以使用受管理的 Claude 账户。", - "managedAccountUnsupported": "虽然已在 WSL 中添加 Claude 账户,但 Claude 聊天仍需使用 Windows 中的 Claude 账户。", - "modelUnavailable": "{{agent}} 无法使用 {{detail}}。请选择其他模型并重新发送。", + "attachmentLargerThan": "此消息中的一张图片超过 {{size}} MB,因此消息未发送", + "attachmentNoSource": "此消息中的一张图片没有可发送的文件,因此消息未发送", + "attachmentNotAFile": "此消息中的一张图片不是文件,因此消息未发送", + "attachmentTooLarge": "此消息中的一张图片过大,因此消息未发送", + "attachmentTooMany": "此消息包含的图片过多,因此未发送", + "attachmentTotalMoreThan": "此消息中的图片总计超过 {{size}} MB,因此消息未发送", + "attachmentTotalTooLarge": "此消息中的图片总大小过大,因此消息未发送", + "attachmentUnreadable": "无法读取此消息中的附件,因此消息未发送", + "attachmentUnsupportedType": "{{agent}} 仅接受 PNG、JPEG、GIF 和 WebP 图片,因此此消息未发送", + "backgroundTaskNotStopped": "后台任务未停止", + "backgroundTasksNotStopped": "后台任务未停止", + "backgroundTasksRunning": "后台任务仍在运行", + "cancelUnconfirmed": "未能确认是否已取消", + "cancelled": "此消息在智能体开始处理前已撤回", + "chatClosed": "此消息发送前聊天已关闭", + "chooseClaudeAccount": "请在 Claude 账户设置中选择或添加一个", + "chooseClaudeAccountThenRunCommand": "请在 Claude 账户设置中选择或添加一个,然后重新运行 /{{command}}", + "chooseClaudeAccountThenSend": "请在 Claude 账户设置中选择或添加一个,然后重新发送您的消息", + "claudeAccountFolderMissing": "所选 Claude 账户的文件夹不存在。请重新登录该账户或选择其他账户", + "claudeAccountSetupFailed": "无法设置所选 Claude 账户。请重试或选择其他账户", + "claudeEffortInvalid": "Claude 的推理强度无效;请选择 low、medium、high、xhigh 或 max,然后重新发送", + "claudeManagedNotSignedIn": "此 Claude 账户尚未登录。请在 Claude 账户设置中重新登录", + "claudeSystemNotSignedIn": "Claude 尚未登录。请运行 `{{loginCommand}}`,或在 Claude 账户设置中选择账户", + "cliMissing": "在运行此聊天的计算机上找不到 {{agent}}。请安装它,或检查设置 → 智能体中的命令", + "cliMissingInWslDistro": "WSL 发行版 {{distro}} 中未安装 {{agent}}。请在 {{distro}} 中安装它,或检查设置 → 智能体中的命令", + "cliTooOld": "{{agent}} {{installedVersion}} 版本过旧,无法用于聊天。请更新到 {{minimumVersion}} 或更高版本", + "codexManagedNotSignedIn": "此 Codex 账户尚未登录。请在 Codex 账户设置中重新登录", + "codexSystemNotSignedIn": "Codex 尚未登录。请运行 `{{loginCommand}}`", + "commandAfterAnswer": "请先回答智能体的问题或处理审批请求,然后再运行 /{{command}}", + "commandRefused": "此命令未运行", + "commandRefusedTryAgain": "此命令未运行。请重试", + "commandUnavailable": "此命令在 {{agent}} 聊天中不可用,因此未发送", + "compactionFailed": "压缩失败", + "compactionFailedQuoted": "压缩失败:{{detail}}", + "compactionUnconfirmed": "未确认压缩是否完成", + "conversationOpenElsewhere": "Codex 仍占用此对话。请稍后重试,或关闭其他 Codex 终端", + "conversationOpenInTerminal": "{{agent}} 已在另一个终端中运行此对话。请退出那里的 {{agent}} 或关闭该终端,然后在这里继续", + "couldNotRestart": "{{agent}} 无法重新启动", + "couldNotStart": "{{agent}} 无法启动", + "couldNotStop": "无法停止 {{agent}}", + "couldNotStopTheAgent": "无法停止智能体", + "editSavedArguments": "请在设置 > 智能体 > 参数中编辑", + "emptyMessage": "此消息为空,因此未发送", + "fullAccessAsRoot": "{{agent}} 以 root 身份运行时不会使用完全访问。请在运行此聊天的计算机的“设置”→“智能体”中为 {{agent}} 选择其他权限,然后开始新的聊天", + "historyInOtherAccount": "此聊天的历史记录位于另一个 Claude 账户中。请切换回该账户以继续此聊天", + "historyTooLarge": "此对话的历史记录过大,无法在此恢复", + "hostFault": "Orca 遇到问题,因此此操作未完成", + "hostFaultTryAgain": "Orca 遇到问题,因此此操作未完成。请重试", + "hostRestarted": "此消息发送前 Orca 已重新启动", + "hostStopped": "{{agent}} 始终未完成启动,因此 Orca 已将其停止", + "interactiveAgentNotSignedIn": "请在运行此聊天的电脑上启动 `{{loginCommand}}` 并使用 `{{slashCommand}}` 登录 {{agent}}", + "launchFolderMissing": "此聊天运行所在的文件夹已不存在。请恢复该文件夹以继续此聊天", + "launchPreparationFailed": "Orca 无法在运行此聊天的计算机上准备启动 {{agent}}", + "managedAccountEnvOverride": "此次 Claude 启动设置了自己的 Anthropic 登录变量。请移除这些变量以使用受管理的 Claude 账户", + "managedAccountUnsupported": "虽然已在 WSL 中添加 Claude 账户,但 Claude 聊天仍需使用 Windows 中的 Claude 账户", + "modelUnavailable": "{{agent}} 无法使用 {{detail}}。请选择其他模型并重新发送", "modelUnavailableUpdate": "{{agent}} 无法使用 {{detail}}。请将 {{agent}} 更新到 {{minimumVersion}} 或更高版本,以便重启后继续使用;或者选择其他模型并重新发送。", "modelNotSelected": "{{agent}} 没有选择模型。请检查模型选择和 {{agent}} 登录状态,然后重新发送。", - "noTurnToStop": "{{agent}} 没有正在运行的轮次可停止。", - "notDelivered": "此消息未送达。", - "notDeliveredSendAgain": "此消息未送达。请重新发送以继续。", - "notSignedIn": "{{agent}} 尚未登录。", - "previousExitUnverifiable": "无法停止之前的 {{agent}}。", - "providerExitedAnswer": "{{agent}} 已停止,因此您的回答未发送。发送消息以继续。", - "providerExitedRejection": "{{agent}} 在发送此消息前已停止。", - "providerExitedRow": "{{agent}} 在生成此回复时停止了。您可以在此对话中继续。", - "providerRateLimited": "{{agent}} 已被限流,正在重试。", - "providerUnavailable": "{{agent}} 因服务繁忙而无法回复。请选择其他模型,或稍等片刻后重新发送。", - "providerSafetyStopped": "{{agent}} 在安全检查后停止了此次回复。请检查您的请求后重新发送。", - "providerResponseFailed": "{{agent}} 未能完成此回复。打开详情了解更多信息。", - "selectedModel": "所选模型", - "providerRejected": "{{agent}} 未接受此消息。", - "providerRejectedQuoted": "{{agent}} 未接受此消息:{{detail}}。", - "providerRetryLastError": "上次错误:{{detail}}。", - "providerRetryNumber": "第 {{attempt}} 次重试。", - "providerRetryNumberOf": "第 {{attempt}} 次重试,共 {{maxRetries}} 次。", - "providerRetrying": "{{agent}} 遇到临时问题,正在重试。", - "providerRetryingQuoted": "{{agent}} 正在重试:{{detail}}。", - "providerStartFailed": "{{agent}} 在完成启动前已停止。", + "noTurnToStop": "{{agent}} 没有正在运行的轮次可停止", + "notDelivered": "此消息未送达", + "notDeliveredSendAgain": "此消息未送达。请重新发送以继续", + "notSignedIn": "{{agent}} 尚未登录", + "previousExitUnverifiable": "无法停止之前的 {{agent}}", + "providerExitedAnswer": "{{agent}} 已停止,因此您的回答未发送。发送消息以继续", + "providerExitedRejection": "{{agent}} 在发送此消息前已停止", + "providerExitedRow": "{{agent}} 在生成此回复时停止了。您可以在此对话中继续", + "providerRateLimited": "{{agent}} 已被限流,正在重试", + "providerRejected": "{{agent}} 未接受此消息", + "providerRejectedQuoted": "{{agent}} 未接受此消息:{{detail}}", + "providerRetryLastError": "上次错误:{{detail}}", + "providerRetryNumber": "第 {{attempt}} 次重试", + "providerRetryNumberOf": "第 {{attempt}} 次重试,共 {{maxRetries}} 次", + "providerRetrying": "{{agent}} 遇到临时问题,正在重试", + "providerRetryingQuoted": "{{agent}} 正在重试:{{detail}}", + "providerStartFailed": "{{agent}} 在完成启动前已停止", "savedConversationMissing": "{{agent}} 找不到此聊天已保存的对话。", - "queueFull": "等待智能体处理的消息过多,因此此消息未发送。", - "quitTerminalAgent": "请退出该智能体,以便在此处继续聊天。", - "runCommandAgain": "请重新运行 /{{command}}。", - "runCommandWhenDone": "完成后再运行 /{{command}}。", - "runtimeNotInstalled": "运行此聊天的计算机上未安装 {{agent}}。请在最新版本的 Orca 中从聊天里安装。", - "sendAgainToTryOnceMore": "请重新发送您的消息,再试一次。", - "sendToTryAgain": "请发送您的消息以重试。", - "sessionNotRestored": "{{agent}} 无法重新打开之前的会话,因此此聊天将在新会话中继续。{{agent}} 不记得之前的消息。", - "signInFirst": "请先登录。", - "signInThenRunCommand": "请登录,然后重新运行 /{{command}}。", - "signInThenSend": "请登录,然后重新发送您的消息。", - "startNewChat": "请开始新的聊天以继续。", - "startTimedOut": "{{agent}} 启动时间过长({{seconds}} 秒后 {{method}} 仍无响应)。", - "startTimedOutKeepsHappening": "如果此问题持续出现,运行此聊天的计算机可能负载过重。", - "stopRefused": "{{agent}} 未停止。", - "stopRefusedQuoted": "{{agent}} 未停止:{{detail}}。", - "terminalAgentHoldsChat": "此聊天仍在终端智能体中打开。", + "queueFull": "等待智能体处理的消息过多,因此此消息未发送", + "quitTerminalAgent": "请退出该智能体,以便在此处继续聊天", + "runCommandAgain": "请重新运行 /{{command}}", + "runCommandWhenDone": "完成后再运行 /{{command}}", + "runtimeNotInstalled": "运行此聊天的计算机上未安装 {{agent}}。请在最新版本的 Orca 中从聊天里安装", + "sendAgainToTryOnceMore": "请重新发送您的消息,再试一次", + "sendToTryAgain": "请发送您的消息以重试", + "sessionNotRestored": "{{agent}} 无法重新打开之前的会话,因此此聊天将在新会话中继续。{{agent}} 不记得之前的消息", + "signInFirst": "请先登录", + "signInThenRunCommand": "请登录,然后重新运行 /{{command}}", + "signInThenSend": "请登录,然后重新发送您的消息", + "startNewChat": "请开始新的聊天以继续", + "startTimedOut": "{{agent}} 启动时间过长({{seconds}} 秒后 {{method}} 仍无响应)", + "startTimedOutKeepsHappening": "如果此问题持续出现,运行此聊天的计算机可能负载过重", + "stopRefused": "{{agent}} 未停止", + "stopRefusedQuoted": "{{agent}} 未停止:{{detail}}", + "terminalAgentHoldsChat": "此聊天仍在终端智能体中打开", "theAgent": "智能体", - "thenSendAgain": "然后再次发送消息。", - "usageLimitReached": "{{agent}} 已达到使用上限。", - "usageLimitReachedNamed": "{{agent}} 已达到{{window}}上限。", - "usageLimitResetsAt": "将在 {{when}} 重置。", - "usageLimitSendAfterReset": "重置后发送消息即可继续。", + "thenSendAgain": "然后再次发送消息", + "usageLimitReached": "{{agent}} 已达到使用上限", + "usageLimitReachedNamed": "{{agent}} 已达到{{window}}上限", + "usageLimitResetsAt": "将在 {{when}} 重置", + "usageLimitSendAfterReset": "重置后发送消息即可继续", "usageLimitWindowCredits": "额外用量", "usageLimitWindowSession": "会话", "usageLimitWindowWeekly": "每周", "usageLimitWindowWeeklyModel": "模型每周", - "waitForBackgroundTasks": "请等待后台任务完成。", - "waitForStart": "请等待智能体完成启动。", - "writeFailed": "Orca 无法将此消息交给智能体,因此消息未发送。", - "pluginInputRequired": "{{agent}} 已停止,因为“{{plugin}}”插件正在终端窗格中等待输入。请为聊天会话禁用该插件,或在 {{agent}} 终端中运行任务。" + "waitForBackgroundTasks": "请等待后台任务完成", + "waitForStart": "请等待智能体完成启动", + "writeFailed": "Orca 无法将此消息交给智能体,因此消息未发送", + "pluginInputRequired": "{{agent}} 已停止,因为“{{plugin}}”插件正在终端窗格中等待输入。请为聊天会话禁用该插件,或在 {{agent}} 终端中运行任务。", + "providerUnavailable": "{{agent}} 因服务繁忙而无法回复。请选择其他模型,或稍等片刻后重新发送。", + "providerSafetyStopped": "{{agent}} 在安全检查后停止了此次回复。请检查您的请求后重新发送。", + "providerResponseFailed": "{{agent}} 未能完成此回复。打开详情了解更多信息。", + "selectedModel": "所选模型" }, "fileReader": { "copyReviewNotes": "复制评审备注", @@ -2219,8 +2225,8 @@ "title": "浮动工作区" }, "githubPrMutations": { - "reviewThreadUpdateFailed": "更新评审讨论串失败。", - "titleUpdateFailed": "更新标题失败。" + "reviewThreadUpdateFailed": "更新评审讨论串失败", + "titleUpdateFailed": "更新标题失败" }, "githubPrRpc": { "requestFailed": "请求失败:{{method}}" @@ -2277,18 +2283,18 @@ "nativeChatFullContent": { "loadMessageFailed": "显示完整消息:加载失败,点按重试", "loadOutputFailed": "显示完整输出:加载失败,点按重试", - "partialMessage": "仅显示此消息的部分内容。", - "partialOutput": "正在显示 {{total}} 中的 {{shown}}。", + "partialMessage": "仅显示此消息的部分内容", + "partialOutput": "正在显示 {{total}} 中的 {{shown}}", "showFullMessage": "显示完整消息", "showFullOutput": "显示完整输出" }, "nativeChatRenderData": { "defaultAgentLabel": "智能体", - "emptySubtitle": "让 {{agent}} 检查代码、解释输出或进行更改。", + "emptySubtitle": "让 {{agent}} 检查代码、解释输出或进行更改", "emptyTitle": "与 {{agent}} 开始聊天", - "errorSubtitle": "无法读取记录。请切回终端继续工作。", + "errorSubtitle": "无法读取记录。请切回终端继续工作", "errorTitle": "无法加载对话", - "notFoundSubtitle": "发送消息以开始对话,或打开终端视图,查看 {{agent}} 正在做什么。", + "notFoundSubtitle": "发送消息以开始对话,或打开终端视图,查看 {{agent}} 正在做什么", "notFoundTitle": "暂未找到此对话" }, "nativeChatToggleAction": { @@ -2296,22 +2302,22 @@ "switchToTerminalView": "切换到终端视图" }, "newTabAgentHostLaunch": { - "notesNotSent": "智能体已启动,但笔记未发送。", + "notesNotSent": "智能体已启动,但笔记未发送", "notesSent": "笔记已发送", - "notesUnconfirmed": "智能体已启动,但无法确认笔记是否已发送。", - "promptUnconfirmed": "智能体已启动,但无法确认提示词是否已发送。" + "notesUnconfirmed": "智能体已启动,但无法确认笔记是否已发送", + "promptUnconfirmed": "智能体已启动,但无法确认提示词是否已发送" }, "prActionsEngine": { - "mergeFailed": "合并 PR 失败。", - "refreshFailed": "无法刷新拉取请求。" + "mergeFailed": "合并 PR 失败", + "refreshFailed": "刷新 PR 失败" }, "prAiTriageLaunch": { "agentStarted": "智能体已启动", "agentStartedIn": "智能体已在 {{label}} 中启动", - "emptyPrompt": "此操作保存的提示词为空。请在电脑上更新“源代码控制 AI”设置。", - "loadFailed": "无法加载可用的智能体。", - "promptNotSent": "智能体已启动,但提示词未发送。", - "updateRequired": "请更新电脑上的 Orca,以便从手机启动智能体。" + "emptyPrompt": "此操作保存的提示词为空。请在电脑上更新“源代码控制 AI”设置", + "loadFailed": "无法加载可用的智能体", + "promptNotSent": "智能体已启动,但提示词未发送", + "updateRequired": "请更新电脑上的 Orca,以便从手机启动智能体" }, "prSidebarState": { "loadFailed": "无法加载 PR" @@ -2335,7 +2341,7 @@ "steerHint": "提交且不中断模型" }, "queuedMessageComposer": { - "commandsNotAllowed": "排队消息中不能保存命令。", + "commandsNotAllowed": "排队消息中不能保存命令", "editing": "正在编辑消息" }, "quickCommandEditorForm": { @@ -2345,20 +2351,20 @@ "agent": "智能体", "agentPrompt": "智能体提示", "appendEnter": "追加 Enter", - "appendEnterDescription": "立即提交,而不仅仅是插入文本。", + "appendEnterDescription": "立即提交,而不仅仅是插入文本", "chooseAgent": "选择智能体", "commandText": "命令文本", "globalScope": "全局", "label": "名称", "labelPlaceholder": "启动开发服务器", - "olderHostPromptTooLong": "对此主机来说过长。请在主机上更新 Orca 以保存更长的提示词。", + "olderHostPromptTooLong": "对此主机来说过长。请在主机上更新 Orca 以保存更长的提示词", "projectScope": "项目", "prompt": "提示词", - "promptHint": "支持技能、文件路径和内置命令。", + "promptHint": "支持技能、文件路径和内置命令", "promptPlaceholder": "要求智能体调查此工作区", "promptSizeCharacters": "{{used}} / {{max}} 个字符", "promptSizeKilobytes": "{{used}} KB / {{max}} KB", - "promptTooLong": "内容过长,无法保存。", + "promptTooLong": "内容过长,无法保存", "scope": "范围", "terminalCommand": "终端命令" }, @@ -2376,20 +2382,20 @@ "runCommand": "运行 {{label}}" }, "quickCommandsList": { - "emptyState": "暂无快捷命令。", + "emptyState": "暂无快捷命令", "globalGroup": "全局", "newCommand": "新建快捷命令", - "noMatches": "没有匹配的快捷命令。", + "noMatches": "没有匹配的快捷命令", "projectGroup": "此项目", "searchPlaceholder": "搜索快捷命令…" }, "quickCommandsSheet": { "addTitle": "添加快捷命令", "chooseAgentTitle": "选择智能体", - "deleteConfirmMessage": "该快捷命令将从您保存的列表中删除。", + "deleteConfirmMessage": "该快捷命令将从您保存的列表中删除", "deleteConfirmTitle": "删除“{{label}}”?", "editTitle": "编辑快捷命令", - "editorDescription": "保存终端命令或智能体提示词,便于快速调用。", + "editorDescription": "保存终端命令或智能体提示词,便于快速调用", "title": "快捷命令", "untitled": "无题" }, @@ -2417,14 +2423,14 @@ "discardAndLeave": "放弃并离开", "discardChanges": "放弃更改", "discardMessage": "是否用桌面上的最新文件替换手机草稿?", - "draftsHint": "离开前,请复制或放弃手机上的草稿。", + "draftsHint": "离开前,请复制或放弃手机上的草稿", "file": "文件", "markdown": "Markdown", "markdownNote": "Markdown 笔记", "newBrowser": "新浏览器", "newTab": "新标签页", "notesCopied": "注释已复制", - "notesHint": "选择接收当前注释的智能体会话。", + "notesHint": "选择接收当前注释的智能体会话", "removeShortcutMessage": "移除此自定义快捷键?", "renameTerminal": "重命名终端", "sendReviewNotes": "发送评审备注", @@ -2432,17 +2438,17 @@ "terminal": "终端", "terminalName": "终端名称", "unsavedMarkdown": "未保存的 Markdown 更改", - "urlPrompt": "输入 URL,或留空以新建标签页。", + "urlPrompt": "输入 URL,或留空以新建标签页", "allowAutoClose": "允许自动关闭", "renameTerminalFailed": "无法重命名终端。{{reason}}" }, "sourceControlLaunchAgent": { - "noEnabledAgent": "此工作区主机上未检测到已启用的 AI 智能体。", - "savedAgentUnavailable": "为此操作保存的智能体在此工作区主机上不可用。" + "noEnabledAgent": "此工作区主机上未检测到已启用的 AI 智能体", + "savedAgentUnavailable": "为此操作保存的智能体在此工作区主机上不可用" }, "structuredComposerCommand": { - "operationUnconfirmed": "对话操作未获确认。", - "removeAttachments": "使用聊天会话命令前,请先移除附件。" + "operationUnconfirmed": "对话操作未获确认", + "removeAttachments": "使用聊天会话命令前,请先移除附件" }, "structuredSendDelivery": { "messageNotSent": "消息未发送" @@ -2450,7 +2456,8 @@ "tabStrip": { "checkingCapabilities": "正在检查桌面支持的功能,请稍后重试", "newTab": "新标签页", - "quickCommandsUpdateRequired": "使用快捷命令需更新桌面应用" + "quickCommandsUpdateRequired": "使用快捷命令需更新桌面应用", + "tabStatus": "{{title}},{{status}}" }, "terminalActionSheetActions": { "clearTerminal": "清空终端", @@ -2497,7 +2504,7 @@ "useContentCreateActions": { "browserCommandFailed": "浏览器命令执行失败", "browserCreateFailed": "创建浏览器失败", - "browserUnavailable": "浏览器页面暂不可用。", + "browserUnavailable": "浏览器页面暂不可用", "browserUpdateRequired": "需更新桌面端才能使用移动端浏览器串流", "invalidUrl": "请输入有效的 URL", "noteCreateFailed": "创建 Markdown 笔记失败", @@ -2540,7 +2547,7 @@ "notesCopied": "评审笔记已复制", "notesSent": "评审笔记已发送", "notesSentWithWarning": "评审笔记已发送。{{warning}}", - "promptNotSent": "智能体已启动,但笔记未发送。请使用“复制备注”复制后粘贴。", + "promptNotSent": "智能体已启动,但笔记未发送。请使用“复制备注”复制后粘贴", "sendFailed": "发送笔记失败", "startingAgent": "正在启动智能体…", "waitingForDesktop": "等待桌面连接…" @@ -2589,7 +2596,7 @@ "actionFailed": "评论操作失败" }, "usePrTitleAction": { - "disconnected": "未连接到桌面。" + "disconnected": "未连接到桌面" }, "useQuickCommands": { "loadFailed": "加载快捷命令失败", @@ -2597,16 +2604,16 @@ }, "useSessionTerminalSendActions": { "inputTooLarge": "输入内容过大(最大 256 KiB)", - "liveInputInterrupted": "实时输入已中断,输入框已清空。继续前请检查终端。" + "liveInputInterrupted": "实时输入已中断,输入框已清空。继续前请检查终端" }, "useStartup": { - "wakeAgents": "请在主机上打开 Orca,以唤醒睡眠中的智能体。" + "wakeAgents": "请在主机上打开 Orca,以唤醒睡眠中的智能体" }, "useTerminalCreateActions": { "createFailed": "创建终端失败", - "forkBusy": "另一个终端正在打开,请稍候再尝试打开 {{agentName}} 聊天。", - "forkUnavailable": "请在已连接且已更新的主机上打开 {{agentName}} 聊天,然后重试。", - "inputLocked": "终端输入已被另一个客户端锁定。", + "forkBusy": "另一个终端正在打开,请稍候再尝试打开 {{agentName}} 聊天", + "forkUnavailable": "请在已连接且已更新的主机上打开 {{agentName}} 聊天,然后重试", + "inputLocked": "终端输入已被另一个客户端锁定", "notesSent": "笔记已发送", "sendNotesError": "无法发送笔记", "sendNotesFailed": "发送笔记失败", @@ -2628,82 +2635,82 @@ "fallback": "工作树" }, "writeNotice": { - "agentRefused": "智能体拒绝了此请求。", - "agentStarting": "智能体仍在启动。", - "agentStillWorking": "智能体仍在工作。", - "answerFirst": "请先回答问题或审批。", - "attachmentExpired": "此附件已过期。", - "backgroundTasksRunning": "后台任务仍在运行。", - "cancelNotSaved": "无法取消此问题或审批。", - "cannotRunHere": "Orca 无法在此处以聊天方式运行此智能体。", - "capacity": "运行此聊天的计算机上的 Orca 已达到请求上限。请在那台计算机上更新 Orca,然后重试。", - "chatNotFound": "Orca 找不到此聊天。", - "chatSavedByNewerOrca": "此聊天由更新版本的 Orca 保存。", - "clearAfterAnswer": "请先回答智能体的问题或审批,然后再运行 /clear。", - "clearAfterRetry": "请先重试您之前的消息,然后再运行 /clear。", - "clearAfterSending": "您之前的消息仍在发送中。发送完成后再运行 /clear。", - "clearUnfinished": "上一次 /clear 未完成。", - "commandRunning": "/compact 或 /clear 仍在运行。", - "compactAfterAnswer": "请先回答智能体的问题或审批,然后再运行 /compact。", - "compactAfterRetry": "请先重试您之前的消息,然后再运行 /compact。", - "compactAfterSending": "您之前的消息仍在发送中。发送完成后再运行 /compact。", - "continuationSuperseded": "此聊天已有后续进展。请查看最新消息后再继续。", - "conversationCleared": "此对话已被清除。", - "goalsUnsupported": "此智能体不支持目标。", - "historyUnavailable": "Orca 目前无法打开此聊天的历史记录。", - "historyUnreadable": "Orca 无法读取此聊天的已保存历史记录。", - "historyUnusable": "无法加载此聊天。", - "hostReconciling": "Orca 重启后仍在检查此聊天。", - "messageNotSaved": "无法保存您的消息。", - "messageTooLarge": "超过了单条消息 256 KB 的上限。", - "messagesUnsettled": "您之前发送的一条消息尚未确认。", - "notAvailable": "此聊天中无法使用此功能。", - "notDoneAnswer": "您的回答未发送。", - "notDoneCommand": "命令未运行。", - "notDoneGoalChangeIncomplete": "未能完成更改目标。请查看聊天。", - "notDoneOption": "设置未更改。", - "notDoneQueuedEdit": "你的编辑未保存。", - "notDoneReadHistory": "无法加载此聊天的历史记录。", - "notDoneSend": "您的消息未发送。", - "notDoneStop": "智能体未停止。", - "notDoneStopTask": "后台任务未停止。", - "notDoneStopTasks": "后台任务未停止。", - "openCurrentConversation": "请打开当前对话以继续。", - "optionRejected": "智能体未接受此设置。", - "outcomeUnknown": "Orca 无法确认发生了什么。请查看聊天。", - "ownerUnproven": "此聊天之前的智能体可能仍在运行。", - "pendingWork": "在使用此命令之前,请等待挂起的工作和消息完成。", - "promptPending": "智能体正在等待您回答问题或审批。", - "questionChanged": "此问题已被回答或已更改。", - "queueTooLarge": "队列中等待的文本过多。", - "quitTerminalAgent": "请退出该智能体,以便在此处继续聊天。", - "reattachFile": "请将其移除后重新附加。", + "agentRefused": "智能体拒绝了此请求", + "agentStarting": "智能体仍在启动", + "agentStillWorking": "智能体仍在工作", + "answerFirst": "请先回答问题或审批", + "attachmentExpired": "此附件已过期", + "backgroundTasksRunning": "后台任务仍在运行", + "cancelNotSaved": "无法取消此问题或审批", + "cannotRunHere": "Orca 无法在此处以聊天方式运行此智能体", + "capacity": "运行此聊天的计算机上的 Orca 已达到请求上限。请在那台计算机上更新 Orca,然后重试", + "chatNotFound": "Orca 找不到此聊天", + "chatSavedByNewerOrca": "此聊天由更新版本的 Orca 保存", + "clearAfterAnswer": "请先回答智能体的问题或审批,然后再运行 /clear", + "clearAfterRetry": "请先重试您之前的消息,然后再运行 /clear", + "clearAfterSending": "您之前的消息仍在发送中。发送完成后再运行 /clear", + "clearUnfinished": "上一次 /clear 未完成", + "commandRunning": "/compact 或 /clear 仍在运行", + "compactAfterAnswer": "请先回答智能体的问题或审批,然后再运行 /compact", + "compactAfterRetry": "请先重试您之前的消息,然后再运行 /compact", + "compactAfterSending": "您之前的消息仍在发送中。发送完成后再运行 /compact", + "continuationSuperseded": "此聊天已有后续进展。请查看最新消息后再继续", + "conversationCleared": "此对话已被清除", + "goalsUnsupported": "此智能体不支持目标", + "historyUnavailable": "Orca 目前无法打开此聊天的历史记录", + "historyUnreadable": "Orca 无法读取此聊天的已保存历史记录", + "historyUnusable": "无法加载此聊天", + "hostReconciling": "Orca 重启后仍在检查此聊天", + "messageNotSaved": "无法保存您的消息", + "messageTooLarge": "超过了单条消息 256 KB 的上限", + "messagesUnsettled": "您之前发送的一条消息尚未确认", + "notAvailable": "此聊天中无法使用此功能", + "notDoneAnswer": "您的回答未发送", + "notDoneCommand": "命令未运行", + "notDoneGoalChangeIncomplete": "未能完成更改目标。请查看聊天", + "notDoneOption": "设置未更改", + "notDoneQueuedEdit": "你的编辑未保存", + "notDoneReadHistory": "无法加载此聊天的历史记录", + "notDoneSend": "您的消息未发送", + "notDoneStop": "智能体未停止", + "notDoneStopTask": "后台任务未停止", + "notDoneStopTasks": "后台任务未停止", + "openCurrentConversation": "请打开当前对话以继续", + "optionRejected": "智能体未接受此设置", + "outcomeUnknown": "Orca 无法确认发生了什么。请查看聊天", + "ownerUnproven": "此聊天之前的智能体可能仍在运行", + "pendingWork": "在使用此命令之前,请等待挂起的工作和消息完成", + "promptPending": "智能体正在等待您回答问题或审批", + "questionChanged": "此问题已被回答或已更改", + "queueTooLarge": "队列中等待的文本过多", + "quitTerminalAgent": "请退出该智能体,以便在此处继续聊天", + "reattachFile": "请将其移除后重新附加", "reattachFiles": "请将它们移除后重新附加。", - "recordFailed": "Orca 无法将此内容保存到聊天历史记录中。", - "recordUnreadable": "Orca 无法读取此聊天的已保存状态。", - "reopenChat": "请重新打开聊天以再次检查。", - "restartFailed": "智能体无法重新启动。", - "runClearWhenDone": "完成后再运行 /clear。", - "runCompactWhenDone": "完成后再运行 /compact。", - "savedByNewerOrca": "这些聊天由更新版本的 Orca 保存。", - "sendOutcomeLost": "Orca 无法确认你的消息已送达智能体。请查看聊天,如有需要请重新发送。", - "settleEarlierMessage": "请等待之前的消息送达,或重试该消息。", - "shortenMessage": "请缩短或拆分后再发送。", - "shrinkQueue": "请删除一条排队的消息,或等待其送达,然后重试。", - "startNewChat": "请开始新的聊天以继续。", - "terminalAgentHoldsChat": "此聊天仍在终端智能体中打开。", - "tryAgain": "请重试。", - "tryAgainComposerSend": "请重新发送。", - "turnActive": "智能体仍在回复。", - "unreachable": "Orca 无法连接到智能体。", - "unsupported": "运行此聊天的计算机需要更新版本的 Orca。请在该计算机上更新 Orca 后重试。", - "updateOrcaToKeepUsing": "请更新 Orca 以继续使用这些聊天。", - "updateOrcaToOpenChat": "请更新 Orca 以打开它。", - "waitForBackgroundTasks": "请等待后台任务完成。", - "waitForCommand": "请等待 /compact 或 /clear 完成。", - "waitForStart": "请等待智能体完成启动。", - "waitForTurn": "请等待智能体完成回复,或将其停止。", - "waitMoment": "请稍候。" + "recordFailed": "Orca 无法将此内容保存到聊天历史记录中", + "recordUnreadable": "Orca 无法读取此聊天的已保存状态", + "reopenChat": "请重新打开聊天以再次检查", + "restartFailed": "智能体无法重新启动", + "runClearWhenDone": "完成后再运行 /clear", + "runCompactWhenDone": "完成后再运行 /compact", + "savedByNewerOrca": "这些聊天由更新版本的 Orca 保存", + "sendOutcomeLost": "Orca 无法确认你的消息已送达智能体。请查看聊天,如有需要请重新发送", + "settleEarlierMessage": "请等待之前的消息送达,或重试该消息", + "shortenMessage": "请缩短或拆分后再发送", + "shrinkQueue": "请删除一条排队的消息,或等待其送达,然后重试", + "startNewChat": "请开始新的聊天以继续", + "terminalAgentHoldsChat": "此聊天仍在终端智能体中打开", + "tryAgain": "请重试", + "tryAgainComposerSend": "请重新发送", + "turnActive": "智能体仍在回复", + "unreachable": "Orca 无法连接到智能体", + "unsupported": "运行此聊天的计算机需要更新版本的 Orca。请在该计算机上更新 Orca 后重试", + "updateOrcaToKeepUsing": "请更新 Orca 以继续使用这些聊天", + "updateOrcaToOpenChat": "请更新 Orca 以打开它", + "waitForBackgroundTasks": "请等待后台任务完成", + "waitForCommand": "请等待 /compact 或 /clear 完成", + "waitForStart": "请等待智能体完成启动", + "waitForTurn": "请等待智能体完成回复,或将其停止", + "waitMoment": "请稍候" }, "workerAutoClose": { "running": "临时协作工作者 · 完成 2 分钟后关闭", @@ -2754,7 +2761,7 @@ }, "settings": { "aboutScreen": { - "openLinkFailed": "无法打开链接。请重试。", + "openLinkFailed": "无法打开链接。请重试", "socialProfile": "Orca 的 X 主页", "sourceCode": "Orca 源代码", "tagline": "助力开发者百倍提效的开源智能体 IDE", @@ -2781,13 +2788,13 @@ }, "appearance": { "language": { - "description": "选择“系统”时,将跟随此设备的语言。权限提示始终使用设备语言。", + "description": "选择“系统”时,将跟随此设备的语言。权限提示始终使用设备语言", "heading": "语言", "systemWithCurrent": "系统({{language}})" }, "theme": { "dark": "深色", - "description": "选择“系统”时,将跟随此设备的浅色或深色设置。", + "description": "选择“系统”时,将跟随此设备的浅色或深色设置", "heading": "主题", "light": "浅色", "system": "系统" @@ -2796,14 +2803,14 @@ }, "browserSettingsScreen": { "desktopBrowser": "桌面 Orca 浏览器", - "desktopBrowserDescription": "在已配对桌面通过串流提供的浏览器中打开。", - "linksDescription": "选择点按终端输出中的 HTTP(S) 链接时使用的浏览器。", + "desktopBrowserDescription": "在已配对桌面通过串流提供的浏览器中打开", + "linksDescription": "选择点按终端输出中的 HTTP(S) 链接时使用的浏览器", "linksHeading": "链接", - "loadFailed": "无法加载浏览器偏好设置。请重试。", + "loadFailed": "无法加载浏览器偏好设置。请重试", "openTerminalLinks": "打开终端链接", "phoneBrowser": "手机浏览器", - "phoneBrowserDescription": "在此手机的 Safari、Chrome 或其他浏览器中打开。", - "saveFailed": "无法保存浏览器偏好设置。请重试。", + "phoneBrowserDescription": "在此手机的 Safari、Chrome 或其他浏览器中打开", + "saveFailed": "无法保存浏览器偏好设置。请重试", "title": "浏览器" }, "menuItems": { @@ -2821,7 +2828,7 @@ "support": "支持" }, "nativeChatSettingsScreen": { - "defaultViewDescription": "选择受支持的智能体会话(Claude、Codex 及其他支持聊天的智能体)在此设备上的打开方式。终端显示原始 CLI;聊天界面则显示与桌面应用类似的聊天界面。您仍可通过长按菜单切换单个会话的视图。", + "defaultViewDescription": "选择受支持的智能体会话(Claude、Codex 及其他支持聊天的智能体)在此设备上的打开方式。终端显示原始 CLI;聊天界面则显示与桌面应用类似的聊天界面。您仍可通过长按菜单切换单个会话的视图", "defaultViewHeading": "默认视图", "off": "关闭", "on": "开启", @@ -2829,21 +2836,21 @@ "title": "聊天界面" }, "nativeNotificationDeliverySettings": { - "loadFailed": "无法加载通知投递设置。请重新打开此页面重试。", - "saveFailed": "无法保存通知投递设置。请重试。", - "updateDesktopHint": "配对已更新的桌面,即可在此手机上接收通知。" + "loadFailed": "无法加载通知投递设置。请重新打开此页面重试", + "saveFailed": "无法保存通知投递设置。请重试", + "updateDesktopHint": "配对已更新的桌面,即可在此手机上接收通知" }, "notificationDisplayTest": { - "accepted": "Orca 推送服务已接受请求。请查看通知。", - "connectDesktop": "请先连接桌面,然后重试。", + "accepted": "Orca 推送服务已接受请求。请查看通知", + "connectDesktop": "请先连接桌面,然后重试", "description": "测试推送送达;推送不可用时,测试本地通知。", - "desktopUnreachable": "无法连接到桌面。请重试。", - "loadFailed": "无法加载已配对的桌面。", - "pairDesktop": "请先配对桌面,然后重试。", - "pushServiceFailed": "无法通过 Orca 推送服务发送。请重试。", - "rateLimited": "通知发送过于频繁。请稍后重试。", + "desktopUnreachable": "无法连接到桌面。请重试", + "loadFailed": "无法加载已配对的桌面", + "pairDesktop": "请先配对桌面,然后重试", + "pushServiceFailed": "无法通过 Orca 推送服务发送。请重试", + "rateLimited": "通知发送过于频繁。请稍后重试", "sendButton": "发送测试通知", - "sendFailed": "无法发送测试推送。", + "sendFailed": "无法发送测试推送", "sending": "正在发送…", "troubleReceivingAlerts": "接收提醒遇到问题?", "troubleshooting": "故障排查", @@ -2858,40 +2865,40 @@ "liveFallbackScheduled": "{{reason}} 已安排本地测试。请检查通知。Orca 运行且保持连接时,可接收实时提醒。" }, "notificationSettingsScreen": { - "description": "智能体需要您提供输入或已完成任务时,在此设备上接收通知。", + "description": "智能体需要您提供输入或已完成任务时,在此设备上接收通知", "enableNotifications": "启用通知", - "loadFailed": "无法加载通知设置。请重试。", - "notificationsBlocked": "系统设置中已禁用通知。", + "loadFailed": "无法加载通知设置。请重试", + "notificationsBlocked": "系统设置中已禁用通知", "openSettings": "打开设置", - "openSettingsFailed": "无法打开系统设置。请重试。", - "saveFailed": "无法保存通知设置。请重试。", + "openSettingsFailed": "无法打开系统设置。请重试", + "saveFailed": "无法保存通知设置。请重试", "title": "通知" }, "pendingCredentialCleanupCard": { - "cleanupUnconfirmed_one": "无法确认此设备上的 {{count}} 个凭据是否已清理。", - "cleanupUnconfirmed_other": "无法确认此设备上的 {{count}} 个凭据是否已清理。", + "cleanupUnconfirmed_one": "无法确认此设备上的 {{count}} 个凭据是否已清理", + "cleanupUnconfirmed_other": "无法确认此设备上的 {{count}} 个凭据是否已清理", "retryCleanup": "重试清除配对凭据", - "retryFailed": "仍无法确认清理结果。请稍后重试。", - "statusCheckFailed": "无法检查此设备上的清理状态。为确保安全,请重试。", + "retryFailed": "仍无法确认清理结果。请稍后重试", + "statusCheckFailed": "无法检查此设备上的清理状态。为确保安全,请重试", "title": "配对凭据清理" }, "uiLanguageSettingsSection": { "pseudoLanguage": "伪本地化(en-XA)" }, "voiceSettingsScreen": { - "connectDesktop": "连接到桌面后即可管理语音设置。", + "connectDesktop": "连接到桌面后即可管理语音设置", "deleteFailed": "删除失败", - "dictationDescription": "通过听写向桌面上任意获得焦点的窗格输入文本。", + "dictationDescription": "通过听写向桌面上任意获得焦点的窗格输入文本", "dictationHeading": "听写", "dictationMode": "听写模式", - "dictationModeDescription": "切换:按一次开始,再按一次停止。按住:按住期间进行听写。", + "dictationModeDescription": "切换:按一次开始,再按一次停止。按住:按住期间进行听写", "dictationModeWithAutoDescription": "自动:轻按开始和停止;在电脑上按住快捷键会一直录音,直到松开。按住:按住期间进行听写。切换:按一次开始,再按一次停止。", "autoMode": "自动", "downloadFailed": "下载失败", "enableDictation": "启用语音听写", "holdMode": "按住", "loadFailed": "加载语音设置失败", - "loadFailedMessage": "加载语音设置失败。", + "loadFailedMessage": "加载语音设置失败", "noneSelected": "未选择", "selectModelFailed": "无法选择模型", "speechModel": "语音模型", @@ -2924,31 +2931,31 @@ "waitingForDesktop": "正在等待桌面…" }, "actions": { - "checkingReviewStatus": "正在检查评审状态。", - "checkoutBeforePublish": "请先检出分支再发布提交。", - "commitStagedChanges": "提交已暂存的更改。", - "committing": "正在提交。", + "checkingReviewStatus": "正在检查评审状态", + "checkoutBeforePublish": "请先检出分支再发布提交", + "commitStagedChanges": "提交已暂存的更改", + "committing": "正在提交", "createPr": "创建PR", - "enterCommitMessage": "请输入提交信息后再提交。", - "forcePushWithLease": "使用 lease 强制推送以更新远程分支。", - "forcePushing": "正在强制推送。", - "linkedReviewUnavailable": "关联的评审分支不可用。", - "publishToOrigin": "将此分支发布到 origin。", - "pullCommits_one": "拉取 {{count}} 个提交。", - "pullCommits_other": "拉取 {{count}} 个提交。", + "enterCommitMessage": "请输入提交信息后再提交", + "forcePushWithLease": "使用 lease 强制推送以更新远程分支", + "forcePushing": "正在强制推送", + "linkedReviewUnavailable": "关联的评审分支不可用", + "publishToOrigin": "将此分支发布到 origin", + "pullCommits_one": "拉取 {{count}} 个提交", + "pullCommits_other": "拉取 {{count}} 个提交", "pushAndCreatePr": "推送并创建 PR", - "pushCommits_one": "推送 {{count}} 个提交。", - "pushCommits_other": "推送 {{count}} 个提交。", - "pushLinkedReview": "将更新推送到关联的评审分支。", - "remoteOperationInProgress": "正在执行远程操作。", - "resolveConflicts": "请先解决冲突再提交。", - "reviewAlreadyMerged": "没有可提交的内容。评审已合并。", - "stageAllChanges": "暂存全部更改。", - "stageFileToCommit": "请至少暂存一个文件后再提交。", + "pushCommits_one": "推送 {{count}} 个提交", + "pushCommits_other": "推送 {{count}} 个提交", + "pushLinkedReview": "将更新推送到关联的评审分支", + "remoteOperationInProgress": "正在执行远程操作", + "resolveConflicts": "请先解决冲突再提交", + "reviewAlreadyMerged": "没有可提交的内容。评审已合并", + "stageAllChanges": "暂存全部更改", + "stageFileToCommit": "请至少暂存一个文件后再提交", "switchBranch": "切换分支", - "syncCounts": "拉取 {{behind}} 个提交,推送 {{ahead}} 个提交。", - "upToDate": "没有可提交的内容。分支已是最新状态。", - "waitForRemoteOperation": "请在远程操作完成后重试。" + "syncCounts": "拉取 {{behind}} 个提交,推送 {{ahead}} 个提交", + "upToDate": "没有可提交的内容。分支已是最新状态", + "waitForRemoteOperation": "请在远程操作完成后重试" }, "branchBaseRef": { "resolveFailed": "无法解析基础分支" @@ -2961,7 +2968,7 @@ "sectionTitle": "已提交的更改" }, "branchCompareOutcome": { - "baseBranchUnavailable": "无法解析用于比较的基础分支。", + "baseBranchUnavailable": "无法解析用于比较的基础分支", "loadFailed": "无法加载已提交的更改" }, "commitDropdown": { @@ -2994,7 +3001,7 @@ "hideFailureDetails": "隐藏提交失败详情", "showDetails": "显示详情", "showFailureDetails": "显示提交失败详情", - "summary": "提交失败。", + "summary": "提交失败", "title": "提交失败" }, "commitMessageAi": { @@ -3012,13 +3019,13 @@ }, "content": { "cancelGeneration": "取消生成提交信息", - "commitMessageDisabled": "提交信息输入已禁用。没有已暂存的文件。", + "commitMessageDisabled": "提交信息输入已禁用。没有已暂存的文件", "commitMessagePlaceholder": "提交信息", - "emptyMessage": "工作树无更改。", + "emptyMessage": "工作树无更改", "emptyTitle": "无本地更改", "generateMessage": "使用 AI 生成提交信息", "reconnecting": "正在重新连接桌面…", - "regenerateHint": "清除消息以重新生成。" + "regenerateHint": "清除消息以重新生成" }, "createPrAction": { "checkingStatus": "正在检查评审状态…", @@ -3036,16 +3043,16 @@ "pushCount_other": "推送 {{count}} 个提交", "remoteBranchFallback": "远程分支", "syncCounts": "拉取 {{behind}} 个,推送 {{ahead}} 个", - "titleForcePushOlderCopiesBranch": "远程只有本地提交的旧副本。使用 lease 强制推送此分支以更新 {{upstreamName}}。", - "titleForcePushOlderCopiesCount_one": "远程只有本地提交的旧副本。使用 lease 强制推送 {{count}} 个分支提交以更新 {{upstreamName}}。", - "titleForcePushOlderCopiesCount_other": "远程只有本地提交的旧副本。使用 lease 强制推送 {{count}} 个分支提交以更新 {{upstreamName}}。", - "titleManualForcePushReplaceRemote_one": "使用 lease 强制推送 {{count}} 个本地提交以更新 {{upstreamName}},并替换仅存在于远程的提交。", - "titleManualForcePushReplaceRemote_other": "使用 lease 强制推送 {{count}} 个本地提交以更新 {{upstreamName}},并替换仅存在于远程的提交。", - "titleManualForcePush_one": "使用 lease 强制推送 {{count}} 个本地提交以更新 {{upstreamName}}。", - "titleManualForcePush_other": "使用 lease 强制推送 {{count}} 个本地提交以更新 {{upstreamName}}。", - "titleUnpublishedForcePushBranch": "使用 lease 强制推送此分支,并在需要时设置上游。", - "titleUnpublishedForcePushCount_one": "使用 lease 强制推送 {{count}} 个分支提交,并在需要时设置上游。", - "titleUnpublishedForcePushCount_other": "使用 lease 强制推送 {{count}} 个分支提交,并在需要时设置上游。" + "titleForcePushOlderCopiesBranch": "远程只有本地提交的旧副本。使用 lease 强制推送此分支以更新 {{upstreamName}}", + "titleForcePushOlderCopiesCount_one": "远程只有本地提交的旧副本。使用 lease 强制推送 {{count}} 个分支提交以更新 {{upstreamName}}", + "titleForcePushOlderCopiesCount_other": "远程只有本地提交的旧副本。使用 lease 强制推送 {{count}} 个分支提交以更新 {{upstreamName}}", + "titleManualForcePushReplaceRemote_one": "使用 lease 强制推送 {{count}} 个本地提交以更新 {{upstreamName}},并替换仅存在于远程的提交", + "titleManualForcePushReplaceRemote_other": "使用 lease 强制推送 {{count}} 个本地提交以更新 {{upstreamName}},并替换仅存在于远程的提交", + "titleManualForcePush_one": "使用 lease 强制推送 {{count}} 个本地提交以更新 {{upstreamName}}", + "titleManualForcePush_other": "使用 lease 强制推送 {{count}} 个本地提交以更新 {{upstreamName}}", + "titleUnpublishedForcePushBranch": "使用 lease 强制推送此分支,并在需要时设置上游", + "titleUnpublishedForcePushCount_one": "使用 lease 强制推送 {{count}} 个分支提交,并在需要时设置上游", + "titleUnpublishedForcePushCount_other": "使用 lease 强制推送 {{count}} 个分支提交,并在需要时设置上游" }, "fileRows": { "addedByThem": "对方已添加", @@ -3053,7 +3060,7 @@ "bothAdded": "双方均已添加", "bothDeleted": "双方均已删除", "bothModified": "双方均已修改", - "committedUnavailable": "已提交的更改不可用。", + "committedUnavailable": "已提交的更改不可用", "deletedByThem": "对方已删除", "deletedByUs": "我方已删除", "loadingCommitted": "正在加载已提交的更改…", @@ -3082,7 +3089,7 @@ "gitHistoryList": { "loadFailed": "加载历史记录失败", "loadFilesFailed": "无法加载提交文件", - "noCommits": "暂无提交。", + "noCommits": "暂无提交", "noFileChanges": "无文件更改", "retryFiles": "重试加载提交文件", "waitingForDesktop": "正在等待桌面…" @@ -3125,17 +3132,17 @@ "pushSucceeded": "推送成功,但创建 {{shortLabel}} 失败:{{error}}" }, "hostedReviewCreateIntent": { - "branchChanged": "准备创建 PR 时分支发生了变化。", - "generateMessageFailed": "无法生成提交信息。请在“源代码控制”中填写后重试。", - "resolveConflicts": "请先解决冲突,再创建 PR。", - "resolveOrStageChanges": "请先处理或暂存更改,再创建 PR。", - "reviewCommitMessage": "请先检查提交信息,然后重试创建 PR。" + "branchChanged": "准备创建 PR 时分支发生了变化", + "generateMessageFailed": "无法生成提交信息。请在“源代码控制”中填写后重试", + "resolveConflicts": "请先解决冲突,再创建 PR", + "resolveOrStageChanges": "请先处理或暂存更改,再创建 PR", + "reviewCommitMessage": "请先检查提交信息,然后重试创建 PR" }, "hostedReviewGitPreparation": { "commitFailed": "提交失败", "refreshFailed": "无法刷新源代码控制", "stageFailed": "暂存更改失败", - "updateBranchFailed": "无法更新远程分支。请重试创建 PR。" + "updateBranchFailed": "无法更新远程分支。请重试创建 PR" }, "hostedReviewRemotePrerequisite": { "forcePushFailed": "使用 lease 强制推送失败", @@ -3144,7 +3151,7 @@ }, "hostedReviewService": { "createFailed": "创建 PR 失败", - "pushBeforeCreateFailed": "推送失败。请解决推送错误后重试。" + "pushBeforeCreateFailed": "推送失败。请解决推送错误后重试" }, "hubTab": { "changes": "更改" @@ -3152,13 +3159,13 @@ "loaders": { "connectingToDesktop": "正在连接桌面…", "loadFailed": "无法加载源代码控制", - "updateDesktop": "请更新 Orca 桌面端,以在手机上使用源代码控制。", + "updateDesktop": "请更新 Orca 桌面端,以在手机上使用源代码控制", "waitingForDesktop": "正在等待桌面…" }, "modals": { "currentBranch": "当前", "discardButton": "放弃", - "discardConfirmMessage": "放弃对“{{path}}”的更改?此操作无法撤销。", + "discardConfirmMessage": "放弃对“{{path}}”的更改?此操作无法撤销", "discardTitle": "放弃更改", "openPrMessage": "在浏览器中打开?", "openPrWithWarning": "在浏览器中打开?\n\n{{warning}}", @@ -3169,22 +3176,22 @@ "unavailableTitle": "源代码控制不可用" }, "prCreate": { - "authRequired": "请在创建 {{reviewLabel}} 之前完成身份验证。", - "baseNotOnRemote": "请先推送基础分支,再创建 {{reviewLabel}}。", - "createdNotRefreshed": "{{titleLabel}} 已创建,但 Orca 暂时无法刷新其信息。", - "defaultBranch": "请在创建 {{reviewLabel}} 之前切换到功能分支。", - "detachedHead": "请在创建 {{reviewLabel}} 之前检出分支。", - "dirty": "请在创建 {{reviewLabel}} 之前提交更改。", - "existing": "{{titleLabel}} 已处于开放状态。", - "existingNumber": "{{titleLabel}} #{{number}} 已处于开放状态。", - "existingReview": "此分支已存在 {{reviewLabel}}。", - "forkHeadUnsupported": "不支持从此复刻仓库创建 {{reviewLabel}}。", - "lookupUnconfirmed": "Orca 无法确认此分支是否已有 {{reviewLabel}}。请稍后重试。", - "needsSync": "请在创建 {{reviewLabel}} 之前同步此分支。", - "noUpstream": "请在创建 {{reviewLabel}} 之前发布提交。", - "notReady": "此分支尚不具备创建 {{reviewLabel}} 的条件。", - "unsupportedMergeRequests": "此仓库不支持创建合并请求。", - "unsupportedPullRequests": "此仓库不支持创建 PR。" + "authRequired": "请在创建 {{reviewLabel}} 之前完成身份验证", + "baseNotOnRemote": "请先推送基础分支,再创建 {{reviewLabel}}", + "createdNotRefreshed": "{{titleLabel}} 已创建,但 Orca 暂时无法刷新其信息", + "defaultBranch": "请在创建 {{reviewLabel}} 之前切换到功能分支", + "detachedHead": "请在创建 {{reviewLabel}} 之前检出分支", + "dirty": "请在创建 {{reviewLabel}} 之前提交更改", + "existing": "{{titleLabel}} 已处于开放状态", + "existingNumber": "{{titleLabel}} #{{number}} 已处于开放状态", + "existingReview": "此分支已存在 {{reviewLabel}}", + "forkHeadUnsupported": "不支持从此复刻仓库创建 {{reviewLabel}}", + "lookupUnconfirmed": "Orca 无法确认此分支是否已有 {{reviewLabel}}。请稍后重试", + "needsSync": "请在创建 {{reviewLabel}} 之前同步此分支", + "noUpstream": "请在创建 {{reviewLabel}} 之前发布提交", + "notReady": "此分支尚不具备创建 {{reviewLabel}} 的条件", + "unsupportedMergeRequests": "此仓库不支持创建合并请求", + "unsupportedPullRequests": "此仓库不支持创建 PR" }, "prLink": { "updatePullRequestFailed": "更新关联的 PR 失败", @@ -3258,84 +3265,84 @@ "syncStatus": "领先 {{ahead}},落后 {{behind}}" }, "textGenerationFailure": { - "agentBinaryNotFound": "在 PATH 中找不到 {{binary}}。请安装 {{label}} 以使用 AI 提交信息。", - "agentCannotGenerateBranchName": "智能体“{{agent}}”不支持源代码控制 AI 分支名称。支持的智能体:{{agents}},或选择“自定义命令”。", - "agentCannotGenerateChatName": "智能体“{{agent}}”不支持聊天名称。支持的智能体:{{agents}},或选择“自定义命令”。", - "agentCannotGenerateCommitMessage": "智能体“{{agent}}”不支持源代码控制 AI 提交信息。支持的智能体:{{agents}},或选择“自定义命令”。", - "agentCannotGeneratePullRequest": "智能体“{{agent}}”不支持源代码控制 AI PR 详情。支持的智能体:{{agents}},或选择“自定义命令”。", - "agentCouldNotStart": "无法启动 {{label}}。请在设置中检查智能体命令后重试。", - "agentFailedToStart": "{{label}} 启动失败。请在设置中检查智能体命令后重试。", - "agentReportedError": "{{label}} 报告了错误。", - "antigravityInvalidEvents": "Antigravity 返回了无效的 JSON 事件。", - "antigravityInvalidResult": "Antigravity 返回了无效的结果。", - "antigravityNoFinalResult": "Antigravity 未返回最终结果。", - "chatNameAgentUnsupported": "请在设置 -> 聊天 -> 聊天名称中为此操作选择支持的聊天命名智能体。支持的智能体:{{agents}},或选择“自定义命令”。", - "chatNameCustomCommandEmpty": "自定义命令为空。请在设置 -> 聊天 -> 聊天名称中添加。", - "cliFailed": "{{label}} CLI 命令执行失败,退出码为 {{exitCode}}。", + "agentBinaryNotFound": "在 PATH 中找不到 {{binary}}。请安装 {{label}} 以使用 AI 提交信息", + "agentCannotGenerateBranchName": "智能体“{{agent}}”不支持源代码控制 AI 分支名称。支持的智能体:{{agents}},或选择“自定义命令”", + "agentCannotGenerateChatName": "智能体“{{agent}}”不支持聊天名称。支持的智能体:{{agents}},或选择“自定义命令”", + "agentCannotGenerateCommitMessage": "智能体“{{agent}}”不支持源代码控制 AI 提交信息。支持的智能体:{{agents}},或选择“自定义命令”", + "agentCannotGeneratePullRequest": "智能体“{{agent}}”不支持源代码控制 AI PR 详情。支持的智能体:{{agents}},或选择“自定义命令”", + "agentCouldNotStart": "无法启动 {{label}}。请在设置中检查智能体命令后重试", + "agentFailedToStart": "{{label}} 启动失败。请在设置中检查智能体命令后重试", + "agentReportedError": "{{label}} 报告了错误", + "antigravityInvalidEvents": "Antigravity 返回了无效的 JSON 事件", + "antigravityInvalidResult": "Antigravity 返回了无效的结果", + "antigravityNoFinalResult": "Antigravity 未返回最终结果", + "chatNameAgentUnsupported": "请在设置 -> 聊天 -> 聊天名称中为此操作选择支持的聊天命名智能体。支持的智能体:{{agents}},或选择“自定义命令”", + "chatNameCustomCommandEmpty": "自定义命令为空。请在设置 -> 聊天 -> 聊天名称中添加", + "cliFailed": "{{label}} CLI 命令执行失败,退出码为 {{exitCode}}", "cliFailedWithDetail": "{{label}} CLI 命令执行失败,退出码为 {{exitCode}}:{{detail}}", - "cliTerminated": "{{label}} CLI 命令在退出前被终止。", + "cliTerminated": "{{label}} CLI 命令在退出前被终止", "cliTerminatedWithDetail": "{{label}} CLI 命令在退出前被终止:{{detail}}", - "commandTemplateEmptyBranchName": "分支名称的命令模板为空。", - "commandTemplateEmptyChatName": "聊天名称的命令模板为空。", - "commandTemplateEmptyCommitMessage": "提交信息的命令模板为空。", - "commandTemplateEmptyPullRequest": "PR 详情的命令模板为空。", - "commitMessageUnparseable": "无法解析生成的提交信息。", - "emptyCommitMessage": "{{label}} 返回了空消息。", + "commandTemplateEmptyBranchName": "分支名称的命令模板为空", + "commandTemplateEmptyChatName": "聊天名称的命令模板为空", + "commandTemplateEmptyCommitMessage": "提交信息的命令模板为空", + "commandTemplateEmptyPullRequest": "PR 详情的命令模板为空", + "commitMessageUnparseable": "无法解析生成的提交信息", + "emptyCommitMessage": "{{label}} 返回了空消息", "emptyCommitMessageWithDetail": "{{label}} 返回了空消息。CLI 输出:{{detail}}", - "emptyJiraSummary": "{{label}} 返回的标题为空。", + "emptyJiraSummary": "{{label}} 返回的标题为空", "emptyJiraSummaryWithDetail": "{{label}} 返回的标题为空。CLI 输出:{{detail}}", - "emptyPullRequestDetails": "{{label}} 返回了空的详细信息。", + "emptyPullRequestDetails": "{{label}} 返回了空的详细信息", "emptyPullRequestDetailsWithDetail": "{{label}} 返回了空的详细信息。CLI 输出:{{detail}}", - "jiraAccountDisconnected": "请在此主机上重新连接所选的 Jira 账户。", - "jiraDescriptionRequired": "描述为必填项。", - "jiraSummaryBusyInOtherDraft": "另一个草稿中已在生成 Jira 标题。", - "jiraSummaryEmptyAfterSanitization": "生成的标题在清理后为空。", - "kimiAgentChangeOnResume": "Kimi 无法在恢复会话时更改智能体。请修改生成预设或 CLI 参数,移除智能体覆盖设置或改为启动新会话。", - "kimiAgentOptionsConflict": "Kimi 收到了冲突或重复的智能体选项。请在生成预设或 CLI 参数中仅保留一个 --agent 或 --agent-file 选项,然后重试。", - "kimiAuthFailed": "Kimi 无法通过身份验证。请在执行主机上登录或修正提供者凭据,然后重试。", - "kimiCancelled": "Kimi 在完成文本生成前取消了请求。请重试。", - "kimiConfigInvalid": "Kimi 的配置无效。请在重试前检查执行主机上的模型和提供者配置。", - "kimiConflictingOptions": "Kimi 收到了冲突的选项:{{option}} 与 {{otherOption}}。请在重试前修正生成预设或 CLI 参数。", - "kimiConnectionFailed": "Kimi 无法连接到提供者。请检查执行主机上的网络,然后重试。", - "kimiContextOverflow": "Kimi 的上下文已用尽。请缩短提示词或启动新会话,然后重试。", - "kimiContinueSessionConflict": "Kimi 收到了冲突的选项:--continue, --session。请在重试前修正生成预设或 CLI 参数。", - "kimiCredentialVariableMissing": "Kimi 缺少已配置的凭据环境变量。请在执行主机上设置该变量后重试。", - "kimiCredentialsRequired": "Kimi 需要提供者凭据。请在执行主机上打开 Kimi,配置提供者或登录,然后重试。", - "kimiEmptyAgent": "Kimi 收到的智能体为空。请修正生成预设或 CLI 参数中的该项输入,然后重试。", - "kimiEmptyAgentFilePath": "Kimi 收到了空的智能体文件路径。请修正生成预设或 CLI 参数中的该项输入,然后重试。", - "kimiEmptyModel": "Kimi 收到的模型为空。请修正生成预设或 CLI 参数中的该项输入,然后重试。", - "kimiEmptyPrompt": "Kimi 收到了空提示词。请修正生成预设或 CLI 参数中的该项输入,然后重试。", - "kimiFailed": "Kimi 未能完成文本生成。请在执行主机上打开 Kimi,检查失败原因后再重试。", - "kimiInterrupted": "Kimi 在完成文本生成前被中断。请重试。", - "kimiModelMissing": "Kimi 未配置可用模型。请在执行主机上打开 Kimi,配置或选择模型,然后重试。", - "kimiOptionRejected": "Kimi 拒绝了某个选项或参数。请修正生成预设或 CLI 参数,然后重试。", - "kimiOutputFormatInvalid": "Kimi 输出格式需要提示词模式及受支持的 text 或 stream-json 值。请在重试前修正生成预设或 CLI 参数。", - "kimiPromptHookBlocked": "Kimi 提示词钩子阻止了请求,或无法启动此轮交互。请在重试前检查 Kimi 钩子和配置。", - "kimiProviderLimited": "Kimi 已达到提供者限制,或提供者正忙。请等待后再重试,或降低请求频率。", - "kimiResponseBlocked": "Kimi 无法返回响应,因为响应被阻止。请在重试前修改提示词或模型配置。", - "kimiSessionIdRequired": "Kimi 在提示词模式下恢复会话需要会话 ID。请修正生成预设或 CLI 参数,然后重试。", - "kimiSessionNotFound": "Kimi 找不到请求的会话。请使用现有会话或启动新会话。", - "kimiSessionOccupied": "Kimi 无法使用此会话,因为它在另一个客户端中处于活动状态。请在该客户端中停止会话或退出该客户端,然后重试。", - "kimiSessionOtherDirectory": "此 Kimi 会话属于另一个目录。请在该目录中恢复会话,或使用为此工作区创建的会话。", - "kimiUnreadableOutput": "Kimi 返回了 Orca 无法读取的输出。请重试。", - "noBranchChanges": "没有可供总结的分支更改。", - "noModelForAgent": "{{label}} 没有可用的模型。", - "noStagedChanges": "没有可供总结的已暂存更改。", - "openCodeInvalidEvents": "OpenCode 返回了无效的 JSON 事件。", - "outputTooLarge": "{{label}} CLI 命令产生了过多输出。请检查智能体的 CLI 配置后重试。", - "planAgentUnsupported": "智能体“{{agent}}”不支持 AI 提交信息。", - "planCustomCommandEmpty": "自定义命令为空。请在设置 → Git → AI 提交信息中添加。", - "planModelUnavailable": "模型“{{model}}”不可用于 {{label}}。", - "planModelWithoutThinking": "模型“{{model}}”不支持思考强度设置。", - "planThinkingLevelInvalid": "思考级别“{{level}}”对 {{model}} 无效。", - "promptTooLargeForArgument": "{{label}} 的提示词过大,无法作为单个命令行参数传递。请减少暂存的更改后重试。", - "promptTooLargeForWindows": "{{label}} 的提示词过大,无法用于 Windows 命令行。请减少暂存的更改后重试。", - "pullRequestDetailsUnparseable": "无法解析生成的 PR 详情。", - "sourceControlAgentUnsupported": "请在设置 -> Git -> 源代码控制 AI 中为此操作选择支持的智能体。支持的智能体:{{agents}},或选择“自定义命令”。", - "sourceControlCustomCommandEmpty": "自定义命令为空。请在设置 -> Git -> 源代码控制 AI 中添加。", - "stagedChangesReadFailed": "无法读取已暂存的更改。", - "timedOut": "生成在 {{seconds}} 秒后超时。", - "windowsBatchUnsafeArguments": "{{label}} 通过 Windows 批处理脚本运行,该脚本无法将多行提示词作为参数接收。请在设置中指定智能体的可执行文件,或使用不含 {prompt} 的自定义命令,让 Orca 通过 stdin 发送提示词。" + "jiraAccountDisconnected": "请在此主机上重新连接所选的 Jira 账户", + "jiraDescriptionRequired": "描述为必填项", + "jiraSummaryBusyInOtherDraft": "另一个草稿中已在生成 Jira 标题", + "jiraSummaryEmptyAfterSanitization": "生成的标题在清理后为空", + "kimiAgentChangeOnResume": "Kimi 无法在恢复会话时更改智能体。请修改生成预设或 CLI 参数,移除智能体覆盖设置或改为启动新会话", + "kimiAgentOptionsConflict": "Kimi 收到了冲突或重复的智能体选项。请在生成预设或 CLI 参数中仅保留一个 --agent 或 --agent-file 选项,然后重试", + "kimiAuthFailed": "Kimi 无法通过身份验证。请在执行主机上登录或修正提供者凭据,然后重试", + "kimiCancelled": "Kimi 在完成文本生成前取消了请求。请重试", + "kimiConfigInvalid": "Kimi 的配置无效。请在重试前检查执行主机上的模型和提供者配置", + "kimiConflictingOptions": "Kimi 收到了冲突的选项:{{option}} 与 {{otherOption}}。请在重试前修正生成预设或 CLI 参数", + "kimiConnectionFailed": "Kimi 无法连接到提供者。请检查执行主机上的网络,然后重试", + "kimiContextOverflow": "Kimi 的上下文已用尽。请缩短提示词或启动新会话,然后重试", + "kimiContinueSessionConflict": "Kimi 收到了冲突的选项:--continue, --session。请在重试前修正生成预设或 CLI 参数", + "kimiCredentialVariableMissing": "Kimi 缺少已配置的凭据环境变量。请在执行主机上设置该变量后重试", + "kimiCredentialsRequired": "Kimi 需要提供者凭据。请在执行主机上打开 Kimi,配置提供者或登录,然后重试", + "kimiEmptyAgent": "Kimi 收到的智能体为空。请修正生成预设或 CLI 参数中的该项输入,然后重试", + "kimiEmptyAgentFilePath": "Kimi 收到了空的智能体文件路径。请修正生成预设或 CLI 参数中的该项输入,然后重试", + "kimiEmptyModel": "Kimi 收到的模型为空。请修正生成预设或 CLI 参数中的该项输入,然后重试", + "kimiEmptyPrompt": "Kimi 收到了空提示词。请修正生成预设或 CLI 参数中的该项输入,然后重试", + "kimiFailed": "Kimi 未能完成文本生成。请在执行主机上打开 Kimi,检查失败原因后再重试", + "kimiInterrupted": "Kimi 在完成文本生成前被中断。请重试", + "kimiModelMissing": "Kimi 未配置可用模型。请在执行主机上打开 Kimi,配置或选择模型,然后重试", + "kimiOptionRejected": "Kimi 拒绝了某个选项或参数。请修正生成预设或 CLI 参数,然后重试", + "kimiOutputFormatInvalid": "Kimi 输出格式需要提示词模式及受支持的 text 或 stream-json 值。请在重试前修正生成预设或 CLI 参数", + "kimiPromptHookBlocked": "Kimi 提示词钩子阻止了请求,或无法启动此轮交互。请在重试前检查 Kimi 钩子和配置", + "kimiProviderLimited": "Kimi 已达到提供者限制,或提供者正忙。请等待后再重试,或降低请求频率", + "kimiResponseBlocked": "Kimi 无法返回响应,因为响应被阻止。请在重试前修改提示词或模型配置", + "kimiSessionIdRequired": "Kimi 在提示词模式下恢复会话需要会话 ID。请修正生成预设或 CLI 参数,然后重试", + "kimiSessionNotFound": "Kimi 找不到请求的会话。请使用现有会话或启动新会话", + "kimiSessionOccupied": "Kimi 无法使用此会话,因为它在另一个客户端中处于活动状态。请在该客户端中停止会话或退出该客户端,然后重试", + "kimiSessionOtherDirectory": "此 Kimi 会话属于另一个目录。请在该目录中恢复会话,或使用为此工作区创建的会话", + "kimiUnreadableOutput": "Kimi 返回了 Orca 无法读取的输出。请重试", + "noBranchChanges": "没有可供总结的分支更改", + "noModelForAgent": "{{label}} 没有可用的模型", + "noStagedChanges": "没有可供总结的已暂存更改", + "openCodeInvalidEvents": "OpenCode 返回了无效的 JSON 事件", + "outputTooLarge": "{{label}} CLI 命令产生了过多输出。请检查智能体的 CLI 配置后重试", + "planAgentUnsupported": "智能体“{{agent}}”不支持 AI 提交信息", + "planCustomCommandEmpty": "自定义命令为空。请在设置 → Git → AI 提交信息中添加", + "planModelUnavailable": "模型“{{model}}”不可用于 {{label}}", + "planModelWithoutThinking": "模型“{{model}}”不支持思考强度设置", + "planThinkingLevelInvalid": "思考级别“{{level}}”对 {{model}} 无效", + "promptTooLargeForArgument": "{{label}} 的提示词过大,无法作为单个命令行参数传递。请减少暂存的更改后重试", + "promptTooLargeForWindows": "{{label}} 的提示词过大,无法用于 Windows 命令行。请减少暂存的更改后重试", + "pullRequestDetailsUnparseable": "无法解析生成的 PR 详情", + "sourceControlAgentUnsupported": "请在设置 -> Git -> 源代码控制 AI 中为此操作选择支持的智能体。支持的智能体:{{agents}},或选择“自定义命令”", + "sourceControlCustomCommandEmpty": "自定义命令为空。请在设置 -> Git -> 源代码控制 AI 中添加", + "stagedChangesReadFailed": "无法读取已暂存的更改", + "timedOut": "生成在 {{seconds}} 秒后超时", + "windowsBatchUnsafeArguments": "{{label}} 通过 Windows 批处理脚本运行,该脚本无法将多行提示词作为参数接收。请在设置中指定智能体的可执行文件,或使用不含 {prompt} 的自定义命令,让 Orca 通过 stdin 发送提示词" }, "useMobileCommitFailureRecovery": { "launchFailed": "启动智能体失败", @@ -3344,6 +3351,9 @@ "useMobileCommitMessageGeneration": { "generateFailed": "生成提交信息失败" }, + "useMobileCreatePrRunner": { + "branchRequired": "创建 PR 前,请先检出分支" + }, "useMobileGitRequests": { "actionFailed": "源代码控制操作失败", "branchUnavailable": "无法获取分支状态", @@ -3360,8 +3370,8 @@ }, "tasks": { "composerSource": { - "baseFailed": "无法解析基础分支。", - "forkPushWarning": "此 PR 未开启“允许维护者编辑”;向 fork 仓库推送可能会被 GitHub 拒绝。" + "baseFailed": "无法解析基础分支", + "forkPushWarning": "此 PR 未开启“允许维护者编辑”;向 fork 仓库推送可能会被 GitHub 拒绝" }, "detailCommentRenderers": { "commentPlaceholder": "添加评论", @@ -3380,7 +3390,7 @@ "changeStatus": "更改状态", "fieldHidden": "不在卡片上显示", "fieldShown": "在卡片上显示", - "fieldsSubtitle": "选择要在条目卡片上显示的项目字段。", + "fieldsSubtitle": "选择要在条目卡片上显示的项目字段", "fieldsTitle": "项目字段", "gitlabFilter": "GitLab 筛选", "gitlabView": "GitLab 视图", @@ -3390,10 +3400,10 @@ "linearIssue": "Linear 议题", "linearWorkspace": "Linear 工作区", "loadingStates": "正在加载状态…", - "noFields": "此视图没有可显示的额外字段。", + "noFields": "此视图没有可显示的额外字段", "noStates": "无可用状态", "switchWorkspaceFailed": "切换工作区失败", - "teamsSubtitle": "选择要在“任务”中显示的团队。", + "teamsSubtitle": "选择要在“任务”中显示的团队", "teamsTitle": "Linear 团队", "teams_one": "{{count}} 个团队", "teams_other": "{{count}} 个团队" @@ -3413,33 +3423,39 @@ }, "githubProjectPickers": { "add": "添加", - "addByUrlHint": "使用“通过 URL 添加”来访问未列出的项目。", + "addByUrlHint": "使用“通过 URL 添加”来访问未列出的项目", "addPlaceholder": "通过 URL 或 owner/number 添加", "adding": "添加中…", "browseAll": "浏览全部", "browseLoading": "浏览全部(加载中…)", "chooseView": "选择项目视图", "loadFailed": "无法加载项目", - "noMatches": "没有匹配的项目。", - "noMoreProjects": "没有更多项目。", + "noMatches": "没有匹配的项目", + "noMoreProjects": "没有更多项目", "noProjects": "尚未加载任何项目", "organizationsError": "组织:{{message}}", - "organizationsLoadFailed": "{{count}} 个组织未能加载。", - "ownerLoadFailed": "无法加载 {{owner}} 的项目。", + "organizationsLoadFailed": "{{count}} 个组织未能加载", + "ownerLoadFailed": "无法加载 {{owner}} 的项目", "pin": "固定", "pinned": "已固定", "recent": "最近的", - "retryHint": "点按重试。", + "retryHint": "点按重试", "searchProjects": "搜索项目", - "subtitle": "为“任务”页面选择项目视图。", + "subtitle": "为“任务”页面选择项目视图", "title": "GitHub 项目", - "unsupportedLayout": "Orca 暂不支持此 GitHub 项目布局。", + "unsupportedLayout": "Orca 暂不支持此 GitHub 项目布局", "view": "项目视图" }, "githubViewControls": { "openView": "在 GitHub 中打开视图" }, "hostedMerge": { + "confirmGitHubMerge": "合并 PR #{{number}}?", + "confirmGitHubSquash": "压缩提交并合并 PR #{{number}}?", + "confirmGitHubRebase": "变基并合并 PR #{{number}}?", + "confirmGitLabMerge": "要将合并请求 #{{number}} 合并吗?", + "confirmGitLabSquash": "要将合并请求 #{{number}} 的提交压缩后合并吗?", + "confirmGitLabRebase": "要将合并请求 #{{number}} 变基后合并吗?", "merged": "已合并", "closed": "已关闭", "conflicts": "有冲突", @@ -3454,7 +3470,7 @@ "copyGitHubLink": "复制 GitHub 链接", "copyLinearLink": "复制 Linear 链接", "creating": "创建中…", - "mergeConflicts": "GitHub 报告存在合并冲突。", + "mergeConflicts": "GitHub 报告存在合并冲突", "mergeMergeRequest": "合并合并请求", "mergePullRequest": "合并 PR" }, @@ -3463,10 +3479,10 @@ "checks": "检查项", "description": "描述", "discussion": "讨论", - "noChecks": "未找到检查项。", - "noComments": "暂无评论。", - "noPipelineRuns": "此 MR 没有运行任何管道。", - "noSubIssues": "没有子议题。", + "noChecks": "未找到检查项", + "noComments": "暂无评论", + "noPipelineRuns": "此 MR 没有运行任何管道", + "noSubIssues": "没有子议题", "none": "没有任何", "pipeline": "管道", "pipelineJobs_one": "{{count}} 个作业", @@ -3485,8 +3501,8 @@ "labels": "标签", "loadingAssignees": "正在加载负责人…", "loadingLabels": "正在加载标签…", - "noAssignableUsers": "未找到此仓库中可指派的用户。", - "noLabels": "此仓库没有标签。", + "noAssignableUsers": "未找到此仓库中可指派的用户", + "noLabels": "此仓库没有标签", "none": "没有任何", "removeLabels": "移除标签,以英文逗号分隔", "removeUsernames": "移除用户名,以英文逗号分隔", @@ -3496,16 +3512,16 @@ "updateLabels": "更新标签" }, "itemReviewSections": { - "binaryFile": "二进制文件。", + "binaryFile": "二进制文件", "changedFilesTitle": "已更改文件", "descriptionPlaceholder": "描述", - "fileContentsUnavailable": "文件内容不可用。", + "fileContentsUnavailable": "文件内容不可用", "hideFile": "隐藏", "loadingReviewers": "正在加载评审人…", "markUnviewed": "标记未查看", "markViewed": "标记已查看", - "noDescription": "没有描述。", - "noReviewerSuggestions": "未找到推荐的评审人。", + "noDescription": "没有描述", + "noReviewerSuggestions": "未找到推荐的评审人", "noReviewersRequested": "未请求评审人", "requestReview": "请求评审", "reviewersPlaceholder": "邀请评审人", @@ -3514,17 +3530,17 @@ "viewFile": "查看" }, "legacySurface": { - "loadIssuesFailed": "无法从 {{source}} 加载议题。", + "loadIssuesFailed": "无法从 {{source}} 加载议题", "mergeAction": "合并", "mergeMethodTitle": "合并方式", "mergePullRequestTitle": "合并 PR", - "mergeRequestMergeMessage": "请选择此合并请求的合并方式。", + "mergeRequestMergeMessage": "请选择此合并请求的合并方式", "mergeRequestTitle": "合并请求", - "pullRequestMergeMessage": "请选择此 PR 的合并方式。", + "pullRequestMergeMessage": "请选择此 PR 的合并方式", "retryLoadingIssues": "重试从 {{source}} 加载议题", "retrying": "正在重试…", - "sourceFallback": "{{repo}} 的首选议题来源 upstream 不可用,已改用 origin。", - "subIssueDataUnavailable": "您的token无法获取子议题数据。", + "sourceFallback": "{{repo}} 的首选议题来源 upstream 不可用,已改用 origin", + "subIssueDataUnavailable": "您的token无法获取子议题数据", "updateItemTitle": "更新条目" }, "linearList": { @@ -3535,10 +3551,10 @@ }, "listSurface": { "connectLinearButton": "连接 Linear", - "connectLinearMessage": "直接在“任务”中浏览并开始处理分配给您的 Linear 议题。", + "connectLinearMessage": "直接在“任务”中浏览并开始处理分配给您的 Linear 议题", "connectLinearTitle": "连接您的 Linear 账户", "jiraStatusFailed": "读取 Jira 状态失败", - "updateDesktopMessage": "此移动端“任务”视图需要更高版本的桌面端运行时。", + "updateDesktopMessage": "此移动端“任务”视图需要更高版本的桌面端运行时", "updateDesktopTitle": "更新 Orca 桌面端" }, "options": { @@ -3624,15 +3640,15 @@ "prFileDiff": { "commentOnLine": "在第 {{line}} 行添加评论", "commentPlaceholder": "添加评审评论", - "noTextChanges": "未发现文本更改。", - "showingDiffLines": "显示前 {{limit}} 行差异,共 {{total}} 行。" + "noTextChanges": "未发现文本更改", + "showingDiffLines": "显示前 {{limit}} 行差异,共 {{total}} 行" }, "projectComments": { "comments_one": "{{count}} 条评论", "comments_other": "{{count}} 条评论", "discussion": "讨论", "editComment": "编辑评论", - "noComments": "暂无评论。", + "noComments": "暂无评论", "reopenThread": "重新打开讨论串", "reply": "回复", "resolveThread": "解决讨论串", @@ -3641,7 +3657,7 @@ "show": "显示" }, "projectDetailDrawer": { - "addRepositoryFromDesktop": "{{repository}} 尚未添加到 Orca。请在桌面应用中添加此仓库,然后刷新移动端的“任务”。", + "addRepositoryFromDesktop": "{{repository}} 尚未添加到 Orca。请在桌面应用中添加此仓库,然后刷新移动端的“任务”", "clearType": "清除类型", "closeItem": "关闭条目", "copyGitHubLink": "复制 GitHub 链接", @@ -3652,8 +3668,8 @@ "issueType": "议题类型", "loadingIssueTypes": "正在加载议题类型…", "mergePullRequest": "合并 PR", - "mergeRepositoryRequirement": "合并前需在 Orca 中添加此仓库。", - "noIssueTypes": "此仓库未配置议题类型。", + "mergeRepositoryRequirement": "合并前需在 Orca 中添加此仓库", + "noIssueTypes": "此仓库未配置议题类型", "noType": "无类型", "openInGitHub": "在 GitHub 中打开", "projectItem": "项目条目", @@ -3663,15 +3679,15 @@ "repositoryNotInOrca": "仓库不在 Orca 中", "status": "状态", "type": "类型", - "workspaceCreationRequirement": "只能从 GitHub 议题和 PR 创建工作区。" + "workspaceCreationRequirement": "只能从 GitHub 议题和 PR 创建工作区" }, "projectFieldEditors": { "clearField": "清空字段", "completedIteration": "已完成 · {{startDate}} · {{duration}} 天", "datePlaceholder": "YYYY-MM-DD", - "invalidDate": "请按 YYYY-MM-DD 格式输入日期。", - "invalidNumber": "请输入有效数字。", - "noIterations": "暂无可用迭代。", + "invalidDate": "请按 YYYY-MM-DD 格式输入日期", + "invalidNumber": "请输入有效数字", + "noIterations": "暂无可用迭代", "numberPlaceholder": "数字", "projectFields": "项目字段", "saveField": "保存字段", @@ -3684,26 +3700,26 @@ "labels": "标签", "loadingAssignees": "正在加载负责人…", "loadingLabels": "正在加载标签…", - "noAssignableUsers": "未找到此仓库中可设为负责人的用户。", - "noDescription": "没有描述。", - "noLabels": "此仓库中没有标签。", + "noAssignableUsers": "未找到此仓库中可设为负责人的用户", + "noDescription": "没有描述", + "noLabels": "此仓库中没有标签", "none": "无", "saveDescription": "保存描述", "saveTitle": "保存标题", "title": "标题" }, "projectReviewPanels": { - "binaryFile": "二进制文件。", + "binaryFile": "二进制文件", "changedFiles": "已更改文件", "checks": "检查项", - "fileUnavailable": "文件内容不可用。", + "fileUnavailable": "文件内容不可用", "hideFile": "隐藏", "loadingReviewers": "正在加载评审人…", "markUnviewed": "标记未查看", "markViewed": "标记已查看", - "noChecks": "未找到检查项。", + "noChecks": "未找到检查项", "noReviewers": "未请求评审人", - "noSuggestions": "未找到推荐的评审人。", + "noSuggestions": "未找到推荐的评审人", "requestReview": "请求评审", "requestReviewers": "邀请评审人", "rerunAll": "全部重新运行", @@ -3727,18 +3743,18 @@ "allRepositories": "所有仓库", "githubView": "GitHub 视图", "issueSources": "GitHub 议题来源", - "issueSourcesDescription": "选择每个仓库从 upstream 还是 origin 查询和创建工作项。", + "issueSourcesDescription": "选择每个仓库从 upstream 还是 origin 查询和创建工作项", "issues": "议题", - "noIssueSources": "没有其他可用的议题来源。", + "noIssueSources": "没有其他可用的议题来源", "origin": "origin", - "pageHint": "跳转到已加载或可用的结果页。", + "pageHint": "跳转到已加载或可用的结果页", "pageLoaded": "已加载", "pageNotLoaded": "加载更早的结果", "pageNumber": "第 {{page}} 页", "pages": "GitHub 结果页", "pullRequests": "PR", "queryingSource": "正在查询 {{source}}", - "repoDescription": "选择要查询的仓库。", + "repoDescription": "选择要查询的仓库", "repos": "仓库", "upstream": "上游" }, @@ -3786,8 +3802,8 @@ "smart": "智能" }, "sparsePresetDraft": { - "directoryRequired": "添加至少一个目录。", - "repoRelativeDirectoriesRequired": "使用仓库相对目录,而不是根目录、绝对路径或父段。" + "directoryRequired": "添加至少一个目录", + "repoRelativeDirectoriesRequired": "使用仓库相对目录,而不是根目录、绝对路径或父段" }, "taskViewOptions": { "allSubtitle": "所选站点中未解决的议题", @@ -3808,16 +3824,16 @@ "descriptionPlaceholder": "补充背景信息", "fileIn": "在 {{slug}} 中创建议题", "issueSource": "议题来源", - "keySecurityHint": "密钥通过主机操作系统的钥匙串加密,并存储在本地。", - "linearConnectSubtitle": "粘贴个人 API 密钥,即可浏览该工作区的议题。", + "keySecurityHint": "密钥通过主机操作系统的钥匙串加密,并存储在本地", + "linearConnectSubtitle": "粘贴个人 API 密钥,即可浏览该工作区的议题", "linearSettingsLink": "Linear 设置 / 安全 / 新建 API 密钥", "linearTeam": "Linear 团队", - "linearTeamSubtitle": "在所选 Linear 团队中创建议题。", + "linearTeamSubtitle": "在所选 Linear 团队中创建议题", "newIssueTitle": "新建 {{providerLabel}} 议题", "origin": "origin", "personalApiKey": "个人API密钥", "repository": "仓库", - "repositorySubtitle": "在所选仓库中创建议题。", + "repositorySubtitle": "在所选仓库中创建议题", "team": "团队", "title": "标题", "titlePlaceholder": "任务标题", @@ -3827,7 +3843,7 @@ "blankTerminal": "空白终端" }, "workspaceCreateDrawer": { - "addRepository": "创建 Linear 工作区前,请先添加 Git 仓库。", + "addRepository": "创建 Linear 工作区前,请先添加 Git 仓库", "advanced": "高级", "agent": "智能体", "connectFirst": "请先连接仓库", @@ -3836,20 +3852,20 @@ "detectingAgents": "正在检测智能体…", "remoteRepository": "远程仓库", "repository": "仓库", - "repositoryNotFound": "未找到仓库。", + "repositoryNotFound": "未找到仓库", "selectRepository": "选择仓库", "startFrom": "创建起点", "title": "创建工作区", "workspaceName": "工作区名称" }, "workspaceCreateProjection": { - "nameAlreadyExists": "“{{name}}”已存在。", - "nameRequired": "请输入名称。", - "nameTooLong": "名称不能超过80个字符。", + "nameAlreadyExists": "“{{name}}”已存在", + "nameRequired": "请输入名称", + "nameTooLong": "名称不能超过80个字符", "openShell": "打开 shell" }, "workspaceOptionPickers": { - "baseBranchSubtitle": "选择现有分支或引用。", + "baseBranchSubtitle": "选择现有分支或引用", "baseBranchTitle": "创建起点", "branchName": "分支名称:{{name}}", "defaultBranch": "默认分支", @@ -3858,7 +3874,7 @@ "fullCheckout": "完整检出", "fullCheckoutSubtitle": "使用整个仓库", "newPreset": "新预设", - "noBranches": "没有匹配的分支。", + "noBranches": "没有匹配的分支", "searchBranches": "搜索分支", "sparseCheckoutTitle": "稀疏检出" }, @@ -3889,11 +3905,11 @@ "runSetupTitle": "运行 {{name}} 的设置脚本?", "setupChangedTitle": "{{name}} 的设置脚本已更改", "setupScript": "设置脚本", - "setupSubtitle": "创建此工作区前,请选择是否运行 {{name}} 的设置脚本。", + "setupSubtitle": "创建此工作区前,请选择是否运行 {{name}} 的设置脚本", "setupTitle": "运行设置脚本?", "skipSetupAndCreate": "跳过设置脚本并创建", - "trustFailed": "无法将设置脚本设为可信。", - "trustSubtitle": "工作区启动前,此仓库的 orca.yaml 会在您的电脑上运行。请仅在信任此仓库时运行。" + "trustFailed": "无法将设置脚本设为可信", + "trustSubtitle": "工作区启动前,此仓库的 orca.yaml 会在您的电脑上运行。请仅在信任此仓库时运行" }, "worktreeCreateRetry": { "createFailed": "创建工作区失败" @@ -3944,13 +3960,13 @@ "shellStateScreen": { "checkingHost": "正在检查主机", "connectToDownload": "连接到此主机以下载最新版本的应用", - "documentLoadFailed": "无法打开已下载的应用。", - "downloadFailed": "无法从此主机下载最新版本的应用。", - "hostProfileUnreadable": "无法在此设备上读取此主机的信息。请重试。", - "isolationUnavailable": "此设备的 WebView 版本过旧,无法安全打开工作区。", + "documentLoadFailed": "无法打开已下载的应用", + "downloadFailed": "无法从此主机下载最新版本的应用", + "hostProfileUnreadable": "无法在此设备上读取此主机的信息。请重试", + "isolationUnavailable": "此设备的 WebView 版本过旧,无法安全打开工作区", "openingWorkspace": "正在打开工作区", - "renderProcessGone": "工作区已停止响应。", - "statusUnreadable": "无法读取此主机的状态。请返回后重新打开。", + "renderProcessGone": "工作区已停止响应", + "statusUnreadable": "无法读取此主机的状态。请返回后重新打开", "tryAgain": "重试" } }, @@ -3958,8 +3974,8 @@ "branchChoice": { "automaticName": "自动命名", "existing": "现有分支", - "existingHint": "新提交将添加到此分支。", - "hostUpdateRequired": "请更新工作区主机上的 Orca,以复用分支或明确选择创建独立分支。", + "existingHint": "新提交将添加到此分支", + "hostUpdateRequired": "请更新工作区主机上的 Orca,以复用分支或明确选择创建独立分支", "newHint": "创建新的本地分支", "newName": "新分支名称", "title": "此工作树使用的分支" @@ -3993,7 +4009,7 @@ "noFilterMatches": "没有符合筛选条件的工作区", "noMatches": "没有匹配的工作区", "reopen": "重新打开以更新", - "reopenDetail": "此页面尚无法识别此主机的工作区列表格式。" + "reopenDetail": "此页面尚无法识别此主机的工作区列表格式" }, "workspaceListSections": { "all": "全部", diff --git a/mobile/src/i18n/page-locale-catalog-source.test.ts b/mobile/src/i18n/page-locale-catalog-source.test.ts index d69a92dc1b2..98d2ab77a1a 100644 --- a/mobile/src/i18n/page-locale-catalog-source.test.ts +++ b/mobile/src/i18n/page-locale-catalog-source.test.ts @@ -204,15 +204,4 @@ describe('the page language catalog', () => { expect(i18n.getMobileUiLocale()).toBe('ko') expect(i18n.translate('greeting', 'Hello')).toBe('안녕하세요') }) - - it('imports the chunk an older shell left on disk, with no wait and no request', async () => { - chunksOnDisk.set('es', { greeting: 'Hola' }) - const client = fakeClient('reconnecting') - openPage(client, fakeStore({})) - - await i18n.activateMobileUiLocale('es') - - expect(i18n.translate('greeting', 'Hello')).toBe('Hola') - expect(client.sent).toHaveLength(0) - }) }) diff --git a/mobile/src/mobile-web-shell/ShellStateScreen.tsx b/mobile/src/mobile-web-shell/ShellStateScreen.tsx index d22e7e2c055..bc9d7ccaa91 100644 --- a/mobile/src/mobile-web-shell/ShellStateScreen.tsx +++ b/mobile/src/mobile-web-shell/ShellStateScreen.tsx @@ -1,5 +1,6 @@ import type { ReactNode } from 'react' -import { Pressable, Text, View } from 'react-native' +import { Platform, Pressable, Text, View } from 'react-native' +import { currentWebViewProvider } from '../../modules/orca-mobile-web-shell/src' import { ProtocolBlockScreen } from '../components/ProtocolBlockScreen' import { colors, radii, spacing, typography } from '../theme/mobile-theme' import { themedStyleSheet } from '../theme/themed-styles' @@ -65,11 +66,30 @@ function Failed({ useMobileColorScheme() // Retry cannot change a settled isolation gate or give an unsupported WebView the missing fence. const retryable = state.reason !== 'isolation-unavailable' && state.reason !== 'status-unreadable' + const provider = state.reason === 'isolation-unavailable' ? currentWebViewProvider() : null + // Unknown provider (older binary): a missing feature is still the likely cause. + const webViewTooOld = + Platform.OS === 'android' && + state.reason === 'isolation-unavailable' && + provider?.hasShellFeatures !== true return ( - {failureMessage(state.reason, t)} + {webViewTooOld + ? t( + 'webShell.shellStateScreen.isolationUnavailableAndroid', + 'Orca needs Android System WebView or Chrome 101 or newer. Update it from the Play Store, or pick a newer one in Developer options > WebView implementation.' + ) + : failureMessage(state.reason, t)} + {webViewTooOld && provider ? ( + + {t('webShell.shellStateScreen.webViewInUse', 'This device has {{name}} {{version}}.', { + name: provider.name, + version: provider.version + })} + + ) : null} {retryable ? ( [styles.retryButton, pressed && styles.pressed]} @@ -160,6 +180,12 @@ const styles = themedStyleSheet(() => ({ textAlign: 'center', marginBottom: spacing.lg }, + failedDetail: { + fontSize: typography.metaSize, + color: colors.textSecondary, + textAlign: 'center', + marginBottom: spacing.lg + }, retryButton: { backgroundColor: colors.bgRaised, paddingVertical: spacing.sm + 2, diff --git a/mobile/src/mobile-web-shell/generation-store-file-system.test.ts b/mobile/src/mobile-web-shell/generation-store-file-system.test.ts deleted file mode 100644 index 7b170ea268f..00000000000 --- a/mobile/src/mobile-web-shell/generation-store-file-system.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' - -// Mock the import-time native module to test only the URI converter. -vi.mock('expo-file-system', () => ({ - Directory: class {}, - File: class {}, - Paths: { cache: '' } -})) - -import { generationDirectoryPath } from './generation-store-file-system' - -describe('generationDirectoryPath', () => { - it('hands the native view the absolute path both loaders demand', () => { - expect( - generationDirectoryPath('file:///var/mobile/Caches/mobile-web/abc/generations/def') - ).toBe('/var/mobile/Caches/mobile-web/abc/generations/def') - expect(generationDirectoryPath('file:///data/user/0/com.stably.orca.mobile/cache/mw')).toBe( - '/data/user/0/com.stably.orca.mobile/cache/mw' - ) - }) - - it('decodes what a uri escaped and a path spells literally', () => { - expect(generationDirectoryPath('file:///var/Orca%20Mobile/mobile-web')).toBe( - '/var/Orca Mobile/mobile-web' - ) - }) - - it('leaves a value that is already a path alone, so nobody can decode one twice', () => { - expect(generationDirectoryPath('/var/mobile/Caches/100%25')).toBe('/var/mobile/Caches/100%25') - }) -}) diff --git a/mobile/src/mobile-web-shell/generation-store.test.ts b/mobile/src/mobile-web-shell/generation-store.test.ts deleted file mode 100644 index 7b5ebd20edf..00000000000 --- a/mobile/src/mobile-web-shell/generation-store.test.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { createGenerationStore } from './generation-store' -import { deriveHostCacheKey } from './host-cache-key' -import type { MobileWebBundleFetchResult } from '../transport/web-bundle/mobile-web-bundle-fetch' -import { computeMobileWebBundleId } from '../../../src/shared/mobile-web-bundle/manifest-contract' -import { - createFakeGenerationFileSystem as createFakeFileSystem, - FAKE_GENERATION_ROOT -} from './generation-file-system-fake' - -const ROOT = FAKE_GENERATION_ROOT -const HOST = deriveHostCacheKey('host-a') - -function buildResult(options: { - buildId?: string - assets?: readonly { path: string; byteLength: number; kind?: string }[] - bytes?: ReadonlyMap -}): MobileWebBundleFetchResult { - const listed = options.assets ?? [ - { path: 'index.html', byteLength: 4 }, - { path: 'assets/app.js', byteLength: 2 } - ] - const assets = listed.map((asset, index) => ({ - path: asset.path, - sha256: String(index).repeat(64).slice(0, 64), - byteLength: asset.byteLength, - contentType: 'text/html; charset=utf-8', - ...(asset.kind === undefined ? {} : { kind: asset.kind }) - })) - const totalBytes = assets.reduce((sum, asset) => sum + asset.byteLength, 0) - return { - manifest: { - schemaVersion: 1, - buildId: options.buildId ?? computeMobileWebBundleId(assets), - minCompatibleRuntimeProtocolVersion: 2, - runtimeProtocolVersion: 2, - entrypoint: 'index.html', - totalBytes, - assets - }, - assets: - options.bytes ?? - new Map(assets.map((asset) => [asset.path, new Uint8Array(asset.byteLength).fill(7)])), - reused: [], - totalBytes, - elapsedMs: 1 - } -} - -// Derive ids from assets so the cached manifest passes its digest check. -const BUILD = buildResult({}).manifest.buildId -const SECOND = { assets: [{ path: 'index.html', byteLength: 8 }] } -const SECOND_BUILD = buildResult(SECOND).manifest.buildId - -async function activate( - store: ReturnType, - hostKey: string, - result = buildResult({}) -): Promise { - await store.commitGeneration(await store.stageGeneration(hostKey, result)) -} - -// Commit deletes the old build first, so it must not run under a page still loading that build's chunks. -describe('an update staged behind a live page', () => { - it('stays staged while a page reads the old build, and the next read after it commits', async () => { - const fs = createFakeFileSystem() - const store = createGenerationStore({ fileSystem: fs }) - await activate(store, HOST) - const release = store.holdGeneration(HOST) - store.deferCommit(await store.stageGeneration(HOST, buildResult(SECOND))) - - expect((await store.readActiveGeneration(HOST))?.buildId).toBe(BUILD) - expect(await fs.fileExists(`${ROOT}/${HOST}/generations/${BUILD}/index.html`)).toBe(true) - - release() - expect((await store.readActiveGeneration(HOST))?.buildId).toBe(SECOND_BUILD) - expect(await fs.fileExists(`${ROOT}/${HOST}/generations/${BUILD}/index.html`)).toBe(false) - }) - - it('stages a build without its language-catalog chunks and still commits it at the next launch', async () => { - const fs = createFakeFileSystem() - const first = createGenerationStore({ fileSystem: fs }) - await activate(first, HOST) - first.holdGeneration(HOST) - const withCatalog = buildResult({ - assets: [ - { path: 'index.html', byteLength: 8 }, - { path: 'assets/de.js', byteLength: 3, kind: 'catalog' } - ], - bytes: new Map([['index.html', new Uint8Array(8)]]) - }) - first.deferCommit(await first.stageGeneration(HOST, withCatalog)) - - const relaunched = createGenerationStore({ fileSystem: fs }) - - const build = withCatalog.manifest.buildId - expect((await relaunched.readActiveGeneration(HOST))?.buildId).toBe(build) - expect(await fs.fileExists(`${ROOT}/${HOST}/generations/${build}/assets/de.js`)).toBe(false) - }) -}) diff --git a/mobile/src/mobile-web-shell/generation-asset-path.ts b/mobile/src/mobile-web-shell/generations/generation-asset-path.ts similarity index 100% rename from mobile/src/mobile-web-shell/generation-asset-path.ts rename to mobile/src/mobile-web-shell/generations/generation-asset-path.ts diff --git a/mobile/src/mobile-web-shell/generation-cache-uri.ts b/mobile/src/mobile-web-shell/generations/generation-cache-uri.ts similarity index 100% rename from mobile/src/mobile-web-shell/generation-cache-uri.ts rename to mobile/src/mobile-web-shell/generations/generation-cache-uri.ts diff --git a/mobile/src/mobile-web-shell/generation-deferred-commits.ts b/mobile/src/mobile-web-shell/generations/generation-deferred-commits.ts similarity index 100% rename from mobile/src/mobile-web-shell/generation-deferred-commits.ts rename to mobile/src/mobile-web-shell/generations/generation-deferred-commits.ts diff --git a/mobile/src/mobile-web-shell/generation-file-system-fake.ts b/mobile/src/mobile-web-shell/generations/generation-file-system-fake.ts similarity index 100% rename from mobile/src/mobile-web-shell/generation-file-system-fake.ts rename to mobile/src/mobile-web-shell/generations/generation-file-system-fake.ts diff --git a/mobile/src/mobile-web-shell/generation-host-directories.ts b/mobile/src/mobile-web-shell/generations/generation-host-directories.ts similarity index 100% rename from mobile/src/mobile-web-shell/generation-host-directories.ts rename to mobile/src/mobile-web-shell/generations/generation-host-directories.ts diff --git a/mobile/src/mobile-web-shell/generation-host-order.ts b/mobile/src/mobile-web-shell/generations/generation-host-order.ts similarity index 100% rename from mobile/src/mobile-web-shell/generation-host-order.ts rename to mobile/src/mobile-web-shell/generations/generation-host-order.ts diff --git a/mobile/src/mobile-web-shell/generation-legacy-root.ts b/mobile/src/mobile-web-shell/generations/generation-legacy-root.ts similarity index 100% rename from mobile/src/mobile-web-shell/generation-legacy-root.ts rename to mobile/src/mobile-web-shell/generations/generation-legacy-root.ts diff --git a/mobile/src/mobile-web-shell/generation-manifest-read.ts b/mobile/src/mobile-web-shell/generations/generation-manifest-read.ts similarity index 97% rename from mobile/src/mobile-web-shell/generation-manifest-read.ts rename to mobile/src/mobile-web-shell/generations/generation-manifest-read.ts index 71c6ee09e18..22b768876d0 100644 --- a/mobile/src/mobile-web-shell/generation-manifest-read.ts +++ b/mobile/src/mobile-web-shell/generations/generation-manifest-read.ts @@ -2,7 +2,7 @@ import { MobileWebBundleManifestReadSchema, shellDownloadedAssets, type MobileWebBundleManifestRead -} from '../transport/web-bundle/mobile-web-bundle-reply-schemas' +} from '../../transport/web-bundle/mobile-web-bundle-reply-schemas' import { MANIFEST_FILE_NAME } from './generation-asset-path' import { joinUri } from './generation-cache-uri' import { parseJson } from './generation-host-order' diff --git a/mobile/src/mobile-web-shell/generation-reuse.ts b/mobile/src/mobile-web-shell/generations/generation-reuse.ts similarity index 94% rename from mobile/src/mobile-web-shell/generation-reuse.ts rename to mobile/src/mobile-web-shell/generations/generation-reuse.ts index f7eb4b257f2..45ca906afa5 100644 --- a/mobile/src/mobile-web-shell/generation-reuse.ts +++ b/mobile/src/mobile-web-shell/generations/generation-reuse.ts @@ -1,5 +1,5 @@ -import type { MobileWebBundleReusableAssets } from '../transport/web-bundle/mobile-web-bundle-fetch' -import type { MobileWebBundleAssetRead } from '../transport/web-bundle/mobile-web-bundle-reply-schemas' +import type { MobileWebBundleReusableAssets } from '../../transport/web-bundle/mobile-web-bundle-fetch' +import type { MobileWebBundleAssetRead } from '../../transport/web-bundle/mobile-web-bundle-reply-schemas' import { requireStorablePath } from './generation-asset-path' import { joinUri } from './generation-cache-uri' import type { ActiveGeneration } from './generation-store' diff --git a/mobile/src/mobile-web-shell/generation-staging-assets.ts b/mobile/src/mobile-web-shell/generations/generation-staging-assets.ts similarity index 82% rename from mobile/src/mobile-web-shell/generation-staging-assets.ts rename to mobile/src/mobile-web-shell/generations/generation-staging-assets.ts index cd61866c2b4..d8a083ba353 100644 --- a/mobile/src/mobile-web-shell/generation-staging-assets.ts +++ b/mobile/src/mobile-web-shell/generations/generation-staging-assets.ts @@ -1,5 +1,5 @@ -import type { MobileWebBundleFetchResult } from '../transport/web-bundle/mobile-web-bundle-fetch' -import { shellDownloadedAssets } from '../transport/web-bundle/mobile-web-bundle-reply-schemas' +import type { MobileWebBundleFetchResult } from '../../transport/web-bundle/mobile-web-bundle-fetch' +import { shellDownloadedAssets } from '../../transport/web-bundle/mobile-web-bundle-reply-schemas' import { requireStorablePath } from './generation-asset-path' import { joinUri } from './generation-cache-uri' diff --git a/mobile/src/mobile-web-shell/generation-store-file-system.ts b/mobile/src/mobile-web-shell/generations/generation-store-file-system.ts similarity index 88% rename from mobile/src/mobile-web-shell/generation-store-file-system.ts rename to mobile/src/mobile-web-shell/generations/generation-store-file-system.ts index 74189aeb408..06aa62f880e 100644 --- a/mobile/src/mobile-web-shell/generation-store-file-system.ts +++ b/mobile/src/mobile-web-shell/generations/generation-store-file-system.ts @@ -1,4 +1,5 @@ import { Directory, File } from 'expo-file-system' +import { Platform } from 'react-native' export type GenerationDirectoryEntry = { readonly name: string @@ -127,7 +128,23 @@ export function createExpoGenerationFileSystem(rootUri: string): GenerationFileS } }, async moveDirectory(fromUri, toUri) { - new Directory(fromUri).move(new Directory(toUri)) + const from = new Directory(fromUri) + // Below API 26, Expo 55's move copies a directory without its contents; its copy is recursive. + if (Platform.OS === 'android' && Number(Platform.Version) < 26) { + const to = new Directory(toUri) + try { + from.copy(to) + } catch (error) { + // Readers trust a generation by its manifest, so a failed copy must leave no partial tree. + if (to.exists) { + to.delete() + } + throw error + } + from.delete() + return + } + from.move(new Directory(toUri)) }, async moveFile(fromUri, toUri) { new File(fromUri).move(new File(toUri)) diff --git a/mobile/src/mobile-web-shell/generation-store.ts b/mobile/src/mobile-web-shell/generations/generation-store.ts similarity index 96% rename from mobile/src/mobile-web-shell/generation-store.ts rename to mobile/src/mobile-web-shell/generations/generation-store.ts index 0e78ad2a2d6..c406de60e90 100644 --- a/mobile/src/mobile-web-shell/generation-store.ts +++ b/mobile/src/mobile-web-shell/generations/generation-store.ts @@ -1,8 +1,8 @@ -import type { MobileWebBundleManifestRead } from '../transport/web-bundle/mobile-web-bundle-reply-schemas' +import type { MobileWebBundleManifestRead } from '../../transport/web-bundle/mobile-web-bundle-reply-schemas' import type { MobileWebBundleFetchResult, MobileWebBundleReusableAssets -} from '../transport/web-bundle/mobile-web-bundle-fetch' +} from '../../transport/web-bundle/mobile-web-bundle-fetch' import { joinUri } from './generation-cache-uri' import { createGenerationHostOrder, withHostLast } from './generation-host-order' import { createDeferredCommits } from './generation-deferred-commits' @@ -18,7 +18,7 @@ import { listGenerationHostDirectories } from './generation-host-directories' import { isHostCacheKey } from './host-cache-key' -import type { MobileWebShellUpdateFailure } from './mobile-web-shell-update-failure' +import type { MobileWebShellUpdateFailure } from '../mobile-web-shell-update-failure' import { forgetHostUpdateFailuresIn, readUpdateFailureLog, @@ -216,7 +216,7 @@ export function createGenerationStore(options: { manifest: staged.manifest } const entries = await fs.list(generations) - // A build-id directory alone proves nothing: pre-API-26 Android moves can leave it empty. Require its activation manifest before reusing it. + // A build-id directory alone proves nothing; require its activation manifest before reusing it. const existing = entries.find((entry) => entry.name === staged.buildId) if ( existing?.isDirectory === true && @@ -238,7 +238,7 @@ export function createGenerationStore(options: { } await fs.createDirectory(generations) await fs.moveDirectory(staged.directory, target) - // Below API 26, Expo Android FileSystemPath.kt moves directories via non-recursive copy/delete and can leave an empty target; failed source deletion leaves tmp for sweeping. + // Never activate a target without its manifest; a source left in tmp is swept. if (!(await fs.fileExists(joinUri(target, MANIFEST_FILE_NAME)))) { await fs.delete(target) throw new Error(`generation ${staged.buildId} did not carry its manifest through the rename`) diff --git a/mobile/src/mobile-web-shell/host-cache-key.ts b/mobile/src/mobile-web-shell/generations/host-cache-key.ts similarity index 100% rename from mobile/src/mobile-web-shell/host-cache-key.ts rename to mobile/src/mobile-web-shell/generations/host-cache-key.ts diff --git a/mobile/src/mobile-web-shell/mobile-web-shell-update-failure-log.ts b/mobile/src/mobile-web-shell/generations/mobile-web-shell-update-failure-log.ts similarity index 96% rename from mobile/src/mobile-web-shell/mobile-web-shell-update-failure-log.ts rename to mobile/src/mobile-web-shell/generations/mobile-web-shell-update-failure-log.ts index 8e6bcab8b67..1b53f810efa 100644 --- a/mobile/src/mobile-web-shell/mobile-web-shell-update-failure-log.ts +++ b/mobile/src/mobile-web-shell/generations/mobile-web-shell-update-failure-log.ts @@ -1,5 +1,5 @@ import { z } from 'zod' -import { MobileWebBundleErrorCodeSchema } from '../../../src/shared/mobile-web-bundle/bundle-rpc-contract' +import { MobileWebBundleErrorCodeSchema } from '../../../../src/shared/mobile-web-bundle/bundle-rpc-contract' import { joinUri } from './generation-cache-uri' import type { GenerationFileSystem } from './generation-store-file-system' import { @@ -7,7 +7,7 @@ import { MOBILE_WEB_SHELL_UPDATE_FAILURE_REASONS, MOBILE_WEB_SHELL_UPDATE_FAILURE_WALLS, type MobileWebShellUpdateFailure -} from './mobile-web-shell-update-failure' +} from '../mobile-web-shell-update-failure' // Keep enough history to distinguish one bad download from repeated failures without growing diagnostic storage. export const MAX_UPDATE_FAILURES_PER_HOST = 5 diff --git a/mobile/src/mobile-web-shell/process-generation-store.ts b/mobile/src/mobile-web-shell/generations/process-generation-store.ts similarity index 88% rename from mobile/src/mobile-web-shell/process-generation-store.ts rename to mobile/src/mobile-web-shell/generations/process-generation-store.ts index 144fe4bf4bc..d6c9bcc9391 100644 --- a/mobile/src/mobile-web-shell/process-generation-store.ts +++ b/mobile/src/mobile-web-shell/generations/process-generation-store.ts @@ -1,8 +1,8 @@ import { Directory, Paths } from 'expo-file-system' -import { generationStoreDirectory } from '../../modules/orca-mobile-web-shell/src/generation-store-directory' +import { generationStoreDirectory } from '../../../modules/orca-mobile-web-shell/src/generation-store-directory' import { createGenerationStore, type GenerationStore } from './generation-store' import { createExpoGenerationFileSystem } from './generation-store-file-system' -import { dropHomeSparePage } from './home-spare-page' +import { dropHomeSparePage } from '../home-spare-page' const GENERATION_STORE_DIRECTORY_NAME = 'mobile-web' diff --git a/mobile/src/mobile-web-shell/removed-host-shell-cache.ts b/mobile/src/mobile-web-shell/generations/removed-host-shell-cache.ts similarity index 100% rename from mobile/src/mobile-web-shell/removed-host-shell-cache.ts rename to mobile/src/mobile-web-shell/generations/removed-host-shell-cache.ts diff --git a/mobile/src/mobile-web-shell/home-spare-page.ts b/mobile/src/mobile-web-shell/home-spare-page.ts index bf93ad3d371..8124dfa1cd4 100644 --- a/mobile/src/mobile-web-shell/home-spare-page.ts +++ b/mobile/src/mobile-web-shell/home-spare-page.ts @@ -3,9 +3,9 @@ import { discardSpareDocument, prepareSpareDocument } from '../../modules/orca-mobile-web-shell/src/spare-document' -import type { GenerationStore } from './generation-store' -import { generationDirectoryPath } from './generation-store-file-system' -import { deriveHostCacheKey } from './host-cache-key' +import type { GenerationStore } from './generations/generation-store' +import { generationDirectoryPath } from './generations/generation-store-file-system' +import { deriveHostCacheKey } from './generations/host-cache-key' import { mintShellSessionId } from './shell-session-id' // A Home entry claims the spare about 0.2 s after the tap on a simulator; a native screen keeps it no longer. diff --git a/mobile/src/mobile-web-shell/mobile-web-shell-runtime.ts b/mobile/src/mobile-web-shell/mobile-web-shell-runtime.ts index 44e53bfd614..13dcb5edd6e 100644 --- a/mobile/src/mobile-web-shell/mobile-web-shell-runtime.ts +++ b/mobile/src/mobile-web-shell/mobile-web-shell-runtime.ts @@ -1,6 +1,6 @@ import { BRIDGE_READY_RETRY_MAX_MS } from './bridge/bridge-client-init-handshake' -import type { GenerationStore } from './generation-store' -import { processGenerationStore } from './process-generation-store' +import type { GenerationStore } from './generations/generation-store' +import { processGenerationStore } from './generations/process-generation-store' import { setForegroundTimer } from './foreground-timer' import { claimHomeSparePage } from './home-spare-page' import { mintShellSessionId } from './shell-session-id' diff --git a/mobile/src/mobile-web-shell/mobile-web-shell-session-effects.test.ts b/mobile/src/mobile-web-shell/mobile-web-shell-session-effects.test.ts index b023ae70955..b829980919f 100644 --- a/mobile/src/mobile-web-shell/mobile-web-shell-session-effects.test.ts +++ b/mobile/src/mobile-web-shell/mobile-web-shell-session-effects.test.ts @@ -7,6 +7,7 @@ const doubles = vi.hoisted(() => ({ })) vi.mock('expo-file-system', () => ({ Directory: class {}, File: class {}, Paths: { cache: '' } })) +vi.mock('react-native', () => ({ Platform: { OS: 'ios' } })) // The runner's deadlines live in the runtime module, whose foreground timer reads React Native's AppState. vi.mock('./foreground-timer', () => ({ setForegroundTimer: () => () => {} })) vi.mock('../transport/rpc/rpc-operation', () => ({ @@ -20,9 +21,9 @@ vi.mock('../transport/web-bundle/mobile-web-bundle-fetch', () => ({ import type { RpcClient } from '../transport/rpc/rpc-client-contract' import { computeMobileWebBundleId } from '../../../src/shared/mobile-web-bundle/manifest-contract' import type { MobileWebBundleFetchResult } from '../transport/web-bundle/mobile-web-bundle-fetch' -import { createGenerationStore, type GenerationStore } from './generation-store' -import { createFakeGenerationFileSystem } from './generation-file-system-fake' -import { deriveHostCacheKey } from './host-cache-key' +import { createGenerationStore, type GenerationStore } from './generations/generation-store' +import { createFakeGenerationFileSystem } from './generations/generation-file-system-fake' +import { deriveHostCacheKey } from './generations/host-cache-key' import { download } from './mobile-web-shell-session-effects' const CLIENT: RpcClient = { @@ -114,64 +115,6 @@ describe('a download that reuses the cached generation', () => { return done.then(() => events) } - it('writes no staging bytes when canceled while its staging waits in the store queue', async () => { - const fileSystem = createFakeGenerationFileSystem() - const store = createGenerationStore({ fileSystem }) - const NEXT = bundle(16) - const BLOCKER = deriveHostCacheKey('host-b') - let enterBlocker = (): void => {} - const blockerEntered = new Promise((resolve) => { - enterBlocker = resolve - }) - let releaseBlocker = (): void => {} - const blockerReleased = new Promise((resolve) => { - releaseBlocker = resolve - }) - const list = fileSystem.list.bind(fileSystem) - fileSystem.list = async (uri) => { - if (uri.includes(`/${BLOCKER}/`)) { - enterBlocker() - await blockerReleased - } - return list(uri) - } - const writes: string[] = [] - const writeBytes = fileSystem.writeBytes.bind(fileSystem) - fileSystem.writeBytes = async (uri, bytes) => { - writes.push(uri) - await writeBytes(uri, bytes) - } - let blocker: Promise = Promise.resolve() - doubles.fetch = async () => { - blocker = store.readActiveGeneration(BLOCKER) - await blockerEntered - return NEXT - } - let markQueued = (): void => {} - const stageQueued = new Promise((resolve) => { - markQueued = resolve - }) - const downloads = new Set() - const run = runFor( - { - ...store, - stageGeneration: (...args) => { - const staged = store.stageGeneration(...args) - markQueued() - return staged - } - }, - downloads - ) - - await stageQueued - downloads.forEach((controller) => controller.abort()) - releaseBlocker() - await Promise.all([run, blocker]) - - expect(writes.filter((uri) => uri.includes(`/tmp/${NEXT.manifest.buildId}/`))).toEqual([]) - }) - it('stages from the offered snapshot without reopening its manifest after fetch', async () => { const { fileSystem, store } = await cachedStore() doubles.fetch = async () => { diff --git a/mobile/src/mobile-web-shell/mobile-web-shell-session-effects.ts b/mobile/src/mobile-web-shell/mobile-web-shell-session-effects.ts index a8d939a15d7..257e9af5ad1 100644 --- a/mobile/src/mobile-web-shell/mobile-web-shell-session-effects.ts +++ b/mobile/src/mobile-web-shell/mobile-web-shell-session-effects.ts @@ -9,14 +9,14 @@ import { import type { MobileWebBundleCompatManifest } from '../transport/web-bundle/mobile-web-bundle-compat' import { runRpcOperation } from '../transport/rpc/rpc-operation' import type { RpcClient } from '../transport/rpc/rpc-client-contract' -import type { GenerationStore, StagedGeneration } from './generation-store' +import type { GenerationStore, StagedGeneration } from './generations/generation-store' import type { createShellPageDeadline } from './shell-page-deadline' import { DOCUMENT_LOAD_DEADLINE_MS, PAGE_READY_DEADLINE_MS, type MobileWebShellRuntime } from './mobile-web-shell-runtime' -import { generationDirectoryPath } from './generation-store-file-system' +import { generationDirectoryPath } from './generations/generation-store-file-system' import type { CachedGeneration, MobileWebShellSessionEffect, diff --git a/mobile/src/mobile-web-shell/mobile-web-shell-update-failure-log.test.ts b/mobile/src/mobile-web-shell/mobile-web-shell-update-failure-log.test.ts deleted file mode 100644 index cd783473a9d..00000000000 --- a/mobile/src/mobile-web-shell/mobile-web-shell-update-failure-log.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { computeMobileWebBundleId } from '../../../src/shared/mobile-web-bundle/manifest-contract' -import type { MobileWebBundleFetchResult } from '../transport/web-bundle/mobile-web-bundle-fetch' -import { createFakeGenerationFileSystem } from './generation-file-system-fake' -import { createGenerationStore } from './generation-store' -import { deriveHostCacheKey } from './host-cache-key' -import type { MobileWebShellUpdateFailure } from './mobile-web-shell-update-failure' -import { appendUpdateFailure } from './mobile-web-shell-update-failure-log' - -const LOG = 'update-failures.json' - -function failure(hostId: string, at: number): MobileWebShellUpdateFailure { - return { - hostId, - at, - reason: 'asset-checksum-mismatch', - hostCode: null, - offeredBuildId: 'c'.repeat(64), - cachedBuildId: 'b'.repeat(64), - outcome: 'opened-cached', - wall: null - } -} - -describe('appendUpdateFailure', () => { - it('drops a build id that is not a digest rather than keep host text', () => { - const [entry] = appendUpdateFailure([], { - ...failure('host-1', 0), - offeredBuildId: 'https://host/?token=SECRET' - }) - expect(entry?.offeredBuildId).toBeNull() - }) -}) - -describe('the generation store keeps the log', () => { - it('writes, reads back and survives a relaunch', async () => { - const fileSystem = createFakeGenerationFileSystem() - await createGenerationStore({ fileSystem }).recordUpdateFailure(failure('host-1', 5)) - expect(await createGenerationStore({ fileSystem }).readUpdateFailures()).toEqual([ - failure('host-1', 5) - ]) - }) - - it("forgets one host's records and leaves the others", async () => { - const fileSystem = createFakeGenerationFileSystem() - const store = createGenerationStore({ fileSystem }) - await store.recordUpdateFailure(failure('host-1', 1)) - await store.recordUpdateFailure(failure('host-2', 2)) - await store.forgetHostUpdateFailures('host-1') - expect((await store.readUpdateFailures()).map((entry) => entry.hostId)).toEqual(['host-2']) - await store.forgetHostUpdateFailures('host-2') - expect(fileSystem.text(LOG)).toBeNull() - }) - - it("outlives the host's own cache, which a recovery deletes", async () => { - const fileSystem = createFakeGenerationFileSystem() - const store = createGenerationStore({ fileSystem }) - const host = deriveHostCacheKey('host-1') - const assets = [ - { path: 'index.html', sha256: '1'.repeat(64), byteLength: 1, contentType: 'text/html' } - ] - const buildId = computeMobileWebBundleId(assets) - const bundle: MobileWebBundleFetchResult = { - manifest: { - schemaVersion: 1, - buildId, - minCompatibleRuntimeProtocolVersion: 2, - runtimeProtocolVersion: 2, - entrypoint: 'index.html', - totalBytes: 1, - assets - }, - assets: new Map([['index.html', new Uint8Array(1)]]), - reused: [], - totalBytes: 1, - elapsedMs: 1 - } - await store.commitGeneration(await store.stageGeneration(host, bundle)) - expect((await store.readActiveGeneration(host))?.buildId).toBe(buildId) - expect(fileSystem.paths()).toContain(`${host}/generations/${buildId}/manifest.json`) - expect(fileSystem.bytes(`${host}/generations/${buildId}/index.html`)).toEqual(new Uint8Array(1)) - const recorded = failure('host-1', 1) - await store.recordUpdateFailure(recorded) - await store.deleteHostCache(host) - expect(fileSystem.paths().some((path) => path === host || path.startsWith(`${host}/`))).toBe( - false - ) - expect(await store.readActiveGeneration(host)).toBeNull() - expect(await store.readUpdateFailures()).toEqual([recorded]) - }) - - it('reads a corrupt log as empty and keeps the entries that still parse', async () => { - const fileSystem = createFakeGenerationFileSystem() - const store = createGenerationStore({ fileSystem }) - await fileSystem.writeText(`${fileSystem.rootUri}/${LOG}`, '{not json') - expect(await store.readUpdateFailures()).toEqual([]) - await fileSystem.writeText( - `${fileSystem.rootUri}/${LOG}`, - JSON.stringify([failure('host-1', 1), { ...failure('host-1', 2), url: 'wss://x/?t=1' }]) - ) - expect(await store.readUpdateFailures()).toEqual([failure('host-1', 1)]) - }) -}) diff --git a/mobile/src/mobile-web-shell/use-mobile-web-shell-session.test.ts b/mobile/src/mobile-web-shell/use-mobile-web-shell-session.test.ts index c5b70b1822f..1ff5d92c198 100644 --- a/mobile/src/mobile-web-shell/use-mobile-web-shell-session.test.ts +++ b/mobile/src/mobile-web-shell/use-mobile-web-shell-session.test.ts @@ -7,7 +7,11 @@ import type { MobileWebBundleFetchResult } from '../transport/web-bundle/mobile-web-bundle-fetch' import type { MobileWebBundleManifestRead } from '../transport/web-bundle/mobile-web-bundle-reply-schemas' -import type { ActiveGeneration, GenerationStore, StagedGeneration } from './generation-store' +import type { + ActiveGeneration, + GenerationStore, + StagedGeneration +} from './generations/generation-store' import type { DownloadProgressFeed } from './download-progress-feed' import type { MobileWebShellSessionState } from './mobile-web-shell-session-contract' import '../transport/rpc/rpc-delivery-ambiguity' @@ -205,7 +209,6 @@ function createFakeStore(): { } } -// Use recorded timers so deadline tests assert requested delays without wall-clock waits. type ArmedTimer = { delayMs: number; run: () => void; cancelled: boolean } function createTimerSeam() { @@ -347,7 +350,6 @@ async function flush(): Promise { await act(async () => undefined) } -// Entry import failures can finish WebView load without mounting a boundary or sending ready; the deadline must recover that silent blank page. describe('the wait for the page to speak', () => { beforeEach(() => { doubles.manifestReads = 0 @@ -358,24 +360,6 @@ describe('the wait for the page to speak', () => { doubles.gates.hostCapabilities = [MOBILE_WEB_BUNDLE_CAPABILITY] }) - async function ready(fake = createFakeStore()): Promise { - const mounted = await mount(fake.store) - fake.settleCacheRead(activeGeneration()) - await flush() - expect(mounted.states().at(-1)?.kind).toBe('ready') - return mounted - } - - // A remount mints the replacement's session before React commits it; reports the retired view already queued must not land on it. - it('does not charge a second fault from the retired view to its replacement', async () => { - const mounted = await ready() - await act(async () => { - mounted.shellFailed('document-load-failed') - mounted.shellFailed('document-load-failed') - }) - expect(mounted.states().at(-1)?.kind).toBe('ready') - }) - it('opens a page Home booted under its session id, and remounts under a fresh one', async () => { const fake = createFakeStore() const mounted = await mount(fake.store, undefined, async () => 'home-spare') @@ -389,21 +373,6 @@ describe('the wait for the page to speak', () => { expect(mounted.states().at(-1)).toMatchObject({ kind: 'ready', sessionId: 'session-1' }) }) - it('stays ready when the page speaks after document load and the timers fire', async () => { - const mounted = await ready() - await act(async () => { - mounted.documentLoaded() - mounted.pageReady() - }) - await act(async () => { - mounted.timers.fire() - }) - expect(mounted.states().at(-1)?.kind).toBe('ready') - await act(async () => { - mounted.tree.unmount() - }) - }) - it('re-arms a session the route rebuilt, with the host and its gates unchanged', async () => { // A route change rebuilds the session too; re-arm gates even if their verdict did not change. const fake = createFakeStore() @@ -454,5 +423,3 @@ describe('the wait for the page to speak', () => { }) }) }) - -// RN holds timers while backgrounded and fires overdue ones on resume, before the suspended WebView has loaded anything. diff --git a/mobile/src/mobile-web-shell/use-mobile-web-shell-session.ts b/mobile/src/mobile-web-shell/use-mobile-web-shell-session.ts index ab448fb5e17..9c85c0aa08c 100644 --- a/mobile/src/mobile-web-shell/use-mobile-web-shell-session.ts +++ b/mobile/src/mobile-web-shell/use-mobile-web-shell-session.ts @@ -6,8 +6,8 @@ import { downloadFraction, type DownloadProgressFeed } from './download-progress-feed' -import type { GenerationStore } from './generation-store' -import { deriveHostCacheKey } from './host-cache-key' +import type { GenerationStore } from './generations/generation-store' +import { deriveHostCacheKey } from './generations/host-cache-key' import { runShellEffect, type FlowManifest } from './mobile-web-shell-session-effects' import { documentMayTalk } from './mobile-web-shell-gates' import { readMobileWebShellReachability } from './mobile-web-shell-reachability' diff --git a/mobile/src/session/MobileSessionHeader.tsx b/mobile/src/session/MobileSessionHeader.tsx index 9020e7d7486..d1f108b6851 100644 --- a/mobile/src/session/MobileSessionHeader.tsx +++ b/mobile/src/session/MobileSessionHeader.tsx @@ -1,12 +1,13 @@ import { useRef, useState, useSyncExternalStore } from 'react' import { StyleSheet, View } from 'react-native' import { SafeAreaView } from 'react-native-safe-area-context' -import { ChevronLeft, GitBranch, MoreHorizontal, PanelLeftOpen } from 'lucide-react-native' +import { ChevronLeft, MoreHorizontal, PanelLeftOpen } from 'lucide-react-native' import { NavBar, NavBarRefreshLine } from '../components/nav-bar/NavBar' import { useRefreshHint } from '../query/refresh-hint' import { NavBarButton } from '../components/nav-bar/NavBarButton' import { MobileSessionHeaderMoreMenu } from './MobileSessionHeaderMoreMenu' -import { MobileSessionTabBar } from './tabs/MobileSessionTabBar' +import { MobileSourceControlButton } from './MobileSourceControlButton' +import { MobileSessionTabStrip } from './tabs/MobileSessionTabStrip' import { MobileSessionTitleBlock } from './MobileSessionTitleBlock' import type { SessionTitleCard } from './tabs/use-session-title-card' import { styles } from './mobile-session-styles' @@ -30,6 +31,7 @@ export function MobileSessionHeader({ const t = useMobileTranslation() const { hostId, + worktreeId, isFloatingWorkspaceRoute, presentedConnState, forceReconnectHost, @@ -58,11 +60,11 @@ export function MobileSessionHeader({ // Why: a sideways phone is ~390pt tall, so the tabs share the top bar instead of taking a second row. const hasTabs = visibleTabs.length > 0 const tabsInTopBar = (layout.isLandscapePhone || sideRail) && hasTabs - // Bar buttons otherwise leave the tab bar too narrow to read on a narrow header. + // Bar buttons otherwise leave less than two readable tabs on a narrow header. const actionsCollapsed = tabsInTopBar && (headerWidth ?? layout.width) < 600 const sourceControlInBar = !isFloatingWorkspaceRoute && !actionsCollapsed const tabStrip = hasTabs ? ( - {sourceControlInBar ? ( - handlePanelTap('sourceControl')} /> ) : null} diff --git a/mobile/src/session/MobileSessionSheets.tsx b/mobile/src/session/MobileSessionSheets.tsx index 7cf3bf558db..fe6f590a3d2 100644 --- a/mobile/src/session/MobileSessionSheets.tsx +++ b/mobile/src/session/MobileSessionSheets.tsx @@ -2,7 +2,7 @@ import { Platform } from 'react-native' import { useMobileTranslation } from '../i18n/use-mobile-translation' import { getRepoIdFromWorktreeId } from '../../../src/shared/worktree/id' import { useClipboardWriter } from '../platform/clipboard' -import { Copy, FileText, RefreshCw } from 'lucide-react-native' +import { Copy, FileText, Globe, RefreshCw, SquareTerminal } from 'lucide-react-native' import { MobileSessionTerminalLayoutSheet } from '../terminal/session/MobileSessionTerminalLayoutSheet' import { QuickCommandsSheet } from '../terminal/quick-commands/QuickCommandsSheet' import { triggerSuccess, triggerError } from '../platform/haptics' @@ -19,7 +19,6 @@ import { isTerminalPhoneDisplayMode } from '../terminal/session/terminal-phone-d import type { MobileSessionController } from './use-mobile-session-controller' import { useMobileAllowAutoCloseActions } from './tabs/mobile-worker-auto-close' import { MobileAgentSessionTabActionSheet } from './tabs/MobileAgentSessionTabActionSheet' -import { MobileNewTabSheet } from './tabs/MobileNewTabSheet' export function MobileSessionSheets({ controller }: { controller: MobileSessionController }) { const t = useMobileTranslation() @@ -91,8 +90,7 @@ export function MobileSessionSheets({ controller }: { controller: MobileSessionC bulkCloseActions, bulkCloseConfirm, closeWithBulkActions, - createTabAgentStatusRow, - createTabAgentOptions, + createTabAgentActions, sendDiffNotesAgentActions } = controller const clipboard = useClipboardWriter() @@ -117,33 +115,61 @@ export function MobileSessionSheets({ controller }: { controller: MobileSessionC agentPromptMaxLength={controller.quickCommandAgentPromptMaxLength} onLaunch={launchQuickCommand} /> - { + setShowCreateTabDrawer(false) + void handleCreateTerminal() + } + }, + // Why: browser/markdown creation resolve a real worktree on the host + // (browser.tabCreate, files.createFile); the floating sentinel is + // terminal-only over RPC, so those options hide there. + ...(isFloatingWorkspaceRoute + ? [] + : [ + { + id: 'browser', + label: t('session.sheets.browser', 'Browser'), + icon: Globe, + closeBeforePress: true, + onPress: () => { + if (browserScreencastSupported !== true) { + showToast( + t( + 'session.sheets.browserUpdateRequired', + 'Desktop update required for mobile browser streaming' + ), + 1600 + ) + return + } + setShowCreateBrowserModal(true) + } + }, + ...(onPairedHost + ? [ + { + id: 'markdownNote', + label: t('session.sheets.markdownNote', 'Markdown Note'), + icon: FileText, + onPress: () => { + setShowCreateTabDrawer(false) + void handleCreateMarkdownNote() + } + } + ] + : []) + ]) + ]} onClose={() => setShowCreateTabDrawer(false)} - onCreateAgent={(agent) => void handleCreateTerminal(agent)} - onCreateTerminal={() => void handleCreateTerminal()} - onCreateBrowser={() => { - if (browserScreencastSupported !== true) { - showToast( - t( - 'session.sheets.browserUpdateRequired', - 'Desktop update required for mobile browser streaming' - ), - 1600 - ) - return - } - setShowCreateBrowserModal(true) - }} - onCreateMarkdownNote={() => void handleCreateMarkdownNote()} /> void +}) { + useMobileColorScheme() + const t = useMobileTranslation() + // Cache-only: the host list reads worktree.ps, and a session's first paint must not wait behind it. + const { data } = useHostQuery( + hostWorktreeCatalogQuery, + { hostId, client: null }, + HOST_LIST_TARGET, + NO_HOST_LIST_INPUT, + { enabled: false } + ) + const pr = data?.worktrees.find((row) => row.worktreeId === worktreeId)?.linkedPR ?? null + const knownState = pr && pr.state !== UNCACHED_LINKED_PR_STATE ? pr.state : null + return ( + + ) +} diff --git a/mobile/src/session/mobile-session-frame-styles.ts b/mobile/src/session/mobile-session-frame-styles.ts index 352a639e607..524a265cc29 100644 --- a/mobile/src/session/mobile-session-frame-styles.ts +++ b/mobile/src/session/mobile-session-frame-styles.ts @@ -58,6 +58,108 @@ export const mobileSessionFrameStyles = themedStyleSheet(() => ({ color: colors.textSecondary, fontSize: typography.metaSize }, + tabBar: { + flexDirection: 'row', + alignItems: 'center', + borderTopWidth: 1, + borderTopColor: colors.borderSubtle + }, + // Cancels the top bar's vertical padding so tab borders run the bar's full height. + tabBarInTopBar: { + flex: 1, + minWidth: 0, + flexDirection: 'row', + alignItems: 'center', + alignSelf: 'stretch', + marginVertical: -spacing.xs, + marginLeft: spacing.md, + borderLeftWidth: 1, + borderLeftColor: colors.borderSubtle + }, + tabScrollFrame: { + flex: 1, + minWidth: 0, + flexDirection: 'row', + alignItems: 'center', + alignSelf: 'stretch' + }, + tabEdgeHint: { + position: 'absolute', + top: 0, + bottom: 0, + justifyContent: 'center', + paddingHorizontal: spacing.xs, + backgroundColor: colors.bgPanel + }, + tabEdgeHintLeft: { + left: 0, + borderRightWidth: 1, + borderRightColor: colors.borderSubtle + }, + tabEdgeHintRight: { + right: 0, + borderLeftWidth: 1, + borderLeftColor: colors.borderSubtle + }, + // Opaque like the chrome behind it: see the chat page scroll (#36553). + tabScroll: { + flex: 1, + maxHeight: 44, + backgroundColor: colors.bgPanel + }, + tabScrollInTopBar: { + alignSelf: 'stretch', + maxHeight: 44 + }, + tabContent: { + paddingLeft: spacing.md, + paddingRight: spacing.sm + }, + tabContentInTopBar: { + paddingLeft: 0 + }, + tab: { + minWidth: 44, + maxWidth: 128, + minHeight: 44, + alignItems: 'center', + justifyContent: 'center', + paddingHorizontal: spacing.sm, + paddingVertical: spacing.sm, + borderBottomWidth: 2, + borderBottomColor: 'transparent', + borderRightWidth: 1, + borderRightColor: colors.borderSubtle + }, + tabFirst: { + borderLeftWidth: 1, + borderLeftColor: colors.borderSubtle + }, + tabActive: { + borderBottomColor: colors.textSecondary, + backgroundColor: colors.bgRaised + }, + tabPressed: { + backgroundColor: colors.translucentFill + }, + tabLabelRow: { + maxWidth: '100%', + flexDirection: 'row', + alignItems: 'center', + gap: spacing.xs + }, + // Prevent web SVG shrink before the title ellipsizes. + tabIcon: { + flexShrink: 0 + }, + tabText: { + flexShrink: 1, + color: colors.textSecondary, + fontSize: 13 + }, + tabTextActive: { + color: colors.textPrimary + }, newTerminalButtonPressed: { backgroundColor: colors.bgRaised }, diff --git a/mobile/src/session/native-chat/composer/mobile-native-chat-file-attachment.test.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-file-attachment.test.ts deleted file mode 100644 index 6a373e8674f..00000000000 --- a/mobile/src/session/native-chat/composer/mobile-native-chat-file-attachment.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { nativeChatTextWithFileReferences } from './mobile-native-chat-file-attachment' - -describe('nativeChatTextWithFileReferences', () => { - it('references each stored file on a line after the text', () => { - expect( - nativeChatTextWithFileReferences('Review these ', [ - { path: '/store/1/spec.pdf' }, - { path: '/store/2/my notes.md' } - ]) - ).toBe('Review these\n@/store/1/spec.pdf @"/store/2/my notes.md"') - }) - - it('sends the references alone when there is no text, and the text alone with no files', () => { - expect(nativeChatTextWithFileReferences(' ', [{ path: '/store/1/spec.pdf' }])).toBe( - '@/store/1/spec.pdf' - ) - expect(nativeChatTextWithFileReferences('hi', [])).toBe('hi') - }) -}) diff --git a/mobile/src/session/native-chat/composer/use-mobile-native-chat-send-error.test.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-send-error.test.ts index 825c6960288..77871ebd73d 100644 --- a/mobile/src/session/native-chat/composer/use-mobile-native-chat-send-error.test.ts +++ b/mobile/src/session/native-chat/composer/use-mobile-native-chat-send-error.test.ts @@ -76,18 +76,6 @@ describe('useMobileNativeChatSendError', () => { expect(api().message).toBeNull() }) - it('a refusal behind a question goes once it is answered', async () => { - await render() - await showing({ working: false, prompt: true }) - await act(async () => - api().show("Answer the agent's question or approval, then run /clear.", { - refusedWhile: 'prompt' - }) - ) - await showing({ working: false, prompt: false }) - expect(api().message).toBeNull() - }) - it('a failure naming nothing the phone shows, or background tasks it cannot see, stays', async () => { await render() await act(async () => api().show('Message not sent')) @@ -115,16 +103,6 @@ describe('useMobileNativeChatSendError', () => { expect(api().message).toBeNull() }) - it('falls back to the toast when the banner is not mounted', async () => { - await act(async () => { - renderer = create(createElement(Harness, { scopeKey: 'terminal-1', bannerMounted: false })) - }) - await act(async () => api().show('Delivery unconfirmed')) - - expect(showToast).toHaveBeenCalledWith('Delivery unconfirmed', 1600) - expect(api().message).toBeNull() - }) - it('toasts a deferred failure that resolves after the user switched tabs', async () => { await render('terminal-1') const showFromTabA = api().show diff --git a/mobile/src/session/native-chat/input/MobileNativeChatOptionPreviewSheet.tsx b/mobile/src/session/native-chat/input/MobileNativeChatOptionPreviewSheet.tsx index 3328570d533..650882bf8a0 100644 --- a/mobile/src/session/native-chat/input/MobileNativeChatOptionPreviewSheet.tsx +++ b/mobile/src/session/native-chat/input/MobileNativeChatOptionPreviewSheet.tsx @@ -8,7 +8,6 @@ import { useMobileTranslation } from '../../../i18n/use-mobile-translation' import { colors, radii, spacing, typography, pressedStyle } from '../../../theme/mobile-theme' import { themedStyleSheet } from '../../../theme/themed-styles' import { useMobileColorScheme } from '../../../theme/use-mobile-color-scheme' -import { optionPreviewFont } from './mobile-native-chat-option-preview' const sheetKey = () => 'option-preview' @@ -117,7 +116,7 @@ const styles = themedStyleSheet(() => ({ text: { padding: spacing.md, color: colors.textPrimary, - fontFamily: optionPreviewFont, + fontFamily: typography.monoFamily, fontSize: typography.bodySize, lineHeight: typography.bodySize * 1.5 }, diff --git a/mobile/src/session/native-chat/input/MobileNativeChatOptionThumbnail.tsx b/mobile/src/session/native-chat/input/MobileNativeChatOptionThumbnail.tsx index 1399a26db65..06b78c62389 100644 --- a/mobile/src/session/native-chat/input/MobileNativeChatOptionThumbnail.tsx +++ b/mobile/src/session/native-chat/input/MobileNativeChatOptionThumbnail.tsx @@ -5,7 +5,6 @@ import { useMobileTranslation } from '../../../i18n/use-mobile-translation' import { colors, radii, spacing, typography, pressedStyle } from '../../../theme/mobile-theme' import { themedStyleSheet } from '../../../theme/themed-styles' import { useMobileColorScheme } from '../../../theme/use-mobile-color-scheme' -import { optionPreviewFont } from './mobile-native-chat-option-preview' const MAX_HEIGHT = 96 - spacing.sm * 2 @@ -96,7 +95,7 @@ const styles = themedStyleSheet(() => ({ top: 0, left: 0, transformOrigin: 'top left', - fontFamily: optionPreviewFont, + fontFamily: typography.monoFamily, fontSize: typography.metaSize, lineHeight: typography.metaSize * 1.25, color: colors.textPrimary, diff --git a/mobile/src/session/native-chat/input/mobile-native-chat-option-preview.ts b/mobile/src/session/native-chat/input/mobile-native-chat-option-preview.ts deleted file mode 100644 index e39b7d52635..00000000000 --- a/mobile/src/session/native-chat/input/mobile-native-chat-option-preview.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Platform } from 'react-native' -import { typography } from '../../../theme/mobile-theme' - -export const optionPreviewFont = Platform.select({ - ios: 'Menlo', - default: typography.monoFamily -}) diff --git a/mobile/src/session/native-chat/input/use-mobile-structured-agent-options.test.ts b/mobile/src/session/native-chat/input/use-mobile-structured-agent-options.test.ts index 7c813e1409e..df00001b2a9 100644 --- a/mobile/src/session/native-chat/input/use-mobile-structured-agent-options.test.ts +++ b/mobile/src/session/native-chat/input/use-mobile-structured-agent-options.test.ts @@ -342,33 +342,6 @@ it('phone captures accepted echoed inputs, preserves false, and freezes empty vs await harness.unmount() }) -it('accepts a typed literal at an attached fence while options refresh with no menu', async () => { - const pending = deferred() - let reads = 0 - const client = optionsClient(() => - ++reads === 1 ? Promise.resolve({ models: [], current: {} }) : pending.promise - ) - const { calls, mutate } = recordingMutate(async () => - accepted({ key: 'model', value: 'literal', options: { model: 'literal' } }, true) - ) - const view = await mountOptions({ ...BASE, client: client.client, mutate }) - await view.rerender({ fence: 2 }) - let result = true - await act(async () => { - result = await view.current().setStructuredOption('model', 'literal') - }) - expect(result).toBe(true) - expect(calls).toHaveLength(1) - await act(async () => pending.resolve({ models: [], current: {} })) - await settle() - await act(async () => { - result = await view.current().setStructuredOption('model', 'literal') - }) - expect(result).toBe(true) - expect(calls).toHaveLength(2) - await view.unmount() -}) - it('refreshes saved planning intent from the same host status stamp without remounting', async () => { let interactionMode: 'default' | 'plan' = 'default' const client = optionsClient(async () => ({ diff --git a/mobile/src/session/native-chat/transcript/mobile-native-chat-stream-frame.test.ts b/mobile/src/session/native-chat/transcript/mobile-native-chat-stream-frame.test.ts index 59938201fe1..4059ee91773 100644 --- a/mobile/src/session/native-chat/transcript/mobile-native-chat-stream-frame.test.ts +++ b/mobile/src/session/native-chat/transcript/mobile-native-chat-stream-frame.test.ts @@ -38,25 +38,4 @@ describe('applyMobileNativeChatStreamFrame', () => { windowReplaced: true }) }) - - it('replaces retained history when replay metadata says no earlier rows remain', () => { - const merger = createNativeChatMerger() - replaceList(merger, ['removed-1', 'removed-2', 'a', 'b'].map(message)) - - const replay = [message('a'), message('b')] - expect( - applyMobileNativeChatStreamFrame({ - merger, - frame: { type: 'snapshot', messages: replay, hasMore: false, beforeOffset: 0 }, - limit: 100, - replaceSnapshot: false - }) - ).toEqual({ - kind: 'messages', - messages: replay, - hasMore: false, - beforeOffset: 0, - windowReplaced: true - }) - }) }) diff --git a/mobile/src/session/native-chat/transcript/mobile-native-chat-tool-styles.ts b/mobile/src/session/native-chat/transcript/mobile-native-chat-tool-styles.ts index 68be83a6c66..92f2b113d27 100644 --- a/mobile/src/session/native-chat/transcript/mobile-native-chat-tool-styles.ts +++ b/mobile/src/session/native-chat/transcript/mobile-native-chat-tool-styles.ts @@ -1,4 +1,4 @@ -import { Platform, StyleSheet } from 'react-native' +import { StyleSheet } from 'react-native' import { colors, radii, spacing, typography } from '../../../theme/mobile-theme' import { MONO_SIZE, scaledType } from './mobile-native-chat-message-styles' import { themedStyleSheet } from '../../../theme/themed-styles' @@ -11,9 +11,6 @@ export function toolType(fontScale: number) { } } -// iOS has no font named `monospace`; it silently falls back to the proportional system face. -const MONO_FAMILY = Platform.OS === 'ios' ? 'Menlo' : typography.monoFamily - export const toolStyles = themedStyleSheet(() => ({ run: { marginTop: spacing.xs @@ -111,7 +108,7 @@ export const toolStyles = themedStyleSheet(() => ({ }, codeText: { color: colors.textPrimary, - fontFamily: MONO_FAMILY + fontFamily: typography.monoFamily }, searchResults: { gap: 2 diff --git a/mobile/src/session/tabs/MobileNewTabSheet.tsx b/mobile/src/session/tabs/MobileNewTabSheet.tsx deleted file mode 100644 index 0f7730ddd75..00000000000 --- a/mobile/src/session/tabs/MobileNewTabSheet.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import { useRef } from 'react' -import { Pressable, Text, View } from 'react-native' -import { FileText, Globe, SquareTerminal } from 'lucide-react-native' -import type { TuiAgent } from '../../../../src/shared/agent-launch/catalog/tui-agent' -import { ActionSheetContent, type ActionSheetAction } from '../../components/ActionSheetModal' -import { BottomDrawer } from '../../components/bottom-drawer/BottomDrawer' -import { - LIST_LEADING_INSET, - ListGroup, - ListRow, - SectionHeader -} from '../../components/list/ListGroup' -import { MobileAgentIcon } from '../../components/MobileAgentIcon' -import { SheetHeader } from '../../components/nav-bar/SheetHeader' -import { useMobileTranslation } from '../../i18n/use-mobile-translation' -import { colors, radii, spacing } from '../../theme/mobile-theme' -import { themedStyleSheet } from '../../theme/themed-styles' -import { useMobileColorScheme } from '../../theme/use-mobile-color-scheme' -import type { MobileNewTabAgentOption } from '../agent-launch/mobile-new-tab-agent-options' - -const AGENT_GRID_COLUMNS = 3 - -type Props = { - visible: boolean - workspaceName: string - agentOptions: readonly MobileNewTabAgentOption[] - /** Loading, none, other-server or error; shown instead of the agent grid. */ - agentStatusRow: ActionSheetAction | null - canCreateBrowser: boolean - canCreateMarkdownNote: boolean - onClose: () => void - onCreateAgent: (agent: TuiAgent) => void - onCreateTerminal: () => void - /** Runs after the sheet has gone, so it may open another modal. */ - onCreateBrowser: () => void - onCreateMarkdownNote: () => void -} - -export function MobileNewTabSheet({ - visible, - workspaceName, - agentOptions, - agentStatusRow, - canCreateBrowser, - canCreateMarkdownNote, - onClose, - onCreateAgent, - onCreateTerminal, - onCreateBrowser, - onCreateMarkdownNote -}: Props) { - useMobileColorScheme() - const t = useMobileTranslation() - // Wait for the iOS sheet window to unmount before presenting another native modal. - const afterCloseRef = useRef<(() => void) | null>(null) - const closeThen = (action: () => void) => { - afterCloseRef.current = action - onClose() - } - const closeAndRun = (action: () => void) => { - onClose() - action() - } - const showAgentGrid = agentStatusRow === null && agentOptions.length > 0 - // Short last rows keep empty slots so every tile stays a third of the row wide. - const agentRows: { options: MobileNewTabAgentOption[]; emptySlots: string[] }[] = [] - for (let start = 0; start < agentOptions.length; start += AGENT_GRID_COLUMNS) { - const options = agentOptions.slice(start, start + AGENT_GRID_COLUMNS) - const emptySlots: string[] = [] - for (let column = options.length; column < AGENT_GRID_COLUMNS; column += 1) { - emptySlots.push(`empty:${column}`) - } - agentRows.push({ options, emptySlots }) - } - const iconColor = colors.textSecondary - return ( - { - const run = afterCloseRef.current - afterCloseRef.current = null - run?.() - }} - dragContentToDismiss - > - - {showAgentGrid || agentStatusRow ? ( - - ) : null} - {agentStatusRow ? : null} - {showAgentGrid ? ( - - {agentRows.map((row) => ( - option.agent).join(':')} style={styles.gridRow}> - {row.options.map((option) => ( - closeAndRun(() => onCreateAgent(option.agent))} - accessibilityRole="button" - accessibilityLabel={option.label} - style={styles.tile} - > - {({ pressed }) => ( - <> - {pressed ? : null} - - - {option.label} - - - )} - - ))} - {row.emptySlots.map((slot) => ( - - ))} - - ))} - - ) : null} - - } - onPress={() => closeAndRun(onCreateTerminal)} - /> - {canCreateBrowser ? ( - } - navigates - onPress={() => closeThen(onCreateBrowser)} - /> - ) : null} - {canCreateMarkdownNote ? ( - } - onPress={() => closeAndRun(onCreateMarkdownNote)} - /> - ) : null} - - - ) -} - -const styles = themedStyleSheet(() => ({ - grid: { gap: spacing.sm }, - gridRow: { flexDirection: 'row', gap: spacing.sm }, - tile: { - flex: 1, - minWidth: 0, - height: 78, - borderRadius: radii.surface, - backgroundColor: colors.sheetGroup, - overflow: 'hidden', - alignItems: 'center', - justifyContent: 'center', - gap: spacing.sm, - paddingHorizontal: spacing.sm - }, - // Same wash as a pressed ListRow, laid over the tile so its own fill stays underneath. - tilePressed: { - position: 'absolute', - top: 0, - right: 0, - bottom: 0, - left: 0, - backgroundColor: colors.translucentFill - }, - tileLabel: { fontSize: 13.5, fontWeight: '600', color: colors.textPrimary, maxWidth: '100%' }, - // Padded like a tile: flex shares space after padding, so a bare spacer would widen its row's tiles. - tileSpacer: { flex: 1, paddingHorizontal: spacing.sm }, - actions: { marginTop: spacing.lg } -})) diff --git a/mobile/src/session/tabs/MobileSessionTabBar.tsx b/mobile/src/session/tabs/MobileSessionTabBar.tsx deleted file mode 100644 index a9aeb494c8e..00000000000 --- a/mobile/src/session/tabs/MobileSessionTabBar.tsx +++ /dev/null @@ -1,361 +0,0 @@ -import { useMemo, useRef, useState } from 'react' -import { Pressable, Text, View } from 'react-native' -import { Plus } from 'lucide-react-native' -import { Gesture, GestureDetector } from 'react-native-gesture-handler' -import Animated, { - Easing, - ReduceMotion, - useAnimatedStyle, - useSharedValue, - withSequence, - withTiming -} from 'react-native-reanimated' -import { triggerMediumImpact, triggerSelection } from '../../platform/haptics' -import { useMobileTranslation } from '../../i18n/use-mobile-translation' -import { AgentStateDot } from '../../components/AgentStateDot' -import { ArrivalFade } from '../../components/ArrivalFade' -import { useDrawerReducedMotion } from '../../components/bottom-drawer/bottom-drawer-constants' -import { SHEET_CURVE } from '../../components/sheet-motion-values' -import { useReducedMotionEnabled } from '../../platform/use-reduced-motion' -import { useKeyboardPersistingTaps } from '../../platform/keyboard-persisting-taps' -import { useNow } from '../../hooks/use-now' -import { agentStateLabel, type AgentDotState } from '../../worktree/agent-row-display' -import { colors, feedback, radii, spacing } from '../../theme/mobile-theme' -import { themedStyleSheet } from '../../theme/themed-styles' -import { useMobileColorScheme } from '../../theme/use-mobile-color-scheme' -import { buildMobileSessionTabRow, type MobileSessionTabRow } from './mobile-session-tab-rows' -import { MobileSessionTabMark } from './MobileSessionTabMark' -import { MobileSessionTabsSheet } from './MobileSessionTabsSheet' -import type { MobileSessionController } from '../use-mobile-session-controller' - -const SWIPE_SETTLE_MS = 250 -// A tab arriving from the side starts this far out, as a share of the tab cell's width. -const SWIPE_ENTRY_SHARE = 0.4 -const FLICK_VELOCITY = 600 -// With no tab on that side, the tab gives only this share of the drag. -const EDGE_RESISTANCE = 0.25 -const DRAG_CLICK_WINDOW_MS = 400 - -// A tab drawn before it had any agent state (from the phone's store) fades its dot in when one lands. -function TabBarDot({ tabId, state }: { tabId: string; state: AgentDotState | undefined }) { - const [startedEmpty] = useState({ tabId, empty: state === undefined }) - if (startedEmpty.tabId === tabId && startedEmpty.empty) { - return - } - return state && state !== 'idle' ? : null -} - -// Mounted with the bare tab, so the motion preference is read before the dot arrives. -function ArrivingTabBarDot({ state }: { state: AgentDotState | undefined }) { - const reducedMotion = useReducedMotionEnabled() - if (!state || state === 'idle') { - return null - } - return ( - - - - ) -} - -/** The tab you're in as one cell: tap for its actions, swipe for the next one; the count shows every tab, + adds one. */ -export function MobileSessionTabBar({ - controller, - inTopBar, - actionsCollapsed = false -}: { - controller: MobileSessionController - inTopBar: boolean - actionsCollapsed?: boolean -}) { - useMobileColorScheme() - const t = useMobileTranslation() - const { - activeSessionTabId, - connState, - createTabBusy, - handleOpenNewTab, - switchSessionTab, - openSessionTabActionSheetAfterKeyboardDismiss, - visibleTabs, - terminals - } = controller - // Why: the first tap must reach the bar with the keyboard open instead of only dismissing it (#5106). - const keepsKeyboard = useKeyboardPersistingTaps('handled') - const now = useNow(60_000) - const rows = useMemo( - () => visibleTabs.map((tab) => buildMobileSessionTabRow(tab, terminals, now)), - [visibleTabs, terminals, now] - ) - const activeIndex = rows.findIndex((row) => row.tab.id === activeSessionTabId) - const active: MobileSessionTabRow | undefined = rows[activeIndex] - const previous = activeIndex > 0 ? rows[activeIndex - 1] : undefined - const next = activeIndex !== -1 ? rows[activeIndex + 1] : undefined - const othersNeedYou = rows.some( - (row) => row.tab.id !== activeSessionTabId && row.group === 'needs-you' - ) - const [sheetOpen, setSheetOpen] = useState(false) - - const reducedMotion = useDrawerReducedMotion() - const offset = useSharedValue(0) - const width = useSharedValue(0) - // On the web, releasing a mouse drag also clicks the tab. - const dragEndedAtRef = useRef(0) - const settle = (to: number) => - withTiming( - to, - reducedMotion - ? { duration: 0, reduceMotion: ReduceMotion.Never } - : { duration: SWIPE_SETTLE_MS, easing: Easing.bezier(...SHEET_CURVE) } - ) - const step = (target: MobileSessionTabRow | undefined, direction: 1 | -1) => { - if (!target) { - offset.value = settle(0) - return - } - triggerSelection() - switchSessionTab(target.tab) - offset.value = withSequence( - withTiming(-direction * width.value * SWIPE_ENTRY_SHARE, { duration: 0 }), - settle(0) - ) - } - // Callbacks run on JS: the session page is a web document, and stepping switches React state. - const pan = Gesture.Pan() - .runOnJS(true) - .enabled(rows.length > 1) - .activeOffsetX([-12, 12]) - .failOffsetY([-10, 10]) - .onUpdate((event) => { - const target = event.translationX > 0 ? previous : next - offset.value = target ? event.translationX : event.translationX * EDGE_RESISTANCE - }) - .onEnd((event) => { - // oxlint-disable-next-line react/purity -- runs when the drag ends, never during render. - dragEndedAtRef.current = Date.now() - const direction = event.translationX > 0 ? 1 : -1 - const flicked = - Math.abs(event.velocityX) > FLICK_VELOCITY && Math.sign(event.velocityX) === direction - if (Math.abs(event.translationX) > width.value / 2 || flicked) { - step(direction === 1 ? previous : next, direction) - return - } - offset.value = settle(0) - }) - // Web has no worklet plugin; mapper hooks need this explicit dependency list. - const contentStyle = useAnimatedStyle( - () => ({ - transform: [{ translateX: offset.value }], - opacity: 1 - Math.min(Math.abs(offset.value) / Math.max(width.value, 1), 1) * 0.6 - }), - [offset, width] - ) - - const status = active?.dotState && active.dotState !== 'idle' ? active.dotState : undefined - const countLabel = - rows.length === 1 - ? t('session.tabBar.oneTab', '1 tab') - : t('session.tabBar.tabCount', '{{count}} tabs', { count: rows.length }) - const tabLabel = [active?.title, status ? agentStateLabel(status) : null] - .filter(Boolean) - .join(', ') - const countAccessibilityLabel = [ - countLabel, - othersNeedYou ? t('session.tabBar.anotherNeedsYou', 'another tab needs you') : null - ] - .filter(Boolean) - .join(', ') - const createDisabled = createTabBusy || connState !== 'connected' - const openTabActions = () => { - // The click a drag release produces on the web belongs to the drag. - if (!active || Date.now() - dragEndedAtRef.current < DRAG_CLICK_WINDOW_MS) { - return - } - openSessionTabActionSheetAfterKeyboardDismiss(active.tab) - } - - return ( - - {/* pan-y keeps vertical touches with the page on the web. */} - - { - width.value = event.nativeEvent.layout.width - }} - > - [styles.tabPress, pressed && styles.cellPressed]} - onPress={openTabActions} - onLongPress={() => { - triggerMediumImpact() - openTabActions() - }} - delayLongPress={400} - disabled={!active} - accessibilityRole="button" - accessibilityLabel={tabLabel || countLabel} - accessibilityHint={t('session.tabBar.actionsHint', 'Shows actions for this tab')} - accessibilityActions={[ - ...(next ? [{ name: 'nextTab', label: t('session.tabBar.next', 'Next tab') }] : []), - ...(previous - ? [{ name: 'previousTab', label: t('session.tabBar.previous', 'Previous tab') }] - : []) - ]} - onAccessibilityAction={(event) => { - const name = event.nativeEvent.actionName - if (name === 'nextTab') { - step(next, -1) - } else if (name === 'previousTab') { - step(previous, 1) - } - }} - > - {/* Only the contents slide, so the cell stays flush with the screen edge. */} - - {active ? ( - <> - - - - - - ) : null} - - {active?.title ?? countLabel} - - - - - - [ - styles.sideCell, - actionsCollapsed && !inTopBar && styles.lastCell, - pressed && styles.cellPressed - ]} - onPress={() => setSheetOpen(true)} - accessibilityRole="button" - accessibilityLabel={countAccessibilityLabel} - accessibilityHint={t('session.tabBar.hint', 'Shows all tabs')} - > - - {rows.length} - - {othersNeedYou ? : null} - - {/* A collapsed bar's + lives in the header's ⋯ menu. */} - {!actionsCollapsed ? ( - [ - styles.sideCell, - !inTopBar && styles.lastCell, - pressed && styles.cellPressed, - createDisabled && styles.cellDisabled - ]} - disabled={createDisabled} - onPress={handleOpenNewTab} - accessibilityRole="button" - accessibilityLabel={t('session.tabStrip.newTab', 'New tab')} - accessibilityState={{ disabled: createDisabled }} - > - - - ) : null} - setSheetOpen(false)} - /> - - ) -} - -const styles = themedStyleSheet(() => ({ - bar: { - height: 44, - flexDirection: 'row', - alignItems: 'stretch', - borderTopWidth: 1, - borderTopColor: colors.borderSubtle - }, - // Cancels the top bar's vertical padding so the cells run the bar's full height. - barInTopBar: { - flex: 1, - minWidth: 0, - flexDirection: 'row', - alignItems: 'stretch', - alignSelf: 'stretch', - marginVertical: -spacing.xs, - marginLeft: spacing.md, - borderLeftWidth: 1, - borderLeftColor: colors.borderSubtle - }, - // The open tab, drawn like the strip's active tab: raised, with a line under it. - tabCell: { - flex: 1, - minWidth: 0, - backgroundColor: colors.bgRaised, - borderBottomWidth: 2, - borderBottomColor: colors.textSecondary, - borderRightWidth: 1, - borderRightColor: colors.borderSubtle, - overflow: 'hidden' - }, - tabPress: { - flex: 1, - justifyContent: 'center', - paddingLeft: spacing.lg, - paddingRight: spacing.sm - }, - tabContent: { flexDirection: 'row', alignItems: 'center', gap: 6 }, - // Keeps web SVGs from shrinking before the title ellipsizes. - mark: { flexShrink: 0 }, - title: { - flexShrink: 1, - minWidth: 0, - fontSize: 14, - fontWeight: '600', - color: colors.textPrimary - }, - sideCell: { - width: 46, - alignItems: 'center', - justifyContent: 'center', - borderRightWidth: 1, - borderRightColor: colors.borderSubtle - }, - // At the screen edge; in the top bar the hairline stays to part the cells from the round buttons. - lastCell: { borderRightWidth: 0 }, - cellPressed: { backgroundColor: colors.translucentFill }, - cellDisabled: { opacity: feedback.disabledOpacity }, - countBox: { - minWidth: 19, - height: 19, - paddingHorizontal: 3, - borderRadius: 6, - borderWidth: 1.8, - borderColor: colors.textPrimary, - alignItems: 'center', - justifyContent: 'center' - }, - countText: { - fontSize: 11, - fontWeight: '700', - color: colors.textPrimary, - fontVariant: ['tabular-nums'] - }, - // Another tab needs you: a red dot on the count's corner, ringed in the bar's colour. - alert: { - position: 'absolute', - top: 8, - right: 9, - width: 9, - height: 9, - borderRadius: radii.pill, - backgroundColor: colors.statusRed, - borderWidth: 2, - borderColor: colors.bgPanel - } -})) diff --git a/mobile/src/session/tabs/MobileSessionTabMark.tsx b/mobile/src/session/tabs/MobileSessionTabMark.tsx deleted file mode 100644 index 67a1d0b3895..00000000000 --- a/mobile/src/session/tabs/MobileSessionTabMark.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { File, FileText, Globe, SquareTerminal } from 'lucide-react-native' -import { MobileAgentIcon } from '../../components/MobileAgentIcon' -import { colors } from '../../theme/mobile-theme' -import { useMobileColorScheme } from '../../theme/use-mobile-color-scheme' -import type { MobileSessionTabRow } from './mobile-session-tab-rows' - -/** The tab's agent icon, else an icon for what kind of tab it is. */ -export function MobileSessionTabMark({ - row, - size -}: { - row: Pick - size: number -}) { - useMobileColorScheme() - if (row.agentId) { - return - } - const Icon = - row.tab.type === 'browser' - ? Globe - : row.tab.type === 'markdown' - ? FileText - : row.tab.type === 'file' - ? File - : SquareTerminal - return -} diff --git a/mobile/src/session/tabs/MobileSessionTabStrip.tsx b/mobile/src/session/tabs/MobileSessionTabStrip.tsx new file mode 100644 index 00000000000..6455c9bf6f8 --- /dev/null +++ b/mobile/src/session/tabs/MobileSessionTabStrip.tsx @@ -0,0 +1,327 @@ +import { useCallback, useMemo, useRef, useState } from 'react' +import { View, Text, ScrollView, Pressable, StyleSheet } from 'react-native' +import { File, FileText, Globe, Plus, SquareTerminal } from 'lucide-react-native' +import { triggerMediumImpact } from '../../platform/haptics' +import { useMobileTranslation } from '../../i18n/use-mobile-translation' +import { MobileAgentIcon } from '../../components/MobileAgentIcon' +import { AgentStateDot } from '../../components/AgentStateDot' +import { ArrivalFade } from '../../components/ArrivalFade' +import { useReducedMotionEnabled } from '../../platform/use-reduced-motion' +import { useNow } from '../../hooks/use-now' +import { + agentDotState, + agentStateLabel, + type AgentDotState +} from '../../worktree/agent-row-display' +import { + getMobileTerminalTabHostAgentIdentity, + getMobileSessionTabTitle, + resolveMobileTerminalTabAgentId +} from '../../terminal/session/mobile-terminal-tab-agent' +import { colors, spacing } from '../../theme/mobile-theme' +import { useMobileColorScheme } from '../../theme/use-mobile-color-scheme' +import { NavBarButton } from '../../components/nav-bar/NavBarButton' +import { + resolveTabStripEdgeHint, + resolveTabStripHiddenTabs, + resolveTabStripTapOffset, + type TabStripHiddenTabs +} from './tab-strip-scroll' +import { styles } from '../mobile-session-styles' +import { useKeyboardPersistingTaps } from '../../platform/keyboard-persisting-taps' +import type { MobileSessionController } from '../use-mobile-session-controller' + +const DOUBLE_TAP_RENAME_MS = 300 + +// A tab drawn before it had any agent state (a strip from the phone's store) fades its dot in when one lands. +function SessionTabAgentDot({ state }: { state: AgentDotState | undefined }) { + const [startedEmpty] = useState(state === undefined) + if (startedEmpty) { + return + } + return state && state !== 'idle' ? : null +} + +// Mounted with the bare tab, so the motion preference is read before the dot arrives. +function ArrivingSessionTabAgentDot({ state }: { state: AgentDotState | undefined }) { + const reducedMotion = useReducedMotionEnabled() + if (!state || state === 'idle') { + return null + } + return ( + + + + ) +} + +export function MobileSessionTabStrip({ + controller, + inTopBar, + actionsCollapsed = false +}: { + controller: MobileSessionController + inTopBar: boolean + actionsCollapsed?: boolean +}) { + useMobileColorScheme() + const t = useMobileTranslation() + const { + activeSessionTabId, + activeSessionTabIdRef, + tabStripRef, + tabStripOffsetRef, + tabStripViewportWidthRef, + tabStripContentWidthRef, + tabLayoutsRef, + connState, + createTabBusy, + handleOpenNewTab, + scrollActiveTabIntoView, + holdTabStripReveal, + cancelHeldTabStripReveal, + switchSessionTab, + openSessionTabActionSheetAfterKeyboardDismiss, + setRenameTarget, + activeHandleRef, + visibleTabs, + terminals + } = controller + const tabBarKeepsKeyboard = useKeyboardPersistingTaps('handled') + const lastTabTapRef = useRef<{ id: string; at: number } | null>(null) + const now = useNow(60_000) + const tabStates = useMemo(() => { + const states = new Map() + for (const tab of visibleTabs) { + // Why: a status restored across a host restart is unconfirmed, so like desktop it shows no live state. + if (tab.type === 'terminal' && tab.agentStatus && !tab.agentStatus.restoredUnconfirmed) { + states.set(tab.id, agentDotState(tab.agentStatus, now)) + } else if (tab.type === 'agent-session' && tab.chatStatus) { + states.set(tab.id, agentDotState(tab.chatStatus, now)) + } + } + return states + }, [visibleTabs, now]) + const [hiddenTabs, setHiddenTabs] = useState({ left: [], right: [] }) + const refreshHiddenTabs = () => { + const next = resolveTabStripHiddenTabs({ + layouts: tabLayoutsRef.current, + viewportWidth: tabStripViewportWidthRef.current, + currentOffset: tabStripOffsetRef.current + }) + // Why: scroll fires every frame; re-render only when a tab crosses an edge. + setHiddenTabs((prev) => + prev.left.join('\n') === next.left.join('\n') && + prev.right.join('\n') === next.right.join('\n') + ? prev + : next + ) + } + const leftHint = resolveTabStripEdgeHint(hiddenTabs.left, tabStates) + const rightHint = resolveTabStripEdgeHint(hiddenTabs.right, tabStates) + const pressTab = useCallback( + (t: (typeof visibleTabs)[number]) => { + const at = Date.now() + const lastTap = lastTabTapRef.current + lastTabTapRef.current = { id: t.id, at } + if ( + lastTap?.id === t.id && + at - lastTap.at < DOUBLE_TAP_RENAME_MS && + t.type === 'terminal' && + typeof t.terminal === 'string' + ) { + lastTabTapRef.current = null + triggerMediumImpact() + setRenameTarget({ + handle: t.terminal, + title: t.title, + isActive: t.terminal === activeHandleRef.current + }) + // The first tap's held reveal still runs once the window closes. + return + } + cancelHeldTabStripReveal() + const nextOffset = resolveTabStripTapOffset({ + tabId: t.id, + tabs: visibleTabs, + layouts: tabLayoutsRef.current, + viewportWidth: tabStripViewportWidthRef.current, + contentWidth: tabStripContentWidthRef.current, + currentOffset: tabStripOffsetRef.current + }) + if (nextOffset !== tabStripOffsetRef.current) { + holdTabStripReveal(nextOffset, DOUBLE_TAP_RENAME_MS) + } + switchSessionTab(t) + }, + [ + activeHandleRef, + cancelHeldTabStripReveal, + holdTabStripReveal, + setRenameTarget, + switchSessionTab, + tabLayoutsRef, + tabStripContentWidthRef, + tabStripOffsetRef, + tabStripRef, + tabStripViewportWidthRef, + visibleTabs + ] + ) + const attachTabStrip = useCallback( + (view: ScrollView | null) => { + if (view) { + tabStripOffsetRef.current = 0 + tabStripViewportWidthRef.current = 0 + tabStripContentWidthRef.current = 0 + tabLayoutsRef.current.clear() + } + tabStripRef.current = view + }, + [ + tabStripRef, + tabStripOffsetRef, + tabStripViewportWidthRef, + tabStripContentWidthRef, + tabLayoutsRef + ] + ) + return ( + + {/* Why: tab taps must register on first press with the keyboard open instead of being eaten by dismissal (#5106). */} + + { + tabStripOffsetRef.current = e.nativeEvent.contentOffset.x + refreshHiddenTabs() + }} + onLayout={(e) => { + tabStripViewportWidthRef.current = e.nativeEvent.layout.width + scrollActiveTabIntoView(activeSessionTabIdRef.current, false) + refreshHiddenTabs() + }} + onContentSizeChange={(width) => { + tabStripContentWidthRef.current = width + scrollActiveTabIntoView(activeSessionTabIdRef.current, false) + refreshHiddenTabs() + }} + > + {visibleTabs.map((tab, index) => { + const tabState = tabStates.get(tab.id) + const hostAgentIdentity = getMobileTerminalTabHostAgentIdentity(tab, terminals) + const title = getMobileSessionTabTitle(tab, hostAgentIdentity) + return ( + [ + styles.tab, + index === 0 && !inTopBar && styles.tabFirst, + tab.id === activeSessionTabId && styles.tabActive, + pressed && styles.tabPressed + ]} + onLayout={(e) => { + const { x, width } = e.nativeEvent.layout + tabLayoutsRef.current.set(tab.id, { x, width }) + if (tab.id === activeSessionTabIdRef.current) { + scrollActiveTabIntoView(tab.id, false) + } + refreshHiddenTabs() + }} + onPress={() => pressTab(tab)} + accessibilityRole="tab" + accessibilityLabel={ + tabState && tabState !== 'idle' + ? t('session.tabStrip.tabStatus', '{{title}}, {{status}}', { + title, + status: agentStateLabel(tabState) + }) + : title + } + accessibilityState={{ selected: tab.id === activeSessionTabId }} + onLongPress={() => { + triggerMediumImpact() + openSessionTabActionSheetAfterKeyboardDismiss(tab) + }} + delayLongPress={400} + > + + + + {tab.type === 'browser' && ( + + )} + {tab.type === 'markdown' && ( + + )} + {tab.type === 'file' && ( + + )} + {tab.type === 'agent-session' && ( + + )} + {tab.type === 'terminal' && + (() => { + const agentId = resolveMobileTerminalTabAgentId(tab, hostAgentIdentity) + return agentId ? ( + + ) : ( + + ) + })()} + + + {title} + + + + ) + })} + + {leftHint ? ( + + + + ) : null} + {rightHint ? ( + + + + ) : null} + + {/* Terminal layout and Quick commands live in the header's ⋯ menu. */} + {!actionsCollapsed ? ( + + + + ) : null} + + ) +} + +// The right inset matches the nav bar's, so the + lines up with the ⋯ above it. +const newTabStyles = StyleSheet.create({ + slot: { + paddingLeft: spacing.sm, + paddingRight: spacing.md + } +}) diff --git a/mobile/src/session/tabs/MobileSessionTabsSheet.tsx b/mobile/src/session/tabs/MobileSessionTabsSheet.tsx deleted file mode 100644 index f8cd5cd1981..00000000000 --- a/mobile/src/session/tabs/MobileSessionTabsSheet.tsx +++ /dev/null @@ -1,220 +0,0 @@ -import { Fragment, useRef, useState } from 'react' -import { Pressable, Text, View } from 'react-native' -import { Plus, X } from 'lucide-react-native' -import { BottomDrawer } from '../../components/bottom-drawer/BottomDrawer' -import { ListGroup, SectionHeader } from '../../components/list/ListGroup' -import { NavBarButton } from '../../components/nav-bar/NavBarButton' -import { SheetHeader } from '../../components/nav-bar/SheetHeader' -import { SwipeRowActions } from '../../components/SwipeRowActions' -import { AgentStateDot } from '../../components/AgentStateDot' -import { useMobileTranslation } from '../../i18n/use-mobile-translation' -import { useNow } from '../../hooks/use-now' -import { formatTimeAgo } from '../../worktree/agent-row-display' -import { colors, radii, spacing } from '../../theme/mobile-theme' -import { themedStyleSheet } from '../../theme/themed-styles' -import { useMobileColorScheme } from '../../theme/use-mobile-color-scheme' -import type { MobileSessionTabGroup, MobileSessionTabRow } from './mobile-session-tab-rows' -import { MobileSessionTabMark } from './MobileSessionTabMark' -import type { MobileSessionController } from '../use-mobile-session-controller' - -const TILE_SIZE = 34 -const TILE_DOT_RING = 2 -const GROUP_ORDER: readonly MobileSessionTabGroup[] = ['needs-you', 'working', 'other'] - -/** Every tab in the workspace, what needs you first; tap one to go there, swipe one to close it. */ -export function MobileSessionTabsSheet({ - controller, - rows, - visible, - onClose -}: { - controller: MobileSessionController - rows: readonly MobileSessionTabRow[] - visible: boolean - onClose: () => void -}) { - useMobileColorScheme() - const t = useMobileTranslation() - const now = useNow(60_000) - const { - activeSessionTabId, - worktreeName, - switchSessionTab, - handleCloseSessionTab, - handleOpenNewTab, - createTabBusy, - connState - } = controller - // Sections hold still while the sheet is open, so a row never moves under a finger. - const [frozenGroups, setFrozenGroups] = useState>() - if (visible && frozenGroups === undefined) { - setFrozenGroups(new Map(rows.map((row) => [row.tab.id, row.group]))) - } - const afterCloseRef = useRef<(() => void) | null>(null) - const sections = GROUP_ORDER.map((group) => ({ - group, - rows: rows.filter((row) => (frozenGroups?.get(row.tab.id) ?? row.group) === group) - })).filter((section) => section.rows.length > 0) - const sectionTitles: Record = { - 'needs-you': t('session.tabsSheet.needsYou', 'Needs you'), - working: t('session.tabsSheet.working', 'Working'), - other: t('session.tabsSheet.everythingElse', 'Everything else') - } - const title = - rows.length === 1 - ? t('session.tabBar.oneTab', '1 tab') - : t('session.tabBar.tabCount', '{{count}} tabs', { count: rows.length }) - - const renderRow = (row: MobileSessionTabRow) => { - const current = row.tab.id === activeSessionTabId - const badge = row.dotState && row.dotState !== 'idle' ? row.dotState : undefined - const time = current - ? t('session.tabsSheet.open', 'Open') - : row.timeAt !== null - ? formatTimeAgo(row.timeAt, now) - : '' - return ( - void handleCloseSessionTab(row.tab) - }} - > - {(guardPress) => ( - { - if (!current) { - switchSessionTab(row.tab) - } - onClose() - })} - > - {({ pressed }) => ( - <> - {current || pressed ? : null} - - - {badge ? ( - - - - ) : null} - - - - {row.title} - - - {row.detail} - - - {time ? ( - {time} - ) : null} - - )} - - )} - - ) - } - - return ( - { - setFrozenGroups(undefined) - const afterClose = afterCloseRef.current - afterCloseRef.current = null - afterClose?.() - }} - > - - - - { - // The new-tab sheet is its own drawer; open it once this one is gone. - afterCloseRef.current = handleOpenNewTab - onClose() - }} - /> - - - - {sections.map((section, index) => ( - - {sections.length > 1 ? ( - - ) : null} - - {section.rows.map(renderRow)} - - - ))} - - - ) -} - -const styles = themedStyleSheet(() => ({ - // Over the sheet header's empty trailing side, centred in its 52pt row. - newTab: { position: 'absolute', top: 8, right: spacing.xs }, - body: { paddingBottom: spacing.lg }, - // Opaque so a swipe's action stays hidden until the row slides off it. - row: { - minHeight: 60, - flexDirection: 'row', - alignItems: 'center', - gap: spacing.md, - paddingHorizontal: spacing.lg, - paddingVertical: spacing.sm, - backgroundColor: colors.sheetGroup - }, - // The tab you're in, or a pressed row, washed like a picked segment on a sheet group. - wash: { - position: 'absolute', - top: 0, - right: 0, - bottom: 0, - left: 0, - backgroundColor: colors.translucentFill - }, - tile: { - width: TILE_SIZE, - height: TILE_SIZE, - borderRadius: radii.tile, - backgroundColor: colors.translucentFill, - alignItems: 'center', - justifyContent: 'center' - }, - // The state dot on the tile's corner, ringed in the group's colour. - tileBadge: { - position: 'absolute', - top: -4, - right: -4, - padding: TILE_DOT_RING, - borderRadius: radii.pill, - backgroundColor: colors.sheetGroup - }, - text: { flex: 1, minWidth: 0, gap: 2 }, - title: { fontSize: 15, fontWeight: '600', color: colors.textPrimary }, - detail: { fontSize: 13, color: colors.textSecondary }, - time: { fontSize: 12, color: colors.textMuted, fontVariant: ['tabular-nums'] }, - timeCurrent: { fontWeight: '600', color: colors.accentBlue } -})) diff --git a/mobile/src/session/tabs/mobile-session-tab-rows.ts b/mobile/src/session/tabs/mobile-session-tab-rows.ts deleted file mode 100644 index 1b2854512f6..00000000000 --- a/mobile/src/session/tabs/mobile-session-tab-rows.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { agentListPreview } from '../../agents/agent-list-row-text' -import { agentStatusGroup } from '../../agents/agent-list-rows' -import { translate } from '../../i18n/mobile-i18n' -import { - getMobileSessionTabTitle, - getMobileTerminalTabHostAgentIdentity, - resolveMobileTerminalTabAgentId -} from '../../terminal/session/mobile-terminal-tab-agent' -import { - agentDotState, - agentRowTimeAt, - agentStateLabel, - type AgentDotState -} from '../../worktree/agent-row-display' -import type { MobileSessionTab } from './mobile-session-tabs' - -export type MobileSessionTabGroup = 'needs-you' | 'working' | 'other' - -export type MobileSessionTabRow = { - tab: MobileSessionTab - title: string - /** The agent whose icon marks the tab; null draws the tab kind's icon. */ - agentId: string | null - dotState: AgentDotState | undefined - group: MobileSessionTabGroup - /** The second line: the state, then what the tab is doing or showing. */ - detail: string - timeAt: number | null -} - -export function mobileSessionTabDotState( - tab: MobileSessionTab, - now: number -): AgentDotState | undefined { - // Why: a status restored across a host restart is unconfirmed, so like desktop it shows no live state. - if (tab.type === 'terminal' && tab.agentStatus && !tab.agentStatus.restoredUnconfirmed) { - return agentDotState(tab.agentStatus, now) - } - if (tab.type === 'agent-session' && tab.chatStatus) { - return agentDotState(tab.chatStatus, now) - } - return undefined -} - -function tabGroup(state: AgentDotState | undefined): MobileSessionTabGroup { - if (!state) { - return 'other' - } - const group = agentStatusGroup(state) - return group === 'needs-you' || group === 'working' ? group : 'other' -} - -function tabContent( - tab: MobileSessionTab, - title: string, - dotState: AgentDotState | undefined -): string { - switch (tab.type) { - case 'terminal': { - const status = tab.agentStatus - if (!status || !dotState) { - return '' - } - return agentListPreview(status, agentStatusGroup(dotState), title) - } - case 'browser': - return tab.url === title ? '' : tab.url - case 'markdown': - case 'file': - return tab.relativePath === title ? '' : tab.relativePath - case 'agent-session': - return '' - } -} - -function tabKindLabel(tab: MobileSessionTab): string { - switch (tab.type) { - case 'browser': - return translate('session.tabRows.browser', 'Browser') - case 'markdown': - return translate('session.tabRows.markdown', 'Markdown note') - case 'file': - return translate('session.tabRows.file', 'File') - case 'agent-session': - return translate('session.tabRows.chat', 'Chat') - case 'terminal': - return translate('session.tabRows.terminal', 'Terminal') - } -} - -export function buildMobileSessionTabRow( - tab: MobileSessionTab, - terminals: readonly { handle: string; agentIdentity?: string }[], - now: number -): MobileSessionTabRow { - const hostAgentIdentity = getMobileTerminalTabHostAgentIdentity(tab, terminals) - const title = getMobileSessionTabTitle(tab, hostAgentIdentity) - const dotState = mobileSessionTabDotState(tab, now) - const stateWord = dotState && dotState !== 'idle' ? agentStateLabel(dotState) : '' - const content = tabContent(tab, title, dotState) - const timeAt = - tab.type === 'terminal' && tab.agentStatus && !tab.agentStatus.restoredUnconfirmed - ? agentRowTimeAt(tab.agentStatus) - : tab.type === 'agent-session' && tab.chatStatus - ? tab.chatStatus.updatedAt - : null - return { - tab, - title, - agentId: - tab.type === 'agent-session' - ? tab.agent - : tab.type === 'terminal' - ? resolveMobileTerminalTabAgentId(tab, hostAgentIdentity) - : null, - dotState, - group: tabGroup(dotState), - detail: [stateWord, content].filter(Boolean).join(' · ') || tabKindLabel(tab), - timeAt - } -} diff --git a/mobile/src/session/tabs/tab-strip-scroll.ts b/mobile/src/session/tabs/tab-strip-scroll.ts index e7d6c85e416..9b9dd9ce99b 100644 --- a/mobile/src/session/tabs/tab-strip-scroll.ts +++ b/mobile/src/session/tabs/tab-strip-scroll.ts @@ -1,3 +1,5 @@ +import type { AgentDotState } from '../../worktree/agent-row-display' + export type TabStripScrollInput = { tabX: number tabWidth: number @@ -34,3 +36,98 @@ export function resolveTabStripScrollOffset({ return Math.min(Math.max(0, nextOffset), maxOffset) } + +type TabLayouts = ReadonlyMap + +export function resolveTabStripTapOffset(args: { + tabId: string + tabs: readonly { id: string }[] + layouts: TabLayouts + viewportWidth: number + contentWidth: number + currentOffset: number +}): number { + const { tabs, layouts, viewportWidth, contentWidth, currentOffset } = args + const index = tabs.findIndex((tab) => tab.id === args.tabId) + const selected = layouts.get(args.tabId) + if (index === -1 || !selected || viewportWidth <= 0) { + return currentOffset + } + const selectedOnly = resolveTabStripScrollOffset({ + tabX: selected.x, + tabWidth: selected.width, + viewportWidth, + contentWidth, + currentOffset + }) + if (selectedOnly === currentOffset) { + return currentOffset + } + const left = selected.x + selected.width / 2 < currentOffset + viewportWidth / 2 + const neighbor = tabs[index + (left ? -1 : 1)] + const layout = neighbor ? layouts.get(neighbor.id) : undefined + let start = selected.x + let end = selected.x + selected.width + if (layout) { + const gap = left ? selected.x - (layout.x + layout.width) : layout.x - end + // Keep the tapped tab whole while revealing as much of its neighbor as fits within both margins. + const peek = Math.min(layout.width, Math.max(0, viewportWidth - 24 - selected.width - gap)) + if (left) { + start -= gap + peek + } else { + end += gap + peek + } + } + return resolveTabStripScrollOffset({ + tabX: start, + tabWidth: end - start, + viewportWidth, + contentWidth, + currentOffset + }) +} + +export type TabStripHiddenTabs = { left: readonly string[]; right: readonly string[] } + +export function resolveTabStripHiddenTabs(args: { + layouts: TabLayouts + viewportWidth: number + currentOffset: number +}): TabStripHiddenTabs { + const left: string[] = [] + const right: string[] = [] + if (args.viewportWidth > 0) { + for (const [tabId, layout] of args.layouts) { + const center = layout.x + layout.width / 2 + if (center < args.currentOffset) { + left.push(tabId) + } else if (center > args.currentOffset + args.viewportWidth) { + right.push(tabId) + } + } + } + return { left, right } +} + +// Lower ranks win when several hidden tabs share an edge; other states get no edge hint. +const EDGE_HINT_RANK: Partial> = { + blocked: 0, + waiting: 0, + working: 1, + monitoring: 1 +} + +export function resolveTabStripEdgeHint( + tabIds: readonly string[], + tabStates: ReadonlyMap +): AgentDotState | null { + let hint: AgentDotState | null = null + for (const tabId of tabIds) { + const state = tabStates.get(tabId) + const rank = state ? EDGE_HINT_RANK[state] : undefined + if (state && rank !== undefined && (hint === null || rank < (EDGE_HINT_RANK[hint] ?? 0))) { + hint = state + } + } + return hint +} diff --git a/mobile/src/session/use-missing-worktree-bounce.test.ts b/mobile/src/session/use-missing-worktree-bounce.test.ts deleted file mode 100644 index 49600fd89d8..00000000000 --- a/mobile/src/session/use-missing-worktree-bounce.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { isSyntheticWorkspaceRoute } from './synthetic-workspace-route' -import { shouldBounceMissingWorktree } from './use-missing-worktree-bounce' - -describe('shouldBounceMissingWorktree', () => { - it('bounces only a host-proven missing worktree', () => { - expect(shouldBounceMissingWorktree('repo::wt', 'missing')).toBe(true) - expect(shouldBounceMissingWorktree('repo::wt', 'unknown')).toBe(false) - expect(shouldBounceMissingWorktree('repo::wt', 'present')).toBe(false) - }) - - it('never bounces synthetic routes the host cannot resolve', () => { - expect(isSyntheticWorkspaceRoute('folder:/Users/x/dir')).toBe(true) - expect(shouldBounceMissingWorktree('folder:/Users/x/dir', 'missing')).toBe(false) - expect(shouldBounceMissingWorktree('global-floating-terminal', 'missing')).toBe(false) - }) -}) diff --git a/mobile/src/session/use-mobile-default-session-view-preference.test.ts b/mobile/src/session/use-mobile-default-session-view-preference.test.ts deleted file mode 100644 index 53891f46444..00000000000 --- a/mobile/src/session/use-mobile-default-session-view-preference.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { createElement } from 'react' -import { act, create, type ReactTestRenderer } from 'react-test-renderer' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { - loadDefaultSessionView, - saveDefaultSessionView, - type MobileSessionView -} from '../storage/session-view-preferences' -import { - useMobileDefaultSessionViewPreference, - type MobileDefaultSessionViewPreference -} from './use-mobile-default-session-view-preference' - -function deferred(): { promise: Promise; resolve: (value: T) => void } { - let resolve!: (value: T) => void - const promise = new Promise((resolvePromise) => { - resolve = resolvePromise - }) - return { promise, resolve } -} - -vi.mock('../storage/session-view-preferences', () => ({ - DEFAULT_SESSION_VIEW: 'terminal', - loadDefaultSessionView: vi.fn(), - saveDefaultSessionView: vi.fn() -})) - -describe('useMobileDefaultSessionViewPreference', () => { - let renderer: ReactTestRenderer | null = null - let preference: MobileDefaultSessionViewPreference | null = null - - beforeEach(() => { - vi.mocked(loadDefaultSessionView).mockReset().mockResolvedValue('terminal') - vi.mocked(saveDefaultSessionView).mockReset().mockResolvedValue(undefined) - }) - - afterEach(() => { - act(() => renderer?.unmount()) - renderer = null - preference = null - }) - - async function mount(): Promise { - function Harness(): null { - preference = useMobileDefaultSessionViewPreference() - return null - } - await act(async () => { - renderer = create(createElement(Harness)) - await Promise.resolve() - }) - } - - it('keeps a fast toggle authoritative over the initial read', async () => { - const initialLoad = deferred() - vi.mocked(loadDefaultSessionView).mockReturnValue(initialLoad.promise) - await mount() - - act(() => preference?.setDefaultView('chat')) - expect(preference?.defaultView).toBe('chat') - - await act(async () => { - initialLoad.resolve('terminal') - await initialLoad.promise - }) - - expect(preference?.defaultView).toBe('chat') - expect(saveDefaultSessionView).toHaveBeenCalledWith('chat') - }) - - it('does not let an older failed write roll back a newer choice', async () => { - const recoveryLoad = deferred() - vi.mocked(loadDefaultSessionView) - .mockResolvedValueOnce('terminal') - .mockReturnValueOnce(recoveryLoad.promise) - vi.mocked(saveDefaultSessionView) - .mockRejectedValueOnce(new Error('storage unavailable')) - .mockResolvedValueOnce(undefined) - await mount() - - act(() => preference?.setDefaultView('chat')) - await act(async () => { - await Promise.resolve() - await Promise.resolve() - }) - act(() => preference?.setDefaultView('terminal')) - - await act(async () => { - recoveryLoad.resolve('chat') - await recoveryLoad.promise - await Promise.resolve() - }) - - expect(preference?.defaultView).toBe('terminal') - expect(saveDefaultSessionView).toHaveBeenNthCalledWith(2, 'terminal') - }) -}) diff --git a/mobile/src/session/use-mobile-session-foundation.ts b/mobile/src/session/use-mobile-session-foundation.ts index cdc21bbabb0..6ecb5ae9870 100644 --- a/mobile/src/session/use-mobile-session-foundation.ts +++ b/mobile/src/session/use-mobile-session-foundation.ts @@ -52,7 +52,6 @@ export function useMobileSessionFoundation() { name: worktreeName, path: worktreePath, hostId: worktreeHostId, - branch: worktreeBranch, resolution: worktreeResolution } = useLiveWorktreeName({ client, @@ -116,7 +115,6 @@ export function useMobileSessionFoundation() { worktreeName, worktreePath, worktreeHostId, - worktreeBranch, worktreeResolution, isWideLayout, activePanel, diff --git a/mobile/src/session/use-mobile-session-panel-route-actions.tsx b/mobile/src/session/use-mobile-session-panel-route-actions.tsx index c4ae529e4a8..6cd74e382eb 100644 --- a/mobile/src/session/use-mobile-session-panel-route-actions.tsx +++ b/mobile/src/session/use-mobile-session-panel-route-actions.tsx @@ -7,7 +7,7 @@ import { shouldShowSessionHeaderChecksAction, panelRouteDescriptor } from './session-panel-host' -import type { ActionSheetAction } from '../components/ActionSheetModal' +import { MobileAgentIcon } from '../components/MobileAgentIcon' import { useMobileTranslation } from '../i18n/use-mobile-translation' import { useWorkspaceExecutionHost, @@ -49,81 +49,127 @@ export function useMobileSessionPanelRouteActions(scope: MobileSessionPresentati quickCommandsSupported, showToast } = scope - const agentStatusRow = (errorHint: string): ActionSheetAction | null => + const otherRuntimeAgentRow = { + id: 'otherServerAgents', + label: t('session.usePanelRouteActions.otherServerAgents', 'Agents on Another Server'), + hint: t('session.usePanelRouteActions.pairServerHint', 'Pair that server directly'), + icon: Bot, + disabled: true, + onPress: () => {} + } + const createTabAgentActions = createTabAgentLoadState === 'loading' - ? { - id: 'detectingAgents', - label: t('session.usePanelRouteActions.detectingAgents', 'Detecting Agents'), - icon: Bot, - disabled: true, - loading: true, - onPress: () => {} - } + ? [ + { + id: 'detectingAgents', + label: t('session.usePanelRouteActions.detectingAgents', 'Detecting Agents'), + icon: Bot, + disabled: true, + loading: true, + onPress: () => {} + } + ] : createTabAgentOptions.length > 0 - ? null - : createTabAgentLoadState === 'loaded' - ? { - id: 'noEnabledAgents', - label: t('session.usePanelRouteActions.noEnabledAgents', 'No Enabled Agents'), - icon: Bot, - disabled: true, - onPress: () => {} + ? createTabAgentOptions.map((option) => ({ + id: `agent:${option.agent}`, + label: option.label, + renderIcon: () => , + onPress: () => { + setShowCreateTabDrawer(false) + void handleCreateTerminal(option.agent) } - : createTabAgentLoadState === 'other-runtime' - ? { - id: 'otherServerAgents', - label: t( - 'session.usePanelRouteActions.otherServerAgents', - 'Agents on Another Server' - ), - hint: t('session.usePanelRouteActions.pairServerHint', 'Pair that server directly'), + })) + : createTabAgentLoadState === 'loaded' + ? [ + { + id: 'noEnabledAgents', + label: t('session.usePanelRouteActions.noEnabledAgents', 'No Enabled Agents'), icon: Bot, disabled: true, onPress: () => {} } + ] + : createTabAgentLoadState === 'other-runtime' + ? [otherRuntimeAgentRow] : createTabAgentLoadState === 'error' - ? { - id: 'presetsUnavailable', - label: t( - 'session.usePanelRouteActions.presetsUnavailable', - 'Agent Presets Unavailable' - ), - hint: errorHint, + ? [ + { + id: 'presetsUnavailable', + label: t( + 'session.usePanelRouteActions.presetsUnavailable', + 'Agent Presets Unavailable' + ), + hint: t( + 'session.usePanelRouteActions.checkHostHint', + 'Check the host connection' + ), + icon: Bot, + disabled: true, + onPress: () => {} + } + ] + : [] + const sendDiffNotesAgentActions = + pendingDiffNotesDelivery === null + ? [] + : createTabAgentLoadState === 'loading' + ? [ + { + id: 'detectingAgents', + label: t('session.usePanelRouteActions.detectingAgents', 'Detecting Agents'), + icon: Bot, + disabled: true, + loading: true, + onPress: () => {} + } + ] + : createTabAgentOptions.length > 0 + ? createTabAgentOptions.map((option) => ({ + id: `agent:${option.agent}`, + label: option.label, + hint: t('session.usePanelRouteActions.newSessionHint', 'New agent session'), + icon: Bot, + onPress: () => { + const delivery = pendingDiffNotesDelivery + setPendingDiffNotesDelivery(null) + if (!delivery) { + return + } + void sendDiffNotesToNewAgent(delivery, async () => { + await handleCreateTerminal(option.agent, { + initialPrompt: delivery.prompt, + onPromptSent: () => void clearDeliveredDiffComments(delivery.comments) + }) + }) + } + })) + : createTabAgentLoadState === 'loaded' + ? [ + { + id: 'noEnabledAgents', + label: t('session.usePanelRouteActions.noEnabledAgents', 'No Enabled Agents'), icon: Bot, disabled: true, onPress: () => {} } - : null - const createTabAgentStatusRow = agentStatusRow( - t('session.usePanelRouteActions.checkHostHint', 'Check the host connection') - ) - const sendDiffNotesStatusRow = agentStatusRow( - t('session.usePanelRouteActions.copyNotesHint', 'Copy notes instead') - ) - const sendDiffNotesAgentActions: ActionSheetAction[] = - pendingDiffNotesDelivery === null - ? [] - : sendDiffNotesStatusRow - ? [sendDiffNotesStatusRow] - : createTabAgentOptions.map((option) => ({ - id: `agent:${option.agent}`, - label: option.label, - hint: t('session.usePanelRouteActions.newSessionHint', 'New agent session'), - icon: Bot, - onPress: () => { - const delivery = pendingDiffNotesDelivery - setPendingDiffNotesDelivery(null) - if (!delivery) { - return - } - void sendDiffNotesToNewAgent(delivery, async () => { - await handleCreateTerminal(option.agent, { - initialPrompt: delivery.prompt, - onPromptSent: () => void clearDeliveredDiffComments(delivery.comments) - }) - }) - } - })) + ] + : createTabAgentLoadState === 'other-runtime' + ? [otherRuntimeAgentRow] + : createTabAgentLoadState === 'error' + ? [ + { + id: 'presetsUnavailable', + label: t( + 'session.usePanelRouteActions.presetsUnavailable', + 'Agent Presets Unavailable' + ), + hint: t('session.usePanelRouteActions.copyNotesHint', 'Copy notes instead'), + icon: Bot, + disabled: true, + onPress: () => {} + } + ] + : [] const handleSessionContentRowLayout = useCallback((event: LayoutChangeEvent) => { const width = Math.round(event.nativeEvent.layout.width) @@ -189,7 +235,7 @@ export function useMobileSessionPanelRouteActions(scope: MobileSessionPresentati ) } return { - createTabAgentStatusRow, + createTabAgentActions, sendDiffNotesAgentActions, handleSessionContentRowLayout, handlePanelTap, diff --git a/mobile/src/session/use-mobile-session-presentation.ts b/mobile/src/session/use-mobile-session-presentation.ts index 8f4b3c23331..374e1db46e8 100644 --- a/mobile/src/session/use-mobile-session-presentation.ts +++ b/mobile/src/session/use-mobile-session-presentation.ts @@ -76,8 +76,11 @@ export function useMobileSessionPresentation(scope: MobileSessionBulkCloseModel) presentedConnState === 'connected' ? showLoadingState && visibleTabs.length === 0 ? t('session.presentation.loadingTabs', 'Loading tabs') - : // The tab count lives in the tab bar, so the header names the branch instead. - (scope.worktreeBranch ?? MOBILE_SESSION_STATUS_LABELS.connected) + : visibleTabs.length === 1 + ? t('session.presentation.oneTab', '1 tab') + : t('session.presentation.tabCount', '{{tabCount}} tabs', { + tabCount: visibleTabs.length + }) : showConnectionRetry ? t('session.presentation.tapToRetry', '{{status}} — tap to retry', { status: verdictDisplayLabel(connectionVerdict) diff --git a/mobile/src/session/use-mobile-session-screen-state.ts b/mobile/src/session/use-mobile-session-screen-state.ts index 45fd4a9d886..bde653c4045 100644 --- a/mobile/src/session/use-mobile-session-screen-state.ts +++ b/mobile/src/session/use-mobile-session-screen-state.ts @@ -1,7 +1,7 @@ import { useState, useRef, useMemo } from 'react' import { useTerminalSplitLayout } from '../terminal/session/use-terminal-split-layout' import { createLiveInputCapture } from '../terminal/session/live-input-capture' -import { Animated } from 'react-native' +import { Animated, type ScrollView } from 'react-native' import type { MobileTerminalLinkOpenMode } from '../storage/preferences' import type { TerminalKeyboardAvoidanceMetrics } from '../terminal/terminal-webview-contract' import { @@ -46,6 +46,11 @@ export function useMobileSessionScreenState(scope: MobileSessionFoundationModel) const activeSessionTabIdRef = useRef(null) // Preserve an explicit phone tab pick while a host snapshot is transiently incomplete. const selectedSessionTabIdRef = useRef(null) + const tabStripRef = useRef(null) + const tabStripOffsetRef = useRef(0) + const tabStripViewportWidthRef = useRef(0) + const tabStripContentWidthRef = useRef(0) + const tabLayoutsRef = useRef>(new Map()) const [markdownDocs, setMarkdownDocs] = useState>(new Map()) const markdownDocsRef = useRef>(new Map()) const [fileDocs, setFileDocs] = useState>(new Map()) @@ -129,6 +134,11 @@ export function useMobileSessionScreenState(scope: MobileSessionFoundationModel) setActiveSessionTabId, activeSessionTabIdRef, selectedSessionTabIdRef, + tabStripRef, + tabStripOffsetRef, + tabStripViewportWidthRef, + tabStripContentWidthRef, + tabLayoutsRef, markdownDocs, setMarkdownDocs, markdownDocsRef, diff --git a/mobile/src/source-control/folder/use-folder-create-flow.test.tsx b/mobile/src/source-control/folder/use-folder-create-flow.test.tsx index c59d2644858..57360d9d270 100644 --- a/mobile/src/source-control/folder/use-folder-create-flow.test.tsx +++ b/mobile/src/source-control/folder/use-folder-create-flow.test.tsx @@ -243,15 +243,6 @@ describe('useFolderCreateFlow', () => { setupDecision: 'skip' }) }) - it("refreshes the folder when a form's create may have landed", async () => { - const refetch = vi.fn() - const { flow } = mountFlow(refetch) - const b = repoIn() - const form = await openComposer(flow, b) - - form.folderLaunch?.submit.begin({ ...b.repo, path: '/w/b' })?.settle('uncertain') - expect(refetch).toHaveBeenCalledTimes(1) - }) async function setupRefusedRetry(flow: { current: Flow | null }) { const a = repoIn() const lost = new FakeSession('connected') diff --git a/mobile/src/source-control/mobile-commit-dropdown-copy.ts b/mobile/src/source-control/mobile-commit-dropdown-copy.ts index 6ed43bd8647..7cc182bde00 100644 --- a/mobile/src/source-control/mobile-commit-dropdown-copy.ts +++ b/mobile/src/source-control/mobile-commit-dropdown-copy.ts @@ -69,6 +69,18 @@ export function mobileCommitDropdownCopy(t: Translate): CommitDropdownCopy { case 'Enter a commit message to commit': return t('sourceControl.commitDropdown.enterMessage', 'Enter a commit message to commit') } - } + }, + commitDisabledStatus: (reason) => { + switch (reason) { + case 'Resolve conflicts before committing': + return t('sourceControl.commitDropdown.statusConflicts', 'Conflicts') + case 'Stage at least one file to commit': + return t('sourceControl.commitDropdown.statusNothingStaged', 'Nothing staged') + case 'Enter a commit message to commit': + return t('sourceControl.commitDropdown.statusNeedsMessage', 'Needs message') + } + }, + statusNotPublished: t('sourceControl.commitDropdown.statusNotPublished', 'Not published'), + statusNoBranch: t('sourceControl.commitDropdown.statusNoBranch', 'No branch') } } diff --git a/mobile/src/source-control/mobile-remote-dropdown-copy.ts b/mobile/src/source-control/mobile-remote-dropdown-copy.ts index a8cea9cbbb3..8f5e9a55ecf 100644 --- a/mobile/src/source-control/mobile-remote-dropdown-copy.ts +++ b/mobile/src/source-control/mobile-remote-dropdown-copy.ts @@ -160,6 +160,15 @@ export function mobileRemoteDropdownCopy(t: Translate): RemoteDropdownCopy { manualForcePush: (ahead, behind, upstreamName) => localizedManualForcePush(ahead, behind, upstreamName, t), unpublishedForcePush: (branchCommitsAhead) => - localizedUnpublishedForcePush(branchCommitsAhead, t) + localizedUnpublishedForcePush(branchCommitsAhead, t), + statusUpToDate: t('sourceControl.remoteDropdown.statusUpToDate', 'Up to date'), + statusSetsUpstream: t('sourceControl.remoteDropdown.statusSetsUpstream', 'Sets upstream'), + statusNotPublished: t('sourceControl.remoteDropdown.statusNotPublished', 'Not published'), + statusNoBranch: t('sourceControl.remoteDropdown.statusNoBranch', 'No branch'), + statusMayFail: t('sourceControl.remoteDropdown.statusMayFail', 'May fail'), + statusPublished: t('sourceControl.remoteDropdown.statusPublished', 'Published'), + statusStashFirst: t('sourceControl.remoteDropdown.statusStashFirst', 'Stash first'), + statusReplaces: (behind) => + t('sourceControl.remoteDropdown.statusReplaces', 'Replaces ↓{{behind}}', { behind }) } } diff --git a/mobile/src/source-control/mobile-source-control-actions.ts b/mobile/src/source-control/mobile-source-control-actions.ts index cd819d69476..c4c453ddea4 100644 --- a/mobile/src/source-control/mobile-source-control-actions.ts +++ b/mobile/src/source-control/mobile-source-control-actions.ts @@ -31,6 +31,7 @@ export type MobileSourceControlAction = { iconKey: MobileSourceControlActionIcon disabled?: boolean hint?: string + status?: string loading?: boolean skipAutoClose?: boolean closeBeforePress?: boolean @@ -84,7 +85,7 @@ export function buildMobileSourceControlActions( const busy = args.busyAction !== null const blockForce = (item: DropdownItem): DropdownItem => args.forcePushBlockedReason - ? { ...item, disabled: true, title: args.forcePushBlockedReason } + ? { ...item, disabled: true, title: args.forcePushBlockedReason, status: undefined } : item const row = ( item: DropdownItem, @@ -98,6 +99,7 @@ export function buildMobileSourceControlActions( disabled: busy || item.disabled, // Mobile has no tooltips: show why a row is disabled, and always what Force Push replaces. hint: item.disabled || item.kind === 'force_push' ? item.title : undefined, + status: item.status, loading: args.busyAction === actionId, skipAutoClose: true, onPress diff --git a/mobile/src/source-control/review/mobile-diff-review-rows.test.ts b/mobile/src/source-control/review/mobile-diff-review-rows.test.ts new file mode 100644 index 00000000000..e0acbecf7cc --- /dev/null +++ b/mobile/src/source-control/review/mobile-diff-review-rows.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, it } from 'vitest' +import type { MobileDiffLine } from './mobile-diff-lines' +import { foldEnclosingLine } from './mobile-diff-review-rows' + +const context = (text: string): MobileDiffLine => ({ kind: 'context', text }) + +describe('foldEnclosingLine', () => { + it('names the nearest line above the fold that is indented less than the line after it', () => { + const lines: MobileDiffLine[] = [ + context("describe('queue', () => {"), + context(" it('orders files', () => {"), + context(' const queue = build()'), + context(''), + context(' expect(queue).toHaveLength(3)'), + { kind: 'delete', text: ' removed()' }, + context(' expect(queue[0].scope).toBe(1)') + ] + expect(foldEnclosingLine(lines, 6)).toBe("it('orders files', () => {") + }) + + it('skips blank lines after the fold and returns null when nothing encloses it', () => { + const lines = [ + context('const a = 1'), + context('const b = 2'), + context(''), + context('const c = 3') + ] + expect(foldEnclosingLine(lines, 2)).toBeNull() + expect(foldEnclosingLine(lines, 4)).toBeNull() + }) +}) diff --git a/mobile/src/source-control/review/mobile-diff-review-rows.ts b/mobile/src/source-control/review/mobile-diff-review-rows.ts index 9d140cd4881..1699890b564 100644 --- a/mobile/src/source-control/review/mobile-diff-review-rows.ts +++ b/mobile/src/source-control/review/mobile-diff-review-rows.ts @@ -7,7 +7,15 @@ const MINIMUM_FOLDED_LINES = 3 export type MobileDiffReviewRow = | { kind: 'line'; key: string; line: Line; lineIndex: number } - | { kind: 'fold'; key: string; hiddenCount: number; startIndex: number; endIndex: number } + | { + kind: 'fold' + key: string + hiddenCount: number + startIndex: number + endIndex: number + /** The line the folded code sits inside, shown on the fold like GitHub's hunk header. */ + enclosingLine: string | null + } | { kind: 'thread'; key: string; thread: MobileDiffReviewThread } /** @@ -72,7 +80,8 @@ export function buildMobileDiffReviewRows( key: `fold:${foldStart}`, hiddenCount: foldEnd - foldStart, startIndex: foldStart, - endIndex: foldEnd + endIndex: foldEnd, + enclosingLine: foldEnclosingLine(lines, foldEnd) }) lineIndex = foldEnd - 1 continue @@ -82,3 +91,47 @@ export function buildMobileDiffReviewRows( } return rows } + +const TAB_COLUMNS = 4 + +function indentColumns(text: string): number { + let columns = 0 + for (const char of text) { + if (char === ' ') { + columns += 1 + } else if (char === '\t') { + columns += TAB_COLUMNS + } else { + break + } + } + return columns +} + +/** + * The phone's diff has no `@@` headers, so the fold names its scope itself: the nearest new-file line at or + * above the fold's end that is indented less than the first line shown after it. Blank lines don't count. + */ +export function foldEnclosingLine( + lines: readonly MobileDiffLine[], + foldEnd: number +): string | null { + const counts = (line: MobileDiffLine | undefined): line is MobileDiffLine => + line !== undefined && line.kind !== 'delete' && line.text.trim() !== '' + let nextIndex = foldEnd + while (nextIndex < lines.length && !counts(lines[nextIndex])) { + nextIndex += 1 + } + const next = lines[nextIndex] + if (!counts(next)) { + return null + } + const nextIndent = indentColumns(next.text) + for (let index = foldEnd - 1; index >= 0; index -= 1) { + const line = lines[index] + if (counts(line) && indentColumns(line.text) < nextIndent) { + return line.text.trim() + } + } + return null +} diff --git a/mobile/src/tasks/mobile-tasks-hosted-review.ts b/mobile/src/tasks/mobile-tasks-hosted-review.ts index dbc47832fba..c12cbf19ea8 100644 --- a/mobile/src/tasks/mobile-tasks-hosted-review.ts +++ b/mobile/src/tasks/mobile-tasks-hosted-review.ts @@ -1,7 +1,6 @@ import { getHostedMergeLabel } from './mobile-hosted-check-status' import { projectRowType } from './mobile-tasks-item-mapping' import type { - HostedReviewItem, HostedReviewMergeMethod, PendingHostedMerge, PendingHostedStateChange, @@ -14,6 +13,8 @@ import type { GitHubPRReviewerRow, GitHubWorkItem } from './mobile-tasks-provider-detail-types' +import { GITHUB_PR_MERGE_METHOD_I18N_KEYS } from '../../../src/shared/github/pull-request-merge-methods' +import { translate } from '../i18n/mobile-i18n' export const LINEAR_PRIORITY_LABELS: Record = { 0: 'None', @@ -137,35 +138,59 @@ export function getGitHubMergeLabel(item: GitHubWorkItem): string | null { } export function getHostedReviewMergeMethodLabel(method: HostedReviewMergeMethod): string { - if (method === 'squash') { - return 'Squash and merge' - } - if (method === 'rebase') { - return 'Rebase and merge' - } - return 'Create merge commit' + return translate( + GITHUB_PR_MERGE_METHOD_I18N_KEYS[method], + method === 'squash' + ? 'Squash and merge' + : method === 'rebase' + ? 'Rebase and merge' + : 'Create merge commit' + ) } -export function hostedReviewMergeTargetLabel(item: HostedReviewItem): string { - return item.provider === 'gitlab' ? 'merge request' : 'PR' +function mergeConfirmMessage( + provider: 'github' | 'gitlab', + method: HostedReviewMergeMethod, + number: number | null +): string { + if (provider === 'gitlab') { + if (method === 'squash') { + return translate( + 'tasks.hostedMerge.confirmGitLabSquash', + 'Squash and merge merge request #{{number}}?', + { number } + ) + } + if (method === 'rebase') { + return translate( + 'tasks.hostedMerge.confirmGitLabRebase', + 'Rebase and merge merge request #{{number}}?', + { number } + ) + } + return translate('tasks.hostedMerge.confirmGitLabMerge', 'Merge merge request #{{number}}?', { + number + }) + } + if (method === 'squash') { + return translate('tasks.hostedMerge.confirmGitHubSquash', 'Squash and merge PR #{{number}}?', { + number + }) + } + if (method === 'rebase') { + return translate('tasks.hostedMerge.confirmGitHubRebase', 'Rebase and merge PR #{{number}}?', { + number + }) + } + return translate('tasks.hostedMerge.confirmGitHubMerge', 'Merge PR #{{number}}?', { number }) } export function getHostedMergeConfirmMessage(pending: PendingHostedMerge): string { - const target = hostedReviewMergeTargetLabel(pending.item) - if (pending.method === 'squash') { - return `Squash and merge ${target} #${pending.item.source.number}?` - } - const action = pending.method === 'rebase' ? 'Rebase and merge' : 'Merge' - return `${action} ${target} #${pending.item.source.number}?` + return mergeConfirmMessage(pending.item.provider, pending.method, pending.item.source.number) } export function getProjectGitHubMergeConfirmMessage(pending: PendingProjectGitHubMerge): string { - const number = pending.row.content.number - if (pending.method === 'squash') { - return `Squash and merge PR #${number}?` - } - const action = pending.method === 'rebase' ? 'Rebase and merge' : 'Merge' - return `${action} PR #${number}?` + return mergeConfirmMessage('github', pending.method, pending.row.content.number) } export function hostedStateChangeAction(nextState: PendingHostedStateChange['nextState']): string { diff --git a/mobile/src/tasks/mobile-tasks-item-state-glyph.ts b/mobile/src/tasks/mobile-tasks-item-state-glyph.ts index 8bf32a31f6a..84e66c4ac99 100644 --- a/mobile/src/tasks/mobile-tasks-item-state-glyph.ts +++ b/mobile/src/tasks/mobile-tasks-item-state-glyph.ts @@ -1,14 +1,6 @@ -import { - Circle, - CircleCheck, - CircleDot, - GitMerge, - GitPullRequest, - GitPullRequestClosed, - GitPullRequestDraft, - type LucideIcon -} from 'lucide-react-native' +import { Circle, CircleCheck, CircleDot, type LucideIcon } from 'lucide-react-native' import { prStateColor } from '../components/WorktreeMetaGlyphs' +import { prStateIcon } from '../components/pr-state-token' import { colors } from '../theme/mobile-theme' import type { TaskItem } from './mobile-tasks-project-workspace-types' @@ -16,17 +8,7 @@ export type TaskItemStateGlyph = { icon: LucideIcon; color: string } // The shape says issue or review and its state, coloured as desktop's task page and review icons. function reviewGlyph(state: string): TaskItemStateGlyph { - const color = prStateColor(state === 'opened' ? 'open' : state) - if (state === 'merged') { - return { icon: GitMerge, color } - } - if (state === 'closed') { - return { icon: GitPullRequestClosed, color } - } - if (state === 'draft') { - return { icon: GitPullRequestDraft, color } - } - return { icon: GitPullRequest, color } + return { icon: prStateIcon(state), color: prStateColor(state === 'opened' ? 'open' : state) } } function issueGlyph(state: string): TaskItemStateGlyph { diff --git a/mobile/src/terminal/session/use-mobile-session-keyboard-state.ts b/mobile/src/terminal/session/use-mobile-session-keyboard-state.ts index 785f282bb4f..ec532d01bf5 100644 --- a/mobile/src/terminal/session/use-mobile-session-keyboard-state.ts +++ b/mobile/src/terminal/session/use-mobile-session-keyboard-state.ts @@ -1,9 +1,10 @@ -import { useEffect, useCallback } from 'react' +import { useEffect, useCallback, useRef } from 'react' import { currentSoftKeyboardHeight, subscribeSoftKeyboard } from '../../platform/keyboard-occlusion' import { useTerminalViewportRefit } from '../terminal-viewport-refit' import { removeCustomKey, type CustomKey } from '../terminal-custom-keys' import { useWorkspaceExecutionHost } from '../../navigation/workspace-execution-host' import { writeLastVisitedWorktree } from '../../worktree/last-visited-worktree-by-host' +import { resolveTabStripScrollOffset } from '../../session/tabs/tab-strip-scroll' import type { MobileSessionLifecycleModel } from '../../session/use-mobile-session-lifecycle' export type MobileSessionKeyboardScope = Pick< @@ -11,6 +12,7 @@ export type MobileSessionKeyboardScope = Pick< | 'activeHandleRef' | 'visibleTerminalHandlesRef' | 'terminalPaneViewportsRef' + | 'activeSessionTabId' | 'clientRef' | 'connState' | 'deviceTokenRef' @@ -20,6 +22,11 @@ export type MobileSessionKeyboardScope = Pick< | 'setShowCustomKeyModal' | 'showNativeChatRef' | 'subscribeToTerminal' + | 'tabLayoutsRef' + | 'tabStripContentWidthRef' + | 'tabStripOffsetRef' + | 'tabStripRef' + | 'tabStripViewportWidthRef' | 'terminalFrameRef' | 'terminalRefs' | 'terminals' @@ -38,6 +45,12 @@ export function useMobileSessionKeyboardState(scope: MobileSessionKeyboardScope) connState, terminals, terminalTextScale, + activeSessionTabId, + tabStripRef, + tabStripOffsetRef, + tabStripViewportWidthRef, + tabStripContentWidthRef, + tabLayoutsRef, setCustomKeys, setShowCustomKeyModal, deviceTokenRef, @@ -85,6 +98,55 @@ export function useMobileSessionKeyboardState(scope: MobileSessionKeyboardScope) ) }, [notifyKeyboardVisibility]) + const heldTabStripRevealRef = useRef | null>(null) + const cancelHeldTabStripReveal = useCallback(() => { + if (heldTabStripRevealRef.current) { + clearTimeout(heldTabStripRevealRef.current) + heldTabStripRevealRef.current = null + } + }, []) + useEffect(() => cancelHeldTabStripReveal, [cancelHeldTabStripReveal]) + // Hold strip movement through double-tap detection so its second tap reaches the same tab. + const holdTabStripReveal = useCallback( + (offset: number, delayMs: number) => { + cancelHeldTabStripReveal() + heldTabStripRevealRef.current = setTimeout(() => { + heldTabStripRevealRef.current = null + if (offset !== tabStripOffsetRef.current) { + tabStripOffsetRef.current = offset + tabStripRef.current?.scrollTo({ x: offset, animated: true }) + } + }, delayMs) + }, + [cancelHeldTabStripReveal] + ) + + const scrollActiveTabIntoView = useCallback((tabId: string | null, animated: boolean) => { + if (!tabId || heldTabStripRevealRef.current) { + return + } + const layout = tabLayoutsRef.current.get(tabId) + if (!layout) { + return + } + const nextOffset = resolveTabStripScrollOffset({ + tabX: layout.x, + tabWidth: layout.width, + viewportWidth: tabStripViewportWidthRef.current, + contentWidth: tabStripContentWidthRef.current, + currentOffset: tabStripOffsetRef.current + }) + if (nextOffset !== tabStripOffsetRef.current) { + tabStripOffsetRef.current = nextOffset + tabStripRef.current?.scrollTo({ x: nextOffset, animated }) + } + }, []) + + useEffect(() => { + const id = requestAnimationFrame(() => scrollActiveTabIntoView(activeSessionTabId, true)) + return () => cancelAnimationFrame(id) + }, [activeSessionTabId, scrollActiveTabIntoView]) + const executionHost = useWorkspaceExecutionHost() useEffect(() => { if (hostId && worktreeId) { @@ -109,6 +171,9 @@ export function useMobileSessionKeyboardState(scope: MobileSessionKeyboardScope) notifyTerminalFrameWidth, notifyKeyboardVisibility, notifyTerminalCellBoxChange, + scrollActiveTabIntoView, + holdTabStripReveal, + cancelHeldTabStripReveal, handleDeleteCustomKey, handleManageShortcuts } diff --git a/mobile/src/test-support/rpc-recording/adapters/codex-reset-credit-mount-adapters.ts b/mobile/src/test-support/rpc-recording/adapters/codex-reset-credit-mount-adapters.ts index 7f7c6d78df0..f1825228dcd 100644 --- a/mobile/src/test-support/rpc-recording/adapters/codex-reset-credit-mount-adapters.ts +++ b/mobile/src/test-support/rpc-recording/adapters/codex-reset-credit-mount-adapters.ts @@ -1,7 +1,9 @@ import { mountFixture } from '../recorder-fixture-shape' import type { operationModuleLoader } from '../operation-module-loader' import type { MountAdapter } from '../recording-scenario' -import type { AccountsSnapshot } from '../../../components/accounts-snapshot' +import type { AccountsSnapshot } from '../../../accounts/accounts-snapshot' +import type * as AccountsSnapshotModule from '../../../accounts/accounts-snapshot' +import type * as CodexResetCreditModule from '../../../accounts/usage/codex-reset-credit' const ACCOUNT_REVISION = 1_700_000_000_000 @@ -34,13 +36,11 @@ export function codexResetCreditMountAdapters( ): Record { return { 'accounts.codex-reset-credit': ({ client }) => { - const credit = modules.load( - 'mobile/src/components/codex-reset-credit.ts' + const credit = modules.load( + 'mobile/src/accounts/usage/codex-reset-credit.ts' ) const snapshot = modules - .load( - 'mobile/src/components/accounts-snapshot.ts' - ) + .load('mobile/src/accounts/accounts-snapshot.ts') .decodeAccountsSnapshot(CODEX_ACCOUNTS) let settled: unknown = null return { diff --git a/mobile/src/theme/mobile-code-font.ios.ts b/mobile/src/theme/mobile-code-font.ios.ts new file mode 100644 index 00000000000..08958808e0d --- /dev/null +++ b/mobile/src/theme/mobile-code-font.ios.ts @@ -0,0 +1,2 @@ +// iOS has no family named `monospace`; it falls back to the proportional system face. +export const codeFontFamily: string = 'Menlo' diff --git a/mobile/src/theme/mobile-code-font.ts b/mobile/src/theme/mobile-code-font.ts new file mode 100644 index 00000000000..fff01e62848 --- /dev/null +++ b/mobile/src/theme/mobile-code-font.ts @@ -0,0 +1,2 @@ +// Android's generic family is its system code font; .ios.ts and .web.ts pick theirs. +export const codeFontFamily: string = 'monospace' diff --git a/mobile/src/theme/mobile-code-font.web.ts b/mobile/src/theme/mobile-code-font.web.ts new file mode 100644 index 00000000000..142e76ba365 --- /dev/null +++ b/mobile/src/theme/mobile-code-font.web.ts @@ -0,0 +1,3 @@ +// WebKit draws generic `monospace` as Courier; name the system code fonts first. +export const codeFontFamily: string = + 'ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace' diff --git a/mobile/src/theme/mobile-theme.ts b/mobile/src/theme/mobile-theme.ts index 963ad2f3995..7d53f8422eb 100644 --- a/mobile/src/theme/mobile-theme.ts +++ b/mobile/src/theme/mobile-theme.ts @@ -1,3 +1,5 @@ +import { codeFontFamily } from './mobile-code-font' + // Desktop's main.css tokens per scheme; keep mobile on these instead of introducing inline colors. export type MobileColorScheme = 'light' | 'dark' @@ -55,24 +57,32 @@ const darkColors = { statusPurple: '#d8b4fe', gitDecorationAdded: '#81b88b', gitDecorationDeleted: '#c74e39', - // Desktop's `--diff-*-ground` and `--diff-*-gutter` mixes. - diffAddedBg: 'rgba(129, 184, 139, 0.16)', - diffDeletedBg: 'rgba(199, 78, 57, 0.18)', - diffAddedGutter: 'rgba(129, 184, 139, 0.3)', - diffDeletedGutter: 'rgba(199, 78, 57, 0.32)', + // GitHub's (Primer) diff colours, Kelvin's choice for every phone diff: row ground, line-number cell over it, + // the +/− sign, unchanged line numbers, and the blue "unchanged lines" fold band. + diffAddedBg: 'rgba(46, 160, 67, 0.15)', + diffDeletedBg: 'rgba(248, 81, 73, 0.13)', + diffAddedGutter: 'rgba(63, 185, 80, 0.3)', + diffDeletedGutter: 'rgba(248, 81, 73, 0.3)', + diffAddedSign: '#3fb950', + diffDeletedSign: '#f85149', + diffLineNumber: '#6e7681', + diffFoldBg: 'rgba(56, 139, 253, 0.1)', + diffFoldGutter: 'rgba(56, 139, 253, 0.22)', + diffFoldText: '#4493f8', // Desktop's `--chat-diff-*`: decoration mixed toward foreground for tinted rows. chatDiffAdded: '#a5ccac', chatDiffRemoved: '#d68273', - // Monaco's `vs-dark`; function and meta come from VS Code Dark+, which Monaco lacks. - syntaxComment: '#608b4e', - syntaxKeyword: '#569cd6', - syntaxString: '#ce9178', - syntaxNumber: '#b5cea8', - syntaxType: '#3dc9b0', - syntaxFunction: '#dcdcaa', - syntaxVariable: '#74b0df', - syntaxMeta: '#c586c0', + // GitHub's Primer dark syntax palette (prettylights); type is its built-in orange, tag covers keys and tag names. + syntaxComment: '#8b949e', + syntaxKeyword: '#ff7b72', + syntaxString: '#a5d6ff', + syntaxNumber: '#79c0ff', + syntaxType: '#ffa657', + syntaxFunction: '#d2a8ff', + syntaxVariable: '#ffa657', + syntaxMeta: '#79c0ff', + syntaxTag: '#7ee787', // Terminal WebView background (Tokyonight) — separate from app chrome terminalBg: '#1a1b26' @@ -121,22 +131,29 @@ const lightColors: MobilePalette = { statusPurple: '#9333ea', gitDecorationAdded: '#587c0c', gitDecorationDeleted: '#ad0707', - diffAddedBg: 'rgba(88, 124, 12, 0.13)', - diffDeletedBg: 'rgba(173, 7, 7, 0.11)', - diffAddedGutter: 'rgba(88, 124, 12, 0.26)', - diffDeletedGutter: 'rgba(173, 7, 7, 0.22)', + diffAddedBg: '#dafbe1', + diffDeletedBg: '#ffebe9', + diffAddedGutter: '#aceebb', + diffDeletedGutter: '#ffcecb', + diffAddedSign: '#1a7f37', + diffDeletedSign: '#cf222e', + diffLineNumber: '#6e7781', + diffFoldBg: '#ddf4ff', + diffFoldGutter: 'rgba(84, 174, 255, 0.4)', + diffFoldText: '#0969da', chatDiffAdded: '#415a0b', chatDiffRemoved: '#7c0808', - // Monaco's `vs`; function and meta from VS Code Light+. - syntaxComment: '#008000', - syntaxKeyword: '#0000ff', - syntaxString: '#a31515', - syntaxNumber: '#098658', - syntaxType: '#008080', - syntaxFunction: '#795e26', - syntaxVariable: '#001188', - syntaxMeta: '#af00db', + // GitHub's Primer light syntax palette (prettylights). + syntaxComment: '#59636e', + syntaxKeyword: '#cf222e', + syntaxString: '#0a3069', + syntaxNumber: '#0550ae', + syntaxType: '#953800', + syntaxFunction: '#8250df', + syntaxVariable: '#953800', + syntaxMeta: '#0550ae', + syntaxTag: '#116329', terminalBg: '#1a1b26' } @@ -208,7 +225,7 @@ export const typography = { titleSize: 18, bodySize: 14, metaSize: 12, - monoFamily: 'monospace' as const + monoFamily: codeFontFamily } as const // One press and one disabled look for every control; fills on press use colors.translucentFill. diff --git a/mobile/src/worktree/agent-row-display.ts b/mobile/src/worktree/agent-row-display.ts index 5fc384ec91d..5969f45afc0 100644 --- a/mobile/src/worktree/agent-row-display.ts +++ b/mobile/src/worktree/agent-row-display.ts @@ -88,7 +88,7 @@ export function agentDisplayLabel(row: RuntimeWorktreeAgentRow, now: number): st // Mirror desktop lastEnteredDoneAt: date main-agent failures independently while subagents remain active. export function agentRowTimeAt( - row: AgentRowVerdictSource & Pick + row: Pick ): number { if (row.state !== 'done' && row.mainAgent && agentVerdictDisplayMark(row) === 'failed') { return row.mainAgent.stateStartedAt diff --git a/mobile/src/worktree/session-worktree-record-reply-schema.ts b/mobile/src/worktree/session-worktree-record-reply-schema.ts index 6ac8c10d1b8..c5b807e093c 100644 --- a/mobile/src/worktree/session-worktree-record-reply-schema.ts +++ b/mobile/src/worktree/session-worktree-record-reply-schema.ts @@ -14,7 +14,6 @@ export const sessionWorktreeRecordSchema = z repo: salvagedOptional('repo', z.string().nullable()), path: salvagedOptional('path', z.string()), hostId: salvagedOptional('hostId', z.string()), - branch: salvagedOptional('branch', z.string().nullable()), diffComments: z.unknown().optional() }) ) @@ -23,11 +22,6 @@ export const sessionWorktreeRecordSchema = z ( reply ): - | (WorktreeDisplayNameSource & { - path?: string - hostId?: string - branch?: string | null - diffComments?: unknown - }) + | (WorktreeDisplayNameSource & { path?: string; hostId?: string; diffComments?: unknown }) | undefined => reply.worktree ) diff --git a/mobile/src/worktree/use-live-worktree-name.ts b/mobile/src/worktree/use-live-worktree-name.ts index 3a09dcb5650..4501b3a1922 100644 --- a/mobile/src/worktree/use-live-worktree-name.ts +++ b/mobile/src/worktree/use-live-worktree-name.ts @@ -30,8 +30,6 @@ export type LiveWorktreeName = { /** Where the worktree lives on its host; null until the host's record arrives. */ path: string | null hostId: string | null - /** The checked-out branch without refs/heads/; null for folders, detached heads and until the record arrives. */ - branch: string | null resolution: WorktreeShowResolution } @@ -50,7 +48,6 @@ export function useLiveWorktreeName({ name: string path?: string | null hostId?: string | null - branch?: string | null }>(() => ({ worktreeId, name: routeNameHint })) // Key verdicts by route so a previous workspace’s deletion cannot escape into the new one. const [resolved, setResolved] = useState<{ @@ -128,16 +125,13 @@ export function useLiveWorktreeName({ if (liveName) { const path = worktree?.path || null const hostId = worktree?.hostId ?? null - // Match desktop formatBranchName by hiding the refs/heads/ prefix. - const branch = worktree?.branch?.replace(/^refs\/heads\//, '') || null setWorktreeName((current) => current.worktreeId === worktreeId && current.name === liveName && current.path === path && - current.hostId === hostId && - current.branch === branch + current.hostId === hostId ? current - : { worktreeId, name: liveName, path, hostId, branch } + : { worktreeId, name: liveName, path, hostId } ) } hasSuccessfulRefresh = true @@ -203,19 +197,12 @@ export function useLiveWorktreeName({ ) if (isFloatingWorkspace) { - return { - name: getFloatingWorkspaceTitle(), - path: null, - hostId: 'local', - branch: null, - resolution: 'unknown' - } + return { name: getFloatingWorkspaceTitle(), path: null, hostId: 'local', resolution: 'unknown' } } return { name: worktreeName.worktreeId === worktreeId ? worktreeName.name : routeNameHint, path: worktreeName.worktreeId === worktreeId ? (worktreeName.path ?? null) : null, hostId: worktreeName.worktreeId === worktreeId ? (worktreeName.hostId ?? null) : null, - branch: worktreeName.worktreeId === worktreeId ? (worktreeName.branch ?? null) : null, resolution: resolved.worktreeId === worktreeId ? resolved.resolution : 'unknown' } } diff --git a/native/computer-use-macos/Sources/OrcaComputerUseMacOS/main.swift b/native/computer-use-macos/Sources/OrcaComputerUseMacOS/main.swift index a1541e50c4e..082516b941e 100644 --- a/native/computer-use-macos/Sources/OrcaComputerUseMacOS/main.swift +++ b/native/computer-use-macos/Sources/OrcaComputerUseMacOS/main.swift @@ -3155,15 +3155,18 @@ private final class AgentRuntime: NSObject, NSApplicationDelegate { private final class PermissionRuntime: NSObject, NSApplicationDelegate { private let initialPermission: PermissionKind? + private let copy: PermissionWindowCopy private var windowController: PermissionWindowController? - init(initialPermission: PermissionKind?) { + init(initialPermission: PermissionKind?, copy: PermissionWindowCopy) { self.initialPermission = initialPermission + self.copy = copy } func applicationDidFinishLaunching(_ notification: Notification) { windowController = PermissionWindowController( initialPermission: initialPermission, + copy: copy, terminateWhenDragAssistantCloses: initialPermission != nil ) if let initialPermission { @@ -3189,25 +3192,36 @@ private final class PermissionWindowController: NSWindowController { private var dragAssistant: PermissionDragAssistantController? private var dragAssistantPermission: PermissionKind? private let initialPermission: PermissionKind? + private let copy: PermissionWindowCopy private let terminateWhenDragAssistantCloses: Bool private var permissionStatusRefresh: PermissionStatusRefreshCoordinator? - convenience init(initialPermission: PermissionKind? = nil, terminateWhenDragAssistantCloses: Bool = false) { + convenience init( + initialPermission: PermissionKind? = nil, + copy: PermissionWindowCopy, + terminateWhenDragAssistantCloses: Bool = false + ) { let window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 300, height: 315), styleMask: [.titled, .closable, .miniaturizable, .fullSizeContentView], backing: .buffered, defer: false ) - window.title = "Enable Orca Computer Use" + window.title = copy.windowTitle window.titleVisibility = .hidden window.titlebarAppearsTransparent = true window.backgroundColor = PermissionPalette.background window.center() window.isReleasedWhenClosed = false - self.init(window: window, initialPermission: initialPermission, terminateWhenDragAssistantCloses: terminateWhenDragAssistantCloses) + self.init( + window: window, + initialPermission: initialPermission, + copy: copy, + terminateWhenDragAssistantCloses: terminateWhenDragAssistantCloses + ) window.contentView = PermissionView( frame: window.contentView?.bounds ?? .zero, + copy: copy, showDragAssistant: { [weak self] permission in self?.showDragAssistant(for: permission) }, @@ -3217,8 +3231,14 @@ private final class PermissionWindowController: NSWindowController { ) } - init(window: NSWindow?, initialPermission: PermissionKind?, terminateWhenDragAssistantCloses: Bool) { + init( + window: NSWindow?, + initialPermission: PermissionKind?, + copy: PermissionWindowCopy, + terminateWhenDragAssistantCloses: Bool + ) { self.initialPermission = initialPermission + self.copy = copy self.terminateWhenDragAssistantCloses = terminateWhenDragAssistantCloses super.init(window: window) permissionStatusRefresh = PermissionStatusRefreshCoordinator( @@ -3240,6 +3260,7 @@ private final class PermissionWindowController: NSWindowController { dragAssistantPermission = permission dragAssistant = PermissionDragAssistantController( permission: permission, + copy: copy, fallbackVisibleFrame: window?.screen?.visibleFrame, onRefreshPermissions: { [weak self] in self?.refreshPermissions() @@ -3322,39 +3343,39 @@ private enum PermissionKind: CaseIterable { } } - var dragInstruction: String { + func dragInstruction(copy: PermissionWindowCopy) -> String { switch self { case .accessibility: - "Drag Orca Computer Use into the list above to allow Accessibility." + copy.dragAccessibilityInstruction case .screenshots: - "Drag Orca Computer Use into the list above to allow Screenshots." + copy.dragScreenshotsInstruction } } - var title: String { + func title(copy: PermissionWindowCopy) -> String { switch self { case .accessibility: - "Accessibility" + copy.accessibilityTitle case .screenshots: - "Screenshots" + copy.screenshotsTitle } } - var detail: String { + func detail(copy: PermissionWindowCopy) -> String { switch self { case .accessibility: - "Read and control app interfaces" + copy.accessibilityDetail case .screenshots: - "Capture windows for visual state" + copy.screenshotsDetail } } - var icon: NSImage { + func icon(copy: PermissionWindowCopy) -> NSImage { switch self { case .accessibility: - NSImage(systemSymbolName: "figure", accessibilityDescription: "Accessibility") ?? NSImage() + NSImage(systemSymbolName: "figure", accessibilityDescription: copy.accessibilityTitle) ?? NSImage() case .screenshots: - NSImage(systemSymbolName: "camera.viewfinder", accessibilityDescription: "Screen Recording") ?? NSImage() + NSImage(systemSymbolName: "camera.viewfinder", accessibilityDescription: copy.screenRecordingDescription) ?? NSImage() } } @@ -3380,13 +3401,20 @@ private enum PermissionKind: CaseIterable { private final class PermissionView: NSView { private let appURL = Bundle.main.bundleURL + private let copy: PermissionWindowCopy private let showDragAssistant: (PermissionKind) -> Void private let close: () -> Void private var contentStack: NSStackView? private var contentConstraints: [NSLayoutConstraint] = [] private var permissionStatus: PermissionStatusSnapshot? - init(frame frameRect: NSRect, showDragAssistant: @escaping (PermissionKind) -> Void, close: @escaping () -> Void) { + init( + frame frameRect: NSRect, + copy: PermissionWindowCopy, + showDragAssistant: @escaping (PermissionKind) -> Void, + close: @escaping () -> Void + ) { + self.copy = copy self.showDragAssistant = showDragAssistant self.close = close super.init(frame: frameRect) @@ -3428,15 +3456,15 @@ private final class PermissionView: NSView { let ready = !checking && missingPermissions.isEmpty let titleText = checking - ? "Checking Computer Use" - : (ready ? "Computer Use is Ready" : "Enable Orca Computer Use") + ? copy.checkingTitle + : (ready ? copy.readyTitle : copy.enableTitle) let title = label(titleText, size: 22, weight: .bold) let subtitle = label( checking - ? "Checking Accessibility and Screenshots." + ? copy.checkingSubtitle : (ready - ? "Orca can use local apps when you ask." - : "Grant permissions so Orca can use apps when you ask."), + ? copy.readySubtitle + : copy.permissionSubtitle), size: 12, weight: .regular ) @@ -3497,13 +3525,13 @@ private final class PermissionView: NSView { row.layer?.backgroundColor = PermissionPalette.card.cgColor row.translatesAutoresizingMaskIntoConstraints = false - let iconView = NSImageView(image: permission.icon) + let iconView = NSImageView(image: permission.icon(copy: copy)) iconView.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 30, weight: .regular) iconView.contentTintColor = .controlAccentColor iconView.translatesAutoresizingMaskIntoConstraints = false - let titleLabel = label(permission.title, size: 13, weight: .bold) - let detailLabel = label(permission.detail, size: 11, weight: .regular) + let titleLabel = label(permission.title(copy: copy), size: 13, weight: .bold) + let detailLabel = label(permission.detail(copy: copy), size: 11, weight: .regular) detailLabel.textColor = PermissionPalette.secondaryText let textStack = NSStackView(views: [titleLabel, detailLabel]) textStack.orientation = .vertical @@ -3511,7 +3539,7 @@ private final class PermissionView: NSView { textStack.spacing = 4 textStack.translatesAutoresizingMaskIntoConstraints = false - let button = NSButton(title: "Allow", target: nil, action: nil) + let button = NSButton(title: copy.allowButton, target: nil, action: nil) button.bezelStyle = .rounded button.controlSize = .regular button.font = NSFont.systemFont(ofSize: 13, weight: .semibold) @@ -3521,8 +3549,8 @@ private final class PermissionView: NSView { .foregroundColor: NSColor.white, .font: NSFont.systemFont(ofSize: 13, weight: .semibold) ] - button.attributedTitle = NSAttributedString(string: "Allow", attributes: buttonTitleAttributes) - button.attributedAlternateTitle = NSAttributedString(string: "Allow", attributes: buttonTitleAttributes) + button.attributedTitle = NSAttributedString(string: copy.allowButton, attributes: buttonTitleAttributes) + button.attributedAlternateTitle = NSAttributedString(string: copy.allowButton, attributes: buttonTitleAttributes) let target = ButtonTarget(action) button.target = target button.action = #selector(ButtonTarget.run) @@ -3550,7 +3578,7 @@ private final class PermissionView: NSView { } private func doneButton() -> NSView { - let button = NSButton(title: "Done", target: nil, action: nil) + let button = NSButton(title: copy.doneButton, target: nil, action: nil) button.bezelStyle = .rounded button.controlSize = .regular button.font = NSFont.systemFont(ofSize: 13, weight: .semibold) @@ -3560,8 +3588,8 @@ private final class PermissionView: NSView { .foregroundColor: NSColor.white, .font: NSFont.systemFont(ofSize: 13, weight: .semibold) ] - button.attributedTitle = NSAttributedString(string: "Done", attributes: buttonTitleAttributes) - button.attributedAlternateTitle = NSAttributedString(string: "Done", attributes: buttonTitleAttributes) + button.attributedTitle = NSAttributedString(string: copy.doneButton, attributes: buttonTitleAttributes) + button.attributedAlternateTitle = NSAttributedString(string: copy.doneButton, attributes: buttonTitleAttributes) let target = ButtonTarget(close) button.target = target button.action = #selector(ButtonTarget.run) @@ -3598,6 +3626,7 @@ private final class PermissionDragAssistantController: NSWindowController { convenience init( permission: PermissionKind, + copy: PermissionWindowCopy, fallbackVisibleFrame: NSRect?, onRefreshPermissions: @escaping () -> Void, onClose: @escaping () -> Void @@ -3608,7 +3637,7 @@ private final class PermissionDragAssistantController: NSWindowController { backing: .buffered, defer: false ) - window.title = "Drag Orca Computer Use" + window.title = copy.dragWindowTitle window.backgroundColor = .clear window.isOpaque = false window.isReleasedWhenClosed = false @@ -3627,7 +3656,11 @@ private final class PermissionDragAssistantController: NSWindowController { onRefreshPermissions: onRefreshPermissions, onClose: onClose ) - window.contentView = PermissionDragAssistantView(permission: permission, appURL: Bundle.main.bundleURL) { [weak self] in + window.contentView = PermissionDragAssistantView( + permission: permission, + copy: copy, + appURL: Bundle.main.bundleURL + ) { [weak self] in self?.dismissFromCloseButton() } } @@ -3902,11 +3935,18 @@ private final class PermissionDragAssistantController: NSWindowController { private final class PermissionDragAssistantView: NSView { private let permission: PermissionKind + private let copy: PermissionWindowCopy private let appURL: URL private let close: () -> Void - init(permission: PermissionKind, appURL: URL, close: @escaping () -> Void) { + init( + permission: PermissionKind, + copy: PermissionWindowCopy, + appURL: URL, + close: @escaping () -> Void + ) { self.permission = permission + self.copy = copy self.appURL = appURL self.close = close super.init(frame: .zero) @@ -3927,7 +3967,10 @@ private final class PermissionDragAssistantView: NSView { let closeButton = NSButton(title: "", target: nil, action: nil) closeButton.bezelStyle = .shadowlessSquare closeButton.isBordered = false - closeButton.image = NSImage(systemSymbolName: "xmark", accessibilityDescription: "Close") + closeButton.image = NSImage( + systemSymbolName: "xmark", + accessibilityDescription: copy.closeButtonDescription + ) closeButton.imagePosition = .imageOnly closeButton.contentTintColor = PermissionPalette.secondaryText closeButton.controlSize = .small @@ -3937,7 +3980,7 @@ private final class PermissionDragAssistantView: NSView { closeButton.action = #selector(ButtonTarget.run) objc_setAssociatedObject(closeButton, "orca-action", target, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) - let instruction = label(permission.dragInstruction, size: 12, weight: .semibold) + let instruction = label(permission.dragInstruction(copy: copy), size: 12, weight: .semibold) instruction.textColor = PermissionPalette.primaryText instruction.maximumNumberOfLines = 2 @@ -4360,9 +4403,12 @@ private func runAgent(socketPath: String, token: String?) { } @MainActor -private func runPermissionCheck(initialPermission: PermissionKind? = nil) { +private func runPermissionCheck( + initialPermission: PermissionKind? = nil, + copy: PermissionWindowCopy +) { let app = NSApplication.shared - let delegate = PermissionRuntime(initialPermission: initialPermission) + let delegate = PermissionRuntime(initialPermission: initialPermission, copy: copy) app.delegate = delegate // Why: setup must foreground reliably; the long-running agent path stays accessory-only. app.setActivationPolicy(.regular) @@ -4486,6 +4532,11 @@ private func writeAll(_ data: Data, to fd: Int32) -> Bool { } let arguments = Array(CommandLine.arguments.dropFirst()) +let permissionLocale = arguments.firstIndex(of: "--locale").flatMap { index -> String? in + let valueIndex = index + 1 + return valueIndex < arguments.count ? arguments[valueIndex] : nil +} +let permissionCopy = PermissionWindowCopy(localeIdentifier: permissionLocale) if arguments.first == "--agent" { guard arguments.count >= 2 else { fputs("usage: orca-computer-use-macos --agent --token-file \n", stderr) @@ -4505,9 +4556,12 @@ if arguments.first == "--agent" { } runAgent(socketPath: arguments[1], token: token) } else if arguments.first == "--permissions" { - runPermissionCheck() + runPermissionCheck(copy: permissionCopy) } else if arguments.first == "--permission" { - runPermissionCheck(initialPermission: PermissionKind.parse(arguments.dropFirst().first)) + runPermissionCheck( + initialPermission: PermissionKind.parse(arguments.dropFirst().first), + copy: permissionCopy + ) } else if arguments.first == "--permission-status" { printPermissionStatus() } else if arguments.first == "--permission-status-file" { diff --git a/native/computer-use-macos/Sources/OrcaComputerUseMacOSCore/PermissionWindowCopy.swift b/native/computer-use-macos/Sources/OrcaComputerUseMacOSCore/PermissionWindowCopy.swift new file mode 100644 index 00000000000..ec8711d2873 --- /dev/null +++ b/native/computer-use-macos/Sources/OrcaComputerUseMacOSCore/PermissionWindowCopy.swift @@ -0,0 +1,116 @@ +import Foundation + +public struct PermissionWindowCopy: Equatable, Sendable { + public let windowTitle: String + public let checkingTitle: String + public let readyTitle: String + public let enableTitle: String + public let checkingSubtitle: String + public let readySubtitle: String + public let permissionSubtitle: String + public let accessibilityTitle: String + public let accessibilityDetail: String + public let screenshotsTitle: String + public let screenshotsDetail: String + public let screenRecordingDescription: String + public let allowButton: String + public let doneButton: String + public let dragWindowTitle: String + public let dragAccessibilityInstruction: String + public let dragScreenshotsInstruction: String + public let closeButtonDescription: String + + public init(localeIdentifier: String?) { + let normalized = (localeIdentifier ?? "") + .trimmingCharacters(in: .whitespacesAndNewlines) + .lowercased() + .replacingOccurrences(of: "_", with: "-") + if normalized == "zh" || normalized.hasPrefix("zh-cn") || normalized.hasPrefix("zh-hans") { + self = Self.chinese + } else { + self = Self.english + } + } + + private static let english = PermissionWindowCopy( + windowTitle: "Enable Orca Computer Use", + checkingTitle: "Checking Computer Use", + readyTitle: "Computer Use is Ready", + enableTitle: "Enable Orca Computer Use", + checkingSubtitle: "Checking Accessibility and Screenshots.", + readySubtitle: "Orca can use local apps when you ask.", + permissionSubtitle: "Grant permissions so Orca can use apps when you ask.", + accessibilityTitle: "Accessibility", + accessibilityDetail: "Read and control app interfaces", + screenshotsTitle: "Screenshots", + screenshotsDetail: "Capture windows for visual state", + screenRecordingDescription: "Screen Recording", + allowButton: "Allow", + doneButton: "Done", + dragWindowTitle: "Drag Orca Computer Use", + dragAccessibilityInstruction: "Drag Orca Computer Use into the list above to allow Accessibility.", + dragScreenshotsInstruction: "Drag Orca Computer Use into the list above to allow Screenshots.", + closeButtonDescription: "Close" + ) + + private static let chinese = PermissionWindowCopy( + windowTitle: "启用 Orca 计算机使用功能", + checkingTitle: "正在检查计算机使用权限", + readyTitle: "计算机使用功能已就绪", + enableTitle: "启用 Orca 计算机使用功能", + checkingSubtitle: "正在检查辅助功能和屏幕截图权限。", + readySubtitle: "当你提出要求时,Orca 可以使用本地应用。", + permissionSubtitle: "授予权限,以便 Orca 在你提出要求时使用应用。", + accessibilityTitle: "辅助功能", + accessibilityDetail: "读取并控制应用界面", + screenshotsTitle: "屏幕截图", + screenshotsDetail: "捕获窗口以识别视觉状态", + screenRecordingDescription: "屏幕录制", + allowButton: "允许", + doneButton: "完成", + dragWindowTitle: "拖入 Orca Computer Use", + dragAccessibilityInstruction: "将 Orca Computer Use 拖入上方列表以允许辅助功能。", + dragScreenshotsInstruction: "将 Orca Computer Use 拖入上方列表以允许屏幕截图。", + closeButtonDescription: "关闭" + ) + + private init( + windowTitle: String, + checkingTitle: String, + readyTitle: String, + enableTitle: String, + checkingSubtitle: String, + readySubtitle: String, + permissionSubtitle: String, + accessibilityTitle: String, + accessibilityDetail: String, + screenshotsTitle: String, + screenshotsDetail: String, + screenRecordingDescription: String, + allowButton: String, + doneButton: String, + dragWindowTitle: String, + dragAccessibilityInstruction: String, + dragScreenshotsInstruction: String, + closeButtonDescription: String + ) { + self.windowTitle = windowTitle + self.checkingTitle = checkingTitle + self.readyTitle = readyTitle + self.enableTitle = enableTitle + self.checkingSubtitle = checkingSubtitle + self.readySubtitle = readySubtitle + self.permissionSubtitle = permissionSubtitle + self.accessibilityTitle = accessibilityTitle + self.accessibilityDetail = accessibilityDetail + self.screenshotsTitle = screenshotsTitle + self.screenshotsDetail = screenshotsDetail + self.screenRecordingDescription = screenRecordingDescription + self.allowButton = allowButton + self.doneButton = doneButton + self.dragWindowTitle = dragWindowTitle + self.dragAccessibilityInstruction = dragAccessibilityInstruction + self.dragScreenshotsInstruction = dragScreenshotsInstruction + self.closeButtonDescription = closeButtonDescription + } +} diff --git a/skill-guides/orca-cli.md b/skill-guides/orca-cli.md index fcedd851a73..ddd4193d06f 100644 --- a/skill-guides/orca-cli.md +++ b/skill-guides/orca-cli.md @@ -28,9 +28,9 @@ Prefer `--json` for agent-driven calls. If the CLI is missing, say so explicitly A full handoff transfers ownership to another agent or worktree, then the original agent stops. Treat requests phrased as "hand off", "handoff", "handover", "give this to another agent", "give this to another worktree", "another agent", or "another worktree" as full handoffs unless the user expects the result back ("have another agent review this and report") or explicitly asks to supervise, monitor, wait for results, track completion, coordinate a DAG, use decision gates, or manage ask/reply. -A handoff is done when the new worktree id and agent handle have been reported and the prompt was delivered: the launch's `prompt.outcome` is `journaled` or `handed-to-terminal`, or, for an agent that was already running, the send receipt reported `accepted: true`. Do not wait for the receiving agent to finish. +A handoff is done when the new worktree id and agent handle have been reported and the prompt was delivered: the launch's `prompt.outcome` is `journaled` or `handed-to-terminal`, or, for an agent that was already running, the `terminal send` receipt reported `accepted: true` or `chat send` reported `delivery` `submitted` or `queued`. Do not wait for the receiving agent to finish. -Do not use `orca orchestration task-create`, `orca orchestration dispatch --inject`, or `orca orchestration check --wait` for full handoffs. `task-create` is also forbidden because it records coordinator-owned tracking state; if a task row is needed, the user asked for supervised orchestration. Deliver the prompt with the agent launch, or with terminal commands for an agent that is already running. +Do not use `orca orchestration task-create`, `orca orchestration dispatch --inject`, or `orca orchestration check --wait` for full handoffs. `task-create` is also forbidden because it records coordinator-owned tracking state; if a task row is needed, the user asked for supervised orchestration. Deliver the prompt with the agent launch, or with `terminal send` or `chat send` for an agent that is already running. For local work in the caller’s project, omit `--repo` and `--project`. Pass one to target another project or when Orca asks you to disambiguate; do not pick a repo from a list for unambiguous same-project work. The project comes from the caller’s directory, not the project visible in the app. Paired-server calls require an explicit server-side target. @@ -62,6 +62,14 @@ Existing-terminal handoff: ORCA terminal send --terminal --text "" --enter --json ``` +Existing-chat handoff, for an agent that runs as a chat (`outcome.kind` `structured`): + +```text +ORCA chat send --session --text "" --json +ORCA chat send --session --text "" --wait --timeout-ms 600000 --json +ORCA chat wait --session --timeout-ms 600000 --json +``` + ## Starting agents `worktree create --agent` (new checkout) and `agent launch` (existing worktree) are how to start an agent. They go through Orca's agent launch, the same one the app's new-agent tab uses: the user's Chat | CLI choice for that agent decides whether it opens as a chat or a terminal, and the result reports which (`outcome.kind`) and why (`receipt.detail`). When a chat is not possible, such as for an agent without chat support, the launch starts a terminal and the receipt says so. `--surface chat|terminal` picks one for that launch instead of the setting; pass it only when the user asked for a chat or a terminal. `--surface chat` is refused when Orca can establish before starting anything that the agent cannot open as a chat. If support cannot be checked, the launch can fall back to a terminal. If chat becomes unavailable only after a new workspace is created, Orca keeps that workspace, its setup and default tabs, then opens a terminal; the receipt explains the fallback. `terminal create` makes a terminal for shells and commands. @@ -273,6 +281,24 @@ Terminal rules: - For long output, use cursor reads. After a limited tail preview, page from `oldestCursor`; after a cursor read, continue with `nextCursor` while `limited` is true and `nextCursor !== latestCursor`. - `--direction vertical` splits left/right. `--direction horizontal` splits top/bottom. +## Chats + +Agents launched as chats are read and messaged with `chat`, not `terminal`. `chat list` names each chat's workspace, agent, state and last reply; `--session` takes the `session` it reports or the `handle` a launch returned. + +```text +ORCA chat list --json +ORCA chat list --state working --json +ORCA chat read --session --limit 10 --json +ORCA chat send --session --text "" --json +``` + +- `chat read` returns messages, tool calls, errors, and approvals or questions; `pending: true` marks one waiting for the user. +- `chat send` sends the text as the user's message. While the agent works, a host with a message queue holds it until the turn ends and reports `delivery: "queued"`. +- A refused send was not delivered. Read the chat again before resending. +- `chat send --wait` (or `chat wait`) returns when the chat settles, using `chat list` states: `settled: "done"`, or `"blocked"` on an approval or question, with the entries since the last user message; `settled: "timeout"` or `"held"` (queued message stopped or failed) exits 1. Pass `--timeout-ms`. Long or quoted text goes through `--text-file -` on stdin. +- Paired hosts can `chat list` only; read, send and wait run on the host machine. +- When relaying for a user from outside Orca (for example a voice or messaging assistant on the same machine), report from `chat list` and `chat read`, repeat an instruction back and get the user's confirmation before `chat send`, and send the user's words without adding instructions. + ## Artifacts @@ -282,8 +308,8 @@ Use them only when the user explicitly asks to publish through Orca. A generic r public link, page, or URL does not select Orca, and a provider the user names always wins. **Only a human can turn publishing on or off.** `share` and `update` need the device-wide -setting under Settings → Artifacts ("Allow publishing public artifact links"); there is no -CLI or RPC way to grant it. `list`, `unshare`, and `delete` are never gated, so old links +setting under Settings → Artifacts ("Allow publishing public artifact links"), which is on +for new profiles; there is no CLI or RPC way to grant it. `list`, `unshare`, and `delete` are never gated, so old links stay auditable and revocable. A denied share fails with `artifact_sharing_disabled` before any upload. Do not retry. Tell diff --git a/skill-guides/orca-cli/references/browser.md b/skill-guides/orca-cli/references/browser.md index d10112b75f0..8e9564eab9a 100644 --- a/skill-guides/orca-cli/references/browser.md +++ b/skill-guides/orca-cli/references/browser.md @@ -71,6 +71,7 @@ Browser rules: - Pass `--page ` on every command that acts on one page; `ORCA --help` lists `--page` when it does. `tab list`, `tab current`, `tab create` and `open-url` take no `--page`, and `tab switch`/`tab close` pick a tab by `--index` or `--page`, never both, since `--page` wins. Take the ID from `result.tab.browserPageId` in `ORCA tab current --json` or `result.browserPageId` in `ORCA tab create --json` and keep it for the task; `tab current` shows the routed tab, not the one you pin. When the user means a specific tab, find it by URL or title in `ORCA tab list --json`. - Without `--page`, a command goes to the worktree's current tab. That stays the agent's tab while it has had a command in the last 20 seconds or so, even after the user picks another (`tab current` reports it too), then moves to the user's pick. - After `ORCA tab switch`, pass the new page's `browserPageId`. +- When the user says they left notes or comments on a page, read them with `ORCA tab annotations --page ` (the current tab without `--page`). It prints the notes they haven't sent, the same text the tab's Copy button gives, and `--json` returns them in `result.annotations`. Notes the user already sent arrive in your chat instead. - A popup window a page opens (sign-in, payment) is listed in `ORCA tab list --json` as a `popup-` page with `openerBrowserPageId`. If a click seems to do nothing, check `tab list`, then drive the popup with `--page popup-`. When it closes, continue on the opener page. - Browser commands default to the current worktree. `--page` reaches the page in any worktree unless you also pass `--worktree `. Use `--worktree all` only intentionally. - `tab list` shows every tab in the tab bar. After a restart, tabs the user has not opened report `loaded: false`; `tab switch` or any `--page` command loads one in the background without changing the user's visible tab. diff --git a/skill-guides/orca-per-workspace-env.md b/skill-guides/orca-per-workspace-env.md index 6a7dfff336b..2ccc5e7cf9a 100644 --- a/skill-guides/orca-per-workspace-env.md +++ b/skill-guides/orca-per-workspace-env.md @@ -301,6 +301,17 @@ timeoutSeconds: destroy: 120 ``` +Recipe scripts inherit Orca's whole environment by default, including any API keys and tokens in +it. Set `passEnv` to pass only the variables the scripts need, as exact names or a prefix ending in +`*`; `PATH`, `HOME`, `USER`, `SHELL`, `LANG`, `TMPDIR` and similar basics are always kept, and the +`ORCA_*` recipe variables are always set. Recipes that use an SSH agent also need `SSH_AUTH_SOCK`, +and provider CLIs need their own credential or config variables. A malformed `passEnv` is reported +and limits the scripts to the basic variables until it is fixed. + +```yaml +passEnv: [GH_TOKEN, GITHUB_TOKEN, 'CLOUDSDK_*'] +``` + A timed-out `create` may still have started a VM, so make `create` idempotent per `ORCA_VM_INSTANCE_ID` or have it record the resource before slow work starts. diff --git a/src/cli/browser/browser-extension.ts b/src/cli/browser/browser-extension.ts index 8a95b6c7a4a..471efb88e63 100644 --- a/src/cli/browser/browser-extension.ts +++ b/src/cli/browser/browser-extension.ts @@ -16,7 +16,7 @@ export const BROWSER_EXTENSION_HANDLERS: Record = { ) printResult(result, json, ({ active, extensions }) => !active - ? 'Browser extensions are disabled in Settings › Experimental.' + ? 'Browser extensions are turned off in Settings › Browser › Extensions.' : extensions.length === 0 ? 'No browser extensions installed.' : extensions diff --git a/src/cli/browser/browser-format.ts b/src/cli/browser/browser-format.ts index 63a3d5d814f..ac3e7122022 100644 --- a/src/cli/browser/browser-format.ts +++ b/src/cli/browser/browser-format.ts @@ -1,10 +1,12 @@ import { readBrowserActionEffects } from '../../shared/browser-action-effects' import { writeCliScreenshotTempFile } from '../cli-screenshot-temp-file' import type { RuntimeRpcSuccess } from '../../shared/runtime-rpc-envelope' +import { formatBrowserAnnotationsAsMarkdown } from '../../shared/browser/annotations/browser-annotation-output' import type { BrowserProfileListResult, BrowserScreenshotResult, BrowserSnapshotResult, + BrowserTabAnnotationsResult, BrowserTabCurrentResult, BrowserTabListResult, BrowserTabProfileCloneResult, @@ -132,6 +134,13 @@ export function formatTabShow(result: BrowserTabShowResult | BrowserTabCurrentRe ].join('\n') } +// The same text the tab's Copy button gives, so an agent reads what the user would send. +export function formatTabAnnotations(result: BrowserTabAnnotationsResult): string { + return result.annotations.length > 0 + ? formatBrowserAnnotationsAsMarkdown(result.annotations) + : `No unsent notes on tab ${result.tab.browserPageId}` +} + export function formatTabProfileShow(result: BrowserTabProfileShowResult): string { return [ `page: ${result.browserPageId}`, diff --git a/src/cli/browser/browser-tab.ts b/src/cli/browser/browser-tab.ts index 74edfe04e53..7ee72d93664 100644 --- a/src/cli/browser/browser-tab.ts +++ b/src/cli/browser/browser-tab.ts @@ -1,11 +1,17 @@ import type { + BrowserTabAnnotationsResult, BrowserTabCurrentResult, BrowserTabListResult, BrowserTabShowResult, BrowserTabSwitchResult } from '../../shared/browser/runtime/runtime-browser-contracts' import type { CommandHandler } from '../dispatch' -import { formatTabList, formatTabListWithProfiles, formatTabShow } from './browser-format' +import { + formatTabAnnotations, + formatTabList, + formatTabListWithProfiles, + formatTabShow +} from './browser-format' import { printResult } from '../format' import { getOptionalNonNegativeIntegerFlag, @@ -42,6 +48,11 @@ export const BROWSER_TAB_HANDLERS: Record = { const result = await client.call('browser.tabShow', target) printResult(result, json, formatTabShow) }, + 'tab annotations': async ({ flags, client, cwd, json }) => { + const target = await getBrowserCommandTarget(flags, cwd, client) + const result = await client.call('browser.tabAnnotations', target) + printResult(result, json, formatTabAnnotations) + }, 'tab current': async ({ flags, client, cwd, json }) => { const worktree = await getBrowserWorktreeSelector(flags, cwd, client) const result = await client.call('browser.tabCurrent', { worktree }) diff --git a/src/cli/bundled-skill-guides.ts b/src/cli/bundled-skill-guides.ts index 6aaf42ad5c4..f33c96a13e9 100644 --- a/src/cli/bundled-skill-guides.ts +++ b/src/cli/bundled-skill-guides.ts @@ -256,9 +256,9 @@ const ORCA_CLI_MARKDOWN = [ "", "A full handoff transfers ownership to another agent or worktree, then the original agent stops. Treat requests phrased as \"hand off\", \"handoff\", \"handover\", \"give this to another agent\", \"give this to another worktree\", \"another agent\", or \"another worktree\" as full handoffs unless the user expects the result back (\"have another agent review this and report\") or explicitly asks to supervise, monitor, wait for results, track completion, coordinate a DAG, use decision gates, or manage ask/reply.", "", - "A handoff is done when the new worktree id and agent handle have been reported and the prompt was delivered: the launch's `prompt.outcome` is `journaled` or `handed-to-terminal`, or, for an agent that was already running, the send receipt reported `accepted: true`. Do not wait for the receiving agent to finish.", + "A handoff is done when the new worktree id and agent handle have been reported and the prompt was delivered: the launch's `prompt.outcome` is `journaled` or `handed-to-terminal`, or, for an agent that was already running, the `terminal send` receipt reported `accepted: true` or `chat send` reported `delivery` `submitted` or `queued`. Do not wait for the receiving agent to finish.", "", - "Do not use `orca orchestration task-create`, `orca orchestration dispatch --inject`, or `orca orchestration check --wait` for full handoffs. `task-create` is also forbidden because it records coordinator-owned tracking state; if a task row is needed, the user asked for supervised orchestration. Deliver the prompt with the agent launch, or with terminal commands for an agent that is already running.", + "Do not use `orca orchestration task-create`, `orca orchestration dispatch --inject`, or `orca orchestration check --wait` for full handoffs. `task-create` is also forbidden because it records coordinator-owned tracking state; if a task row is needed, the user asked for supervised orchestration. Deliver the prompt with the agent launch, or with `terminal send` or `chat send` for an agent that is already running.", "", "For local work in the caller’s project, omit `--repo` and `--project`. Pass one to target another project or when Orca asks you to disambiguate; do not pick a repo from a list for unambiguous same-project work. The project comes from the caller’s directory, not the project visible in the app. Paired-server calls require an explicit server-side target.", "", @@ -290,6 +290,14 @@ const ORCA_CLI_MARKDOWN = [ "ORCA terminal send --terminal --text \"\" --enter --json", "```", "", + "Existing-chat handoff, for an agent that runs as a chat (`outcome.kind` `structured`):", + "", + "```text", + "ORCA chat send --session --text \"\" --json", + "ORCA chat send --session --text \"\" --wait --timeout-ms 600000 --json", + "ORCA chat wait --session --timeout-ms 600000 --json", + "```", + "", "## Starting agents", "", "`worktree create --agent` (new checkout) and `agent launch` (existing worktree) are how to start an agent. They go through Orca's agent launch, the same one the app's new-agent tab uses: the user's Chat | CLI choice for that agent decides whether it opens as a chat or a terminal, and the result reports which (`outcome.kind`) and why (`receipt.detail`). When a chat is not possible, such as for an agent without chat support, the launch starts a terminal and the receipt says so. `--surface chat|terminal` picks one for that launch instead of the setting; pass it only when the user asked for a chat or a terminal. `--surface chat` is refused when Orca can establish before starting anything that the agent cannot open as a chat. If support cannot be checked, the launch can fall back to a terminal. If chat becomes unavailable only after a new workspace is created, Orca keeps that workspace, its setup and default tabs, then opens a terminal; the receipt explains the fallback. `terminal create` makes a terminal for shells and commands.", @@ -501,6 +509,24 @@ const ORCA_CLI_MARKDOWN = [ "- For long output, use cursor reads. After a limited tail preview, page from `oldestCursor`; after a cursor read, continue with `nextCursor` while `limited` is true and `nextCursor !== latestCursor`.", "- `--direction vertical` splits left/right. `--direction horizontal` splits top/bottom.", "", + "## Chats", + "", + "Agents launched as chats are read and messaged with `chat`, not `terminal`. `chat list` names each chat's workspace, agent, state and last reply; `--session` takes the `session` it reports or the `handle` a launch returned.", + "", + "```text", + "ORCA chat list --json", + "ORCA chat list --state working --json", + "ORCA chat read --session --limit 10 --json", + "ORCA chat send --session --text \"\" --json", + "```", + "", + "- `chat read` returns messages, tool calls, errors, and approvals or questions; `pending: true` marks one waiting for the user.", + "- `chat send` sends the text as the user's message. While the agent works, a host with a message queue holds it until the turn ends and reports `delivery: \"queued\"`.", + "- A refused send was not delivered. Read the chat again before resending.", + "- `chat send --wait` (or `chat wait`) returns when the chat settles, using `chat list` states: `settled: \"done\"`, or `\"blocked\"` on an approval or question, with the entries since the last user message; `settled: \"timeout\"` or `\"held\"` (queued message stopped or failed) exits 1. Pass `--timeout-ms`. Long or quoted text goes through `--text-file -` on stdin.", + "- Paired hosts can `chat list` only; read, send and wait run on the host machine.", + "- When relaying for a user from outside Orca (for example a voice or messaging assistant on the same machine), report from `chat list` and `chat read`, repeat an instruction back and get the user's confirmation before `chat send`, and send the user's words without adding instructions.", + "", "", "", "## Artifacts", @@ -510,8 +536,8 @@ const ORCA_CLI_MARKDOWN = [ "public link, page, or URL does not select Orca, and a provider the user names always wins.", "", "**Only a human can turn publishing on or off.** `share` and `update` need the device-wide", - "setting under Settings → Artifacts (\"Allow publishing public artifact links\"); there is no", - "CLI or RPC way to grant it. `list`, `unshare`, and `delete` are never gated, so old links", + "setting under Settings → Artifacts (\"Allow publishing public artifact links\"), which is on", + "for new profiles; there is no CLI or RPC way to grant it. `list`, `unshare`, and `delete` are never gated, so old links", "stay auditable and revocable.", "", "A denied share fails with `artifact_sharing_disabled` before any upload. Do not retry. Tell", @@ -740,6 +766,7 @@ const ORCA_CLI_BROWSER_REFERENCE_MARKDOWN = [ "- Pass `--page ` on every command that acts on one page; `ORCA --help` lists `--page` when it does. `tab list`, `tab current`, `tab create` and `open-url` take no `--page`, and `tab switch`/`tab close` pick a tab by `--index` or `--page`, never both, since `--page` wins. Take the ID from `result.tab.browserPageId` in `ORCA tab current --json` or `result.browserPageId` in `ORCA tab create --json` and keep it for the task; `tab current` shows the routed tab, not the one you pin. When the user means a specific tab, find it by URL or title in `ORCA tab list --json`.", "- Without `--page`, a command goes to the worktree's current tab. That stays the agent's tab while it has had a command in the last 20 seconds or so, even after the user picks another (`tab current` reports it too), then moves to the user's pick.", "- After `ORCA tab switch`, pass the new page's `browserPageId`.", + "- When the user says they left notes or comments on a page, read them with `ORCA tab annotations --page ` (the current tab without `--page`). It prints the notes they haven't sent, the same text the tab's Copy button gives, and `--json` returns them in `result.annotations`. Notes the user already sent arrive in your chat instead.", "- A popup window a page opens (sign-in, payment) is listed in `ORCA tab list --json` as a `popup-` page with `openerBrowserPageId`. If a click seems to do nothing, check `tab list`, then drive the popup with `--page popup-`. When it closes, continue on the opener page.", "- Browser commands default to the current worktree. `--page` reaches the page in any worktree unless you also pass `--worktree `. Use `--worktree all` only intentionally.", "- `tab list` shows every tab in the tab bar. After a restart, tabs the user has not opened report `loaded: false`; `tab switch` or any `--page` command loads one in the background without changing the user's visible tab.", @@ -2087,6 +2114,17 @@ const ORCA_PER_WORKSPACE_ENV_MARKDOWN = [ " destroy: 120", "```", "", + "Recipe scripts inherit Orca's whole environment by default, including any API keys and tokens in", + "it. Set `passEnv` to pass only the variables the scripts need, as exact names or a prefix ending in", + "`*`; `PATH`, `HOME`, `USER`, `SHELL`, `LANG`, `TMPDIR` and similar basics are always kept, and the", + "`ORCA_*` recipe variables are always set. Recipes that use an SSH agent also need `SSH_AUTH_SOCK`,", + "and provider CLIs need their own credential or config variables. A malformed `passEnv` is reported", + "and limits the scripts to the basic variables until it is fixed.", + "", + "```yaml", + "passEnv: [GH_TOKEN, GITHUB_TOKEN, 'CLOUDSDK_*']", + "```", + "", "A timed-out `create` may still have started a VM, so make `create` idempotent per", "`ORCA_VM_INSTANCE_ID` or have it record the resource before slow work starts.", "", diff --git a/src/cli/chat-history.ts b/src/cli/chat-history.ts new file mode 100644 index 00000000000..db4c70730cd --- /dev/null +++ b/src/cli/chat-history.ts @@ -0,0 +1,168 @@ +import type { + AgentSessionHistoryPage, + AgentSessionHistoryResult +} from '../shared/agent-session/agent-session-wire' +import { AGENT_SESSION_HISTORY_MAX_LIMIT } from '../shared/agent-session/agent-session-wire' +import { + AGENT_SESSION_UNATTACHED_REFUSAL_CODE, + isUnattachedAgentSessionReadRefusal +} from '../shared/agent-session/failures/structured-agent-session-read-refusal' +import { structuredAgentSessionQueueSendsNext } from '../shared/agent-session/view/structured-agent-session-live-turn' +import { chatTranscript, formatChatRead, type ChatTranscriptEntry } from './chat-sessions' +import type { RuntimeClient, RuntimeRpcSuccess } from './runtime-client' +import { RuntimeClientError } from './runtime-client' + +export const DEFAULT_READ_LIMIT = 20 +const WAIT_POLL_MS = 1000 + +export type ChatTranscript = { + session: string + entries: ChatTranscriptEntry[] + /** Newest journal row read, so a later `--since` can continue from it. */ + cursor: AgentSessionHistoryPage['window']['newest'] + /** Older rows exist that this 200-row read did not reach, and they were needed. */ + truncated: boolean +} +/** The chat's own turn in `chat list` words (structuredAgentSessionLeadState), plus two wait-only outcomes. */ +export type ChatSettled = 'done' | 'blocked' | 'held' | 'timeout' + +export async function readHistory( + client: RuntimeClient, + session: string, + limit: number +): Promise> { + return client + .call('agentSession.history', { + sessionId: session, + direction: 'tail', + limit + }) + .catch((error: unknown) => { + throw explainChatRefusal(error, session, 'read') + }) +} + +export async function readTranscript( + client: RuntimeClient, + session: string, + limit?: number +): Promise> { + // Status frames and turn markers share the journal, so read the most rows a page allows. + const response = await readHistory(client, session, AGENT_SESSION_HISTORY_MAX_LIMIT) + const { page } = response.result + const all = chatTranscript(page.items, page.actionablePromptIds) + const entries = limit === undefined ? all : all.slice(-limit) + const truncated = page.hasOlder && (limit === undefined || all.length < limit) + return { ...response, result: { session, entries, cursor: page.window.newest, truncated } } +} + +export function requireWorkingFlag(page: AgentSessionHistoryPage): void { + if (page.working === undefined) { + throw new RuntimeClientError( + 'incompatible_runtime', + 'This Orca host does not report when a chat is working, so it cannot wait. Update Orca on the host.' + ) + } +} + +// Settled means no running turn or unanswered send, or a question/approval waiting for the user. +export async function waitForChat( + client: RuntimeClient, + session: string, + timeoutMs: number | undefined, + queuedMessageId?: string +): Promise { + const deadline = timeoutMs === undefined ? Infinity : Date.now() + timeoutMs + for (;;) { + const { page } = (await readHistory(client, session, 1)).result + requireWorkingFlag(page) + if ((page.actionablePromptIds?.length ?? 0) > 0) { + return 'blocked' + } + // Between turns the host names its next automatic send while working is briefly false. + const sendsNext = structuredAgentSessionQueueSendsNext( + page.nextQueuedMessageId, + page.working === true + ) + if (!page.working && !sendsNext) { + // Still queued with nothing running or about to send: stopped, failed or held across a reopen. + const held = page.queuedMessages?.some((m) => m.messageId === queuedMessageId) === true + return held ? 'held' : 'done' + } + if (Date.now() >= deadline) { + return 'timeout' + } + await new Promise((resolve) => setTimeout(resolve, WAIT_POLL_MS)) + } +} + +// After a wait, the turn's entries: everything after the last user message. +export async function readSettledTurn( + client: RuntimeClient, + session: string, + settled: ChatSettled +): Promise> { + if (settled === 'timeout' || settled === 'held') { + // Chained commands such as `send --wait && ...` need a failing exit when the chat did not settle. + process.exitCode = 1 + } + const response = await readTranscript(client, session) + const { entries, truncated } = response.result + const lastUser = entries.findLastIndex((e) => e.kind === 'message' && e.role === 'user') + // A held message never ran, so the last turn on the page is not its reply. + const turn = settled === 'held' ? [] : entries.slice(lastUser + 1) + return { + ...response, + result: { + ...response.result, + entries: turn, + truncated: settled !== 'held' && truncated && lastUser === -1, + settled + } + } +} + +export function formatSettled(result: ChatTranscript & { settled: ChatSettled }): string { + const status = + result.settled === 'timeout' + ? 'Still working when the wait timed out.' + : result.settled === 'held' + ? 'Your message is held in the queue (the chat was stopped or the send failed). Resume it in Orca.' + : result.settled === 'blocked' + ? 'Blocked: waiting for you to answer an approval or question.' + : 'Done.' + return result.entries.length === 0 ? status : `${formatChatRead(result)}\n${status}` +} + +// The host answers with bare wire codes; say what they mean for this command. +export function explainChatRefusal( + error: unknown, + sessionId: string, + action: 'rename' | 'read' | 'send to' +): unknown { + if (!(error instanceof RuntimeClientError)) { + return error + } + if (error.message === 'agent_session_identity_required') { + return new RuntimeClientError( + 'agent_session_identity_required', + `No chat with session id ${sessionId} on this host.` + ) + } + if (isUnattachedAgentSessionReadRefusal(error)) { + return new RuntimeClientError( + AGENT_SESSION_UNATTACHED_REFUSAL_CODE, + `No open chat with session id ${sessionId} on this host. Find it with \`orca chat list\`.` + ) + } + if ( + error.message === 'structured_agent_session_unsupported' || + error.code === 'method_not_found' + ) { + return new RuntimeClientError( + 'incompatible_runtime', + `This Orca host cannot ${action} chats from the CLI. Update Orca on that host, or check that it has chats turned on.` + ) + } + return error +} diff --git a/src/cli/chat-sessions.ts b/src/cli/chat-sessions.ts new file mode 100644 index 00000000000..e88453284f6 --- /dev/null +++ b/src/cli/chat-sessions.ts @@ -0,0 +1,175 @@ +import { agentSessionPromptQuestions } from '../shared/agent-session/agent-session-question-answer' +import { isActionableStructuredAgentSessionPrompt } from '../shared/agent-session/view/structured-agent-session-live-turn' +import { isRootAgentJournalItem } from '../shared/agent-session/journal/agent-session-journal-producer' +import type { AgentJournalRenderItem } from '../shared/agent-session/journal/agent-session-journal-types' +import type { + RuntimeWorktreeAgentRow, + RuntimeWorktreePsSummary +} from '../shared/runtime-worktree-contracts' +import { structuredAgentSessionTabId } from '../shared/agent-session/view/structured-agent-session-projection' +import { RuntimeClientError } from './runtime-client' + +const CHAT_HANDLE_PREFIX = structuredAgentSessionTabId('') + +export type ChatSessionEntry = { + session: string + handle: string + worktreeId: string + worktree: string + agentType: string | null + state: RuntimeWorktreeAgentRow['state'] + title: string | null + lastAssistantMessage: string | null + updatedAt: number +} + +export type ChatTranscriptEntry = + | { kind: 'message'; role: string; text: string } + | { kind: 'tool'; name: string; state: string } + | { kind: 'approval' | 'question'; text: string; pending: boolean } + | { kind: 'error'; text: string } + +/** The session id a chat is addressed by, from its id, its handle, or a pane key that names it. */ +export function parseChatSessionSelector(value: string): string { + const withoutHandle = value.startsWith(CHAT_HANDLE_PREFIX) + ? value.slice(CHAT_HANDLE_PREFIX.length) + : value + // A pane key is the chat's handle and its leaf: ":". + const session = withoutHandle.split(':')[0]?.trim() ?? '' + if (session.length === 0) { + throw new RuntimeClientError( + 'invalid_argument', + '--session needs a chat session id or handle; run `orca chat list` to find one.' + ) + } + return session +} + +/** The top-level chats in a worktree summary. Terminal agents and subagents are left out: + * terminals are read with `orca terminal`, and a subagent is reached through its parent chat. */ +export function listChatSessions( + worktrees: readonly RuntimeWorktreePsSummary[] +): ChatSessionEntry[] { + return worktrees.flatMap((worktree) => + worktree.agents + .filter( + (agent) => agent.parentPaneKey === null && agent.paneKey.startsWith(CHAT_HANDLE_PREFIX) + ) + .map((agent) => { + const session = parseChatSessionSelector(agent.paneKey) + return { + session, + handle: structuredAgentSessionTabId(session), + worktreeId: worktree.worktreeId, + worktree: worktree.displayName, + agentType: agent.agentType, + state: agent.state, + title: agent.displayName ?? agent.taskTitle, + lastAssistantMessage: agent.lastAssistantMessage, + updatedAt: agent.updatedAt + } + }) + ) +} + +function messageText(item: AgentJournalRenderItem): string { + if (item.body.kind !== 'message') { + return '' + } + return item.body.blocks + .map((block) => + block.type === 'text' ? block.text : block.type === 'image-ref' ? '[image]' : '' + ) + .filter((text) => text.length > 0) + .join('\n') + .trim() +} + +/** The conversation as a reader follows it: messages, the tools the agent ran, and the + * approvals and questions it raised. Provider status frames and turn markers are left out. */ +export function chatTranscript( + items: readonly AgentJournalRenderItem[], + actionablePromptIds?: readonly string[] +): ChatTranscriptEntry[] { + // An ended agent's unanswered prompts stay pending in the journal but can no longer be answered. + const waiting = (item: AgentJournalRenderItem, state: string): boolean => + state === 'pending' && + isActionableStructuredAgentSessionPrompt(item.itemId, actionablePromptIds) + const entries: ChatTranscriptEntry[] = [] + for (const item of items) { + // Subagents share the journal; their rows belong to their own section, not the chat's turn. + if (!isRootAgentJournalItem(item)) { + continue + } + const body = item.body + if (body.kind === 'message') { + const text = messageText(item) + // Reasoning is the model's scratch work, folded away in the app too. + if (text.length > 0 && body.role !== 'reasoning') { + entries.push({ kind: 'message', role: body.role, text }) + } + } else if (body.kind === 'status' && body.tone === 'error') { + // Start failures and dead agents land as error status rows; without them a wait reads "Done.". + entries.push({ kind: 'error', text: String(body.text) }) + } else if (body.kind === 'tool-call') { + entries.push({ kind: 'tool', name: body.name, state: body.state }) + } else if (body.kind === 'approval') { + entries.push({ + kind: 'approval', + text: body.title, + pending: waiting(item, body.resolution.state) + }) + } else if (body.kind === 'question') { + entries.push({ + kind: 'question', + // Grouped prompts keep their real questions in `questions`; `question` is then a heading. + text: agentSessionPromptQuestions(body) + .map((q) => q.question) + .join('\n'), + pending: waiting(item, body.resolution.state) + }) + } + } + return entries +} + +export function formatChatList(result: { chats: ChatSessionEntry[] }): string { + if (result.chats.length === 0) { + return 'No chats.' + } + return result.chats + .map((chat) => + [ + `${chat.worktree} · ${chat.agentType ?? 'agent'} · ${chat.state}`, + ` session: ${chat.session}`, + ...(chat.title ? [` title: ${chat.title}`] : []), + ...(chat.lastAssistantMessage + ? [` last reply: ${chat.lastAssistantMessage.replace(/\s+/g, ' ').slice(0, 200)}`] + : []) + ].join('\n') + ) + .join('\n\n') +} + +export function formatChatRead(result: { + session: string + entries: ChatTranscriptEntry[] +}): string { + if (result.entries.length === 0) { + return `No messages in ${result.session}.` + } + return result.entries + .map((entry) => { + if (entry.kind === 'message') { + return `${entry.role}: ${entry.text}` + } + if (entry.kind === 'error') { + return `[error] ${entry.text}` + } + if (entry.kind === 'tool') { + return `[tool ${entry.name}: ${entry.state}]` + } + return `[${entry.kind}${entry.pending ? ', waiting for you' : ''}] ${entry.text}` + }) + .join('\n') +} diff --git a/src/cli/command-scoped-flag-help.ts b/src/cli/command-scoped-flag-help.ts index fc5c6c56006..92e83f0a753 100644 --- a/src/cli/command-scoped-flag-help.ts +++ b/src/cli/command-scoped-flag-help.ts @@ -2,7 +2,22 @@ const FILE_OPEN_FOCUS_HELP = "--focus Bring the user to the file (switches Orca's window to its worktree)" +const CHAT_SESSION_HELP = + '--session Chat session id or handle from chat list or agent launch' + const COMMAND_SCOPED_FLAG_HELP: Record> = { + 'chat rename': { + session: '--session Chat session id from chat list or agent launch' + }, + 'chat list': { + state: '--state Only chats in this state: working, blocked, waiting or done' + }, + 'chat read': { session: CHAT_SESSION_HELP }, + 'chat send': { + session: CHAT_SESSION_HELP, + wait: '--wait Wait until the chat finishes or needs your answer' + }, + 'chat wait': { session: CHAT_SESSION_HELP }, 'extension reload': { 'extension-id': '--extension-id Installed unpacked extension ID; also accepted positionally', diff --git a/src/cli/flag-help-text.ts b/src/cli/flag-help-text.ts index 108cf43bf8f..1e283dd828f 100644 --- a/src/cli/flag-help-text.ts +++ b/src/cli/flag-help-text.ts @@ -36,6 +36,7 @@ export const FLAG_HELP_TEXT: Record = { interrupt: '--interrupt Send as an interrupt-style input when supported', 'keep-open': '--keep-open Keep the worker open after it finishes', 'spec-file': '--spec-file Read the spec from a file or stdin', + 'text-file': '--text-file Read the text from a file or stdin', id: '--id Identifier for a target item or permission', issue: '--issue Linked GitHub issue number', 'gitlab-issue': diff --git a/src/cli/handler-group-manifest.ts b/src/cli/handler-group-manifest.ts index 9cc19bf9f86..31606226998 100644 --- a/src/cli/handler-group-manifest.ts +++ b/src/cli/handler-group-manifest.ts @@ -207,7 +207,7 @@ export const HANDLER_GROUPS: readonly HandlerGroup[] = [ }, { name: 'chat', - keys: ['chat rename'], + keys: ['chat rename', 'chat list', 'chat read', 'chat send', 'chat wait'], load: async () => (await import('./handlers/chat.js')).CHAT_HANDLERS }, { diff --git a/src/cli/handlers/chat.test.ts b/src/cli/handlers/chat.test.ts index 50005f098b6..177a839ad13 100644 --- a/src/cli/handlers/chat.test.ts +++ b/src/cli/handlers/chat.test.ts @@ -1,7 +1,183 @@ import { afterEach, describe, expect, it, vi } from 'vitest' +import { SendParams } from '../../shared/rpc-contract/structured-agent-session-params' +import { AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY } from '../../shared/agent-session/agent-session-runtime-capabilities' import { RuntimeClient } from '../runtime-client' import { CHAT_HANDLERS } from './chat' +const SESSION = 'codex_8eb631ab_59c5_41e4_8672_01cfe0a6fd5f' + +function ok(result: unknown) { + return { id: 'req', ok: true, result, _meta: { runtimeId: 'runtime-1' } } +} + +function historyPage( + items: unknown[], + fence: number | undefined = 3, + pageOverrides: Record = {} +) { + return ok({ + ok: true, + page: { + sessionId: SESSION, + epoch: 'e', + fence, + direction: 'tail', + items, + removedItemIds: [], + submissions: [], + window: { + oldest: null, + newest: { epoch: 'e', sequence: 9 }, + nextCursor: { epoch: 'e', sequence: 9 } + }, + ...pageOverrides + } + }) +} + +function item(body: unknown) { + return { itemId: 'i', revision: 1, sequence: 1, observedAt: 1, body } +} + +function fakeClient( + responses: unknown[], + capabilities: string[] = [AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY] +): RuntimeClient & { call: ReturnType } { + const client = new RuntimeClient('/tmp/orca-chat-test', 60_000, null, null) + const call = vi.fn() + for (const response of responses) { + call.mockResolvedValueOnce(response) + } + vi.spyOn(client, 'call').mockImplementation(call) + vi.spyOn(client, 'getCliStatus').mockResolvedValue({ + id: 'status', + ok: true, + result: { + app: { running: true, pid: 123 }, + runtime: { state: 'ready', reachable: true, runtimeId: 'runtime-1', capabilities }, + graph: { state: 'ready' } + }, + _meta: { runtimeId: 'runtime-1' } + }) + return Object.assign(client, { call }) +} + +async function run( + command: string, + flags: Record, + client: RuntimeClient +) { + const logs: string[] = [] + const spy = vi.spyOn(console, 'log').mockImplementation((line: string) => logs.push(line)) + try { + await CHAT_HANDLERS[command]!({ + flags: new Map(Object.entries(flags)), + client, + cwd: '/tmp', + json: true + }) + } finally { + spy.mockRestore() + } + return JSON.parse(logs.join('\n')).result +} + +afterEach(() => { + vi.useRealTimers() + vi.restoreAllMocks() +}) + +describe('chat send', () => { + it('sends a host-valid message fenced to the chat it read, queued while the agent works', async () => { + const client = fakeClient([ + historyPage([], 7), + ok({ + ok: true, + replayed: false, + fence: 7, + cursor: { epoch: 'e', sequence: 2 }, + value: { + clientMessageId: 'm-1', + queued: { messageId: 'q-1', position: 1, state: 'waiting' } + } + }) + ]) + const result = await run('chat send', { session: SESSION, text: 'Run the tests' }, client) + const params = client.call.mock.calls[1]![1] + expect(client.call.mock.calls[1]![0]).toBe('agentSession.send') + // The host validates the same schema, so a malformed envelope or body fails here. + expect(SendParams.safeParse(params).success).toBe(true) + expect(params).toMatchObject({ + envelope: { sessionId: SESSION, expectedRuntimeFence: 7 }, + delivery: 'queue-if-active', + body: { kind: 'message', role: 'user', blocks: [{ type: 'text', text: 'Run the tests' }] } + }) + expect(result).toEqual({ + session: SESSION, + delivery: 'queued', + clientMessageId: 'm-1', + queuePosition: 1 + }) + }) + + it('reports a host refusal as an error instead of a sent message', async () => { + const client = fakeClient([ + historyPage([], 2), + ok({ + ok: false, + refusal: { code: 'agent_session_fence_mismatch', message: 'The chat restarted.' } + }) + ]) + await expect(run('chat send', { session: SESSION, text: 'hi' }, client)).rejects.toMatchObject({ + code: 'agent_session_fence_mismatch' + }) + }) + + it('with --wait, waits for its queued message to run and returns that turn', async () => { + vi.useFakeTimers() + const client = fakeClient([ + historyPage([], 7, { working: true }), + ok({ + ok: true, + replayed: false, + fence: 7, + cursor: { epoch: 'e', sequence: 2 }, + value: { + clientMessageId: 'm-1', + queued: { messageId: 'q-1', position: 1, state: 'waiting' } + } + }), + // The earlier turn ended, but the queued message has not been handed to the agent yet. + historyPage([], 7, { + working: false, + queuedMessages: [{ messageId: 'q-1' }], + nextQueuedMessageId: 'q-1' + }), + historyPage([], 7, { working: true, queuedMessages: [] }), + historyPage([], 7, { working: false, queuedMessages: [], actionablePromptIds: [] }), + historyPage([ + item({ kind: 'message', role: 'user', blocks: [{ type: 'text', text: 'Earlier' }] }), + item({ kind: 'message', role: 'assistant', blocks: [{ type: 'text', text: 'Old reply' }] }), + item({ kind: 'message', role: 'user', blocks: [{ type: 'text', text: 'Run the tests' }] }), + item({ kind: 'message', role: 'assistant', blocks: [{ type: 'text', text: 'All pass' }] }) + ]) + ]) + const pending = run( + 'chat send', + { session: SESSION, text: 'Run the tests', wait: true }, + client + ) + await vi.advanceTimersByTimeAsync(5_000) + const result = await pending + expect(client.call).toHaveBeenCalledTimes(6) + expect(result).toMatchObject({ + delivery: 'queued', + settled: 'done', + entries: [{ kind: 'message', role: 'assistant', text: 'All pass' }] + }) + }) +}) + function chatClient(isRemote: boolean): { client: RuntimeClient; call: ReturnType } { const client = new RuntimeClient('/tmp/orca-chat-test', 60_000, null, null) vi.spyOn(client, 'isRemote', 'get').mockReturnValue(isRemote) diff --git a/src/cli/handlers/chat.ts b/src/cli/handlers/chat.ts index f9303026a8d..51d6a8dbc0f 100644 --- a/src/cli/handlers/chat.ts +++ b/src/cli/handlers/chat.ts @@ -1,11 +1,64 @@ -import type { CommandHandler } from '../dispatch' -import { getPresentStringFlag, getRequiredStringFlag } from '../flags' -import { printResult } from '../format' -import { RuntimeClientError } from '../runtime-client' +import { randomUUID } from 'node:crypto' +import type { + AgentSessionMutationResult, + AgentSessionSendResult +} from '../../shared/agent-session/agent-session-wire' +import { AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY } from '../../shared/agent-session/agent-session-runtime-capabilities' +import type { + RuntimeWorktreePsResult, + RuntimeWorktreeRecord +} from '../../shared/runtime-worktree-contracts' +import { createStructuredAgentSessionOperationId } from '../../shared/agent-session/lifecycle/structured-agent-session-mutation' +import { + structuredAgentSessionMessageSendMutation, + structuredAgentSessionSendBody +} from '../../shared/agent-session/requests/structured-agent-session-send-mutation' +import { AGENT_STATUS_STATES } from '../../shared/agent-status/contracts/agent-status-types' import { readInjectedAgentSessionId } from '../../shared/agent-session/lifecycle/agent-session-caller-env' +import { + DEFAULT_READ_LIMIT, + explainChatRefusal, + formatSettled, + readHistory, + readSettledTurn, + readTranscript, + requireWorkingFlag, + waitForChat +} from '../chat-history' +import { + formatChatList, + formatChatRead, + listChatSessions, + parseChatSessionSelector +} from '../chat-sessions' +import { readTextOrFileFlag } from '../command-body-input' +import type { CommandHandler } from '../dispatch' +import { + getOptionalPositiveIntegerFlag, + getOptionalStringFlag, + getPresentStringFlag, + getRequiredStringFlag +} from '../flags' +import { printResult } from '../format' +import { getOptionalWorktreeSelector } from '../selectors' +import type { RuntimeClient } from '../runtime-client' +import { RuntimeClientError } from '../runtime-client' + +const MAX_READ_LIMIT = 100 type ChatRenameResult = { name: string | null; applied: boolean } +// Paired CLIs lack the host's chat read/send capability; refuse before the host does with a bare code. +function readSession(flags: Map, client: RuntimeClient): string { + if (client.isRemote) { + throw new RuntimeClientError( + 'runtime_unsupported', + 'Reading and messaging chats on a paired host is not supported yet. Run this on the host machine.' + ) + } + return parseChatSessionSelector(getRequiredStringFlag(flags, 'session')) +} + export const CHAT_HANDLERS: Record = { 'chat rename': async ({ flags, client, json }) => { const name = getRequiredStringFlag(flags, 'name') @@ -24,34 +77,119 @@ export const CHAT_HANDLERS: Record = { const result = await client .call('agentSession.rename', { sessionId, name }) .catch((error: unknown) => { - throw explainRenameRefusal(error, sessionId) + throw explainChatRefusal(error, sessionId, 'rename') }) if (!result.result.applied) { throw new RuntimeClientError('invalid_argument', 'Not renamed: the name has no visible text.') } printResult(result, json, (value) => `Renamed chat to "${value.name}".`) + }, + 'chat list': async ({ flags, client, cwd, json }) => { + const state = getOptionalStringFlag(flags, 'state') + if (state !== undefined && !AGENT_STATUS_STATES.some((known) => known === state)) { + throw new RuntimeClientError( + 'invalid_argument', + `--state must be one of: ${AGENT_STATUS_STATES.join(', ')}.` + ) + } + const selector = await getOptionalWorktreeSelector(flags, 'worktree', cwd, client) + const shown = selector + ? ( + await client.call<{ worktree: RuntimeWorktreeRecord }>('worktree.show', { + worktree: selector + }) + ).result.worktree + : undefined + const result = await client.call('worktree.ps', {}) + // A local and an SSH copy can share an id; the host tells them apart when both name one. + const worktrees = result.result.worktrees.filter( + (w) => + !shown || + (w.worktreeId === shown.id && + (w.hostId === undefined || shown.hostId === undefined || w.hostId === shown.hostId)) + ) + const chats = listChatSessions(worktrees).filter((chat) => !state || chat.state === state) + printResult({ ...result, result: { chats } }, json, formatChatList) + }, + 'chat read': async ({ flags, client, json }) => { + const session = readSession(flags, client) + const limit = getOptionalPositiveIntegerFlag(flags, 'limit') ?? DEFAULT_READ_LIMIT + if (limit > MAX_READ_LIMIT) { + throw new RuntimeClientError('invalid_argument', `--limit must be at most ${MAX_READ_LIMIT}.`) + } + printResult(await readTranscript(client, session, limit), json, formatChatRead) + }, + 'chat wait': async ({ flags, client, json }) => { + const session = readSession(flags, client) + const timeoutMs = getOptionalPositiveIntegerFlag(flags, 'timeout-ms') + const settled = await waitForChat(client, session, timeoutMs) + printResult(await readSettledTurn(client, session, settled), json, formatSettled) + }, + 'chat send': async ({ flags, client, cwd, json }) => { + const session = readSession(flags, client) + const text = (await readTextOrFileFlag(flags, cwd, 'text', true)) ?? '' + if (text.trim().length === 0) { + throw new RuntimeClientError('invalid_argument', 'The message must not be empty.') + } + const wait = flags.has('wait') + const timeoutMs = getOptionalPositiveIntegerFlag(flags, 'timeout-ms') + const status = await client.getCliStatus() + if (!status.result.runtime.reachable) { + throw new RuntimeClientError( + 'runtime_unavailable', + 'Orca could not reach the execution host, so nothing was sent. Retry once it is reachable.' + ) + } + // A working chat holds a queued message until its turn ends; older hosts get an ordinary send. + const queue = + status.result.runtime.capabilities?.includes( + AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY + ) === true + // The send is fenced to the session's current runtime, so a restarted chat refuses it. + const { page } = (await readHistory(client, session, 1)).result + if (wait) { + requireWorkingFlag(page) + } + const { fence } = page + if (fence === undefined) { + throw new RuntimeClientError( + 'agent_session_not_running', + `Chat ${session} has no running session on this host, so nothing was sent. Open it in Orca and retry.` + ) + } + const mutation = structuredAgentSessionMessageSendMutation({ + sessionId: session, + clientOperationId: createStructuredAgentSessionOperationId(randomUUID), + expectedRuntimeFence: fence, + body: structuredAgentSessionSendBody(text, []), + ...(queue ? { delivery: 'queue-if-active' as const } : {}) + }) + const result = await client.call>( + 'agentSession.send', + mutation + ) + if (!result.result.ok) { + const { code, message } = result.result.refusal + throw explainChatRefusal(new RuntimeClientError(code, message), session, 'send to') + } + const value = result.result.value + const sent = { + session, + delivery: 'queued' in value ? ('queued' as const) : ('submitted' as const), + clientMessageId: value.clientMessageId, + ...('queued' in value ? { queuePosition: value.queued.position } : {}) + } + if (!wait) { + printResult({ ...result, result: sent }, json, (r) => + r.delivery === 'queued' + ? `Queued for ${r.session}; it is sent when the current turn ends.` + : `Sent to ${r.session}.` + ) + return + } + const queuedId = 'queued' in value ? value.queued.messageId : undefined + const settled = await waitForChat(client, session, timeoutMs, queuedId) + const turn = await readSettledTurn(client, session, settled) + printResult({ ...turn, result: { ...sent, ...turn.result } }, json, formatSettled) } } - -// The host answers with bare wire codes; say what they mean for this command. -function explainRenameRefusal(error: unknown, sessionId: string): unknown { - if (!(error instanceof RuntimeClientError)) { - return error - } - if (error.message === 'agent_session_identity_required') { - return new RuntimeClientError( - 'agent_session_identity_required', - `No chat with session id ${sessionId} on this host.` - ) - } - if ( - error.message === 'structured_agent_session_unsupported' || - error.code === 'method_not_found' - ) { - return new RuntimeClientError( - 'incompatible_runtime', - 'This Orca host cannot rename chats from the CLI. Update Orca on that host, or check that it has chats turned on.' - ) - } - return error -} diff --git a/src/cli/handlers/orchestration/worker-agent-views.ts b/src/cli/handlers/orchestration/worker-agent-views.ts index ac76e9c214a..ca993bc66c1 100644 --- a/src/cli/handlers/orchestration/worker-agent-views.ts +++ b/src/cli/handlers/orchestration/worker-agent-views.ts @@ -108,6 +108,7 @@ export type WorkerListResult = { dispatchStatus: string agentTerminalHandle: string | null terminalState: string | null + coordinatedFrom?: string | null resource?: { worktreeId?: string | null; autoReleaseAt?: string | null } | null projection?: WorkerProjection }[] @@ -133,6 +134,7 @@ type WorkerListRow = { terminalState?: string workspace?: string host?: string + coordinatedFrom?: string attention?: string[] autoReleaseAt?: string next?: string @@ -168,6 +170,7 @@ export const WORKER_LIST_VIEW: OrchestrationAgentView = new Set(['agent.launch', 'agent.launchReplay']) +function namesChatCaller(method: string): boolean { + return AGENT_LAUNCH_METHODS.has(method) || method.startsWith('browser.') +} + /** The caller evidence one request carries, read from this process's environment once. */ export class OrchestrationRequestEvidence { private readonly orchestration: RuntimeOrchestrationEnvelope // A chat's session id means nothing on another server, so reads there go like a shell's. private readonly remoteRead: RuntimeOrchestrationEnvelope - private readonly agentLaunchCaller: RuntimeOrchestrationEnvelope['orchestrationCompatibilityEvidence'] + private readonly chatCaller: RuntimeOrchestrationEnvelope['orchestrationCompatibilityEvidence'] constructor(env: NodeJS.ProcessEnv) { this.orchestration = createOrchestrationCompatibilityEnvelope(env) @@ -44,7 +48,7 @@ export class OrchestrationRequestEvidence { ...this.orchestration, orchestrationCompatibilityEvidence: Object.keys(shell).length > 0 ? shell : undefined } - this.agentLaunchCaller = createAgentLaunchCallerEvidence(env) + this.chatCaller = createChatCallerEvidence(env) } envelopeFor( @@ -58,8 +62,8 @@ export class OrchestrationRequestEvidence { compatibilityInvocationId: request.requestId ?? base.compatibilityInvocationId } } - return AGENT_LAUNCH_METHODS.has(method) && !request.remote && this.agentLaunchCaller - ? { orchestrationCompatibilityEvidence: this.agentLaunchCaller } + return namesChatCaller(method) && !request.remote && this.chatCaller + ? { orchestrationCompatibilityEvidence: this.chatCaller } : {} } } diff --git a/src/cli/runtime/orchestration-request-evidence.test.ts b/src/cli/runtime/orchestration-request-evidence.test.ts index aceef390bc2..e8234f2223a 100644 --- a/src/cli/runtime/orchestration-request-evidence.test.ts +++ b/src/cli/runtime/orchestration-request-evidence.test.ts @@ -26,3 +26,18 @@ describe('caller evidence on requests to another server', () => { ).toEqual({ agentSessionId: '11111111-1111-4111-8111-111111111111' }) }) }) + +describe('caller evidence on browser commands', () => { + it('names the chat on this host, so its run can show the page it drove', () => { + const evidence = new OrchestrationRequestEvidence(CHAT) + const request = { mutation: false, requestId: undefined } + expect( + evidence.envelopeFor('browser.click', { ...request, remote: false }) + .orchestrationCompatibilityEvidence + ).toEqual({ agentSessionId: '11111111-1111-4111-8111-111111111111' }) + expect( + evidence.envelopeFor('browser.click', { ...request, remote: true }) + .orchestrationCompatibilityEvidence + ).toBeUndefined() + }) +}) diff --git a/src/cli/specs/browser-basic.ts b/src/cli/specs/browser-basic.ts index 2d9ea0f589e..b25628d9e4a 100644 --- a/src/cli/specs/browser-basic.ts +++ b/src/cli/specs/browser-basic.ts @@ -206,6 +206,12 @@ export const BROWSER_BASIC_COMMAND_SPECS: CommandSpec[] = withBrowserPageTarget( usage: 'orca tab show --page [--worktree ] [--json]', allowedFlags: [...GLOBAL_FLAGS, 'page', 'worktree'] }, + { + path: ['tab', 'annotations'], + summary: "Show the notes the user left on a browser tab and hasn't sent yet", + usage: 'orca tab annotations [--page ] [--worktree ] [--json]', + allowedFlags: [...GLOBAL_FLAGS, 'page', 'worktree'] + }, { path: ['tab', 'current'], summary: 'Show the current browser tab', diff --git a/src/cli/specs/chat.ts b/src/cli/specs/chat.ts index 28fb41556dd..ae73e34d6ed 100644 --- a/src/cli/specs/chat.ts +++ b/src/cli/specs/chat.ts @@ -15,5 +15,57 @@ export const CHAT_COMMAND_SPECS: CommandSpec[] = [ 'orca chat rename --name "Migrate auth to OAuth"', 'orca chat rename --session --name "Release notes" --json' ] + }, + { + path: ['chat', 'list'], + summary: 'List agent chats with their workspace, state and last reply', + usage: 'orca chat list [--worktree ] [--state ] [--json]', + allowedFlags: [...GLOBAL_FLAGS, 'worktree', 'state'], + notes: [ + 'Lists the top-level chats Orca shows as agent tabs. Terminal agents are read with `orca terminal`.', + '--state keeps chats in one state: working, blocked, waiting or done.' + ], + examples: ['orca chat list --json', 'orca chat list --state working'] + }, + { + path: ['chat', 'read'], + summary: 'Read the latest messages of an agent chat', + usage: 'orca chat read --session [--limit ] [--json]', + allowedFlags: [...GLOBAL_FLAGS, 'session', 'limit'], + notes: [ + '--session takes the session id or handle from `orca chat list` or `orca agent launch`.', + '--limit is the number of entries shown (messages, tool calls, approvals and questions); the default is 20 and the maximum 100.', + 'Approvals and questions waiting for an answer are marked "waiting for you".' + ], + examples: ['orca chat read --session codex_1234 --limit 10'] + }, + { + path: ['chat', 'send'], + summary: 'Send a message to an agent chat', + usage: + 'orca chat send --session (--text | --text-file ) [--wait] [--timeout-ms ] [--json]', + allowedFlags: [...GLOBAL_FLAGS, 'session', 'text', 'text-file', 'wait', 'timeout-ms'], + notes: [ + 'Sends the text as your message, as if typed in the chat. --text-file - reads it from stdin.', + 'While the agent is working, hosts with a message queue hold the message until the turn ends; the result says "queued".', + '--wait returns once the chat finishes or waits for your answer, with what it did since your message. It exits 1 when the wait times out or the message is held in a stopped queue.', + 'A chat that restarted since it was read refuses the send; read it again and resend.' + ], + examples: [ + 'orca chat send --session codex_1234 --text "Run the tests, then summarize failures"', + 'orca chat send --session codex_1234 --text "Run the tests" --wait --timeout-ms 600000 --json', + 'cat notes.md | orca chat send --session codex_1234 --text-file -' + ] + }, + { + path: ['chat', 'wait'], + summary: 'Wait until an agent chat finishes or needs your answer', + usage: 'orca chat wait --session [--timeout-ms ] [--json]', + allowedFlags: [...GLOBAL_FLAGS, 'session', 'timeout-ms'], + notes: [ + 'Settles on the chat\'s own turn, in `chat list` words: "done", or "blocked" on an approval or question. Background agents it started can still show as working or waiting in `chat list`. "held" and "timeout" exit 1.', + 'Prints what the chat did since the last user message. A wait that times out exits 1.' + ], + examples: ['orca chat wait --session codex_1234 --timeout-ms 600000 --json'] } ] diff --git a/src/main/acp/discovery/acp-listing-session-models.ts b/src/main/acp/discovery/acp-listing-session-models.ts new file mode 100644 index 00000000000..0c35c338adc --- /dev/null +++ b/src/main/acp/discovery/acp-listing-session-models.ts @@ -0,0 +1,148 @@ +import { setTimeout as delay } from 'node:timers/promises' +import { observeAcpForkSupport } from '../capabilities/acp-fork-support' +import { + assertStructuredAgentResolutionCurrent, + type StructuredAgentResolutionOperation +} from '../../native-chat/structured-agent-command-resolution' +import type { AgentSessionModelOption } from '../../../shared/agent-session/agent-session-wire' +import type { AcpSessionModelDiscovery } from './acp-model-discovery-policy' +import type { AcpLaunchSpec } from '../launch/acp-launch-contract' +import type { AcpSessionStarted, AcpSessionStartOptions } from '../protocol/acp-session-setup' +import { AcpStructuredOptions } from '../options/acp-structured-options' +import type { + InitializeResponse, + SetSessionConfigOptionResponse +} from '../generated/acp-protocol.generated' +import { withTimeout } from '../../../shared/promise-timeout-fallback' +import { AcpAgentError } from '../transport/acp-errors' + +/** Session-free capability boundary: no session methods are exposed. */ +export type AcpModelCatalogConnection = { + initialize(): Promise + requestSessionFreeExtension(method: string, params: unknown): Promise + close(): Promise +} + +export type AcpModelCatalogSessionConnection = Omit< + AcpModelCatalogConnection, + 'requestSessionFreeExtension' +> & { + start(options: AcpSessionStartOptions): Promise + setConfigOption(configId: string, value: string): Promise + deleteSession(sessionId: string): Promise +} + +// OpenCode can answer -32603 while its providers are still opening; a later attempt lists them. +async function startListingSession( + connection: AcpModelCatalogSessionConnection, + workspace: string, + operation?: StructuredAgentResolutionOperation +): Promise { + for (const backoffMs of [250, 500]) { + try { + return await connection.start({ cwd: workspace, mcpServers: [] }) + } catch (error) { + if (!(error instanceof AcpAgentError && error.code === -32603)) { + throw error + } + } + await delay(backoffMs, undefined, { signal: operation?.signal }) + assertStructuredAgentResolutionCurrent(operation) + } + return connection.start({ cwd: workspace, mcpServers: [] }) +} + +/** Lists models from a disposable session, learning menus for the models it starts on or switches to. */ +export async function readSessionModels( + spec: AcpLaunchSpec, + listing: AcpSessionModelDiscovery, + connection: AcpModelCatalogSessionConnection, + workspace: string, + operation?: StructuredAgentResolutionOperation, + selectedModels?: readonly string[], + launchedModel?: string, + ready?: (cleanup: () => Promise) => void +): Promise<{ models: AgentSessionModelOption[]; attemptedModels: string[] }> { + const initialized = await connection.initialize() + assertStructuredAgentResolutionCurrent(operation) + observeAcpForkSupport(spec.agent, initialized) + const deletes = Boolean(initialized.agentCapabilities?.sessionCapabilities?.delete) + if (!deletes && !listing.sessionFolderArgs) { + throw new Error(`${spec.agent} cannot delete a session, so it lists its models only in chats`) + } + const started = await startListingSession(connection, workspace, operation) + let stopped = false + const cleanup = async (): Promise => { + stopped = true + if (deletes) { + await connection.deleteSession(started.sessionId).catch((error: unknown) => { + console.warn(`[acp-model-catalog] ${spec.agent} kept its listing session:`, error) + }) + } + } + // Startup and menu discovery have separate budgets; cleanup also runs on cancellation. + ready?.(cleanup) + const options = new AcpStructuredOptions(spec.dialect) + options.adoptSession(started.response, 'new') + let models = options.read().models + const attemptedModels: string[] = [] + try { + if (launchedModel !== undefined) { + attemptedModels.push(launchedModel) + const running = options.read().current.model + // An unresolved --model leaves OMP on its default with a menu that is not that model's. + if (running !== launchedModel) { + models = models.map((row) => + row.id === running ? { ...row, efforts: [], effortsKnown: false as const } : row + ) + } + } else if (spec.dialect.effortChangesModel) { + const byId = new Map(models.map((model) => [model.id, model])) + const targets = selectedModels ? selectedModels.flatMap((id) => byId.get(id) ?? []) : models + const sweep = async () => { + for (const model of targets) { + if (stopped) { + return + } + assertStructuredAgentResolutionCurrent(operation) + if (model.effortsKnown !== false) { + continue + } + attemptedModels.push(model.id) + try { + for (let attempt = 0; attempt < 2 && !stopped; attempt++) { + const write = options.write('model', model.id) + if (write?.method !== 'config') { + break + } + const reply = await connection.setConfigOption(write.configId, write.value) + if (stopped) { + return + } + assertStructuredAgentResolutionCurrent(operation) + options.adoptConfigOptions(reply.configOptions) + const observed = options.read() + if (observed.current.model !== model.id) { + continue + } + const known = observed.models.find((row) => row.id === model.id) + if (known) { + models = models.map((row) => (row.id === model.id ? known : row)) + } + break + } + } catch { + assertStructuredAgentResolutionCurrent(operation) + } + } + } + await withTimeout(sweep(), 5_000, undefined) + } + assertStructuredAgentResolutionCurrent(operation) + return { models, attemptedModels } + } finally { + if (!ready) { + await cleanup() + } + } +} diff --git a/src/main/acp/discovery/acp-model-catalog-probe.test.ts b/src/main/acp/discovery/acp-model-catalog-probe.test.ts new file mode 100644 index 00000000000..85f040a7fb3 --- /dev/null +++ b/src/main/acp/discovery/acp-model-catalog-probe.test.ts @@ -0,0 +1,196 @@ +import { mkdtemp, rm } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, describe, expect, it } from 'vitest' +import { acpLaunchSpecFor } from '../launch/acp-launch-registry' +import type { AcpLaunchSpec } from '../launch/acp-launch-contract' +import { createAcpModelCatalogProbe } from './acp-model-catalog-probe' +import { AcpSessionRuntime } from '../protocol/acp-session-runtime' +import { AcpScriptedAgent } from '../process/testing/acp-scripted-agent.test-support' +import { openCodeAcpAccountBinding } from '../../opencode/opencode-structured-account-home' +import { AcpAgentExitedError } from '../transport/acp-errors' +// Real `omp acp` 18.17.0 session/new replies: started on its default fake/wide, with +// `--model fake/narrow`, and with `--model fake/gone`, which it cannot resolve. +import recorded from '../fixtures/omp-v18.17.0-model-efforts.json' + +// Bypass the app's managed-account service for this fixture. +const OPENCODE: AcpLaunchSpec = { + ...acpLaunchSpecFor('opencode')!, + account: openCodeAcpAccountBinding(() => ({ + list: () => ({ activeAccountId: null, accounts: [] }), + restoreOriginalEnvironment: () => {}, + environmentForAccount: () => ({}) + })) +} + +const agents: AcpScriptedAgent[] = [] +afterEach(() => { + for (const agent of agents.splice(0)) { + agent.close() + } +}) + +describe('ACP model catalog probes', () => { + it('lists the catalog after OpenCode answers session/new with -32603 while starting', async () => { + const agent = new AcpScriptedAgent() + agents.push(agent) + agent.on('initialize', (frame) => + agent.reply(frame, { + protocolVersion: 1, + agentCapabilities: { sessionCapabilities: { delete: {} } } + }) + ) + let sessionNews = 0 + agent.on('session/new', (frame) => { + sessionNews += 1 + if (sessionNews === 1) { + agent.fail(frame, -32603, 'Internal error: Internal service failure', { + errorName: 'InvalidRequestError' + }) + return + } + agent.reply(frame, { + sessionId: 'probe-session', + configOptions: [ + { + id: 'model', + name: 'Model', + category: 'model', + type: 'select', + currentValue: 'opencode/exo-free', + options: [ + { value: 'opencode/big-pickle', name: 'Big Pickle' }, + { value: 'opencode/exo-free', name: 'Exo Free' } + ] + } + ] + }) + }) + agent.on('session/delete', (frame) => agent.reply(frame, {})) + agent.on('session/set_config_option', (frame) => agent.fail(frame, -32602, 'Model unavailable')) + + const success = await createAcpModelCatalogProbe(OPENCODE, { + resolveEnvironment: async () => ({ PATH: '/usr/bin', HOME: '/home/user' }), + resolveCommand: () => '/opt/opencode/bin/opencode', + probeVersion: async () => ({ version: '2.0.29' }), + homePath: '/home/user', + dataDirectory: '/orca-data', + connectSession: () => { + const runtime = new AcpSessionRuntime(agent.stdout, agent.stdin) + return { + initialize: () => runtime.initialize(), + start: (options) => runtime.start(options), + setConfigOption: (id, value) => runtime.setConfigOption(id, value), + deleteSession: (sessionId) => runtime.deleteSession(sessionId), + close: async () => runtime.close() + } + } + })({ kind: 'opencode', locator: { kind: 'unmanaged' } }, { workspacePath: '/work/project' }) + + expect(sessionNews).toBe(2) + expect(success.models.map((model) => model.id)).toEqual([ + 'opencode/big-pickle', + 'opencode/exo-free' + ]) + }) +}) + +async function listOmp(selectedModels?: string[]) { + const agent = new AcpScriptedAgent() + agents.push(agent) + let launchedModel: string | undefined + agent.on('initialize', (frame) => agent.reply(frame, { protocolVersion: 1 })) + agent.on('session/new', (frame) => + agent.reply(frame, { + sessionId: 'probe-session', + ...(launchedModel === 'fake/narrow' + ? recorded.narrow + : launchedModel === 'fake/gone' + ? recorded.unresolved + : recorded.new) + }) + ) + const dataDirectory = await mkdtemp(join(tmpdir(), 'orca-omp-efforts-')) + try { + const listing = await createAcpModelCatalogProbe(acpLaunchSpecFor('omp')!, { + resolveEnvironment: async () => ({ PATH: '/usr/bin', HOME: '/home/user' }), + resolveCommand: () => '/opt/omp/bin/omp', + probeVersion: async () => ({ version: '18.17.0' }), + homePath: '/home/user', + dataDirectory, + connectSession: (launch) => { + const at = launch.args.indexOf('--model') + launchedModel = at === -1 ? undefined : launch.args[at + 1] + if (launchedModel?.includes(':')) { + // OMP 18.17.0 prints `Model "fake/gone:high" not found.` and exits 1 before ACP starts. + const exited = async () => { + throw new AcpAgentExitedError('Model "fake/gone:high" not found.') + } + return { + initialize: exited, + start: exited, + setConfigOption: exited, + deleteSession: exited, + close: async () => {} + } + } + const runtime = new AcpSessionRuntime(agent.stdout, agent.stdin) + return { + initialize: () => runtime.initialize(), + start: (options) => runtime.start(options), + setConfigOption: (id, value) => runtime.setConfigOption(id, value), + deleteSession: (sessionId) => runtime.deleteSession(sessionId), + close: async () => runtime.close() + } + } + })( + { variable: 'PI_CODING_AGENT_DIR', path: '/homes/omp' }, + { workspacePath: '/work/project', ...(selectedModels ? { selectedModels } : {}) } + ) + // A model switch would record usage in the user's OMP account. + expect(agent.frames.map((frame) => frame.method)).toEqual(['initialize', 'session/new']) + return (id: string) => listing.models.find((model) => model.id === id) + } finally { + await rm(dataDirectory, { recursive: true, force: true }) + } +} + +const levels = (model: { efforts: { value: string }[] } | undefined) => + model?.efforts.map((effort) => effort.value) + +it("lists a picked OMP model with its own thinking levels, not the startup model's", async () => { + const listed = await listOmp() + expect(levels(listed('fake/wide'))).toEqual([ + 'off', + 'auto', + 'minimal', + 'low', + 'medium', + 'high', + 'xhigh' + ]) + expect(listed('fake/narrow')).toMatchObject({ efforts: [], effortsKnown: false }) + + const picked = await listOmp(['fake/narrow']) + expect(levels(picked('fake/narrow'))).toEqual(['off', 'auto', 'low', 'high']) + expect(picked('fake/narrow')).not.toHaveProperty('effortsKnown') + expect(picked('fake/wide')).toMatchObject({ efforts: [], effortsKnown: false }) +}) + +it('trusts no menu when OMP cannot start on the picked model', async () => { + const picked = await listOmp(['fake/gone']) + expect(picked('fake/wide')).toMatchObject({ efforts: [], effortsKnown: false }) +}) + +it('still lists OMP when it cannot start on the picked model', async () => { + const picked = await listOmp(['fake/gone:high']) + expect(levels(picked('fake/wide'))).toEqual([ + 'off', + 'auto', + 'minimal', + 'low', + 'medium', + 'high', + 'xhigh' + ]) +}) diff --git a/src/main/acp/discovery/acp-model-catalog-probe.ts b/src/main/acp/discovery/acp-model-catalog-probe.ts index 7df8a4a31f9..8b935339fc8 100644 --- a/src/main/acp/discovery/acp-model-catalog-probe.ts +++ b/src/main/acp/discovery/acp-model-catalog-probe.ts @@ -1,8 +1,5 @@ import { observeAcpForkSupport } from '../capabilities/acp-fork-support' -import { - assertStructuredAgentResolutionCurrent, - type StructuredAgentResolutionOperation -} from '../../native-chat/structured-agent-command-resolution' +import { assertStructuredAgentResolutionCurrent } from '../../native-chat/structured-agent-command-resolution' import { homedir } from 'node:os' import { join } from 'node:path' import type { AgentCliVersionReader } from '../../agent-launch/preflight/agent-cli-version-probe' @@ -19,40 +16,22 @@ import { acpRunFolder } from '../launch/acp-private-temp' import { acpListingDependsOnRelease, acpListingNeedsChatFolder, - acpModelListingForRelease, - type AcpSessionModelDiscovery + acpModelListingForRelease } from './acp-model-discovery-policy' import type { AcpLaunchSpec } from '../launch/acp-launch-contract' -import type { AcpSessionStarted, AcpSessionStartOptions } from '../protocol/acp-session-setup' import { checkAcpLaunchVersion } from '../launch/acp-launch-version' import { resolveAcpLaunchInvocation, type AcpLaunchInvocationDeps } from '../launch/acp-structured-launch-resolution' -import { AcpStructuredOptions } from '../options/acp-structured-options' -import type { - InitializeResponse, - SetSessionConfigOptionResponse -} from '../generated/acp-protocol.generated' -import { withTimeout } from '../../../shared/promise-timeout-fallback' -import { AcpAgentError } from '../transport/acp-errors' +import { + readSessionModels, + type AcpModelCatalogConnection, + type AcpModelCatalogSessionConnection +} from './acp-listing-session-models' +import { AcpAgentError, AcpAgentExitedError } from '../transport/acp-errors' import { AgentModelCatalogUnavailableError } from '../../native-chat/agent-model-catalog/agent-model-catalog-unavailable' - -/** Session-free capability boundary: no session methods are exposed. */ -export type AcpModelCatalogConnection = { - initialize(): Promise - requestSessionFreeExtension(method: string, params: unknown): Promise - close(): Promise -} - -export type AcpModelCatalogSessionConnection = Omit< - AcpModelCatalogConnection, - 'requestSessionFreeExtension' -> & { - start(options: AcpSessionStartOptions): Promise - setConfigOption(configId: string, value: string): Promise - deleteSession(sessionId: string): Promise -} +import { usesModelSpecificAcpEfforts } from '../../../shared/agent-session/options/agent-model-catalog-ownership' export type AcpModelCatalogProbeDeps = AcpLaunchInvocationDeps & { probeVersion?: AgentCliVersionReader @@ -112,6 +91,11 @@ export function createAcpModelCatalogProbe( envToDelete } const run = { label: spec.agent, signal: options?.signal } + // OMP records every model switch as account usage; starting on the picked model records none. + const launchedModel = + spec.launchesWithModel && usesModelSpecificAcpEfforts(spec.agent) + ? options?.selectedModels?.[0] + : undefined let models: AgentSessionModelOption[] let attemptedModels: string[] | undefined if (listing.kind === 'command') { @@ -132,32 +116,49 @@ export function createAcpModelCatalogProbe( } // Remove disposable session storage after the process closes. const folderArgs = listing.sessionFolderArgs - const folder = folderArgs - ? await acpRunFolder(join(deps.dataDirectory, 'acp-listing-sessions', spec.agent)) - : null - try { - assertStructuredAgentResolutionCurrent(operation) - const args = - folderArgs && folder ? [...launch.args, ...folderArgs(folder.path)] : launch.args - const result = await runAgentModelCatalogSession( - () => (deps.connectSession ?? createAcpAgentConnection)({ ...launch, args }), - (connection, ready) => - readSessionModels( - spec, - listing, - connection, - workspace, - operation, - options?.selectedModels, - spec.dialect.effortChangesModel ? ready : undefined - ), - run - ) - models = result.models - attemptedModels = result.attemptedModels - } finally { - await folder?.remove() + const listInSession = async (model: string | undefined) => { + const folder = folderArgs + ? await acpRunFolder(join(deps.dataDirectory, 'acp-listing-sessions', spec.agent)) + : null + try { + assertStructuredAgentResolutionCurrent(operation) + const args = [ + ...prefixArgs, + ...spec.args({ fullAccess: false, pluginDir: null, model }), + ...(folderArgs && folder ? folderArgs(folder.path) : []) + ] + return await runAgentModelCatalogSession( + () => (deps.connectSession ?? createAcpAgentConnection)({ ...launch, args }), + (connection, ready) => + readSessionModels( + spec, + listing, + connection, + workspace, + operation, + options?.selectedModels, + model, + spec.dialect.effortChangesModel ? ready : undefined + ), + run + ) + } finally { + await folder?.remove() + } } + let result: Awaited> + try { + result = await listInSession(launchedModel) + } catch (error) { + // OMP exits before ACP on a model it cannot start (a stale `:level` id); list without it. + if (launchedModel === undefined || !(error instanceof AcpAgentExitedError)) { + throw error + } + assertStructuredAgentResolutionCurrent(operation) + result = { ...(await listInSession(undefined)), attemptedModels: [launchedModel] } + } + models = result.models + attemptedModels = result.attemptedModels } else { models = await runAgentModelCatalogSession( () => (deps.connect ?? createAcpAgentConnection)(launch), @@ -189,87 +190,3 @@ export function createAcpModelCatalogProbe( const folderlessListing = (spec: AcpLaunchSpec) => new AgentModelCatalogListingStoppedError(`${spec.agent} lists in a chat's folder`) - -async function readSessionModels( - spec: AcpLaunchSpec, - listing: AcpSessionModelDiscovery, - connection: AcpModelCatalogSessionConnection, - workspace: string, - operation?: StructuredAgentResolutionOperation, - selectedModels?: readonly string[], - ready?: (cleanup: () => Promise) => void -): Promise<{ models: AgentSessionModelOption[]; attemptedModels: string[] }> { - const initialized = await connection.initialize() - assertStructuredAgentResolutionCurrent(operation) - observeAcpForkSupport(spec.agent, initialized) - const deletes = Boolean(initialized.agentCapabilities?.sessionCapabilities?.delete) - if (!deletes && !listing.sessionFolderArgs) { - throw new Error(`${spec.agent} cannot delete a session, so it lists its models only in chats`) - } - const started = await connection.start({ cwd: workspace, mcpServers: [] }) - let stopped = false - const cleanup = async (): Promise => { - stopped = true - if (deletes) { - await connection.deleteSession(started.sessionId).catch((error: unknown) => { - console.warn(`[acp-model-catalog] ${spec.agent} kept its listing session:`, error) - }) - } - } - // Startup and menu discovery have separate budgets; cleanup also runs on cancellation. - ready?.(cleanup) - const options = new AcpStructuredOptions(spec.dialect) - options.adoptSession(started.response, 'new') - let models = options.read().models - const attemptedModels: string[] = [] - try { - if (spec.dialect.effortChangesModel) { - const byId = new Map(models.map((model) => [model.id, model])) - const targets = selectedModels ? selectedModels.flatMap((id) => byId.get(id) ?? []) : models - const sweep = async () => { - for (const model of targets) { - if (stopped) { - return - } - assertStructuredAgentResolutionCurrent(operation) - if (model.effortsKnown !== false) { - continue - } - attemptedModels.push(model.id) - try { - for (let attempt = 0; attempt < 2 && !stopped; attempt++) { - const write = options.write('model', model.id) - if (write?.method !== 'config') { - break - } - const reply = await connection.setConfigOption(write.configId, write.value) - if (stopped) { - return - } - assertStructuredAgentResolutionCurrent(operation) - options.adoptConfigOptions(reply.configOptions) - const observed = options.read() - if (observed.current.model !== model.id) { - continue - } - const known = observed.models.find((row) => row.id === model.id) - if (known) { - models = models.map((row) => (row.id === model.id ? known : row)) - } - break - } - } catch { - assertStructuredAgentResolutionCurrent(operation) - } - } - } - await withTimeout(sweep(), 5_000, undefined) - } - assertStructuredAgentResolutionCurrent(operation) - return { models, attemptedModels } - } finally { - if (!ready) { - await cleanup() - } - } -} diff --git a/src/main/acp/fixtures/omp-v18.17.0-model-efforts.json b/src/main/acp/fixtures/omp-v18.17.0-model-efforts.json new file mode 100644 index 00000000000..4ba4f7835a0 --- /dev/null +++ b/src/main/acp/fixtures/omp-v18.17.0-model-efforts.json @@ -0,0 +1,102 @@ +{ + "new": { + "configOptions": [ + { + "id": "model", + "name": "Model", + "category": "model", + "type": "select", + "currentValue": "fake/wide", + "options": [ + { "value": "fake/wide", "name": "Wide", "description": "fake/wide" }, + { "value": "fake/narrow", "name": "Narrow", "description": "fake/narrow" }, + { + "value": "apple/on-device", + "name": "Apple AFM 3 Core Advanced", + "description": "apple/on-device" + } + ] + }, + { + "id": "thinking", + "name": "Thinking", + "category": "thought_level", + "type": "select", + "currentValue": "high", + "options": [ + { "value": "off", "name": "Off" }, + { "value": "auto", "name": "Auto", "description": "Auto-detect per prompt" }, + { "value": "minimal", "name": "minimal" }, + { "value": "low", "name": "low" }, + { "value": "medium", "name": "medium" }, + { "value": "high", "name": "high" }, + { "value": "xhigh", "name": "xhigh" } + ] + } + ] + }, + "narrow": { + "configOptions": [ + { + "id": "model", + "name": "Model", + "category": "model", + "type": "select", + "currentValue": "fake/narrow", + "options": [ + { "value": "fake/wide", "name": "Wide", "description": "fake/wide" }, + { "value": "fake/narrow", "name": "Narrow", "description": "fake/narrow" }, + { + "value": "apple/on-device", + "name": "Apple AFM 3 Core Advanced", + "description": "apple/on-device" + } + ] + }, + { + "id": "thinking", + "name": "Thinking", + "category": "thought_level", + "type": "select", + "currentValue": "high", + "options": [ + { "value": "off", "name": "Off" }, + { "value": "auto", "name": "Auto", "description": "Auto-detect per prompt" }, + { "value": "low", "name": "low" }, + { "value": "high", "name": "high" } + ] + } + ] + }, + "unresolved": { + "configOptions": [ + { + "id": "model", + "name": "Model", + "category": "model", + "type": "select", + "currentValue": "fake/wide", + "options": [ + { "value": "fake/wide", "name": "Wide", "description": "fake/wide" }, + { "value": "fake/narrow", "name": "Narrow", "description": "fake/narrow" }, + { + "value": "apple/on-device", + "name": "Apple AFM 3 Core Advanced", + "description": "apple/on-device" + } + ] + }, + { + "id": "thinking", + "name": "Thinking", + "category": "thought_level", + "type": "select", + "currentValue": "off", + "options": [ + { "value": "off", "name": "Off" }, + { "value": "auto", "name": "Auto", "description": "Auto-detect per prompt" } + ] + } + ] + } +} diff --git a/src/main/acp/options/acp-structured-options.ts b/src/main/acp/options/acp-structured-options.ts index 5327bde5116..8ba7d511888 100644 --- a/src/main/acp/options/acp-structured-options.ts +++ b/src/main/acp/options/acp-structured-options.ts @@ -250,10 +250,7 @@ export class AcpStructuredOptions { model.id === currentModel ? { efforts: sessionEfforts } : (modelOption || effortOption) && !advertised - ? { - efforts: this.dialect.clampsUnlistedEffort ? sessionEfforts : [], - effortsKnown: false as const - } + ? { efforts: [], effortsKnown: false as const } : { efforts: [] } return { ...model, diff --git a/src/main/acp/session/acp-structured-antigravity-errors.test.ts b/src/main/acp/session/acp-structured-antigravity-errors.test.ts deleted file mode 100644 index fabcc889944..00000000000 --- a/src/main/acp/session/acp-structured-antigravity-errors.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { afterEach, expect, it } from 'vitest' -import { closeProviderTimelineRigs } from '../../native-chat/agent-session-timeline/provider-timeline-assembler-test-support' -import { acpLaunchSpecFor } from '../launch/acp-launch-registry' -import { - openAcpAdapterRig, - sendHello, - waitFor -} from './testing/acp-structured-adapter.test-support' - -afterEach(closeProviderTimelineRigs) - -const quotaError = `Cloud Code Assist API error (429): { - "error": { - "code": 429, - "message": "Individual quota reached. Please upgrade your subscription to increase your limits. Resets in 3h42m11s.", - "status": "RESOURCE_EXHAUSTED", - "details": [ - { - "@type": "type.googleapis.com/google.rpc.ErrorInfo", - "reason": "QUOTA_EXHAUSTED", - "domain": "cloudcode-pa.googleapis.com", - "metadata": { - "quotaResetDelay": "3h42m11.598227131s", - "quotaResetTimeStamp": "2026-11-10T15:58:51Z", - "uiMessage": "true", - "model": "claude-opus-5-5-high" - } - }, - { - "@type": "type.googleapis.com/google.rpc.RetryInfo", - "retryDelay": "13331.598227131s" - } - ] - } -}` - -it('publishes the Cloud Code Assist message instead of its JSON envelope in chat', async () => { - const rig = await openAcpAdapterRig({ - spec: acpLaunchSpecFor('antigravity')!, - script: (agent) => - agent.on('session/prompt', (frame) => - agent.fail(frame, -32603, 'Internal error', { details: quotaError }) - ) - }) - await rig.acquire() - await sendHello(rig, 'send-1') - await waitFor(async () => - expect((await rig.rig.rows()).filter((row) => row.body.kind === 'status')).toEqual([ - expect.objectContaining({ - body: { - kind: 'status', - tone: 'error', - text: 'Individual quota reached. Please upgrade your subscription to increase your limits. Resets in 3h42m11s.' - } - }) - ]) - ) -}) diff --git a/src/main/agent-hooks/README.md b/src/main/agent-hooks/README.md index 3ed3b46dc06..04e3d43a4e8 100644 --- a/src/main/agent-hooks/README.md +++ b/src/main/agent-hooks/README.md @@ -47,6 +47,7 @@ terminal answered queries the way Orca does. | pi (`pi`) | ✅ live, 1.3.0 | required (`PI_PROGRAM_STATUS=1` forces it) | all five | all three | session name, dialog title, first line of an error | — | extension | Fallback | | oh-my-pi (`omp`) | ✅ live, 18.10.3 | sends without asking | all five | permission, question | on `blocked`/`error` only | — | extension | Fallback | | Codex (`codex`) | ✅ live, 0.163.0 | sends without asking | all five | none sent (0.163) | none | — | hooks | Fallback; state only | +| Kiro (`kiro`) | reported on 3.1.0 (#40567), not run live | — | — | — | — | — | hooks | Fallback; reports as `app=kiro-cli` | ### Agents that don't send OSC 7501 yet @@ -55,7 +56,7 @@ terminal answered queries the way Orca does. | OpenCode (`opencode`, `opencode2`) | installed binary v2.0.16 and source | plugin | | Kilocode (`kilo`) | installed package and source | — | | Cursor (`cursor`) | installed binary 2026.06.02 | hooks | -| Amp, Droid, Hermes, Muse, Devin, Kiro | installed binaries | hooks | +| Amp, Droid, Hermes, Muse, Devin | installed binaries | hooks | | Qoder (`qoder`) | installed binary 1.1.65 | hooks | | CodeBuddy (`codebuddy`) | installed package | hooks | | Jcode (`jcode`) | installed binary 0.95.0 | hooks | @@ -84,7 +85,7 @@ When an agent ships OSC 7501 support, or changes what it reports: 1. Run it in a PTY whose terminal answers `OSC 7501 ; ?` and record the reports. 2. If its `app` id differs from Orca's agent id, add the mapping to `APP_TO_AGENT_TYPE` in `src/shared/program-status/agent-status-projector.ts` (examples: `claude-code` → `claude`, - `grok-build` → `grok`). Otherwise hook precedence can't match its rows. + `grok-build` → `grok`, `kiro-cli` → `kiro`). Otherwise hook precedence can't match its rows. 3. Update the row and the date above. ## Plugin tool hooks (`agent.tool.before` / `.after`) diff --git a/src/main/agent-hooks/installation/commands/managed-hook-command-matching.ts b/src/main/agent-hooks/installation/commands/managed-hook-command-matching.ts index 82b599b4a5e..80232cc79d2 100644 --- a/src/main/agent-hooks/installation/commands/managed-hook-command-matching.ts +++ b/src/main/agent-hooks/installation/commands/managed-hook-command-matching.ts @@ -6,9 +6,7 @@ import { import type { HookCommandConfig, HookDefinition } from '../configuration/hook-config-schema' // Match script names so reinstalls sweep entries from old and parallel installations. -export function createManagedCommandMatcher( - scriptFileName: string -): (command: string | undefined) => boolean { +export function createManagedCommandMatcher(scriptFileName: string): (command: unknown) => boolean { const scriptStem = scriptFileName.replace(/\.(?:cmd|ps1|sh)$/, '') // Sweep every platform suffix after a platform switch. const needles = [ @@ -19,8 +17,9 @@ export function createManagedCommandMatcher( ] // The native executable selects its provider through argv[1]. const nativeHook = `agent-hooks/${WINDOWS_NATIVE_HOOK_EXECUTABLE_NAME} ${getWindowsNativeHookAgent(scriptFileName)} ` + // hooks.json is user-editable, so a command may not be a string. return (command) => { - if (!command) { + if (typeof command !== 'string' || !command) { return false } const decodedCommand = decodePowerShellEncodedCommand(command) diff --git a/src/main/agent-hooks/runtime/agent-hook-runtime-deps.ts b/src/main/agent-hooks/runtime/agent-hook-runtime-deps.ts index 1d65427fe77..4d65da58001 100644 --- a/src/main/agent-hooks/runtime/agent-hook-runtime-deps.ts +++ b/src/main/agent-hooks/runtime/agent-hook-runtime-deps.ts @@ -19,6 +19,8 @@ export function agentHookRuntimeDeps( getAgentStatusSnapshot: () => server.getStatusSnapshot().filter((entry) => entry.providerSessionOnly !== true), getAgentStatusSnapshotForPane: (paneKey) => server.getStatusSnapshotForPane(paneKey), + getPublicAgentStatusSnapshotForPane: (paneKey) => + server.getPublicStatusSnapshotForPane(paneKey), // Include resume identities so mobile can locate provider transcripts, including Pi sessions. getAgentProviderSessionSnapshot: (tabId) => tabId === undefined diff --git a/src/main/agent-hooks/server/combined-agent-status-entries.ts b/src/main/agent-hooks/server/combined-agent-status-entries.ts new file mode 100644 index 00000000000..d1468ed141f --- /dev/null +++ b/src/main/agent-hooks/server/combined-agent-status-entries.ts @@ -0,0 +1,59 @@ +import { isTmuxInnerSubject } from '../../../shared/tmux-selected-status' +import { + getLegacyStatusListingOrder, + type HookListenerState +} from '../../../shared/agent-hook-listener/listener-state' +import { + serializeAgentStatusSubject, + type AgentStatusSubject +} from '../../../shared/agent-status/contracts/agent-status-subject' +import type { AgentStatusStore } from '../../../shared/agent-status/store/agent-status-store' +import type { EnrichedAgentHookEventPayload } from './server-types' +import { structuredStatusLegacyEvent } from './server-structured-status-row' +import type { ProgramStatusFacetStore } from './program-status/facet-store' + +const UNORDERED_STATUS_ROW = Number.MAX_SAFE_INTEGER + +export function combinedAgentStatusEntries( + source: { + state: HookListenerState + programStatusFacets: Pick + canonicalStatusStore: Pick + canonicalSubjectsByPane: ReadonlyMap> + canonicalListingOrder: ReadonlyMap + }, + paneKey?: string +): EnrichedAgentHookEventPayload[] { + const rows: { entry: EnrichedAgentHookEventPayload; order: number }[] = [] + const legacy = + paneKey === undefined + ? source.state.lastStatusByPaneKey + : source.state.lastStatusByPaneKey.has(paneKey) + ? [[paneKey, source.state.lastStatusByPaneKey.get(paneKey)!] as const] + : [] + for (const [paneKey, entry] of legacy) { + rows.push({ + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: Main admits enriched legacy rows; shared listeners expose only the base event type. + entry: source.programStatusFacets.stitch(entry as EnrichedAgentHookEventPayload), + order: getLegacyStatusListingOrder(source.state, paneKey) ?? UNORDERED_STATUS_ROW + }) + } + const parents = + paneKey === undefined + ? source.canonicalStatusStore.getParents() + : [...(source.canonicalSubjectsByPane.get(paneKey)?.values() ?? [])].flatMap( + (subject) => source.canonicalStatusStore.getParent(subject) ?? [] + ) + for (const parent of parents) { + if (!parent.status || isTmuxInnerSubject(parent.subject)) { + continue + } + rows.push({ + entry: structuredStatusLegacyEvent(parent.status), + order: + source.canonicalListingOrder.get(serializeAgentStatusSubject(parent.subject)) ?? + UNORDERED_STATUS_ROW + }) + } + return rows.sort((a, b) => a.order - b.order).map(({ entry }) => entry) +} diff --git a/src/main/agent-hooks/server/program-status/facet-store.ts b/src/main/agent-hooks/server/program-status/facet-store.ts index f18e03a2578..ba11e041db7 100644 --- a/src/main/agent-hooks/server/program-status/facet-store.ts +++ b/src/main/agent-hooks/server/program-status/facet-store.ts @@ -3,6 +3,8 @@ import { type ProgramStatusFacet } from '../../../../shared/program-status/facet' import type { ParsedAgentStatusPayload } from '../../../../shared/agent-status/contracts/agent-status-types' +import type { EnrichedAgentHookEventPayload } from '../server-types' +import { isOpenCodeHookRow } from './hook-precedence' // Bound retained facets across long sessions; evict the least recently changed first. const MAX_PROGRAM_STATUS_FACETS = 1024 @@ -116,8 +118,14 @@ export class ProgramStatusFacetStore { } /** Stitch without mutating the stored row. */ - stitch(row: T): T { - const facet = this.byPaneKey.get(row.paneKey)?.facet + stitch< + T extends Pick< + EnrichedAgentHookEventPayload, + 'paneKey' | 'programStatus' | 'observation' | 'payload' + > + >(row: T): T { + // Another session's block or title must not decorate this pane. + const facet = isOpenCodeHookRow(row) ? undefined : this.byPaneKey.get(row.paneKey)?.facet if (facet === row.programStatus) { return row } diff --git a/src/main/agent-hooks/server/program-status/hook-precedence.ts b/src/main/agent-hooks/server/program-status/hook-precedence.ts index c6e1e332197..25210340efe 100644 --- a/src/main/agent-hooks/server/program-status/hook-precedence.ts +++ b/src/main/agent-hooks/server/program-status/hook-precedence.ts @@ -6,6 +6,17 @@ import type { EnrichedAgentHookEventPayload } from '../server-types' // Long tool calls can be hook-silent; allow sustained disagreement before yielding to OSC 7501. export const HOOK_SILENCE_BEFORE_PROGRAM_STATUS_FALLBACK_MS = 2 * 60 * 1000 +function isOpenCodeAgent(agentType: string | undefined): boolean { + return agentType === 'opencode' || agentType === 'opencode2' +} + +/** OpenCode's OSC 7501 covers every session sharing its folder's tabs; its hook covers only the pane's own. */ +export function isOpenCodeHookRow( + row: Pick +): boolean { + return row.observation?.origin === 'hook' && isOpenCodeAgent(row.payload.agentType) +} + /** Hook precedence ends at this time; undefined means no yield, Infinity means silence cannot end it. */ export function programStatusHookYieldEndsAt( previous: EnrichedAgentHookEventPayload | undefined, @@ -15,6 +26,14 @@ export function programStatusHookYieldEndsAt( if (previous?.observation?.origin !== 'hook' || previous.providerSessionOnly === true) { return undefined } + // OpenCode's OSC 7501 idle means every session rests, so only that can overrule a silent hook. + if ( + isOpenCodeHookRow(previous) && + isOpenCodeAgent(payload.agentType) && + payload.state !== 'done' + ) { + return Infinity + } const sameAgent = payload.agentType === undefined || payload.agentType === previous.payload.agentType // Different app IDs can be forks; only a completed hook agent lets a different program take over immediately. @@ -41,11 +60,19 @@ export function programStatusHookYieldEndsAt( ) { return Infinity } - // Settled turns are naturally silent; a later wait must prove intervening program work. - if (previous.payload.state === 'done' && payload.state === 'waiting') { - return programWorkingSince !== undefined && programWorkingSince > previous.receivedAt + // A settled turn yields only to program work begun after it (a replayed done keeps its own time): + // Codex re-reports the settled turn's working while a background terminal it started runs. + if ( + previous.payload.state === 'done' && + (payload.state === 'waiting' || payload.state === 'working') + ) { + const doneAt = previous.evidenceObservedAt ?? previous.receivedAt + if (programWorkingSince === undefined || programWorkingSince <= doneAt) { + return Infinity + } + return payload.state === 'waiting' ? undefined - : Infinity + : previous.receivedAt + HOOK_SILENCE_BEFORE_PROGRAM_STATUS_FALLBACK_MS } // A question sends no hooks while open, so a `working` that began before it (e.g. re-sent by the // lease renewal) proves nothing; a working transition after it keeps the silence fallback. diff --git a/src/main/agent-hooks/server/server-codex-question-skip.ts b/src/main/agent-hooks/server/server-codex-question-skip.ts new file mode 100644 index 00000000000..e59e028baaf --- /dev/null +++ b/src/main/agent-hooks/server/server-codex-question-skip.ts @@ -0,0 +1,41 @@ +import { codexRowAfterQuestionSkip } from '../../../shared/agent-hook-listener/providers/codex-question-skip' +import { AGENT_STATUS_STALE_AFTER_MS } from '../../../shared/agent-status/contracts/agent-status-freshness' +import type { AgentQuestionAnsweredInferenceRequest } from '../../../shared/agent-status/lifecycle/agent-question-answered-intent' +import { CODEX_ASYNC_QUESTION_TOOL } from '../../../shared/codex-async-question-input' +import { AgentHookServerStatusInference } from './server-status-inference' +import { isValidPaneKey } from './server-status-identity' +import type { EnrichedAgentHookEventPayload } from './server-types' + +/** Codex's skip key drops an async question in its TUI and reports nothing, so the renderer + * forwards the keystroke as a `codexSkip` question inference for a waiting Codex row. */ +export abstract class AgentHookServerCodexQuestionSkip extends AgentHookServerStatusInference { + override inferQuestionAnswered(request: AgentQuestionAnsweredInferenceRequest): boolean { + if (!request.codexSkip) { + return super.inferQuestionAnswered(request) + } + if (!isValidPaneKey(request.paneKey)) { + return false + } + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the server stores only enriched rows here, as inferQuestionAnswered already assumes. + const existing = this.state.lastStatusByPaneKey.get(request.paneKey) as + | EnrichedAgentHookEventPayload + | undefined + const payload = existing?.payload + // Codex keeps emitting hooks behind an open question and a skip may follow a skip, so the + // row's clock is no baseline; the prompt still fences a keystroke from a later turn. + if ( + !existing || + existing.providerSessionOnly || + existing.restoredUnconfirmed || + payload?.agentType !== 'codex' || + payload.toolName !== CODEX_ASYNC_QUESTION_TOOL || + payload.state !== 'waiting' || + payload.prompt !== request.baselinePrompt || + Date.now() - existing.receivedAt > AGENT_STATUS_STALE_AFTER_MS + ) { + return false + } + const row = codexRowAfterQuestionSkip(this.state, existing) + return row !== null && this.applyRestatedStatus(row) !== undefined + } +} diff --git a/src/main/agent-hooks/server/server-ingest-terminal.ts b/src/main/agent-hooks/server/server-ingest-terminal.ts index 184f4761918..a15b3514900 100644 --- a/src/main/agent-hooks/server/server-ingest-terminal.ts +++ b/src/main/agent-hooks/server/server-ingest-terminal.ts @@ -180,6 +180,13 @@ export abstract class AgentHookServerIngestTerminal extends AgentHookServerInges const previous = this.state.lastStatusByPaneKey.get(paneKey) as | EnrichedAgentHookEventPayload | undefined + // OSC 7501 names OpenCode 2 `opencode`; the row its hook or launch named keeps the generation. + const payload: ParsedAgentStatusPayload = + event.fromProgramStatus === true && + event.payload.agentType === 'opencode' && + previous?.payload.agentType === 'opencode2' + ? { ...event.payload, agentType: 'opencode2' } + : event.payload // OpenCode 1 run loads hooks in-process; a hook during the command owns its status. const hookOwnsCommand = event.yieldsToHookSince !== undefined && @@ -189,7 +196,7 @@ export abstract class AgentHookServerIngestTerminal extends AgentHookServerInges // Record ordering before removal, which also marks a program turn boundary. const workingSince = event.fromProgramStatus === true - ? this.programStatusFacets.noteState(paneKey, event.payload, now) + ? this.programStatusFacets.noteState(paneKey, payload, now) : undefined if (event.removesProgramStatusRow === true) { this.hookSilenceRechecks.cancel(paneKey) @@ -205,7 +212,7 @@ export abstract class AgentHookServerIngestTerminal extends AgentHookServerInges } const yieldEndsAt = event.fromProgramStatus === true - ? programStatusHookYieldEndsAt(previous, event.payload, workingSince) + ? programStatusHookYieldEndsAt(previous, payload, workingSince) : undefined const hookOwnsAgent = yieldEndsAt !== undefined && now < yieldEndsAt if (event.fromProgramStatus === true) { @@ -235,7 +242,7 @@ export abstract class AgentHookServerIngestTerminal extends AgentHookServerInges // OSC 7501 uses the hook precedence above; other terminal reports cannot settle child-held work. (event.fromProgramStatus !== true && previous?.payload.agentType === 'claude' && - event.payload.agentType === 'claude' && + payload.agentType === 'claude' && isAgentStatusHeldOpenByChildWork(previous.payload) && previous.payload.subagents?.some((subagent) => subagent.state === 'working') === true) ) { @@ -258,10 +265,10 @@ export abstract class AgentHookServerIngestTerminal extends AgentHookServerInges previous.worktreeId === worktreeId && // A terminal handle joins row identity; acquiring or replacing it requires publication. previous.terminalHandle === (terminalHandle ?? previous.terminalHandle) && - terminalStatusPayloadMatchesHook(previous.payload, event.payload, preserveActiveTurnStamp) && + terminalStatusPayloadMatchesHook(previous.payload, payload, preserveActiveTurnStamp) && // OSC 7501 child-only changes still require publication; absent children means none remain. (event.fromProgramStatus !== true || - agentSubagentsEqual(previous.payload.subagents, event.payload.subagents)) + agentSubagentsEqual(previous.payload.subagents, payload.subagents)) ) { // An authority transfer must refresh enriched subscribers even for an identical payload. this.refreshTerminalStatusEvidence( @@ -274,24 +281,22 @@ export abstract class AgentHookServerIngestTerminal extends AgentHookServerInges } // Terminal status carries no provider session; retain eligible cached identity without treating unknown as a mismatch (#10630). const claimedAgentType = - event.payload.agentType && event.payload.agentType !== 'unknown' - ? event.payload.agentType - : undefined + payload.agentType && payload.agentType !== 'unknown' ? payload.agentType : undefined // A live agent's turn after `done` keeps its session (OSC 7501 reports hookless slash commands); a new run or an exited agent's resume-only row does not. Launch seeds are not completed turns. const preservedProviderSession = previous?.providerSession && (claimedAgentType === undefined || claimedAgentType === previous.payload.agentType) && (previous.payload.state !== 'done' || - event.payload.state === 'done' || + payload.state === 'done' || previous.observation?.origin === 'launch' || (!newRun && previous.providerSessionOnly !== true)) ? previous.providerSession : undefined // Without a new main-agent fact, preserve it only while the row's state and agent still match. const preservedMainAgent = - event.payload.mainAgent ?? + payload.mainAgent ?? (previous?.payload.mainAgent && - previous.payload.state === event.payload.state && + previous.payload.state === payload.state && (claimedAgentType === undefined || claimedAgentType === previous.payload.agentType) ? previous.payload.mainAgent : undefined) @@ -304,9 +309,7 @@ export abstract class AgentHookServerIngestTerminal extends AgentHookServerInges connectionId, ...(preservedProviderSession ? { providerSession: preservedProviderSession } : {}), ...(terminalHandle ? { terminalHandle } : {}), - payload: preservedMainAgent - ? { ...event.payload, mainAgent: preservedMainAgent } - : event.payload + payload: preservedMainAgent ? { ...payload, mainAgent: preservedMainAgent } : payload }, undefined, event.origin ?? 'osc', diff --git a/src/main/agent-hooks/server/server-listeners.ts b/src/main/agent-hooks/server/server-listeners.ts index 7db72a6c592..ec8a7911ef7 100644 --- a/src/main/agent-hooks/server/server-listeners.ts +++ b/src/main/agent-hooks/server/server-listeners.ts @@ -1,15 +1,11 @@ import { cliWriterExecutionMatcher, type CliWriterExecutionMatches } from './cli-writer-observation' -import { isTmuxInnerSubject } from '../../../shared/tmux-selected-status' import type { AgentStatusClearIpcPayload, AgentStatusIpcPayload } from '../../../shared/agent-status/contracts/agent-status-ipc-payload' import type { ClaudeStatusLineRateLimits } from '../../../shared/claude-statusline-rate-limits' import type { HookTransportInterferenceReport } from '../../../shared/agent-hook-listener/transport/agent-hook-transport-interference' -import { - getLegacyStatusListingOrder, - type HookListenerState -} from '../../../shared/agent-hook-listener/listener-state' +import type { HookListenerState } from '../../../shared/agent-hook-listener/listener-state' import type { AgentHookAuthorityEvidence, AgentHookProviderSessionIdentity, @@ -20,15 +16,11 @@ import type { } from './server-types' import { toAgentStatusIpcPayload } from './server-status-identity' import { AgentHookServerState } from './server-state' -import { serializeAgentStatusSubject } from '../../../shared/agent-status/contracts/agent-status-subject' -import { structuredStatusLegacyEvent } from './server-structured-status-row' +import { combinedAgentStatusEntries } from './combined-agent-status-entries' import { PaneTimers } from './program-status/pane-timers' import { ProgramStatusFacetStore } from './program-status/facet-store' import { parsePaneKey } from '../../../shared/workspace-layout/stable-pane-id' -// Unassigned rows sort after the listing counter, which starts at 1. -const UNORDERED_STATUS_ROW = Number.MAX_SAFE_INTEGER - export abstract class AgentHookServerListeners extends AgentHookServerState { protected providerRowsByTab: Map | null = null protected statusChangeNotificationVersion = 0 @@ -76,27 +68,17 @@ export abstract class AgentHookServerListeners extends AgentHookServerState { this.providerRowsByTab = null } - private combinedStatusEntries(): EnrichedAgentHookEventPayload[] { - const rows: { entry: EnrichedAgentHookEventPayload; order: number }[] = [] - for (const [paneKey, entry] of this.state.lastStatusByPaneKey) { - rows.push({ - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: Main admits enriched legacy rows; shared listeners expose only the base event type. - entry: this.programStatusFacets.stitch(entry as EnrichedAgentHookEventPayload), - order: getLegacyStatusListingOrder(this.state, paneKey) ?? UNORDERED_STATUS_ROW - }) - } - for (const parent of this.canonicalStatusStore.getParents()) { - if (!parent.status || isTmuxInnerSubject(parent.subject)) { - continue - } - rows.push({ - entry: structuredStatusLegacyEvent(parent.status), - order: - this.canonicalListingOrder.get(serializeAgentStatusSubject(parent.subject)) ?? - UNORDERED_STATUS_ROW - }) - } - return rows.sort((a, b) => a.order - b.order).map(({ entry }) => entry) + private combinedStatusEntries(paneKey?: string): EnrichedAgentHookEventPayload[] { + return combinedAgentStatusEntries( + { + state: this.state, + programStatusFacets: this.programStatusFacets, + canonicalStatusStore: this.canonicalStatusStore, + canonicalSubjectsByPane: this.canonicalSubjectsByPane, + canonicalListingOrder: this.canonicalListingOrder + }, + paneKey + ) } /** Report repeated hook-body truncation once per process; fail-open handling otherwise hides it (#11217). */ setTransportInterferenceListener( @@ -248,6 +230,12 @@ export abstract class AgentHookServerListeners extends AgentHookServerState { return this.buildStatusChangeNotification().providerSessions } + getPublicStatusSnapshotForPane(paneKey: string): AgentStatusIpcPayload[] { + return this.combinedStatusEntries(paneKey) + .filter((entry) => entry.providerSessionOnly !== true) + .map(toAgentStatusIpcPayload) + } + getStatusSnapshotForPane(paneKey: string): AgentStatusIpcPayload[] { const legacy = this.state.lastStatusByPaneKey.get(paneKey) if (legacy) { diff --git a/src/main/agent-hooks/server/server-status-disposition.ts b/src/main/agent-hooks/server/server-status-disposition.ts index 33a1750d1b7..a52c68af8eb 100644 --- a/src/main/agent-hooks/server/server-status-disposition.ts +++ b/src/main/agent-hooks/server/server-status-disposition.ts @@ -12,9 +12,9 @@ import { RETIRED_PANE_FENCES_MAX } from './server-constants' import type { RetiredPaneAlias, RetiredPaneFence } from './server-types' -import { AgentHookServerStatusInference } from './server-status-inference' +import { AgentHookServerCodexQuestionSkip } from './server-codex-question-skip' -export abstract class AgentHookServerStatusDisposition extends AgentHookServerStatusInference { +export abstract class AgentHookServerStatusDisposition extends AgentHookServerCodexQuestionSkip { protected markTabClosedForAgentStatus(tabId: string): void { // Refresh insertion order so only the oldest closed tabs are evicted. this.closedAgentStatusTabIds.delete(tabId) diff --git a/src/main/agent-hooks/server/testing/identity/server-claude-resume-record-continuity.test.ts b/src/main/agent-hooks/server/testing/identity/server-claude-resume-record-continuity.test.ts index 6c356e7b35b..35b2bdc1a6e 100644 --- a/src/main/agent-hooks/server/testing/identity/server-claude-resume-record-continuity.test.ts +++ b/src/main/agent-hooks/server/testing/identity/server-claude-resume-record-continuity.test.ts @@ -4,7 +4,7 @@ import { join } from 'node:path' import { afterEach, beforeEach, expect, it, vi } from 'vitest' import { AgentHookServer } from '../../agent-hook-server' import { HOOK_SILENCE_BEFORE_PROGRAM_STATUS_FALLBACK_MS } from '../../program-status/hook-precedence' -import { buildBody, PANE, postHookEvent } from '../server.test-fixtures' +import { buildBody, ingestProgramStatusOsc, PANE, postHookEvent } from '../server.test-fixtures' const SESSION = '70efcb3f-ae17-4863-9318-649f5469408b' @@ -54,14 +54,7 @@ it('keeps the start folder and effort when a terminal status row precedes the ne vi.useFakeTimers({ toFake: ['Date'] }) vi.setSystemTime(Date.now() + HOOK_SILENCE_BEFORE_PROGRAM_STATUS_FALLBACK_MS) // Claude reports OSC 7501 `working` just before UserPromptSubmit. - server.ingestTerminalStatus({ - paneKey: PANE, - tabId: 'tab-1', - worktreeId: 'wt-1', - connectionId: null, - fromProgramStatus: true, - payload: { prompt: '', state: 'working', agentType: 'claude' } - }) + ingestProgramStatusOsc(server, '\x1b]7501;state=working:app=claude-code\x1b\\') await claudeHook({ hook_event_name: 'UserPromptSubmit', prompt: 'next', cwd: '/repo/sub' }) expect(recordedSession()).toMatchObject({ id: SESSION, cwd: '/repo', effort: 'max' }) diff --git a/src/main/agent-hooks/server/testing/identity/server-kiro-program-status-identity.test.ts b/src/main/agent-hooks/server/testing/identity/server-kiro-program-status-identity.test.ts new file mode 100644 index 00000000000..f58869bff09 --- /dev/null +++ b/src/main/agent-hooks/server/testing/identity/server-kiro-program-status-identity.test.ts @@ -0,0 +1,64 @@ +import { mkdtempSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, beforeEach, expect, it } from 'vitest' +import { createProgramStatusProjector } from '../../../../../shared/program-status/agent-status-projector' +import { AgentHookServer } from '../../agent-hook-server' +import { buildBody, PANE, postHookEvent } from '../server.test-fixtures' + +const SESSION = 'sess_11111111-2222-4333-8444-555555555555' + +// Shape written by kiro-cli 3.1.0's TUI, which reports under its binary name. +const kiroOsc = (state: string): string => `\x1b]7501;state=${state}:app=kiro-cli\x07` + +let dir: string +let server: AgentHookServer +let projector: ReturnType + +beforeEach(async () => { + dir = mkdtempSync(join(tmpdir(), 'orca-kiro-program-status-')) + server = new AgentHookServer() + await server.start({ env: 'production', userDataPath: dir }) + projector = createProgramStatusProjector() +}) + +afterEach(() => { + server.stop() + rmSync(dir, { recursive: true, force: true }) +}) + +async function kiroHook(hookEventName: string, payload: Record = {}) { + const response = await postHookEvent( + server, + buildBody({ session_id: SESSION, hook_event_name: hookEventName, cwd: '/repo', ...payload }), + '/hook/kiro' + ) + expect(response.status).toBe(204) +} + +function kiroReports(state: string): void { + for (const { payload } of projector.process(kiroOsc(state)).payloads) { + server.ingestTerminalStatus({ + paneKey: PANE, + tabId: 'tab-1', + worktreeId: 'wt-1', + connectionId: null, + fromProgramStatus: true, + payload + }) + } +} + +function recordedRow() { + const row = server.getStatusSnapshot()[0] + return { agentType: row?.agentType, sessionId: row?.providerSession?.id } +} + +it('keeps the Kiro session through a turn that Kiro also reports over OSC 7501', async () => { + kiroReports('working') + await kiroHook('UserPromptSubmit', { prompt: 'hi' }) + await kiroHook('Stop') + kiroReports('done') + + expect(recordedRow()).toEqual({ agentType: 'kiro', sessionId: SESSION }) +}) diff --git a/src/main/agent-hooks/server/testing/providers/codex/server-codex-background-terminal-working.test.ts b/src/main/agent-hooks/server/testing/providers/codex/server-codex-background-terminal-working.test.ts new file mode 100644 index 00000000000..378a9a6739e --- /dev/null +++ b/src/main/agent-hooks/server/testing/providers/codex/server-codex-background-terminal-working.test.ts @@ -0,0 +1,40 @@ +import { afterEach, beforeEach, expect, it, vi } from 'vitest' +import { AgentHookServer } from '../../../agent-hook-server' +import { HOOK_SILENCE_BEFORE_PROGRAM_STATUS_FALLBACK_MS } from '../../../program-status/hook-precedence' +import { buildBody, ingestProgramStatusOsc, postHookEvent } from '../../server.test-fixtures' + +const TURN = { session_id: 'session-1', turn_id: 'turn-1' } + +let server: AgentHookServer + +beforeEach(async () => { + server = new AgentHookServer() + await server.start({ env: 'production' }) +}) + +afterEach(() => { + vi.useRealTimers() + server.stop() +}) + +async function codexHook(hookEventName: string, payload: Record = {}) { + const response = await postHookEvent( + server, + buildBody({ ...TURN, hook_event_name: hookEventName, ...payload }), + '/hook/codex' + ) + expect(response.status).toBe(204) +} + +it('keeps a finished Codex turn done while its background terminal keeps OSC 7501 working', async () => { + await codexHook('UserPromptSubmit', { prompt: 'start sleep 900 in the background' }) + // Codex 0.167 sends this at the turn start and nothing after it while `sleep 900` runs. + const working = ingestProgramStatusOsc(server, '\x1b]7501;state=working:app=codex\x1b\\') + await codexHook('Stop', { last_assistant_message: 'ok' }) + + vi.useFakeTimers({ toFake: ['Date', 'setTimeout', 'clearTimeout'] }) + server.ingestTerminalStatus({ ...working, renewsProgramStatusLease: true }) + vi.advanceTimersByTime(HOOK_SILENCE_BEFORE_PROGRAM_STATUS_FALLBACK_MS + 1) + + expect(server.getStatusSnapshot()[0]?.state).toBe('done') +}) diff --git a/src/main/agent-hooks/server/testing/providers/codex/server-ingest-codex-async-question.test.ts b/src/main/agent-hooks/server/testing/providers/codex/server-ingest-codex-async-question.test.ts index 79714496a2f..fef89b48fd9 100644 --- a/src/main/agent-hooks/server/testing/providers/codex/server-ingest-codex-async-question.test.ts +++ b/src/main/agent-hooks/server/testing/providers/codex/server-ingest-codex-async-question.test.ts @@ -3,7 +3,7 @@ import { normalizeHookPayload } from '../../../../../../shared/agent-hook-listen import { createHookListenerState } from '../../../../../../shared/agent-hook-listener/listener-state' import { buildRelayHookEnvelope } from '../../../../../../wsl-guest/agent-hook-envelope-build' import { AgentHookServer, _internals } from '../../../agent-hook-server' -import { PANE, buildBody } from '../../server.test-fixtures' +import { PANE, buildBody, postHookEvent } from '../../server.test-fixtures' vi.mock('../../../../../telemetry/client', () => ({ track: vi.fn() })) vi.mock('../../../../../telemetry/cohort-classifier', () => ({ @@ -103,4 +103,48 @@ describe('Codex async questions', () => { expect(answered).toMatchObject({ state: 'working' }) expect(answered?.interactivePrompt).toBeUndefined() }) + + it('drops one question per skip keystroke on a local pane, since Codex reports no skip', async () => { + const server = new AgentHookServer() + await server.start({ env: 'production' }) + const row = () => server.getStatusSnapshotForPane(PANE)[0]! + const post = async (payload: Record) => { + await postHookEvent(server, buildBody(payload), '/hook/codex') + return row() + } + const baselineOf = (baseline: { + receivedAt: number + stateStartedAt: number + prompt: string + }) => ({ + paneKey: PANE, + baselineUpdatedAt: baseline.receivedAt, + baselineStateStartedAt: baseline.stateStartedAt, + baselinePrompt: baseline.prompt, + baselineAgentType: 'codex' as const + }) + const skip = (baseline: { receivedAt: number; stateStartedAt: number; prompt: string }) => + server.inferQuestionAnswered({ ...baselineOf(baseline), codexSkip: true }) + try { + await post({ hook_event_name: 'UserPromptSubmit', turn_id: 'turn-1', prompt: 'Set up a db' }) + await post(ASK) + expect(await post(ACCEPTED)).toMatchObject(waitingOnQuestion) + + // An answer inference (e.g. Enter sent over RPC) is not a skip. + expect(server.inferQuestionAnswered(baselineOf(row()))).toBe(false) + // Two quick skips share the renderer's stale baseline; both must land. + const stale = row() + expect(skip(stale)).toBe(true) + expect(row()).toMatchObject(waitingOnQuestion) + expect(skip(stale)).toBe(true) + expect(row()).toMatchObject({ state: 'working', mainAgent: { state: 'working' } }) + expect(row().interactivePrompt).toBeUndefined() + // Later hooks in the same turn must not resurrect the skipped question. + const bash = { hook_event_name: 'PreToolUse', turn_id: 'turn-1', tool_name: 'Bash' } + expect(await post(bash)).toMatchObject({ state: 'working' }) + expect(skip(row())).toBe(false) + } finally { + server.stop() + } + }) }) diff --git a/src/main/agent-hooks/server/testing/providers/droid/server-droid-mission-resume.test.ts b/src/main/agent-hooks/server/testing/providers/droid/server-droid-mission-resume.test.ts new file mode 100644 index 00000000000..ed5bba85694 --- /dev/null +++ b/src/main/agent-hooks/server/testing/providers/droid/server-droid-mission-resume.test.ts @@ -0,0 +1,96 @@ +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, beforeEach, describe, expect, it } from 'vitest' +import { createHookListenerState } from '../../../../../../shared/agent-hook-listener/listener-state' +import { normalizeHookPayload } from '../../../../../../shared/agent-hook-listener/normalization/normalize-hook-payload' +import { AgentHookServer } from '../../../agent-hook-server' +import { buildBody, PANE, postHookEvent } from '../../server.test-fixtures' + +const ROOT_ID = '5883db93-32ca-48da-ba29-db952021d273' +const WORKER_ID = 'dc08d047-adfd-4190-a0f4-6c3f7167d394' + +describe('Droid mission resume identity', () => { + let dir: string + let server: AgentHookServer + + beforeEach(async () => { + dir = mkdtempSync(join(tmpdir(), 'orca-droid-server-')) + server = new AgentHookServer() + await server.start({ env: 'production' }) + }) + + afterEach(() => { + server.stop() + rmSync(dir, { recursive: true, force: true }) + }) + + // Droid writes `callingSessionId` on the first transcript record of sub-sessions only. + function transcript(id: string, callingSessionId?: string): string { + const path = join(dir, `${id}.jsonl`) + const start = { type: 'session_start', id, ...(callingSessionId ? { callingSessionId } : {}) } + writeFileSync(path, `${JSON.stringify(start)}\n`) + return path + } + + function body(sessionId: string, transcriptPath: string, event: string) { + return buildBody( + { + hook_event_name: event, + session_id: sessionId, + transcript_path: transcriptPath, + tool_name: 'Execute', + prompt: 'run the mission' + }, + { launchToken: 'droid-token' } + ) + } + + async function post(sessionId: string, transcriptPath: string, event: string) { + expect( + (await postHookEvent(server, body(sessionId, transcriptPath, event), '/hook/droid')).status + ).toBe(204) + } + + const resumeId = () => server.getStatusSnapshotForPane(PANE)[0]?.providerSession?.id + + it('keeps the orchestrator as the resume target while its workers report', async () => { + const rootPath = transcript(ROOT_ID) + const workerPath = transcript(WORKER_ID, ROOT_ID) + + await post(WORKER_ID, workerPath, 'PreToolUse') + expect(resumeId()).toBeUndefined() + + await post(ROOT_ID, rootPath, 'UserPromptSubmit') + await post(WORKER_ID, workerPath, 'PreToolUse') + await post(WORKER_ID, workerPath, 'Stop') + expect(resumeId()).toBe(ROOT_ID) + + // Dismissing the row keeps only the resume identity; the mission is still running. + server.dropStatusEntry(PANE) + await post(WORKER_ID, workerPath, 'PreToolUse') + expect(resumeId()).toBe(ROOT_ID) + }) + + it('keeps the orchestrator when a restarted relay forwards a worker hook', () => { + // A cold relay has no pane row, so it forwards the worker hook with no session. + const relayed = (sessionId: string, transcriptPath: string) => { + const event = normalizeHookPayload( + createHookListenerState(), + 'droid', + body(sessionId, transcriptPath, 'PreToolUse'), + 'production' + ) + if (!event) { + throw new Error('Missing Droid event') + } + return event + } + server.ingestRemote(relayed(ROOT_ID, transcript(ROOT_ID)), 'host-1') + const worker = relayed(WORKER_ID, transcript(WORKER_ID, ROOT_ID)) + expect(worker.providerSession).toBeUndefined() + + server.ingestRemote(worker, 'host-1') + expect(resumeId()).toBe(ROOT_ID) + }) +}) diff --git a/src/main/agent-hooks/server/testing/providers/opencode/server-opencode2-program-status.test.ts b/src/main/agent-hooks/server/testing/providers/opencode/server-opencode2-program-status.test.ts new file mode 100644 index 00000000000..14f73339076 --- /dev/null +++ b/src/main/agent-hooks/server/testing/providers/opencode/server-opencode2-program-status.test.ts @@ -0,0 +1,89 @@ +import { afterEach, expect, it, vi } from 'vitest' +import { AgentHookServer } from '../../../agent-hook-server' +import { HOOK_SILENCE_BEFORE_PROGRAM_STATUS_FALLBACK_MS } from '../../../program-status/hook-precedence' +import { buildBody, ingestProgramStatusOsc, PANE, postHookEvent } from '../../server.test-fixtures' + +vi.mock('../../../../../telemetry/client', () => ({ track: vi.fn() })) +vi.mock('../../../../../telemetry/cohort-classifier', () => ({ getCohortAtEmit: () => ({}) })) + +let server: AgentHookServer | undefined +afterEach(() => { + vi.useRealTimers() + server?.stop() +}) + +function oscStatus(state: 'working' | 'done'): void { + // OpenCode 2 reports OSC 7501 as `app=opencode`. + server!.ingestTerminalStatus({ + paneKey: PANE, + tabId: 'tab-1', + worktreeId: 'wt-1', + connectionId: null, + fromProgramStatus: true, + payload: { state, prompt: '', agentType: 'opencode' } + }) +} + +async function hook(hook_event_name: string, prompt = ''): Promise { + const body = buildBody({ hook_event_name, sessionID: 'ses_opencode2', prompt }) + expect((await postHookEvent(server!, body, '/hook/opencode2')).status).toBe(204) +} + +it('keeps OpenCode 2 hooks and their session on a pane its OSC 7501 reports as opencode', async () => { + server = new AgentHookServer() + await server.start({ env: 'production' }) + oscStatus('working') + await hook('SessionBusy', 'rename the branch') + expect(server.getStatusSnapshot()[0]).toMatchObject({ + agentType: 'opencode2', + prompt: 'rename the branch' + }) + + await hook('SessionIdle') + oscStatus('done') + expect(server.getStatusSnapshot()[0]).toMatchObject({ + agentType: 'opencode2', + state: 'done', + providerSession: { id: 'ses_opencode2' } + }) +}) + +it('keeps an idle OpenCode 2 pane done while another session in its folder works', async () => { + server = new AgentHookServer() + await server.start({ env: 'production' }) + await hook('SessionBusy', 'rename the branch') + await hook('SessionIdle') + + vi.useFakeTimers({ toFake: ['Date', 'setTimeout', 'clearTimeout'] }) + vi.advanceTimersByTime(1) + // Captured from an idle OpenCode 2.2.6 TUI while another TUI in its folder ran a turn. + const otherSession = Buffer.from('Title PARENTSPAWN').toString('base64') + ingestProgramStatusOsc( + server, + `\x1b]7501;state=working:app=opencode:title=${otherSession}\x1b\\` + + `\x1b]7501;state=working:id=ses_e37f56b97ffeLXB4e0RO7uYUBV:app=opencode:title=${otherSession}\x1b\\` + ) + vi.advanceTimersByTime(HOOK_SILENCE_BEFORE_PROGRAM_STATUS_FALLBACK_MS + 1) + + expect(server.getStatusSnapshot()[0]).toMatchObject({ + state: 'done', + providerSession: { id: 'ses_opencode2' } + }) +}) + +it('keeps a permission prompt from another OpenCode session off a working pane', async () => { + server = new AgentHookServer() + await server.start({ env: 'production' }) + await hook('SessionBusy', 'rename the branch') + + const request = Buffer.from('rm -rf build').toString('base64') + ingestProgramStatusOsc( + server, + `\x1b]7501;state=blocked:kind=permission:app=opencode:msg=${request}\x1b\\` + + `\x1b]7501;state=blocked:kind=permission:id=ses_other:app=opencode:msg=${request}\x1b\\` + ) + + const [row] = server.getStatusSnapshot() + expect(row).toMatchObject({ state: 'working' }) + expect(row?.programStatus).toBeUndefined() +}) diff --git a/src/main/agent-hooks/server/testing/server.test-fixtures.ts b/src/main/agent-hooks/server/testing/server.test-fixtures.ts index 9b380067b2f..4cd27a5c1d7 100644 --- a/src/main/agent-hooks/server/testing/server.test-fixtures.ts +++ b/src/main/agent-hooks/server/testing/server.test-fixtures.ts @@ -1,4 +1,5 @@ import { makePaneKey } from '../../../../shared/workspace-layout/stable-pane-id' +import { createProgramStatusProjector } from '../../../../shared/program-status/agent-status-projector' import type { AgentHookServer } from '../agent-hook-server' export const LEAF_1 = '11111111-1111-4111-8111-111111111111' @@ -44,6 +45,22 @@ export function buildBody(payload: Record, overrides: Partial ({ track: vi.fn() })) vi.mock('../../../../telemetry/cohort-classifier', () => ({ getCohortAtEmit: vi.fn(() => ({})) })) @@ -51,6 +52,53 @@ function terminal(server: AgentHookServer, paneKey: string): void { afterEach(() => vi.restoreAllMocks()) describe('structured canonical production slice', () => { + it('publishes the same public pane evidence while preserving resume-only provider identity', () => { + const server = new AgentHookServer() + const deps = agentHookRuntimeDeps(server, { read: () => ({ kind: 'unobserved' }) }, () => ({})) + server.recordLaunchResumeIdentity({ + paneKey: PANE, + agentType: 'codex', + providerSession: { key: 'session_id', id: 'resume-only' }, + launchedAt: 100 + }) + expect(deps.getPublicAgentStatusSnapshotForPane(PANE)).toEqual([]) + expect(deps.getAgentStatusSnapshotForPane(PANE)).toEqual([ + expect.objectContaining({ + providerSessionOnly: true, + providerSession: { key: 'session_id', id: 'resume-only' } + }) + ]) + expect(deps.getAgentProviderSessionRowsForPane(PANE)).toEqual([ + expect.objectContaining({ + providerSessionOnly: true, + providerSession: { key: 'session_id', id: 'resume-only' } + }) + ]) + terminal(server, PANE) + server.ingestStructuredStatus(summary(), SUBJECT) + const second = makeStructuredAgentStatusSubject( + { ...SCOPE, executionHostId: 'ssh:other' }, + SESSION + ) + server.ingestStructuredStatus({ ...summary(second), agent: 'claude', status: 'idle' }, second) + expect(deps.getAgentStatusSnapshotForPane(PANE).map(({ state }) => state)).toEqual(['working']) + expect( + deps + .getPublicAgentStatusSnapshotForPane(PANE_KEY) + .map(({ agentType, state }) => ({ agentType, state })) + ).toEqual([ + { agentType: 'codex', state: 'working' }, + { agentType: 'claude', state: 'done' } + ]) + expect(deps.getAgentStatusSnapshot().map(({ paneKey, state }) => ({ paneKey, state }))).toEqual( + [ + { paneKey: PANE, state: 'working' }, + { paneKey: PANE_KEY, state: 'working' }, + { paneKey: PANE_KEY, state: 'done' } + ] + ) + }) + it('isolates identical session identifiers across host, WSL and workspace kind scopes', () => { const server = new AgentHookServer() const scopes: AgentStatusExecutionScope[] = [ diff --git a/src/main/agent-launch/trust/agent-workspace-trust-spawn.test.ts b/src/main/agent-launch/trust/agent-workspace-trust-spawn.test.ts index 5bcda0cae73..14cc1d4fec8 100644 --- a/src/main/agent-launch/trust/agent-workspace-trust-spawn.test.ts +++ b/src/main/agent-launch/trust/agent-workspace-trust-spawn.test.ts @@ -8,12 +8,10 @@ async function sshTrustRequest(input: { worktreeId: string globalEnabled?: boolean repoDecision?: AgentWorkspaceTrustDecision - skipForThisLaunch?: boolean }): Promise { const spawnOptions: AgentTrustSpawnFields = {} await applyAgentWorkspaceTrustToSpawn({ launchAgent: 'claude', - skipForThisLaunch: input.skipForThisLaunch, worktreeId: input.worktreeId, cwd: '/srv/app', store: { @@ -56,10 +54,4 @@ describe('agent folder trust follows the repo decision', () => { }) ).toEqual({}) }) - - it("honours this launch's let-agents-ask answer even when the repo has none stored", async () => { - expect( - await sshTrustRequest({ worktreeId: 'repo-1::/srv/app', skipForThisLaunch: true }) - ).toEqual({}) - }) }) diff --git a/src/main/agent-launch/trust/agent-workspace-trust-spawn.ts b/src/main/agent-launch/trust/agent-workspace-trust-spawn.ts index 106da0081d8..aa37a803eaa 100644 --- a/src/main/agent-launch/trust/agent-workspace-trust-spawn.ts +++ b/src/main/agent-launch/trust/agent-workspace-trust-spawn.ts @@ -43,8 +43,6 @@ export function agentWorkspaceTrustDecisionForWorkspace( export function applyAgentWorkspaceTrustToSpawn( args: { launchAgent: unknown - /** The user chose "let agents ask" for this launch; it wins even if saving that answer failed. */ - skipForThisLaunch?: boolean /** Placement workspace id; its root may differ from the agent’s starting folder. */ worktreeId: string | undefined /** Section root to pre-trust for this launch; never part of the terminal identity. */ @@ -64,7 +62,6 @@ export function applyAgentWorkspaceTrustToSpawn( const trustWorkspaceId = resolveAgentWorkspaceTrustOwner(args) if ( !args.isFreshLaunch || - args.skipForThisLaunch === true || !shouldPreTrustAgentWorkspace( args.settings?.agentWorkspaceTrustEnabled, agentWorkspaceTrustDecisionForWorkspace(trustWorkspaceId, args.store) diff --git a/src/main/automations/automation-chat-run-observation.ts b/src/main/automations/automation-chat-run-observation.ts index 02b037b0967..622988efb04 100644 --- a/src/main/automations/automation-chat-run-observation.ts +++ b/src/main/automations/automation-chat-run-observation.ts @@ -55,6 +55,12 @@ function observationForResolvedRun( } const turn = turnItem ? readAgentJournalTurn(turnItem.body) : null if (!turn || !turnItem) { + if ( + submission.dispatchState === 'rejected' && + automationAgentDidNotStart(submission.rejection) + ) { + return { status: 'dispatch_failed', error: automationAgentDidNotStartError(agent) } + } return submission.dispatchState === 'rejected' || submission.dispatchState === 'unknown' ? { status: 'dispatch_failed', @@ -114,3 +120,20 @@ function submissionTurn( ) }) } + +/** Rejections that mean the agent never finished starting, so it never saw the prompt: the start + * passed its limit or was stopped while starting (`hostStopped`), or the agent exited or failed + * while starting. */ +const DID_NOT_START_KINDS: ReadonlySet = new Set([ + 'hostStopped', + 'providerStartFailed', + 'startFailed' +]) + +export function automationAgentDidNotStart(rejection: { kind: string } | undefined): boolean { + return rejection !== undefined && DID_NOT_START_KINDS.has(rejection.kind) +} + +export function automationAgentDidNotStartError(agent: string): string { + return `${agent} did not start (the machine may have slept or startup timed out), so it never received this run's prompt. Run the automation again.` +} diff --git a/src/main/automations/automation-wake-settle.test.ts b/src/main/automations/automation-wake-settle.test.ts new file mode 100644 index 00000000000..c8807619c9b --- /dev/null +++ b/src/main/automations/automation-wake-settle.test.ts @@ -0,0 +1,253 @@ +import { closeTestStores, createStore, testState } from '../persistence/persistence-test-harness' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { mkdtempSync, rmSync } from 'node:fs' +import { join } from 'node:path' +import { tmpdir } from 'node:os' +import type { Repo } from '../../shared/repo-types' +import { AutomationService } from './service' +import { TICK_MS } from './automation-service-tick.test-fixture' +import { createAwakeClock, type AwakeClock } from '../power/awake-clock' +import { AUTOMATION_WAKE_SETTLE_MS, automationSystemSettled } from './automation-wake-settle' + +vi.mock('electron', () => ({ + app: { + getPath: () => testState.dir + }, + safeStorage: { + isEncryptionAvailable: () => true, + encryptString: (plaintext: string) => Buffer.from(`encrypted:${plaintext}`, 'utf-8'), + decryptString: (ciphertext: Buffer) => ciphertext.toString('utf-8').slice('encrypted:'.length) + } +})) + +const makeRepo = (): Repo => ({ + id: 'r1', + path: '/repo', + displayName: 'test', + badgeColor: '#fff', + addedAt: 1 +}) + +type CounterModel = 'counts sleep (macOS/Windows Node)' | 'stops in sleep (Linux)' + +describe.each(['counts sleep (macOS/Windows Node)', 'stops in sleep (Linux)'])( + 'scheduled catch-up after a wake, on a monotonic counter that %s', + (model) => { + let clock: AwakeClock + /** Sleep the fake monotonic counter missed: fake performance only moves with timers. */ + let countedSleep = 0 + + beforeEach(() => { + testState.dir = mkdtempSync(join(tmpdir(), 'orca-automations-wake-test-')) + vi.useFakeTimers({ + toFake: [ + 'Date', + 'performance', + 'setTimeout', + 'clearTimeout', + 'setInterval', + 'clearInterval', + 'setImmediate', + 'clearImmediate' + ] + }) + // Why: offset-less times are local, matching the schedule's local BYHOUR in any CI TZ. + vi.setSystemTime(new Date('2026-11-09T08:00:00')) + countedSleep = 0 + clock = createAwakeClock({ + wallNow: () => Date.now(), + monotonicNow: () => performance.now() + countedSleep, + after: (beat, ms) => { + setTimeout(beat, ms) + } + }) + }) + + afterEach(async () => { + await closeTestStores() + vi.useRealTimers() + rmSync(testState.dir, { recursive: true, force: true }) + }) + + async function awakeFor(ms: number): Promise { + await vi.advanceTimersByTimeAsync(ms) + } + + /** Asleep: no timers run; the wall clock moves on, and so does the counter if it counts sleep. */ + function asleepUntil(when: string): void { + const ms = new Date(when).getTime() - Date.now() + vi.setSystemTime(Date.now() + ms) + if (model === 'counts sleep (macOS/Windows Node)') { + countedSleep += ms + } + } + + async function scheduledService(opts: { tickMs?: number; graceMinutes?: number } = {}) { + const tickMs = opts.tickMs ?? TICK_MS + const store = await createStore() + store.addRepo(makeRepo()) + const automation = store.createAutomation({ + name: 'GitHub i18n issue and PR scan', + prompt: 'Scan', + agentId: 'codex', + projectId: 'r1', + workspaceMode: 'existing', + workspaceId: 'r1::wt1', + timezone: 'America/Los_Angeles', + rrule: 'FREQ=DAILY;BYHOUR=9;BYMINUTE=0', + dtstart: new Date('2026-11-08T00:00:00').getTime(), + missedRunGraceMinutes: opts.graceMinutes ?? 720 + }) + const launch = vi.fn(async () => ({ workspaceId: 'wt-1', terminalSessionId: 'tab-1' })) + const service = new AutomationService(store, { + tickMs, + terminalLauncher: { launch, available: () => true } + }) + service.wakeGate.settled = () => automationSystemSettled(clock) + service.start() + await awakeFor(tickMs) + const statuses = () => store.listAutomationRuns(automation.id).map((run) => run.status) + return { store, automation, launch, service, statuses } + } + + it('does not start a missed run during a dark wake, then catches it up once awake and stable', async () => { + // A one-second tick runs the scheduler inside the two-second dark wake. + const { store, automation, launch, service, statuses } = await scheduledService({ + tickMs: 1_000 + }) + + // The machine sleeps through 09:00 and dark-wakes at 09:08:30 with no resume event. + clock.suspend() + asleepUntil('2026-11-09T09:08:30') + await awakeFor(2_000) + expect(statuses()).toEqual([]) + + // Back to sleep, then a full wake at 09:19:37. + asleepUntil('2026-11-09T09:19:37') + clock.resume() + await awakeFor(AUTOMATION_WAKE_SETTLE_MS - 1_000) + expect(statuses()).toEqual([]) + expect(launch).not.toHaveBeenCalled() + + await awakeFor(2_000) + await vi.waitFor(() => expect(statuses()).toEqual(['dispatched'])) + expect(store.listAutomationRuns(automation.id)[0]!.scheduledFor).toBe( + new Date('2026-11-09T09:00:00').getTime() + ) + expect(launch).toHaveBeenCalledOnce() + service.stop() + }) + + it('does not let the wait after a wake use up a zero-minute grace', async () => { + const { store, automation, service, statuses } = await scheduledService({ graceMinutes: 0 }) + + // Without the wait, the 09:01:01 tick would have launched this run inside its grace. + clock.suspend() + asleepUntil('2026-11-09T09:00:01') + clock.resume() + await awakeFor(TICK_MS) + expect(statuses()).toEqual([]) + + await awakeFor(TICK_MS) + await vi.waitFor(() => expect(statuses()).toEqual(['dispatched'])) + expect(store.listAutomationRuns(automation.id)[0]!.scheduledFor).toBe( + new Date('2026-11-09T09:00:00').getTime() + ) + service.stop() + }) + + /** Holds today's 09:00 zero-grace occurrence: resume at 09:00:01, held by the 09:01:01 tick. */ + async function holdZeroGraceOccurrence() { + clock.suspend() + asleepUntil('2026-11-09T09:00:01') + clock.resume() + await awakeFor(TICK_MS) + } + + /** A run of yesterday's occurrence, still open so its completion lands during a hold. */ + async function priorDispatchedRun( + store: Awaited>['store'], + service: AutomationService, + automationId: string + ) { + const automation = store.listAutomations().find((entry) => entry.id === automationId)! + const run = store.createAutomationRun(automation, new Date('2026-11-08T09:00:00').getTime()) + await service.markDispatchResult({ + runId: run.id, + status: 'dispatched', + workspaceId: 'r1::wt1', + terminalSessionId: 'tab-0', + terminalPtyId: 'pty-0' + }) + return run + } + + const updatedAt = ( + store: Awaited>['store'], + automationId: string + ) => store.listAutomations().find((entry) => entry.id === automationId)!.updatedAt + + it('keeps a held occurrence when an earlier run completes during the hold', async () => { + const { store, automation, launch, service } = await scheduledService({ graceMinutes: 0 }) + const prior = await priorDispatchedRun(store, service, automation.id) + const todays = () => + store + .listAutomationRuns(automation.id) + .filter((run) => run.id !== prior.id) + .map((run) => run.status) + + await holdZeroGraceOccurrence() + expect(todays()).toEqual([]) + const heldUpdatedAt = updatedAt(store, automation.id) + // 09:01:31: the completion watcher reports the earlier run, which also writes its usage. + await awakeFor(TICK_MS / 2) + await service.markDispatchResult({ runId: prior.id, status: 'completed' }) + expect(updatedAt(store, automation.id)).not.toBe(heldUpdatedAt) + + await awakeFor(TICK_MS / 2) + await vi.waitFor(() => expect(todays()).toEqual(['dispatched'])) + expect(launch).toHaveBeenCalledOnce() + service.stop() + }) + + it.each([ + ['a user pause', 'user'], + ['an ownership disable', 'ownership'] + ] as const)( + 'does not keep a held occurrence across %s and re-enable in the same millisecond', + async (_label, disabledBy) => { + const { store, automation, launch, service, statuses } = await scheduledService({ + graceMinutes: 0 + }) + + await holdZeroGraceOccurrence() + const held = store.listAutomations().find((entry) => entry.id === automation.id)! + const at = Date.now() + if (disabledBy === 'user') { + store.updateAutomation(automation.id, { enabled: false }) + } else { + store.disableAutomations(new Set([automation.id])) + } + store.updateAutomation(automation.id, { enabled: true }) + expect(Date.now()).toBe(at) + const restored = store.listAutomations().find((entry) => entry.id === automation.id)! + for (const key of [ + 'enabled', + 'rrule', + 'dtstart', + 'timezone', + 'missedRunPolicy', + 'missedRunGraceMinutes', + 'nextRunAt' + ] as const) { + expect(restored[key]).toEqual(held[key]) + } + + await awakeFor(TICK_MS) + await vi.waitFor(() => expect(statuses()).toEqual(['skipped_missed'])) + expect(launch).not.toHaveBeenCalled() + service.stop() + } + ) + } +) diff --git a/src/main/automations/automation-wake-settle.ts b/src/main/automations/automation-wake-settle.ts new file mode 100644 index 00000000000..19d762a7536 --- /dev/null +++ b/src/main/automations/automation-wake-settle.ts @@ -0,0 +1,101 @@ +import { getSystemAwakeClock, type AwakeClock } from '../power/awake-clock' +import type { Store } from '../persistence/loading-store/store' +import { missedBeyondGrace } from './dispatch-refusal' +import type { Automation } from '../../shared/automations/automation-definition' + +/** How long the machine must stay awake after a wake before scheduled runs start. A dark wake + * (macOS maintenance or Power Nap) lasts seconds, so a run never starts inside one only to have + * its agent frozen mid-start when the machine sleeps again. + * Known limits: wakes repeatedly shorter than this defer scheduling until one lasts; a fresh + * process has no wake history and starts settled; an App Nap-sized stall counts as a wake. */ +export const AUTOMATION_WAKE_SETTLE_MS = 2 * 60_000 + +/** Whether scheduled automation runs may start now. */ +export function automationSystemSettled(clock: AwakeClock = getSystemAwakeClock()): boolean { + return clock.settled(AUTOMATION_WAKE_SETTLE_MS) +} + +type HoldStore = Pick< + Store, + 'listAutomations' | 'getLatestAutomationOccurrence' | 'automationEnablementRevision' +> + +/** The eligibility a hold was granted under: the fields that decide whether and when the + * occurrence may run, plus the store's count of enable/disable transitions, so a pause and + * re-enable revokes the hold even when it restores every field within one millisecond. + * Not `updatedAt`: run completion, usage and retention bookkeeping move it on unchanged + * definitions. A rename or other non-eligibility edit keeps the hold. */ +function eligibilityRevision( + store: Pick, + automation: Automation +): string { + return JSON.stringify([ + store.automationEnablementRevision(automation.id), + automation.enabled, + automation.rrule, + automation.dtstart, + automation.timezone, + automation.missedRunPolicy, + automation.missedRunGraceMinutes + ]) +} + +/** Holds scheduled runs while the system is not settled. It remembers each due occurrence a held + * tick would have launched inside its missed-run grace, so the settled tick that finally + * evaluates it does not count the gate's own delay against that grace. A hold is bound to the + * eligibility it was granted under: once the user changes the schedule or grace, or pauses the + * automation, the current definition's own grace decides. */ +export class AutomationWakeGate { + /** False while asleep, in a dark wake, or just woken. */ + settled: () => boolean = () => true + private readonly held = new Map() + + /** Read lazily: the owning service assigns its store after constructing this gate. */ + constructor(private readonly holdStore: () => Pick) {} + + admits(store: HoldStore, tickMs: number): boolean { + const automations = store.listAutomations() + // Why: each settled() read keeps the awake clock's heartbeat running. With nothing enabled + // there is nothing to hold, so the heartbeat can idle out. Limit: the first read after one is + // enabled has no gap evidence from before it, like a fresh process. + if (!automations.some((automation) => automation.enabled) || this.settled()) { + return true + } + const now = Date.now() + for (const automation of automations) { + if (!automation.enabled || automation.nextRunAt > now) { + continue + } + try { + const scheduledFor = store.getLatestAutomationOccurrence(automation, now) + if ( + scheduledFor !== null && + !missedBeyondGrace({ automation, scheduledFor, now, tickMs }) + ) { + this.held.set(automation.id, { + scheduledFor, + revision: eligibilityRevision(store, automation) + }) + } + } catch { + // A malformed schedule is recorded by the settled tick's own evaluation. + } + } + return false + } + + /** `missedBeyondGrace`, except an occurrence this gate held while in grace stays eligible + * while its definition is unchanged. */ + missedBeyondGrace(input: Parameters[0]): boolean { + const hold = this.held.get(input.automation.id) + const held = + hold !== undefined && + hold.scheduledFor === input.scheduledFor && + hold.revision === eligibilityRevision(this.holdStore(), input.automation) + return !held && missedBeyondGrace(input) + } + + clear(): void { + this.held.clear() + } +} diff --git a/src/main/automations/runtime-automation-service.ts b/src/main/automations/runtime-automation-service.ts index 28b35e2fe05..3a8f4b8d796 100644 --- a/src/main/automations/runtime-automation-service.ts +++ b/src/main/automations/runtime-automation-service.ts @@ -22,6 +22,7 @@ import { } from './runtime-terminal-run-observer' import { closeEarlierHookReviewRunTerminals } from './hook-review-blocked-run-terminals' import { automationRunSetupSkip } from './automation-run-setup-skip' +import { automationSystemSettled } from './automation-wake-settle' const MAX_REMEMBERED_LAUNCHES = 256 @@ -204,6 +205,7 @@ export function createRuntimeAutomationService(input: { }, runTerminalRetention: (owner) => createRuntimeRunTerminalRetention(owner, store, runtime) }) + service.wakeGate.settled = () => automationSystemSettled() runtime.setAutomationService(service) return service } diff --git a/src/main/automations/service.ts b/src/main/automations/service.ts index 57d647710a6..68a601cf861 100644 --- a/src/main/automations/service.ts +++ b/src/main/automations/service.ts @@ -30,12 +30,12 @@ import { createAutomationRunWriter, type AutomationRunWriter } from './automatio import { reportAutomationScheduleDrift } from './schedule-drift-report' import { describeScheduledTickRefusal, - missedBeyondGrace, recordMissedRun, recordRefusedAutomationRun, recordUnevaluableAutomation } from './dispatch-refusal' import type { RunTerminalRetention } from './run-terminal-retention' +import { AutomationWakeGate } from './automation-wake-settle' import type { AutomationsChangedPayload, PublishAutomationsChanged @@ -63,6 +63,7 @@ export class AutomationService { private readonly completionWatcher: AutomationRunCompletionWatcher | null /** Desktop automation traffic holds this lease to defer queued external probes. */ externalProbePriority: ((run: () => T) => T) | null = null + readonly wakeGate = new AutomationWakeGate(() => this.store) constructor( store: Store, @@ -216,7 +217,8 @@ export class AutomationService { } private async evaluateDueRuns(): Promise { - if (this.evaluating || this.stopped) { + // A run started in a dark wake is cut off by the next sleep. + if (this.evaluating || this.stopped || !this.wakeGate.admits(this.store, this.tickMs)) { return } this.evaluating = true @@ -249,6 +251,7 @@ export class AutomationService { } } finally { this.evaluating = false + this.wakeGate.clear() } } @@ -260,7 +263,7 @@ export class AutomationService { await this.runs.advanceNextRun(automation.id, now) return } - if (missedBeyondGrace({ automation, scheduledFor, now, tickMs: this.tickMs })) { + if (this.wakeGate.missedBeyondGrace({ automation, scheduledFor, now, tickMs: this.tickMs })) { await recordMissedRun({ runs: this.runs, automation, scheduledFor }) await this.runs.advanceNextRun(automation.id, now) return diff --git a/src/main/browser/agent-browser/command-queue/agent-browser-bridge-queue.ts b/src/main/browser/agent-browser/command-queue/agent-browser-bridge-queue.ts index eafd92c5188..5b4969e02da 100644 --- a/src/main/browser/agent-browser/command-queue/agent-browser-bridge-queue.ts +++ b/src/main/browser/agent-browser/command-queue/agent-browser-bridge-queue.ts @@ -20,7 +20,7 @@ import { captureRemoteCliBrowserScope, runOutsideRemoteCliBrowserScope } from '../../../runtime/desktop-browser-bridge/remote-cli-browser-scope' -import { getActiveRpcCaller } from '../../../runtime/rpc/rpc-active-caller' +import { captureActiveRpcCall, getActiveRpcCaller } from '../../../runtime/rpc/rpc-active-caller' export abstract class AgentBrowserBridgeQueue extends AgentBrowserBridgeActionEffects { // Serialize tab switches behind commands targeting the current tab. @@ -97,8 +97,10 @@ export abstract class AgentBrowserBridgeQueue extends AgentBrowserBridgeActionEf assertNoJavaScriptDialog(webContentsId, pageId, assertNotRevoked) const sessionName = `${ORCA_TAB_SESSION_PREFIX}${pageId}` const agentCommand = this.browserManager.beginAgentCommand(pageId) - // Queued commands run under the caller ahead of them, so read this one's caller now. + // Queued commands run under the caller ahead of them, so read this one's caller now + // and re-enter its call, or what it marks would count as that other chat's. const caller = getActiveRpcCaller() + const inThisCall = captureActiveRpcCall() // Decided at enqueue: a queued command runs under the caller of the command ahead of it. const reportEffects = options.reportEffects === true && agentCommand.agent const expectedUrl = getRequestedPageUrl() @@ -167,10 +169,12 @@ export abstract class AgentBrowserBridgeQueue extends AgentBrowserBridgeActionEf }, options ) - return origin.run(() => { - started = true - return this.browserManager.runPageCommand(pageId, caller, () => agentCommand.run(run)) - }) + return inThisCall(() => + origin.run(() => { + started = true + return this.browserManager.runPageCommand(pageId, caller, () => agentCommand.run(run)) + }) + ) }, resolve: resolve as (value: unknown) => void, reject diff --git a/src/main/browser/agent-browser/session-routing/agent-browser-bridge-tab-routing.test.ts b/src/main/browser/agent-browser/session-routing/agent-browser-bridge-tab-routing.test.ts index ce28eaa77df..7f8838bd535 100644 --- a/src/main/browser/agent-browser/session-routing/agent-browser-bridge-tab-routing.test.ts +++ b/src/main/browser/agent-browser/session-routing/agent-browser-bridge-tab-routing.test.ts @@ -59,6 +59,10 @@ vi.mock('../../cdp/commands/cdp-bridge', async () => { }) import { AgentBrowserBridge } from '../agent-browser-bridge' +import { + getActiveRpcAgentSessionId, + runWithActiveRpcCaller +} from '../../../runtime/rpc/rpc-active-caller' import { answerAgentBrowserCommands, mockBrowserManager, @@ -125,4 +129,51 @@ describe('AgentBrowserBridge', () => { await b.click('@e2', 'wt-1') expect(clickSessions).toEqual(['orca-tab-tab-a', 'orca-tab-tab-b']) }) + + it("marks a tab switch queued behind another chat's command as the switching chat's", async () => { + const chatA = '11111111-1111-4111-8111-111111111111' + const chatB = '22222222-2222-4222-8222-222222222222' + const tabs = new Map([ + ['tab-a', 1], + ['tab-b', 2] + ]) + const worktrees = new Map([ + ['tab-a', 'wt-1'], + ['tab-b', 'wt-1'] + ]) + const wc1 = mockWebContents(1) + const wc2 = mockWebContents(2) + webContentsFromIdMock.mockImplementation((id: number) => (id === 1 ? wc1 : wc2)) + const marks: [string, string | undefined][] = [] + const b = new AgentBrowserBridge( + mockBrowserManager(tabs, worktrees, { + beginAgentCommand: (pageId: string) => { + marks.push([pageId, getActiveRpcAgentSessionId()]) + return { agent: true, run: (execute) => execute(), end: () => {} } + } + }) + ) + b.setActiveTab(1, 'wt-1') + const held: { releaseA?: () => void } = {} + answerAgentBrowserCommands(execFileMock, stdinWrites, (_command, cb) => { + const answer = (): void => + cb(null, JSON.stringify({ success: true, data: { snapshot: '' } }), '') + if (held.releaseA) { + answer() + } else { + held.releaseA = answer + } + }) + const inChat = (chat: string, run: () => T): T => + runWithActiveRpcCaller({ kind: 'local-cli' }, run, chat) + + const snapshot = inChat(chatA, () => b.snapshot('wt-1')) + await vi.waitFor(() => expect(execFileMock).toHaveBeenCalled()) + const tabSwitch = inChat(chatB, () => b.tabSwitch(undefined, 'wt-1', 'tab-b')) + held.releaseA?.() + await Promise.all([snapshot, tabSwitch]) + + expect(marks).toContainEqual(['tab-b', chatB]) + expect(marks).not.toContainEqual(['tab-b', chatA]) + }) }) diff --git a/src/main/browser/cdp/commands/cdp-screenshot.ts b/src/main/browser/cdp/commands/cdp-screenshot.ts index f43f5c1e194..76cc4726365 100644 --- a/src/main/browser/cdp/commands/cdp-screenshot.ts +++ b/src/main/browser/cdp/commands/cdp-screenshot.ts @@ -1,4 +1,8 @@ -import type { CapturePaintHold } from '../debugger/guest-paint-hold' +import { + holdPaintUntilCdpCaptureSettles, + holdPaintUntilSettled, + type CapturePaintHold +} from '../debugger/guest-paint-hold' import type { WebContents } from 'electron' import { sendGuestCdpCommand } from '../debugger/guest-cdp-command' import { @@ -137,7 +141,8 @@ export function withTimeout( // Undrawn pages can leave captures pending; cheap probes trigger a frame for the original request. function captureUntilDrawn( webContents: WebContents, - params: Record + params: Record, + holdPaint: CapturePaintHold ): Promise<{ data: string } | null> { return new Promise((resolve, reject) => { let settled = false @@ -173,12 +178,12 @@ function captureUntilDrawn( } catch { // Guest teardown can reject repaint requests; still try CDP. } - return sendGuestCdpCommand(webContents, 'Page.captureScreenshot', requestParams).then( - (result) => { - const data = isRecord(result) ? result.data : undefined - return typeof data === 'string' ? { data } : undefined - } - ) + return holdPaintUntilCdpCaptureSettles(webContents, holdPaint, () => + sendGuestCdpCommand(webContents, 'Page.captureScreenshot', requestParams) + ).then((result) => { + const data = isRecord(result) ? result.data : undefined + return typeof data === 'string' ? { data } : undefined + }) } const deadline = setTimeout(() => finish(() => resolve(null)), SCREENSHOT_TIMEOUT_MS) let probes: NodeJS.Timeout[] = [] @@ -223,11 +228,15 @@ export async function captureFullPageScreenshot( if (!clip) { throw new Error('Unable to determine full-page screenshot bounds') } - const frame = await captureUntilDrawn(webContents, { - format, - captureBeyondViewport: true, - clip - }) + const frame = await captureUntilDrawn( + webContents, + { + format, + captureBeyondViewport: true, + clip + }, + holdPaint + ) if (!frame) { throw new Error(SCREENSHOT_TIMEOUT_MESSAGE) } @@ -269,13 +278,13 @@ export async function captureScreenshot( const release = holdPaint() try { - const frame = await captureUntilDrawn(webContents, screenshotParams) + const frame = await captureUntilDrawn(webContents, screenshotParams, holdPaint) if (frame) { return frame } const fallback = await readRemoteCliAdmittedPage(webContents.id, () => withTimeout( - Promise.resolve().then(() => webContents.capturePage()), + holdPaintUntilSettled(holdPaint, () => webContents.capturePage()), FALLBACK_CAPTURE_TIMEOUT_MS, SCREENSHOT_TIMEOUT_MESSAGE ) diff --git a/src/main/browser/cdp/debugger/guest-paint-hold.ts b/src/main/browser/cdp/debugger/guest-paint-hold.ts index 885a3e98a84..c235cf72541 100644 --- a/src/main/browser/cdp/debugger/guest-paint-hold.ts +++ b/src/main/browser/cdp/debugger/guest-paint-hold.ts @@ -1,2 +1,41 @@ +import type { WebContents } from 'electron' +import { acquireElectronDebugger } from './electron-debugger-lease' + /** Draws a hidden guest while a capture or agent input needs its frames; returns its release. */ export type CapturePaintHold = () => () => void + +function retainUntilSettled(acquire: () => () => void, run: () => Promise): Promise { + let release: () => void + try { + release = acquire() + } catch (error) { + return Promise.reject(error) + } + const pending = new Promise((resolve) => resolve(run())) + void pending.then(release, release) + return pending +} + +/** + * Holds paint until Chromium answers the capture, not just while the caller waits. A capture stays + * pending until the guest draws, and while pending it can hold macOS display sleep off ("Capturing"); + * timeouts do not cancel it (#24946). + */ +export function holdPaintUntilSettled( + holdPaint: CapturePaintHold, + capture: () => Promise +): Promise { + return retainUntilSettled(holdPaint, capture) +} + +/** Also keeps the debugger attached: a detach rejects the command while Chromium keeps the capture. */ +export function holdPaintUntilCdpCaptureSettles( + webContents: WebContents, + holdPaint: CapturePaintHold, + capture: () => Promise +): Promise { + return retainUntilSettled( + () => acquireElectronDebugger(webContents).release, + () => retainUntilSettled(holdPaint, capture) + ) +} diff --git a/src/main/browser/cdp/screencast/browser-screencast-first-frame-timeout.test.ts b/src/main/browser/cdp/screencast/browser-screencast-first-frame-timeout.test.ts index 797f2ff07a5..8129fb06766 100644 --- a/src/main/browser/cdp/screencast/browser-screencast-first-frame-timeout.test.ts +++ b/src/main/browser/cdp/screencast/browser-screencast-first-frame-timeout.test.ts @@ -24,6 +24,7 @@ function startOptions(viewport: boolean) { maxHeight: 1200, everyNthFrame: 2, minFrameIntervalMs: 0, + holdPaint: () => () => {}, ...(viewport ? { viewportWidth: 390, viewportHeight: 844 } : {}), onFrame: vi.fn(() => true), onError: vi.fn() @@ -59,6 +60,49 @@ describe('browser screencast first-frame deadline', () => { await session.done }) + it('keeps the page drawable until Chromium answers the captures the stream gave up on', async () => { + let settleCapture!: (image: unknown) => void + const webContents = Object.assign(createMockScreencastWebContents(), { + capturePage: vi.fn( + () => + new Promise((resolve) => { + settleCapture = resolve + }) + ) + }) + let settleScreenshot!: (result: unknown) => void + let rejectScreenshot!: (error: Error) => void + webContents.debugger.sendCommand.mockImplementation(async (method: string) => + method === 'Page.captureScreenshot' + ? new Promise((resolve, reject) => { + settleScreenshot = resolve + rejectScreenshot = reject + }) + : {} + ) + // Electron rejects pending commands on detach, but Chromium keeps the capture. + webContents.debugger.detach.mockImplementation(() => + rejectScreenshot(new Error('target closed while handling command')) + ) + const releasePaint = vi.fn() + const options = { ...startOptions(true), holdPaint: vi.fn(() => releasePaint) } + const session = await start(webContents, options) + + // capturePage's 10 s bound, then the CDP fallback's 8 s. + await vi.advanceTimersByTimeAsync(18_000) + session.stop() + await session.done + expect(options.holdPaint).toHaveBeenCalledTimes(2) + expect(webContents.debugger.detach).not.toHaveBeenCalled() + expect(releasePaint).not.toHaveBeenCalled() + + settleCapture({ getSize: () => ({ width: 0, height: 0 }) }) + settleScreenshot({}) + await vi.advanceTimersByTimeAsync(0) + expect(releasePaint).toHaveBeenCalledTimes(2) + expect(webContents.debugger.detach).toHaveBeenCalledOnce() + }) + it('drops a capture that settles after the limit', async () => { let settleCapture!: (image: unknown) => void const webContents = Object.assign(createMockScreencastWebContents(), { diff --git a/src/main/browser/cdp/screencast/browser-screencast-guest-view-limit.test.ts b/src/main/browser/cdp/screencast/browser-screencast-guest-view-limit.test.ts index 5968bf42069..a07487bfd5b 100644 --- a/src/main/browser/cdp/screencast/browser-screencast-guest-view-limit.test.ts +++ b/src/main/browser/cdp/screencast/browser-screencast-guest-view-limit.test.ts @@ -70,6 +70,7 @@ async function startOversizedStream(guest: ReturnType, onFra deviceScaleFactor: 2, everyNthFrame: 1, minFrameIntervalMs: 0, + holdPaint: () => () => {}, onFrame }) } diff --git a/src/main/browser/cdp/screencast/browser-screencast-lifecycle.test.ts b/src/main/browser/cdp/screencast/browser-screencast-lifecycle.test.ts index 09889e723c7..4443f28f7e3 100644 --- a/src/main/browser/cdp/screencast/browser-screencast-lifecycle.test.ts +++ b/src/main/browser/cdp/screencast/browser-screencast-lifecycle.test.ts @@ -35,6 +35,7 @@ describe('browser screencast lifecycle', () => { maxHeight: 2160, everyNthFrame: 2, minFrameIntervalMs: 0, + holdPaint: () => () => {}, onFrame }) @@ -80,6 +81,7 @@ describe('browser screencast lifecycle', () => { maxHeight: 1200, everyNthFrame: 2, minFrameIntervalMs: 0, + holdPaint: () => () => {}, onFrame: vi.fn() }, isClosed: () => false, diff --git a/src/main/browser/cdp/screencast/browser-screencast-live-frame-allocation.test.ts b/src/main/browser/cdp/screencast/browser-screencast-live-frame-allocation.test.ts index 0d61e942a80..86185d11b0b 100644 --- a/src/main/browser/cdp/screencast/browser-screencast-live-frame-allocation.test.ts +++ b/src/main/browser/cdp/screencast/browser-screencast-live-frame-allocation.test.ts @@ -40,6 +40,7 @@ function createLiveFrameRoute( maxHeight: 1200, everyNthFrame: 2, minFrameIntervalMs: 0, + holdPaint: () => () => {}, onFrame } const isClosed = () => false diff --git a/src/main/browser/cdp/screencast/browser-screencast-snapshot-capture.ts b/src/main/browser/cdp/screencast/browser-screencast-snapshot-capture.ts index 733a4cb542a..b9b3c1f037d 100644 --- a/src/main/browser/cdp/screencast/browser-screencast-snapshot-capture.ts +++ b/src/main/browser/cdp/screencast/browser-screencast-snapshot-capture.ts @@ -1,7 +1,11 @@ import { Buffer } from 'node:buffer' import type { Debugger, WebContents } from 'electron' import { readBrowserScreencastImageSize } from './browser-screencast-image-size' -import { sendDebuggerCommand } from './browser-screencast-debugger-command' +import { runDebuggerCommandWithTimeout } from './browser-screencast-debugger-command' +import { + holdPaintUntilCdpCaptureSettles, + holdPaintUntilSettled +} from '../debugger/guest-paint-hold' import type { BrowserScreencastOptions, PendingScreencastFrame @@ -35,6 +39,7 @@ export function createBrowserScreencastSnapshotCapture( ): BrowserScreencastSnapshotCapture { const { webContents, dbg, options, isClosed, isStopping, getSeq, queueFrame } = deps const { applyDeviceMetricsOverride } = deps + const { holdPaint } = options let snapshotGeneration = 0 let navigationCaptureTimer: ReturnType | null = null @@ -81,7 +86,9 @@ export function createBrowserScreencastSnapshotCapture( try { // Prefer capturePage to avoid CDP tiling; stopped compositing can leave it pending. const nativeImage = await withTimeout( - webContents.capturePage({ x: 0, y: 0, width: viewportWidth, height: viewportHeight }), + holdPaintUntilSettled(holdPaint, () => + webContents.capturePage({ x: 0, y: 0, width: viewportWidth, height: viewportHeight }) + ), SNAPSHOT_CAPTURE_TIMEOUT_MS, null ) @@ -101,7 +108,7 @@ export function createBrowserScreencastSnapshotCapture( } } if (!image) { - const result = await sendDebuggerCommand(dbg, 'Page.captureScreenshot', { + const screenshotParams = { format: options.format, ...(options.format === 'jpeg' ? { quality: options.quality } : {}), ...(viewportWidth && viewportHeight @@ -117,7 +124,12 @@ export function createBrowserScreencastSnapshotCapture( } : {}), captureBeyondViewport: false - }) + } + const result = await runDebuggerCommandWithTimeout('Page.captureScreenshot', () => + holdPaintUntilCdpCaptureSettles(webContents, holdPaint, () => + dbg.sendCommand('Page.captureScreenshot', screenshotParams) + ) + ) if (isSnapshotStale(initialOnly, generation)) { return } diff --git a/src/main/browser/cdp/screencast/browser-screencast-stream-types.ts b/src/main/browser/cdp/screencast/browser-screencast-stream-types.ts index 0676e970411..666bba266b2 100644 --- a/src/main/browser/cdp/screencast/browser-screencast-stream-types.ts +++ b/src/main/browser/cdp/screencast/browser-screencast-stream-types.ts @@ -2,6 +2,7 @@ import type { BrowserScreencastFormat, BrowserScreencastFrameMetadata } from '../../../../shared/browser/screencast/browser-screencast-protocol' +import type { CapturePaintHold } from '../debugger/guest-paint-hold' export type BrowserScreencastOptions = { format: BrowserScreencastFormat @@ -17,6 +18,7 @@ export type BrowserScreencastOptions = { onFrame: (bytes: Uint8Array) => boolean | void onEvent?: (event: BrowserScreencastEvent) => void onError?: (message: string) => void + holdPaint: CapturePaintHold } export type BrowserScreencastViewport = Pick< diff --git a/src/main/browser/cdp/screencast/browser-screencast-stream.test.ts b/src/main/browser/cdp/screencast/browser-screencast-stream.test.ts index 6870a27f172..456ff1f213c 100644 --- a/src/main/browser/cdp/screencast/browser-screencast-stream.test.ts +++ b/src/main/browser/cdp/screencast/browser-screencast-stream.test.ts @@ -27,6 +27,7 @@ describe('startBrowserScreencast', () => { maxHeight: 1200, everyNthFrame: 1, minFrameIntervalMs: 0, + holdPaint: () => () => {}, onFrame }) @@ -84,6 +85,7 @@ describe('startBrowserScreencast', () => { maxHeight: 1200, everyNthFrame: 1, minFrameIntervalMs: 100, + holdPaint: () => () => {}, onFrame }) @@ -136,6 +138,7 @@ describe('startBrowserScreencast', () => { maxHeight: 1200, everyNthFrame: 2, minFrameIntervalMs: 0, + holdPaint: () => () => {}, onFrame: vi.fn(), onEvent }) diff --git a/src/main/browser/desktop-browser-bridge/desktop-browser-bridge-executor.ts b/src/main/browser/desktop-browser-bridge/desktop-browser-bridge-executor.ts index abff471a47b..888cdbb736a 100644 --- a/src/main/browser/desktop-browser-bridge/desktop-browser-bridge-executor.ts +++ b/src/main/browser/desktop-browser-bridge/desktop-browser-bridge-executor.ts @@ -256,22 +256,3 @@ function urlOrigin(value: unknown): string | null { return null } } - -// Routed tabs can still display local files; those remain off-limits to hosts. -// Allow chrome-error: so hosts can navigate away from failed loads. -const HOST_REACHABLE_DOCUMENT_PROTOCOLS = new Set([ - 'http:', - 'https:', - 'about:', - 'blob:', - 'data:', - 'chrome-error:' -]) - -export function isHostReachableDocument(url: string): boolean { - try { - return HOST_REACHABLE_DOCUMENT_PROTOCOLS.has(new URL(url).protocol) - } catch { - return url === '' - } -} diff --git a/src/main/browser/extensions/browser-extension-management.ts b/src/main/browser/extensions/browser-extension-management.ts index fda54bc4fde..0ff29fd1a80 100644 --- a/src/main/browser/extensions/browser-extension-management.ts +++ b/src/main/browser/extensions/browser-extension-management.ts @@ -48,7 +48,7 @@ import { notifyChromeWebStoreUninstalled } from './web-store/browser-extension-w async function settle(action: () => Promise): Promise { if (!isBrowserExtensionSupportEnabled()) { - return { ok: false, error: 'Turn on browser extensions in Settings › Experimental' } + return { ok: false, error: 'Turn on browser extensions in Settings › Browser › Extensions' } } try { await action() diff --git a/src/main/browser/extensions/browser-extension-startup.ts b/src/main/browser/extensions/browser-extension-startup.ts index d388a50d1e7..1cde1e52549 100644 --- a/src/main/browser/extensions/browser-extension-startup.ts +++ b/src/main/browser/extensions/browser-extension-startup.ts @@ -56,7 +56,7 @@ export function initializeBrowserExtensionSupport(options: { } /** - * The experimental setting changed while Orca runs. Off unloads every profile's extensions and + * The extensions setting changed while Orca runs. Off unloads every profile's extensions and * keeps their data; on loads them into every open profile, as a launch would. */ export function switchBrowserExtensionSupport(enabled: boolean): Promise { diff --git a/src/main/browser/extensions/browser-extension-support.ts b/src/main/browser/extensions/browser-extension-support.ts index e1237fa7f6a..ff7739b7a44 100644 --- a/src/main/browser/extensions/browser-extension-support.ts +++ b/src/main/browser/extensions/browser-extension-support.ts @@ -1,4 +1,4 @@ -// Why a live flag: the experimental setting turns extensions on and off without a restart, so +// Why a live flag: the Settings switch turns extensions on and off without a restart, so // every entry point asks at call time. let supportEnabled = false diff --git a/src/main/browser/extensions/profile-sessions/browser-extension-session-loader.ts b/src/main/browser/extensions/profile-sessions/browser-extension-session-loader.ts index 580ff9a83e6..650161fd82e 100644 --- a/src/main/browser/extensions/profile-sessions/browser-extension-session-loader.ts +++ b/src/main/browser/extensions/profile-sessions/browser-extension-session-loader.ts @@ -181,7 +181,7 @@ export async function detachBrowserExtensionsFromProfileSession( getBrowserExtensionDnrStore().forgetProfile(profile.id) } -/** The experimental setting turned off: every profile drops its extensions until it turns on. */ +/** The extensions setting turned off: every profile drops its extensions until it turns on. */ export async function detachBrowserExtensionsFromAllProfileSessions(): Promise { const states = [...stateByProfileId.values()] stateByProfileId.clear() diff --git a/src/main/browser/extensions/web-store/browser-extension-webstore-service.ts b/src/main/browser/extensions/web-store/browser-extension-webstore-service.ts index 1052b409ed7..877495b7048 100644 --- a/src/main/browser/extensions/web-store/browser-extension-webstore-service.ts +++ b/src/main/browser/extensions/web-store/browser-extension-webstore-service.ts @@ -131,7 +131,10 @@ export async function installBrowserExtensionFromWebStore( renderer: Electron.WebContents ): Promise { if (!isBrowserExtensionSupportEnabled()) { - return { status: 'failed', error: 'Turn on browser extensions in Settings › Experimental' } + return { + status: 'failed', + error: 'Turn on browser extensions in Settings › Browser › Extensions' + } } const extensionId = parseChromeWebStoreExtensionInput(input) if (!extensionId) { diff --git a/src/main/browser/guest-lifecycle/page-activity/browser-agent-activity.test.ts b/src/main/browser/guest-lifecycle/page-activity/browser-agent-activity.test.ts index 8a2148e204f..d11c363277f 100644 --- a/src/main/browser/guest-lifecycle/page-activity/browser-agent-activity.test.ts +++ b/src/main/browser/guest-lifecycle/page-activity/browser-agent-activity.test.ts @@ -90,6 +90,18 @@ describe('BrowserAgentActivity', () => { expect(sent).toEqual([]) }) + it("names the chat whose agent's CLI sent the command", () => { + const { activity, sent } = setup() + const chat = '11111111-1111-4111-8111-111111111111' + runWithActiveRpcCaller({ kind: 'local-cli' }, () => activity.beginCommand(PAGE), chat).end() + expect(sent.at(-1)?.data).toEqual({ + browserPageId: PAGE, + worktreeId: 'wt-1', + active: true, + agentSessionId: chat + }) + }) + it('clears the mark once the agent stays idle, and at once when the page closes', () => { const { activity, sent, agentCommand } = setup() agentCommand().end() diff --git a/src/main/browser/guest-lifecycle/page-activity/browser-agent-activity.ts b/src/main/browser/guest-lifecycle/page-activity/browser-agent-activity.ts index b698b215aab..33bd6cf2ef6 100644 --- a/src/main/browser/guest-lifecycle/page-activity/browser-agent-activity.ts +++ b/src/main/browser/guest-lifecycle/page-activity/browser-agent-activity.ts @@ -9,7 +9,10 @@ import { type BrowserAgentActivityEvent, type BrowserAgentCursorEvent } from '../../../../shared/browser-agent-activity-contract' -import { getActiveRpcCaller } from '../../../runtime/rpc/rpc-active-caller' +import { + getActiveRpcAgentSessionId, + getActiveRpcCaller +} from '../../../runtime/rpc/rpc-active-caller' import { remoteCliBrowserScopeController, type RemoteCliBrowserController @@ -35,6 +38,8 @@ type PageActivity = { idleTimer: ReturnType | null /** The SSH host whose command marked the page last, if it came through the desktop bridge. */ controller: RemoteCliBrowserController | null + /** The chat whose agent marked the page last, when its CLI named one. */ + agentSessionId: string | undefined } /** One page-targeted command, held from when it is queued until it settles. */ @@ -80,12 +85,19 @@ export class BrowserAgentActivity { } let page = this.pages.get(browserPageId) if (!page) { - page = { commands: 0, executing: false, idleTimer: null, controller: null } + page = { + commands: 0, + executing: false, + idleTimer: null, + controller: null, + agentSessionId: undefined + } this.pages.set(browserPageId, page) } page.controller = remoteCliBrowserScopeController() ?? null + page.agentSessionId = getActiveRpcAgentSessionId() // Every command republishes, so a reloaded or newly attached window catches up. - this.publish(browserPageId, true, page.controller) + this.publish(browserPageId, true, page) if (page.idleTimer) { clearTimeout(page.idleTimer) page.idleTimer = null @@ -122,20 +134,22 @@ export class BrowserAgentActivity { /** The agent continues on another page (a closed popup's opener), so its claim moves there. */ handOver(fromPageId: string, toPageId: string): void { const existing = this.pages.get(toPageId) + const from = this.pages.get(fromPageId) // A running command restarts the idle window itself when it settles. - if (!this.pages.has(fromPageId) || (existing && existing.commands > 0)) { + if (!from || (existing && existing.commands > 0)) { return } const page = existing ?? { commands: 0, executing: false, idleTimer: null, - controller: this.pages.get(fromPageId)?.controller ?? null + controller: from.controller, + agentSessionId: from.agentSessionId } this.restartIdleWindow(toPageId, page) if (!existing) { this.pages.set(toPageId, page) - this.publish(toPageId, true, page.controller) + this.publish(toPageId, true, page) } } @@ -251,7 +265,7 @@ export class BrowserAgentActivity { private publish( browserPageId: string, active: boolean, - controller: RemoteCliBrowserController | null = null + { controller, agentSessionId }: Partial = {} ): void { const renderer = this.deps.rendererForPage(browserPageId) if (renderer && !renderer.isDestroyed()) { @@ -259,7 +273,8 @@ export class BrowserAgentActivity { browserPageId, worktreeId: this.deps.worktreeForPage(browserPageId), active, - ...(controller ? { controllerHostLabel: controller.hostLabel } : {}) + ...(controller ? { controllerHostLabel: controller.hostLabel } : {}), + ...(agentSessionId ? { agentSessionId } : {}) } renderer.send(BROWSER_AGENT_ACTIVITY_CHANNEL, event) } diff --git a/src/main/claude-accounts/claude-profile-provisioning.test.ts b/src/main/claude-accounts/claude-profile-provisioning.test.ts index 58b70c7aa23..98684a185df 100644 --- a/src/main/claude-accounts/claude-profile-provisioning.test.ts +++ b/src/main/claude-accounts/claude-profile-provisioning.test.ts @@ -131,18 +131,37 @@ describe('Claude profile refresh from the default home', () => { expect((await provision(f)).surfaces['settings.json']).toBe('user-owned') expect(f.read(elsewhere)).toEqual({ mine: true }) }) - it('copies state except the login, caches and install ids, and never copies credentials', async () => { + it('shares configuration while keeping profile runtime state and API authorizations private', async () => { const f = fixture() fs.writeFileSync(join(f.source, '.credentials.json'), 'SOURCE_CREDENTIAL_BYTES') const shared = { mcpServers: { local: { command: 'example' } }, theme: 'dark', hasCompletedOnboarding: true, - autoModeAccepted: true, + bypassPermissionsModeAccepted: true, + favoritePlugins: ['favorite@example'], + preferTmuxOverIterm2: true, + codeReviewLastEffort: 'high', + codeReviewLastMaxFindings: 3, + installMethod: 'global', + autoUpdates: false, + autoUpdatesProtectedForNative: false, + customApiKeyResponses: { rejected: ['PERSONAL_REJECTED_SUFFIX'] }, projects: { '/work': { hasTrustDialogAccepted: true } } } - f.json(join(f.userHome, '.claude.json'), { + const personal = { ...shared, + customApiKeyResponses: { + approved: ['PERSONAL_APPROVED_SUFFIX'], + rejected: ['PERSONAL_REJECTED_SUFFIX'] + }, + groveChoiceSeenAt: { personal: 1 }, + numStartups: 2, + tipsHistory: { tip: 1 }, + seenNotifications: { notice: 1 }, + penguinModeOrgEnabled: false, + futureRuntimeState: { personal: true }, + autoModeAccepted: true, oauthAccount: { emailAddress: 'source@example.com' }, primaryApiKey: 'sk-source', userID: 'source-id', @@ -150,7 +169,6 @@ describe('Claude profile refresh from the default home', () => { firstStartTime: 'source-start', firstStartVersion: '1.0.0', groveConfigCache: { a: 1 }, - groveChoiceSeenAt: { 'account-a': 99, 'account-b': 10 }, cachedArtifactRoster: [], clientDataCacheSlots: {}, passesEligibilityCache: {}, @@ -162,21 +180,32 @@ describe('Claude profile refresh from the default home', () => { lastSeenOrgDefaultUpdatedAt: 1, hasAvailableSubscription: true, subscriptionNoticeCount: 2 - }) + } + f.json(join(f.userHome, '.claude.json'), personal) expect((await provision(f)).surfaces['.claude.json']).toBe('synced') - expect(f.read(join(f.profileHome, '.claude.json'))).toEqual({ - ...shared, - groveChoiceSeenAt: { 'account-a': 99, 'account-b': 10 } - }) + expect(f.read(join(f.profileHome, '.claude.json'))).toEqual(shared) expect(fs.readdirSync(f.profileHome).filter((name) => name.endsWith('.tmp'))).toEqual([]) expect(fs.existsSync(join(f.profileHome, '.credentials.json'))).toBe(false) fs.writeFileSync(join(f.profileHome, '.credentials.json'), 'PROFILE_CREDENTIAL_BYTES') + const profileRuntime = { + groveChoiceSeenAt: { profile: 20 }, + numStartups: 30, + tipsHistory: { tip: 8 }, + seenNotifications: { profileNotice: 9 }, + penguinModeOrgEnabled: true, + futureRuntimeState: { profile: true }, + customApiKeyResponses: { + approved: ['PROFILE_APPROVED_SUFFIX', 'PERSONAL_REJECTED_SUFFIX'], + rejected: ['PROFILE_REJECTED_SUFFIX', 'PERSONAL_APPROVED_SUFFIX'], + profileOnly: true + } + } f.json(join(f.profileHome, '.claude.json'), { + ...profileRuntime, oauthAccount: { emailAddress: 'profile@example.com' }, userID: 'profile-id', groveConfigCache: { b: 2 }, - groveChoiceSeenAt: { 'account-a': 120, 'account-b': 5 }, theme: 'light', onlyHere: true }) @@ -185,11 +214,30 @@ describe('Claude profile refresh from the default home', () => { oauthAccount: { emailAddress: 'profile@example.com' }, userID: 'profile-id', groveConfigCache: { b: 2 }, - groveChoiceSeenAt: { 'account-a': 120, 'account-b': 10 }, onlyHere: true, - ...shared + ...shared, + ...profileRuntime, + hasCompletedOnboarding: true, + customApiKeyResponses: { + approved: ['PROFILE_APPROVED_SUFFIX', 'PERSONAL_REJECTED_SUFFIX'], + rejected: [ + 'PROFILE_REJECTED_SUFFIX', + 'PERSONAL_APPROVED_SUFFIX', + 'PERSONAL_REJECTED_SUFFIX' + ], + profileOnly: true + } + }) + const reset = { ...f.read(join(f.profileHome, '.claude.json')), hasCompletedOnboarding: false } + f.json(join(f.profileHome, '.claude.json'), reset) + f.json(join(f.userHome, '.claude.json'), { + ...personal, + numStartups: 1000, + groveChoiceSeenAt: { personal: 1000 }, + futureRuntimeState: { changed: true } }) expect((await provision(f)).surfaces['.claude.json']).toBe('unchanged') + expect(f.read(join(f.profileHome, '.claude.json'))).toEqual(reset) expect(fs.readFileSync(join(f.source, '.credentials.json'), 'utf8')).toBe( 'SOURCE_CREDENTIAL_BYTES' ) @@ -202,7 +250,13 @@ describe('Claude profile refresh from the default home', () => { const f = fixture() f.json(join(f.userHome, '.claude.json'), { projects: { - '/shared': { hasTrustDialogAccepted: false, allowedTools: ['Read'] }, + '/shared': { + hasTrustDialogAccepted: false, + allowedTools: ['Read'], + lastSessionId: 'personal' + }, + '/runtime-only': { lastSessionId: 'personal' }, + '/malformed': 'invalid', '/default-only': { hasTrustDialogAccepted: true } }, mcpServers: { shared: { command: 'default' } } @@ -210,7 +264,15 @@ describe('Claude profile refresh from the default home', () => { f.json(join(f.profileHome, '.claude.json'), { oauthAccount: LOGIN, projects: { - '/shared': { hasTrustDialogAccepted: true }, + '/shared': { + hasTrustDialogAccepted: true, + hasCompletedProjectOnboarding: true, + projectOnboardingSeenCount: 4, + lastSessionId: 'profile', + exampleFiles: ['profile.ts'], + futureProjectState: true + }, + '/malformed': { lastSessionId: 'keep' }, '/account-only': { hasTrustDialogAccepted: true, allowedTools: ['Bash'] } }, mcpServers: { shared: { command: 'account' }, mine: { command: 'mine' } } @@ -219,7 +281,16 @@ describe('Claude profile refresh from the default home', () => { expect(f.read(join(f.profileHome, '.claude.json'))).toEqual({ oauthAccount: LOGIN, projects: { - '/shared': { hasTrustDialogAccepted: true, allowedTools: ['Read'] }, + '/shared': { + hasTrustDialogAccepted: true, + allowedTools: ['Read'], + hasCompletedProjectOnboarding: true, + projectOnboardingSeenCount: 4, + lastSessionId: 'profile', + exampleFiles: ['profile.ts'], + futureProjectState: true + }, + '/malformed': { lastSessionId: 'keep' }, '/account-only': { hasTrustDialogAccepted: true, allowedTools: ['Bash'] }, '/default-only': { hasTrustDialogAccepted: true } }, diff --git a/src/main/claude-accounts/claude-profile-provisioning.ts b/src/main/claude-accounts/claude-profile-provisioning.ts index ffd28dbb913..42bcdd1a8e5 100644 --- a/src/main/claude-accounts/claude-profile-provisioning.ts +++ b/src/main/claude-accounts/claude-profile-provisioning.ts @@ -19,6 +19,7 @@ import { type ClaudeProfileSurfaceOutcome } from './claude-profile-report' import { syncClaudeProfileSettings } from './claude-profile-settings' +import { mergeClaudeProfileState, selectSharedClaudeProfileState } from './claude-profile-state' import { copyClaudeProfileFile, linkClaudeProfileDirectory } from './claude-profile-sharing' const CLAUDE_PROFILE_MEMORY_IMPORT = '@~/.claude/CLAUDE.md\n' @@ -108,88 +109,6 @@ function isSharedEntry(name: string): boolean { ) } -// Claude 2.1.295 logout keys and subscription notices; onboarding remains shareable. -const CLAUDE_LOGOUT_STATE_KEYS = [ - 'oauthAccount', - 'additionalModelOptionsCache', - 'additionalModelOptionsAnsweredAt', - 'additionalModelCostsCache', - 'modelAccessCache', - 'orgModelDefaultCache', - 'cachedArtifactRoster', - 'artifactRosterDenied', - 'lastSeenOrgDefaultUpdatedAt', - 'clientDataCache', - 'clientDataCacheSlots', - 'autoCompactWindowsCache', - 'cachedUsageUtilization', - 'metricsStatusCache', - 'metricsStatusCacheByPrincipal', - 'githubWebConnectionStatusCache', - 'startupPrefetchedAt', - 'subscriptionNoticeCount', - 'hasAvailableSubscription' -] as const - -const ACCOUNT_BOUND_STATE_KEYS: ReadonlySet = new Set([ - ...CLAUDE_LOGOUT_STATE_KEYS, - 'userID', - 'machineID', - 'firstStartTime', - 'firstStartVersion', - // A copied Console key would override the account's own login. - 'primaryApiKey', - // Claude never refetches this account-specific date. - 'claudeCodeFirstTokenDate' -]) - -function isAccountBoundState(key: string): boolean { - // Logout leaves additional account caches such as groveConfigCache and passes*. - return ( - ACCOUNT_BOUND_STATE_KEYS.has(key) || - key.includes('Cache') || - key.startsWith('cached') || - key.startsWith('passes') - ) -} - -// Merge per entry so a profile keeps its own projects, servers, and Grove confirmations. -const MERGED_BY_ENTRY: ReadonlySet = new Set([ - 'projects', - 'mcpServers', - 'groveChoiceSeenAt' -]) - -function isPlainRecord(value: unknown): value is Record { - return typeof value === 'object' && value !== null && !Array.isArray(value) -} - -function mergeEntries(key: string, current: unknown, source: unknown): unknown { - if (!isPlainRecord(current) || !isPlainRecord(source)) { - return source - } - const merged: Record = { ...current, ...source } - if (key === 'projects') { - for (const [path, entry] of Object.entries(source)) { - const own = current[path] - // Preserve trust granted in this account, including just before launch. - if (isPlainRecord(own) && own.hasTrustDialogAccepted === true && isPlainRecord(entry)) { - merged[path] = { ...entry, hasTrustDialogAccepted: true } - } - } - } - if (key === 'groveChoiceSeenAt') { - // Claude trusts a confirmation only while it is fresh, so keep each account's newest one. - for (const [account, seenAt] of Object.entries(current)) { - const theirs = source[account] - if (typeof seenAt === 'number' && (typeof theirs !== 'number' || seenAt > theirs)) { - merged[account] = seenAt - } - } - } - return merged -} - async function copyState(source: string, target: string): Promise { if (lstatIfPresent(target)?.isSymbolicLink()) { return 'user-owned' @@ -201,11 +120,11 @@ async function copyState(source: string, target: string): Promise !isAccountBoundState(key)) + const shared = selectSharedClaudeProfileState(input.value) if (!lstatIfPresent(target)) { const staged = `${target}.${process.pid}.${randomUUID()}.tmp` try { - writeFileSync(staged, `${JSON.stringify(Object.fromEntries(shared), null, 2)}\n`, { + writeFileSync(staged, `${JSON.stringify(mergeClaudeProfileState({}, shared), null, 2)}\n`, { flag: 'wx', mode: 0o600 }) @@ -219,10 +138,7 @@ async function copyState(source: string, target: string): Promise { - const config = { ...current } - for (const [key, value] of shared) { - config[key] = MERGED_BY_ENTRY.has(key) ? mergeEntries(key, current[key], value) : value - } + const config = mergeClaudeProfileState(current, shared) return JSON.stringify(config) === JSON.stringify(current) ? { kind: 'unchanged' } : { kind: 'changed', config } diff --git a/src/main/claude-accounts/claude-profile-state.ts b/src/main/claude-accounts/claude-profile-state.ts new file mode 100644 index 00000000000..52cf971041a --- /dev/null +++ b/src/main/claude-accounts/claude-profile-state.ts @@ -0,0 +1,172 @@ +// Unknown state belongs to the profile; only deliberate user configuration is shared. +const SHARED_CONFIG_KEYS = [ + 'apiKeyHelper', + 'installMethod', + 'autoUpdates', + 'autoUpdatesProtectedForNative', + 'theme', + 'verbose', + 'preferredNotifChannel', + 'shiftEnterKeyBindingInstalled', + 'editorMode', + 'hasUsedBackslashReturn', + 'autoCompactEnabled', + 'autoScrollEnabled', + 'showTurnDuration', + 'externalEditorContext', + 'showMessageTimestamps', + 'diffTool', + 'env', + 'todoFeatureEnabled', + 'showExpandedTodos', + 'briefTranscript', + 'diffSidebarOpen', + 'messageIdleNotifThresholdMs', + 'autoConnectIde', + 'autoInstallIdeExtension', + 'fileCheckpointingEnabled', + 'terminalProgressBarEnabled', + 'showStatusInTerminalTab', + 'taskCompleteNotifEnabled', + 'inputNeededNotifEnabled', + 'agentPushNotifEnabled', + 'respectGitignore', + 'claudeInChromeDefaultEnabled', + 'hasCompletedClaudeInChromeOnboarding', + 'lspRecommendationDisabled', + 'lspRecommendationNeverPlugins', + 'copyFullResponse', + 'copyOnSelect', + 'leftArrowOpensAgents', + 'defaultToAgentsView', + 'prStatusFooterEnabled', + 'remoteControlAtStartup', + 'autoUploadSessions', + 'autoAddRemoteControlDaemonWorker', + 'remoteDialogSeen', + 'workflowSizeGuideline', + 'favoritePlugins', + 'preferTmuxOverIterm2', + 'codeReviewLastEffort', + 'codeReviewLastMaxFindings', + 'bypassPermissionsModeAccepted', + 'mcpServers' +] as const + +const SHARED_PROJECT_KEYS = [ + 'allowedTools', + 'mcpContextUris', + 'mcpServers', + 'enabledMcpjsonServers', + 'disabledMcpjsonServers', + 'hasClaudeMdExternalIncludesApproved', + 'hasTrustDialogAccepted' +] as const + +function isPlainRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value) +} + +function selectConfigFields( + source: Record, + keys: readonly string[] +): Record { + return Object.fromEntries( + keys.filter((key) => Object.hasOwn(source, key)).map((key) => [key, source[key]]) + ) +} + +export function selectSharedClaudeProfileState( + source: Record +): Record { + const shared = selectConfigFields(source, SHARED_CONFIG_KEYS) + if (isPlainRecord(source.projects)) { + const projects: Record = {} + for (const [path, entry] of Object.entries(source.projects)) { + if (isPlainRecord(entry)) { + const selected = selectConfigFields(entry, SHARED_PROJECT_KEYS) + if (Object.keys(selected).length > 0) { + projects[path] = selected + } + } + } + if (Object.keys(projects).length > 0) { + shared.projects = projects + } + } + if (source.hasCompletedOnboarding === true) { + shared.hasCompletedOnboarding = true + } + if ( + isPlainRecord(source.customApiKeyResponses) && + Array.isArray(source.customApiKeyResponses.rejected) + ) { + const rejected = source.customApiKeyResponses.rejected.filter( + (value) => typeof value === 'string' + ) + if (rejected.length > 0) { + shared.customApiKeyResponses = { rejected } + } + } + return shared +} + +function mergeProjects(current: unknown, source: Record): unknown { + if (current !== undefined && !isPlainRecord(current)) { + return current + } + const projects: Record = { ...current } + for (const [path, entry] of Object.entries(source)) { + const own = projects[path] + if (isPlainRecord(entry) && (own === undefined || isPlainRecord(own))) { + projects[path] = { + ...own, + ...entry, + ...(own?.hasTrustDialogAccepted === true ? { hasTrustDialogAccepted: true } : {}) + } + } + } + return projects +} + +function mergeRejectedApiKeys(current: unknown, source: Record): unknown { + if (current !== undefined && !isPlainRecord(current)) { + return current + } + const previous = current?.rejected + if ((previous !== undefined && !Array.isArray(previous)) || !Array.isArray(source.rejected)) { + return current + } + const rejected = [...(previous ?? [])] + const seen = new Set(rejected) + for (const value of source.rejected) { + if (!seen.has(value)) { + seen.add(value) + rejected.push(value) + } + } + return { ...current, rejected } +} + +export function mergeClaudeProfileState( + current: Record, + shared: Record +): Record { + const config = { ...current } + for (const [key, value] of Object.entries(shared)) { + if (key === 'hasCompletedOnboarding') { + if (!Object.hasOwn(current, key)) { + config[key] = true + } + } else if (key === 'customApiKeyResponses' && isPlainRecord(value)) { + config[key] = mergeRejectedApiKeys(current[key], value) + } else if (key === 'projects' && isPlainRecord(value)) { + config[key] = mergeProjects(current[key], value) + } else if (key === 'mcpServers' && isPlainRecord(current[key]) && isPlainRecord(value)) { + config[key] = { ...current[key], ...value } + } else { + config[key] = value + } + } + return config +} diff --git a/src/main/claude/claude-context-usage-unloaded-turn.test.ts b/src/main/claude/claude-context-usage-unloaded-turn.test.ts index a3a66b047f9..90106391b22 100644 --- a/src/main/claude/claude-context-usage-unloaded-turn.test.ts +++ b/src/main/claude/claude-context-usage-unloaded-turn.test.ts @@ -111,7 +111,8 @@ function readOptions(journal: AgentSessionJournal, agents: StructuredAgentRegist }, serialize: (_sessionId: string, task: () => Promise) => task(), openConversation: async () => running, - conversation: async () => running + conversation: async () => running, + sessions: new Map([[SESSION, running]]) } as unknown as StructuredAgentSessionMutationContext return readStructuredAgentSessionOptions(context, SESSION, { readsWithoutModel: true }) } diff --git a/src/main/claude/claude-rejected-api-key.ts b/src/main/claude/claude-rejected-api-key.ts index 38c61451579..d9afa94d907 100644 --- a/src/main/claude/claude-rejected-api-key.ts +++ b/src/main/claude/claude-rejected-api-key.ts @@ -3,19 +3,27 @@ import { readFile } from 'node:fs/promises' import { homedir } from 'node:os' import { resolveClaudeGlobalConfigFile } from './claude-folder-trust-file' -async function readRejectedApiKeyIds(configFile: string): Promise { +type ClaudeApiKeyResponses = { approved: readonly unknown[]; rejected: readonly unknown[] } + +async function readApiKeyResponses(configFile: string): Promise { + const empty = { approved: [], rejected: [] } try { const parsed: unknown = JSON.parse(await readFile(configFile, 'utf8')) if (typeof parsed !== 'object' || parsed === null || !('customApiKeyResponses' in parsed)) { - return [] + return empty } const responses = parsed.customApiKeyResponses - if (typeof responses !== 'object' || responses === null || !('rejected' in responses)) { - return [] + if (typeof responses !== 'object' || responses === null) { + return empty + } + return { + approved: + 'approved' in responses && Array.isArray(responses.approved) ? responses.approved : [], + rejected: + 'rejected' in responses && Array.isArray(responses.rejected) ? responses.rejected : [] } - return Array.isArray(responses.rejected) ? responses.rejected : [] } catch { - return [] + return empty } } @@ -38,9 +46,10 @@ export async function withoutRejectedClaudeApiKey( style, exists: existsSync }) - const rejected = await readRejectedApiKeyIds(configFile) + const responses = await readApiKeyResponses(configFile) // Claude records answers by the trimmed key's last 20 characters. - if (rejected.includes(apiKey.trim().slice(-20))) { + const suffix = apiKey.trim().slice(-20) + if (!responses.approved.includes(suffix) && responses.rejected.includes(suffix)) { for (const name of keyNames) { delete env[name] } diff --git a/src/main/claude/structured/claude-structured-execution-observations.ts b/src/main/claude/structured/claude-structured-execution-observations.ts index bd27887fdfd..60f7a34ecaf 100644 --- a/src/main/claude/structured/claude-structured-execution-observations.ts +++ b/src/main/claude/structured/claude-structured-execution-observations.ts @@ -41,11 +41,19 @@ export function beginClaudeOptionMutation(session: ClaudeSession, key: string): return sequence } +/** Until a turn carries the pick, the running process's answers name the model it replaced. */ +export function noteClaudeModelPick(session: ClaudeSession, model: string): void { + session.modelPickAwaitingTurn = model + delete session.reportedOptions.reportedModel +} + /** An init names execution; a control answer only acknowledges its input. */ export function observeClaudeExecutionModel(session: ClaudeSession, model: string): boolean { const previous = claudeExecutionObservations(session).model const previousResponse = session.reportedOptions.reportedModel - session.reportedOptions.reportedModel = model + if (!session.modelPickAwaitingTurn) { + session.reportedOptions.reportedModel = model + } if (previous !== model) { delete session.appliedOptions } @@ -93,7 +101,7 @@ function observeClaudeResponseModel( : null, responseModel: response }) ?? response - if (model === session.reportedOptions.reportedModel) { + if (session.modelPickAwaitingTurn || model === session.reportedOptions.reportedModel) { return false } session.reportedOptions.reportedModel = model diff --git a/src/main/claude/structured/claude-structured-response-model.test.ts b/src/main/claude/structured/claude-structured-response-model.test.ts index e37af00c246..4405ad02c96 100644 --- a/src/main/claude/structured/claude-structured-response-model.test.ts +++ b/src/main/claude/structured/claude-structured-response-model.test.ts @@ -152,3 +152,50 @@ it('keeps a model picked during a turn over that turn’s later replies until a await adapter.closeAll() } }) + +it('retires the answered model on a saved pick until a turn carries that pick', async () => { + const claude = fakeClaude({ initModel: 'claude-opus-5-5' }) + const adapter = await acquired(claude) + const connection = claude.connections[0]! + const read = async () => (await adapter.readOptions({ sessionId: 'session-1', fence: 7 })).current + const answer = (uuid: string, model: string) => + claudeFrame(connection, { + type: 'assistant', + uuid, + message: { role: 'assistant', model, content: [] } + }) + const turn = async (clientMessageId: string, model: string) => { + claudeFrame(connection, { type: 'system', subtype: 'session_state_changed', state: 'idle' }) + await adapter.dispatch({ + sessionId: 'session-1', + clientMessageId, + body: USER_MESSAGE, + executionOptions: { model }, + fence: 7 + }) + } + try { + claudeFrame(connection, { type: 'system', subtype: 'init', model: 'claude-opus-5-5' }) + answer('fallback', 'claude-opus-4-8') + expect((await read()).reportedModel).toBe('claude-opus-4-8') + + adapter.noteOptionPick({ sessionId: 'session-1', fence: 7, key: 'model', value: 'sonnet' }) + answer('same-turn', 'claude-opus-4-8') + expect((await read()).reportedModel).toBeUndefined() + expect((await read()).confirmed ?? []).not.toContain('model') + + // A message accepted before the pick runs the model it captured. + await turn('queued-before-pick', 'opus') + claudeFrame(connection, { type: 'system', subtype: 'init', model: 'claude-opus-5-5' }) + answer('queued-answer', 'claude-opus-5-5') + expect((await read()).reportedModel).toBeUndefined() + + await turn('carries-pick', 'sonnet') + expect(connection.calls).toContainEqual({ subtype: 'set_model', params: { model: 'sonnet' } }) + claudeFrame(connection, { type: 'system', subtype: 'init', model: 'claude-sonnet-5-5' }) + answer('next-fallback', 'claude-opus-4-8') + expect((await read()).reportedModel).toBe('claude-opus-4-8') + } finally { + await adapter.closeAll() + } +}) diff --git a/src/main/claude/structured/claude-structured-session-adapter.ts b/src/main/claude/structured/claude-structured-session-adapter.ts index a5158d42421..293bd4e7244 100644 --- a/src/main/claude/structured/claude-structured-session-adapter.ts +++ b/src/main/claude/structured/claude-structured-session-adapter.ts @@ -18,6 +18,7 @@ import { supportsClaudeStructuredLocation } from './launch/claude-structured-loc import * as claudeOptions from './launch/claude-structured-options' import { dispatchClaudeMessage } from './launch/claude-structured-message-options' import { readClaudeStructuredSessionOptions } from './launch/claude-structured-session-options' +import { noteClaudeModelPick } from './claude-structured-execution-observations' import { ClaudeAcquisitionRegistry, type ClaudeSession, @@ -229,6 +230,12 @@ export class ClaudeStructuredSessionAdapter implements StructuredAgentSessionAda deps: this.deps, emit: (session, event) => this.emit(session, event) }) + noteOptionPick: NonNullable = (input) => { + const session = this.sessions.get(input.sessionId) + if (session?.fence === input.fence && input.key === 'model' && input.value) { + noteClaudeModelPick(session, input.value) + } + } readOptions = (input: { sessionId: string; fence: number }) => readClaudeStructuredSessionOptions(this.session(input.sessionId)) releaseAcquisition = (input: ClaudeReleaseRequest): Promise => { diff --git a/src/main/claude/structured/claude-structured-session-state.ts b/src/main/claude/structured/claude-structured-session-state.ts index dcb0231822b..412afc09653 100644 --- a/src/main/claude/structured/claude-structured-session-state.ts +++ b/src/main/claude/structured/claude-structured-session-state.ts @@ -136,6 +136,8 @@ export type ClaudeSession = { fastModePerSessionOptIn?: boolean /** Mutation sequence of the last model report; newer writes outrank it. */ reportedModelMutation: number + /** A saved model pick no turn of this process has carried; its reports predate the pick. */ + modelPickAwaitingTurn?: string /** `dispatchSequence` at the last model write; that turn's replies predate the pick. */ modelMutationDispatch?: number /** Options whose recorded value the provider reported, not merely accepted. */ diff --git a/src/main/claude/structured/launch/claude-structured-message-options.ts b/src/main/claude/structured/launch/claude-structured-message-options.ts index 8463df786cc..abd34fe3d5b 100644 --- a/src/main/claude/structured/launch/claude-structured-message-options.ts +++ b/src/main/claude/structured/launch/claude-structured-message-options.ts @@ -30,6 +30,10 @@ export async function applyClaudeMessageOptions( ): Promise { throwIfSignalAborted(signal) const model = options.model + // Only a turn carrying the newest pick reports on it; earlier captured sends run the replaced model. + if (model === session.modelPickAwaitingTurn) { + delete session.modelPickAwaitingTurn + } if (model && session.appliedInputOptions.get('model') !== model) { await waitForPromiseWithSignal( setClaudeStructuredOption(session, { key: 'model', value: model }, timeoutMs), diff --git a/src/main/claude/structured/launch/claude-structured-session-options.ts b/src/main/claude/structured/launch/claude-structured-session-options.ts index 000c85ec47e..b35843bd7c6 100644 --- a/src/main/claude/structured/launch/claude-structured-session-options.ts +++ b/src/main/claude/structured/launch/claude-structured-session-options.ts @@ -213,6 +213,7 @@ export function claudeStructuredSessionOptionsFrom( const discovered = listedModels(catalog ? { models: catalog } : null) const listed = discovered.length > 0 ? discovered : seedModels() const current = readClaudeCurrentModel(session) + const reportsPick = !session.modelPickAwaitingTurn const model = current.id === 'default' ? undefined : current.id const models = structuredAgentSessionOptionModels(listed, model, (row) => ({ ...row, @@ -230,7 +231,7 @@ export function claudeStructuredSessionOptionsFrom( session.reportedOptions.fastMode ?? (session.fastModeState === undefined ? undefined : session.fastModeState !== 'off') const confirmed = [ - ...(current.confirmed ? ['model'] : []), + ...(current.confirmed && reportsPick ? ['model'] : []), ...(effort && session.confirmedOptions.has('effort') ? ['effort'] : []), ...(fastMode !== undefined && (session.confirmedOptions.has('fastMode') || !session.options.has('fastMode')) @@ -243,7 +244,7 @@ export function claudeStructuredSessionOptionsFrom( ...(changesLive ? {} : { effortFixed: true as const }), current: { model, - reportedModel: session.reportedOptions.reportedModel, + reportedModel: reportsPick ? session.reportedOptions.reportedModel : undefined, reportedPermissionMode: session.reportedOptions.reportedPermissionMode, ...(effort ? { effort } : {}), ...(fastMode !== undefined ? { fastMode } : {}), diff --git a/src/main/codex/structured/catalog/codex-model-catalog-probe.test.ts b/src/main/codex/structured/catalog/codex-model-catalog-probe.test.ts index 3fe0e337ea9..3d6b9c7ade2 100644 --- a/src/main/codex/structured/catalog/codex-model-catalog-probe.test.ts +++ b/src/main/codex/structured/catalog/codex-model-catalog-probe.test.ts @@ -55,58 +55,62 @@ it.each(['saved', 'recover'] as const)( ) describe('codex model catalog probe', () => { - it.each([[[]]])( - "lists a command line with arguments %j from Orca's folder for every chat", - async (prefixArgs) => { - // The chat's repo never picks the list, so no listing runs in a chat's folder. - const invocations: CodexAppServerInvocation[] = [] - const configReads: unknown[] = [] - const probe = createCodexModelCatalogProbe({ - resolveEnvironment: async () => ({ PATH: '/bin' }), - resolveCommand: () => ({ command: '/bin/codex', prefixArgs }), - runSession: async (invocation, body) => { - invocations.push(invocation) - return body({ - request: async (method: string, params: unknown) => { - if (method === 'config/read') { - configReads.push(params) - return { config: {} } - } - return { data: [MODEL_ROW], nextCursor: null } - }, - notify: () => {} - }) - } - }) - const identities: unknown[] = [] - for (const folder of ['/chat-a', '/chat-b']) { - const resolved = await probe.resolve?.( - { variable: 'CODEX_HOME', path: '/homes/a' }, - '/orca-probe', - 'snapshot', - undefined, - folder - ) - identities.push(resolved?.identity) - await resolved?.run() + it.each([ + [[], ['/orca-probe', '/orca-probe']], + [['node_modules/@openai/codex/bin/codex.js'], ['/chat-a', '/chat-b']], + [ + ['-c', 'model_instructions_file="./prompt.md"'], + ['/chat-a', '/chat-b'] + ] + ])('lists a command line with arguments %j from %j', async (prefixArgs, listedIn) => { + // Only the plain CLI shares one listing; user arguments may name files in the chat's folder. + const invocations: CodexAppServerInvocation[] = [] + const configReads: unknown[] = [] + const probe = createCodexModelCatalogProbe({ + resolveEnvironment: async () => ({ PATH: '/bin' }), + resolveCommand: () => ({ command: '/bin/codex', prefixArgs }), + runSession: async (invocation, body) => { + invocations.push(invocation) + return body({ + request: async (method: string, params: unknown) => { + if (method === 'config/read') { + configReads.push(params) + return { config: {} } + } + return { data: [MODEL_ROW], nextCursor: null } + }, + notify: () => {} + }) } - expect(invocations.map((invocation) => invocation.cwd)).toEqual([ + }) + const identities: unknown[] = [] + for (const folder of ['/chat-a', '/chat-b']) { + const resolved = await probe.resolve?.( + { variable: 'CODEX_HOME', path: '/homes/a' }, '/orca-probe', - '/orca-probe' - ]) - expect(invocations[0]?.args.slice(0, prefixArgs.length + 2)).toEqual([ - ...prefixArgs, - '-c', - 'project_root_markers=[]' - ]) - expect(identities[0]).toMatchObject({ cwd: '/orca-probe' }) - expect(identities[1]).toEqual(identities[0]) - // The account's configured default is read for Orca's folder, never the project's. - expect(configReads).toEqual( - expect.arrayContaining([expect.objectContaining({ cwd: '/orca-probe' })]) + 'snapshot', + undefined, + folder ) + identities.push(resolved?.identity) + await resolved?.run() } - ) + expect(invocations.map((invocation) => invocation.cwd)).toEqual(listedIn) + expect(invocations[0]?.args.slice(0, prefixArgs.length)).toEqual(prefixArgs) + // A listing in the chat's folder never loads that folder's project config. + expect(invocations[0]?.args.includes('projects={"/chat-a"={trust_level="untrusted"}}')).toBe( + listedIn[0] === '/chat-a' + ) + expect(invocations[0]?.args).toContain('project_root_markers=[]') + expect(identities[0]).toMatchObject({ cwd: listedIn[0] }) + expect(JSON.stringify(identities[0]) === JSON.stringify(identities[1])).toBe( + listedIn[0] === listedIn[1] + ) + // The account's configured default is read for Orca's folder, never the project's. + expect(configReads).toEqual( + expect.arrayContaining([expect.objectContaining({ cwd: '/orca-probe' })]) + ) + }) it('keeps the listing when config/read never answers', async () => { const server = String.raw` diff --git a/src/main/codex/structured/catalog/codex-model-catalog-probe.ts b/src/main/codex/structured/catalog/codex-model-catalog-probe.ts index fe4b82a24a2..94c26ee190c 100644 --- a/src/main/codex/structured/catalog/codex-model-catalog-probe.ts +++ b/src/main/codex/structured/catalog/codex-model-catalog-probe.ts @@ -4,13 +4,17 @@ import { } from '../../../native-chat/structured-agent-command-resolution' import { codexStructuredLaunchArgs } from '../launch/codex-structured-launch-args' import { overlayEnvironmentVariables } from '../../../../shared/environment-overlay' -import { envWithPathRelativeTo } from '../../../../shared/node-cli-command-resolution' +import { + catalogListingDirectory, + envWithPathRelativeTo +} from '../../../../shared/node-cli-command-resolution' import type { AgentSessionAccountKind } from '../../../../shared/agent-session/agent-session-availability' import { AgentModelCatalogUnavailableError } from '../../../native-chat/agent-model-catalog/agent-model-catalog-unavailable' import { isMissingProviderExecutable } from '../../../provider-process/provider-executable-missing' import { CODEX_SHORT_LIVED_PROBE_APP_SERVER_ARGS } from '../../../codex-cli/codex-read-only-app-server-args' import { runCodexAppServerSession } from '../../app-server/codex-app-server-session' import { fetchCodexModelCatalogListing } from './codex-structured-model-catalog' +import { codexProjectConfigIsolationArgs } from './codex-project-config-isolation' import { applyCodexConfiguredLaunchDefaults } from '../launch/codex-configured-launch-defaults' import { resolveCodexStructuredInvocation, @@ -70,13 +74,17 @@ export function createCodexModelCatalogProbe( ...(launchDirectory ? { resolveWorkingDirectory: () => launchDirectory } : {}) }) assertStructuredAgentResolutionCurrent(operation) - // Every listing runs in `cwd` with the user's command line, as other Codex hosts list from their - // own folder, so the chat's repo never picks the list; relative paths in user arguments are not - // resolved against the chat's folder. No root markers keep Codex from reading a repo above - // Orca's folder too, unless an administrator's managed config sets its own. - const args = [ + const userArgs = [ ...prefixArgs, - ...(cwd ? codexStructuredLaunchArgs((await deps.resolveLaunchArgs?.()) ?? []) : []), + ...(cwd ? codexStructuredLaunchArgs((await deps.resolveLaunchArgs?.()) ?? []) : []) + ] + // A command line that may name files relative to the chat's folder runs there, with that + // folder untrusted so its project config never replaces the account's list. No root markers + // keep Codex from reading a repo above the listing's folder, unless managed config sets its own. + const listIn = catalogListingDirectory(command, userArgs, cwd, launchDirectory) + const args = [ + ...userArgs, + ...(listIn && listIn !== cwd ? await codexProjectConfigIsolationArgs(listIn) : []), '-c', 'project_root_markers=[]', ...CODEX_SHORT_LIVED_PROBE_APP_SERVER_ARGS @@ -90,7 +98,7 @@ export function createCodexModelCatalogProbe( CODEX_HOME: accountHomePath } return { - identity: { command, args, cwd, overlay: Object.entries(overlay).sort() }, + identity: { command, args, cwd: listIn, overlay: Object.entries(overlay).sort() }, run: async ( signal?: AbortSignal, runOperation = operation @@ -103,7 +111,7 @@ export function createCodexModelCatalogProbe( { command, args, - ...(cwd ? { cwd } : {}), + ...(listIn ? { cwd: listIn } : {}), cliPath: command, env, timeoutMs: AGENT_MODEL_CATALOG_PROBE_TIMEOUT_MS, diff --git a/src/main/codex/structured/catalog/codex-project-config-isolation.ts b/src/main/codex/structured/catalog/codex-project-config-isolation.ts new file mode 100644 index 00000000000..07d197e13d1 --- /dev/null +++ b/src/main/codex/structured/catalog/codex-project-config-isolation.ts @@ -0,0 +1,18 @@ +import { realpath } from 'node:fs/promises' + +/** `-c` arguments that keep Codex from loading `dir`'s project config, so a listing that must run + * there still reports only the account's catalog. Needs `project_root_markers=[]` so no folder + * above `dir` is read. Override keys split on dots, so the folders go in the value. A managed + * config that trusts the folder still wins. */ +export async function codexProjectConfigIsolationArgs(dir: string): Promise { + const real = await realpath(dir).catch(() => dir) + // Windows Codex tries an ASCII-lowercased key first; a saved "trusted" one would win. + const spellings = + process.platform === 'win32' + ? [dir, real].map((folder) => folder.replace(/[A-Z]/g, (letter) => letter.toLowerCase())) + : [] + const table = [...new Set([dir, real, ...spellings])] + .map((folder) => `${JSON.stringify(folder)}={trust_level="untrusted"}`) + .join(',') + return ['-c', `projects={${table}}`] +} diff --git a/src/main/codex/structured/catalog/codex-usage-limits.test.ts b/src/main/codex/structured/catalog/codex-usage-limits.test.ts index e84cddfd769..ba885b46b7f 100644 --- a/src/main/codex/structured/catalog/codex-usage-limits.test.ts +++ b/src/main/codex/structured/catalog/codex-usage-limits.test.ts @@ -62,6 +62,33 @@ describe('a Codex usage limit', () => { ]) translator.dispose() }) + it('takes the reset from a nearly spent window when the rejection outruns the last report', () => { + const limits = new CodexUsageLimits() + const rejectedWith = (primaryPercent: number, code = 'usageLimitExceeded') => { + limits.observe('notification:account/rateLimits/updated', { + rateLimits: { + limitId: 'codex', + primary: { usedPercent: primaryPercent, windowDurationMins: 300, resetsAt: RESETS_AT_S }, + secondary: { usedPercent: 70, windowDurationMins: 10080, resetsAt: RESETS_AT_S + 3600 } + } + }) + return limits.failure({ error: { codexErrorInfo: code, message: CODEX_WORDS } })?.usageLimit + } + expect(rejectedWith(99)).toEqual({ window: 'session', resetsAt: RESETS_AT_S * 1000 }) + expect(rejectedWith(50)).toBeUndefined() + expect(rejectedWith(99, 'rateLimitExceeded')).toBeUndefined() + + limits.observe('notification:account/rateLimits/updated', { + rateLimits: { + primary: { usedPercent: 99, windowDurationMins: 300, resetsAt: 1_000_000 }, + secondary: { usedPercent: 95, windowDurationMins: 10080, resetsAt: RESETS_AT_S } + } + }) + expect( + limits.failure({ error: { codexErrorInfo: 'usageLimitExceeded', message: CODEX_WORDS } }) + ?.usageLimit + ).toEqual({ window: 'weekly', resetsAt: RESETS_AT_S * 1000 }) + }) it('merges null account updates and keeps unnamed exhausted windows in reset calculation', () => { const limits = new CodexUsageLimits() const observe = (rateLimits: Record) => diff --git a/src/main/codex/structured/catalog/codex-usage-limits.ts b/src/main/codex/structured/catalog/codex-usage-limits.ts index ca4bfd0c639..4e7fad1cc68 100644 --- a/src/main/codex/structured/catalog/codex-usage-limits.ts +++ b/src/main/codex/structured/catalog/codex-usage-limits.ts @@ -16,6 +16,8 @@ import { const RATE_LIMITS_UPDATED = 'notification:account/rateLimits/updated' const USAGE_LIMIT_ERRORS = ['usageLimitExceeded', 'rateLimitExceeded'] +/** The last report can trail a rejection by the request that went over, so a window this full counts as the spent one. */ +const NEARLY_SPENT_PERCENT = 90 type CodexAccountRateLimits = CodexRateLimitWindowsSnapshot & { rateLimitReachedType?: unknown @@ -62,7 +64,7 @@ export class CodexUsageLimits { const text = [message, additional && additional !== message ? additional : null] .filter((part): part is string => part !== null) .join('\n') - const limit = this.limit() + const limit = this.limit(info.error === 'usageLimitExceeded') return agentSessionFailureFact('usageLimitReached', { ...(limit ? { usageLimit: limit } : {}), detail: providerDiagnostic(text, 'person') @@ -70,21 +72,16 @@ export class CodexUsageLimits { } /** All spent windows must reset; report the latest only if every reset is known. */ - private limit(): AgentSessionUsageLimit | null { + private limit(rejected: boolean): AgentSessionUsageLimit | null { const monthlyPlan = this.snapshot.planType === 'free' || this.snapshot.planType === 'go' - const spent = ( + const reported = ( [ ['primary', monthlyPlan ? 43200 : 300], ['secondary', 10080] ] as const ).flatMap(([position, fallback]) => { const raw = this.snapshot[position] - if ( - !raw || - typeof raw.usedPercent !== 'number' || - !Number.isFinite(raw.usedPercent) || - raw.usedPercent < 100 - ) { + if (!raw || typeof raw.usedPercent !== 'number' || !Number.isFinite(raw.usedPercent)) { return [] } const duration = @@ -99,8 +96,19 @@ export class CodexUsageLimits { ? ('weekly' as const) : ('session' as const) : undefined - return [{ window, resetsAt: raw.resetsAt }] + return [{ window, resetsAt: raw.resetsAt, usedPercent: raw.usedPercent }] }) + // A window that already reset cannot be the one that just rejected. + const live = reported.filter( + (entry) => typeof entry.resetsAt !== 'number' || entry.resetsAt * 1000 > this.now() + ) + const fullest = Math.max(...live.map((entry) => entry.usedPercent)) + const spent = + rejected && + fullest >= NEARLY_SPENT_PERCENT && + !reported.some((entry) => entry.usedPercent >= 100) + ? live.filter((entry) => entry.usedPercent >= fullest) + : reported.filter((entry) => entry.usedPercent >= 100) const reached = this.snapshot.rateLimitReachedType const credits = typeof reached === 'string' && reached.endsWith('credits_depleted') const window: AgentSessionUsageLimitWindow | undefined = credits diff --git a/src/main/codex/structured/items/codex-image-item-translation.ts b/src/main/codex/structured/items/codex-image-item-translation.ts index abbc6ae5308..524e6c8fc46 100644 --- a/src/main/codex/structured/items/codex-image-item-translation.ts +++ b/src/main/codex/structured/items/codex-image-item-translation.ts @@ -1,6 +1,7 @@ import type { AgentJournalMessageItem } from '../../../../shared/agent-session/journal/agent-session-journal-types' import type { NativeChatBlock } from '../../../../shared/native-chat/native-chat-types' import { buildImageDataUri } from '../../../../shared/file-preview/image-data-uri' +import { NATIVE_CHAT_GENERATED_IMAGE_PRESENTATION } from '../../../../shared/native-chat/native-chat-generated-image' import { readString } from '../../app-server/codex-item-field-readers' import type { CodexThreadItem } from './codex-thread-item-identity' @@ -31,6 +32,7 @@ export function generatedImageUrl(item: CodexThreadItem): string | null { export function codexImageItemBody(item: CodexThreadItem): AgentJournalMessageItem { let image: Extract | null = null let text: string + let presentation: string | undefined if (item.type === 'imageView') { const path = imagePath(item, 'path') text = path ? 'Viewed image' : 'Image view: preview unavailable' @@ -54,11 +56,15 @@ export function codexImageItemBody(item: CodexThreadItem): AgentJournalMessageIt ? { type: 'image-ref', url, alt: 'Generated image' } : null text = image ? 'Generated image' : 'Image generated: preview unavailable' + presentation = image ? NATIVE_CHAT_GENERATED_IMAGE_PRESENTATION : undefined } } return { kind: 'message', role: 'assistant', - blocks: [{ type: 'text', text }, ...(image ? [image] : [])] + blocks: [ + { type: 'text', text, ...(presentation ? { presentation } : {}) }, + ...(image ? [image] : []) + ] } } diff --git a/src/main/codex/structured/journal/codex-turn-failures.test.ts b/src/main/codex/structured/journal/codex-turn-failures.test.ts index 9a89ea774a8..96bf3377025 100644 --- a/src/main/codex/structured/journal/codex-turn-failures.test.ts +++ b/src/main/codex/structured/journal/codex-turn-failures.test.ts @@ -31,37 +31,6 @@ function statuses(tap: ReturnType) { } describe('Codex terminal failure categories', () => { - it.each([ - ['rateLimitExceeded', 'usageLimitReached'], - ['flexUnavailable', 'providerUnavailable'], - ['modelNotFound', 'modelUnavailable'], - ['policyCapacityUnavailable', 'providerUnavailable'], - ['misalignmentPolicyViolation', 'providerSafetyStopped'], - ['serverOverloaded', 'providerUnavailable'], - ['cyberPolicy', 'providerSafetyStopped'] - ])('categorizes %s without exposing its diagnostic', (code, kind) => { - for (const info of [code, { [code]: { httpStatusCode: 401 } }]) { - const tap = recorder() - const translator = translatorFor(tap) - translator.handle(notification('error', error(info))) - expect(statuses(tap)).toMatchObject([{ failure: { kind } }]) - expect(statuses(tap)[0]?.text).not.toContain(DIAGNOSTIC) - expect(statuses(tap)[0]?.providerFrame?.payload.head).toContain(DIAGNOSTIC) - translator.dispose() - } - }) - - it('uses the existing usage-limit category for HTTP 429 retry exhaustion', () => { - const tap = recorder() - const translator = translatorFor(tap) - translator.handle( - notification('error', error({ responseTooManyFailedAttempts: { httpStatusCode: 429 } })) - ) - expect(statuses(tap)).toMatchObject([ - { tone: 'warning', failure: { kind: 'usageLimitReached' } } - ]) - }) - it('ends a recorded-shape failed completion carrying an unknown future code', () => { const frames: { case: string diff --git a/src/main/codex/structured/launch/codex-structured-launch-resolution.ts b/src/main/codex/structured/launch/codex-structured-launch-resolution.ts index 82aeeae47b2..3e6cc7fc1e4 100644 --- a/src/main/codex/structured/launch/codex-structured-launch-resolution.ts +++ b/src/main/codex/structured/launch/codex-structured-launch-resolution.ts @@ -29,6 +29,8 @@ import type { StructuredAgentLaunchPartResolver } from '../../../runtime/agent-s import type { CodexStructuredLaunch } from '../session-lifecycle/codex-structured-session-state' import { codexStructuredPermissionPolicy } from '../../../../shared/codex-permission-policy' import { codexStructuredLaunchArgs } from './codex-structured-launch-args' +import { codexOrcaHooksOffArgs } from './codex-structured-orca-hooks-off' +import { getSystemCodexHomePath } from '../../configuration/homes/codex-home-paths' import { LEGACY_NATIVE_CHAT_VISUALS_DIR_ENV, NATIVE_CHAT_SCRATCH_DIR_ENV, @@ -160,7 +162,15 @@ export function codexStructuredLaunchPart( launch: { command, prefixArgs, - args: [...prefixArgs, ...args, 'app-server'], + // Before the user's args: a later -c table replaces this one, so their hooks.state wins. + args: [ + ...prefixArgs, + ...codexOrcaHooksOffArgs( + accountHome.path || environment?.CODEX_HOME || getSystemCodexHomePath() + ), + ...args, + 'app-server' + ], codexHome: accountHome.path, resumeThreadId, // Only created threads may be unsaved; resumed, forked and adopted threads were persisted. diff --git a/src/main/codex/structured/launch/codex-structured-orca-hooks-off.ts b/src/main/codex/structured/launch/codex-structured-orca-hooks-off.ts new file mode 100644 index 00000000000..7e0bc0e370b --- /dev/null +++ b/src/main/codex/structured/launch/codex-structured-orca-hooks-off.ts @@ -0,0 +1,44 @@ +import { createManagedCommandMatcher } from '../../../agent-hooks/installation/commands/managed-hook-command-matching' +import { readHooksJson } from '../../../agent-hooks/installation/configuration/hooks-json-read' +import { escapeTomlBasicString } from '../../configuration/toml/config-toml-syntax' +import { + createCodexHookTrustEntry, + getCodexManagedScriptFileName +} from '../../hooks/definitions/codex-hook-identity' +import { getInPlaceCodexHookHome } from '../../trust/hooks/codex-hook-orca-approvals' +import { computeCodexTrustKey } from '../../trust/identity/codex-trust-identity' + +/** + * Chat strips pane env, so Orca's status hooks only cost a spawn per event, and under Store + * PowerShell every spawn fails (openai/codex#47810). Disable Orca's entries, including older + * forms the installer keeps, for this launch. One inline table because Codex splits `-c` keys + * on every dot, including the one in hooks.json. + */ +export function codexOrcaHooksOffArgs(codexHomePath: string): string[] { + const home = getInPlaceCodexHookHome(codexHomePath) + const isOrcaCommand = createManagedCommandMatcher(getCodexManagedScriptFileName()) + const hooks = readHooksJson(home.hooksJsonPath)?.hooks ?? {} + // hooks.json is user-editable; skip malformed groups and handlers as Codex does. + const entries = Object.entries(hooks).flatMap(([eventName, groups]) => + (Array.isArray(groups) ? groups : []).flatMap((group, groupIndex) => + (Array.isArray(group?.hooks) ? group.hooks : []).flatMap((hook, handlerIndex) => + hook && isOrcaCommand(hook.command) + ? home.keySourcePaths.flatMap((sourcePath) => { + const entry = createCodexHookTrustEntry( + sourcePath, + eventName, + groupIndex, + handlerIndex, + group, + hook + ) + return entry + ? [`"${escapeTomlBasicString(computeCodexTrustKey(entry))}"={enabled=false}`] + : [] + }) + : [] + ) + ) + ) + return entries.length > 0 ? ['-c', `hooks.state={${entries.join(',')}}`] : [] +} diff --git a/src/main/computer/macos-computer-use-permissions.ts b/src/main/computer/macos-computer-use-permissions.ts index a1916f33030..4d06adff039 100644 --- a/src/main/computer/macos-computer-use-permissions.ts +++ b/src/main/computer/macos-computer-use-permissions.ts @@ -29,10 +29,12 @@ let setupGeneration = 0 // Opens that arrive mid-reset wait for it, so reset's helper cleanup can't kill what they open. let resetInProgress: Promise | null = null +/** `locale` comes from the desktop caller; orcad and CLI opens leave the helper on its default copy. */ export function openComputerUsePermissions( - permissionId?: ComputerUsePermissionId + permissionId?: ComputerUsePermissionId, + locale?: string ): Promise { - return openComputerUsePermissionsAsync(permissionId, ++setupRequestSeq, setupGeneration) + return openComputerUsePermissionsAsync(permissionId, locale, ++setupRequestSeq, setupGeneration) } function cancelPendingSetupLaunches(): void { @@ -123,6 +125,7 @@ function launchSetupHelper(request: SetupLaunchRequest): void { async function openComputerUsePermissionsAsync( permissionId: ComputerUsePermissionId | undefined, + locale: string | undefined, seq: number, generation: number ): Promise { @@ -174,6 +177,10 @@ async function openComputerUsePermissionsAsync( } } const helperArgs = permissionId ? ['--permission', permissionId] : ['--permissions'] + if (locale) { + // Why: the helper renders permission copy in the app's UI language. + helperArgs.push('--locale', locale) + } const launch = requestSetupHelperLaunch({ seq, helperAppPath, helperArgs }) return { diff --git a/src/main/ephemeral-vm/recipe-runner.test.ts b/src/main/ephemeral-vm/recipe-runner.test.ts index 0a6ac8abafb..1a5c57afb35 100644 --- a/src/main/ephemeral-vm/recipe-runner.test.ts +++ b/src/main/ephemeral-vm/recipe-runner.test.ts @@ -1,6 +1,7 @@ -import { mkdtempSync, realpathSync, rmSync, writeFileSync } from 'node:fs' +import { mkdtempSync, realpathSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { removeTempDirs } from '../../shared/testing/remove-temp-dirs.test-support' import { afterEach, describe, expect, it } from 'vitest' import { encodePairingOffer } from '../../shared/remote-runtime/pairing/pairing' import { PAIRING_OFFER_VERSION } from '../../shared/remote-runtime/pairing/mobile-relay-pairing-offer' @@ -15,10 +16,8 @@ import type { OrcaVmRecipe } from '../../shared/orca-yaml-hook-types' const tmpRoots: string[] = [] -afterEach(() => { - for (const root of tmpRoots.splice(0)) { - rmSync(root, { recursive: true, force: true }) - } +afterEach(async () => { + await removeTempDirs(tmpRoots.splice(0)) }) function makeRepo(): string { diff --git a/src/main/ephemeral-vm/runtime-recipe-timeouts.test.ts b/src/main/ephemeral-vm/runtime-recipe-timeouts.test.ts index 994ff5d5bb2..713609af83b 100644 --- a/src/main/ephemeral-vm/runtime-recipe-timeouts.test.ts +++ b/src/main/ephemeral-vm/runtime-recipe-timeouts.test.ts @@ -1,7 +1,8 @@ -import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' +import { mkdtempSync, readFileSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { removeTempDirs } from '../../shared/testing/remove-temp-dirs.test-support' +import { afterEach, describe, expect, it, vi } from 'vitest' import { encodePairingOffer } from '../../shared/remote-runtime/pairing/pairing' import { PAIRING_OFFER_VERSION } from '../../shared/remote-runtime/pairing/mobile-relay-pairing-offer' import { getEphemeralVmRuntimeStorePath } from '../../shared/ephemeral-vm-runtime-store' @@ -20,10 +21,8 @@ vi.mock('../workspace-hooks/hooks', () => ({ })) const tempDirs: string[] = [] -afterEach(() => { - for (const root of tempDirs.splice(0)) { - rmSync(root, { recursive: true, force: true }) - } +afterEach(async () => { + await removeTempDirs(tempDirs.splice(0)) }) function makeDir(prefix: string): string { @@ -33,17 +32,6 @@ function makeDir(prefix: string): string { } describe('recipe timeoutSeconds and persisted runtimes', () => { - const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform') - beforeEach(() => { - // Isolate from platform ACL behavior, which secure-file tests cover. - Object.defineProperty(process, 'platform', { configurable: true, value: 'linux' }) - }) - afterEach(() => { - if (originalPlatform) { - Object.defineProperty(process, 'platform', originalPlatform) - } - }) - it('persists a runtime whose recipe sets timeoutSeconds in a shape older builds still read', async () => { const userDataPath = makeDir('orca-vm-timeouts-user-data-') const repoPath = makeDir('orca-vm-timeouts-repo-') @@ -108,4 +96,58 @@ describe('recipe timeoutSeconds and persisted runtimes', () => { getRuntimeRecipeContext(store, userDataPath, provisioned.runtime.id).recipe ).not.toHaveProperty('timeoutSeconds') }) + + it('keeps passEnv out of the persisted snapshot and re-applies it for lifecycle steps', async () => { + const userDataPath = makeDir('orca-vm-passenv-user-data-') + const repoPath = makeDir('orca-vm-passenv-repo-') + const startPath = join(repoPath, 'start.js') + const pairingCode = encodePairingOffer({ + v: PAIRING_OFFER_VERSION, + endpoint: 'wss://vm.example.com', + deviceToken: 'token', + publicKeyB64: 'public-key' + }) + writeFileSync( + startPath, + `console.log(JSON.stringify({ schemaVersion: 1, pairingCode: ${JSON.stringify(pairingCode)}, projectRoot: '/workspace/repo' }))\n` + ) + const recipe: OrcaVmRecipe = { + id: 'remote-vm', + name: 'Remote VM', + create: `"${process.execPath}" "${startPath}"`, + destroy: './destroy.sh', + passEnv: ['GH_TOKEN'] + } + + const provisioned = await provisionEphemeralVmRuntime({ + userDataPath, + repoPath, + recipe, + repoId: 'repo-1', + now: 1_000 + }) + + expect(provisioned.ok).toBe(true) + if (!provisioned.ok) { + return + } + expect(provisioned.runtime.recipe).not.toHaveProperty('passEnv') + const onDisk = JSON.parse(readFileSync(getEphemeralVmRuntimeStorePath(userDataPath), 'utf8')) + expect(RollbackEphemeralVmRuntimeStoreSchema.safeParse(onDisk).success).toBe(true) + + hooks.recipes = [recipe] + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: getRuntimeRecipeContext only reads getRepo from the store. + const store = { + getRepo: () => ({ id: 'repo-1', path: repoPath, kind: 'git' }) + } as unknown as Store + expect( + getRuntimeRecipeContext(store, userDataPath, provisioned.runtime.id).recipe + ).toMatchObject({ passEnv: ['GH_TOKEN'] }) + + // A different recipe that later took the same id does not change the environment. + hooks.recipes = [{ ...recipe, create: './other-create.sh', passEnv: ['OTHER'] }] + expect( + getRuntimeRecipeContext(store, userDataPath, provisioned.runtime.id).recipe + ).not.toHaveProperty('passEnv') + }) }) diff --git a/src/main/ephemeral-vm/runtime-resume-pairing.test.ts b/src/main/ephemeral-vm/runtime-resume-pairing.test.ts index 1cb7937226d..c363f23d766 100644 --- a/src/main/ephemeral-vm/runtime-resume-pairing.test.ts +++ b/src/main/ephemeral-vm/runtime-resume-pairing.test.ts @@ -1,6 +1,8 @@ -import { mkdtempSync, rmSync } from 'node:fs' +import { mkdtempSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { removeTempDirs } from '../../shared/testing/remove-temp-dirs.test-support' +import { removeTree } from '../../shared/windows-transient-lock-removal' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { encodePairingOffer } from '../../shared/remote-runtime/pairing/pairing' import type { PairedRuntimeConnection } from '../../shared/remote-runtime/pairing/paired-runtime-connection' @@ -49,20 +51,13 @@ function connect(serverDataPath: string, desktopDataPath: string, environmentId: describe('resuming a recipe VM server', () => { let desktopDataPath: string let serverDataPath: string - const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform') beforeEach(() => { - // Why: store contents are under test; secure-file tests cover Windows ACLs. - Object.defineProperty(process, 'platform', { configurable: true, value: 'linux' }) desktopDataPath = mkdtempSync(join(tmpdir(), 'orca-resume-desktop-')) serverDataPath = mkdtempSync(join(tmpdir(), 'orca-resume-server-')) }) - afterEach(() => { - if (originalPlatform) { - Object.defineProperty(process, 'platform', originalPlatform) - } - rmSync(desktopDataPath, { recursive: true, force: true }) - rmSync(serverDataPath, { recursive: true, force: true }) + afterEach(async () => { + await removeTempDirs([desktopDataPath, serverDataPath]) }) function provision(): string { @@ -130,7 +125,7 @@ describe('resuming a recipe VM server', () => { it('re-pairs from the fresh code when the host key changed, without asking the server', async () => { const environmentId = provision() const original = resolveEnvironmentPairingOffer(desktopDataPath, environmentId) - rmSync(serverDataPath, { recursive: true, force: true }) + await removeTree(serverDataPath) serverDataPath = mkdtempSync(join(tmpdir(), 'orca-resume-server-')) const probeSavedPairing = vi.fn() @@ -159,7 +154,7 @@ describe('resuming a recipe VM server', () => { ).publicKeyB64 const original = resolveEnvironmentPairingOffer(desktopDataPath, environmentId) const before = listEnvironments(desktopDataPath)[0]! - rmSync(serverDataPath, { recursive: true, force: true }) + await removeTree(serverDataPath) serverDataPath = mkdtempSync(join(tmpdir(), 'orca-resume-server-')) const invalidateTransport = vi.fn() diff --git a/src/main/ephemeral-vm/runtime-service.test.ts b/src/main/ephemeral-vm/runtime-service.test.ts index 8b0eb7b74a9..fa25993a95d 100644 --- a/src/main/ephemeral-vm/runtime-service.test.ts +++ b/src/main/ephemeral-vm/runtime-service.test.ts @@ -1,7 +1,8 @@ -import { existsSync, mkdtempSync, readFileSync, rmSync, truncateSync, writeFileSync } from 'node:fs' +import { existsSync, mkdtempSync, readFileSync, truncateSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { removeTempDirs } from '../../shared/testing/remove-temp-dirs.test-support' +import { afterEach, describe, expect, it, vi } from 'vitest' import { encodePairingOffer } from '../../shared/remote-runtime/pairing/pairing' import { PAIRING_OFFER_VERSION } from '../../shared/remote-runtime/pairing/mobile-relay-pairing-offer' import { @@ -23,10 +24,8 @@ import type { OrcaVmRecipe } from '../../shared/orca-yaml-hook-types' const tempDirs: string[] = [] -afterEach(() => { - for (const root of tempDirs.splice(0)) { - rmSync(root, { recursive: true, force: true }) - } +afterEach(async () => { + await removeTempDirs(tempDirs.splice(0)) }) function makeDir(prefix: string): string { @@ -49,19 +48,6 @@ function nodeCommand(scriptPath: string): string { } describe('ephemeral VM runtime service', () => { - const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform') - - beforeEach(() => { - // Isolate lifecycle tests from platform ACL behavior, which secure-file tests cover. - Object.defineProperty(process, 'platform', { configurable: true, value: 'linux' }) - }) - - afterEach(() => { - if (originalPlatform) { - Object.defineProperty(process, 'platform', originalPlatform) - } - }) - it('persists a successful recipe-created runtime and cleans it up', async () => { const userDataPath = makeDir('orca-ephemeral-vm-service-user-data-') const repoPath = makeDir('orca-ephemeral-vm-service-repo-') diff --git a/src/main/ephemeral-vm/runtime-ssh-cleanup.test.ts b/src/main/ephemeral-vm/runtime-ssh-cleanup.test.ts index 1c36c99c131..1bbecefdcbd 100644 --- a/src/main/ephemeral-vm/runtime-ssh-cleanup.test.ts +++ b/src/main/ephemeral-vm/runtime-ssh-cleanup.test.ts @@ -1,6 +1,7 @@ -import { mkdtempSync, rmSync } from 'node:fs' +import { mkdtempSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { removeTempDirs } from '../../shared/testing/remove-temp-dirs.test-support' import { afterEach, expect, it, vi } from 'vitest' import { upsertEphemeralVmRuntime } from '../../shared/ephemeral-vm-runtime-store' import type { EphemeralVmRuntimeRecord } from '../../shared/ephemeral-vm-runtimes' @@ -8,10 +9,8 @@ import { removeEphemeralVmRuntimeSshTarget } from './runtime-ssh-cleanup' const tempDirs: string[] = [] -afterEach(() => { - for (const dir of tempDirs.splice(0)) { - rmSync(dir, { recursive: true, force: true }) - } +afterEach(async () => { + await removeTempDirs(tempDirs.splice(0)) }) function createRuntime( diff --git a/src/main/ephemeral-vm/workspace-removal.test.ts b/src/main/ephemeral-vm/workspace-removal.test.ts index b5a7d683632..730d48c0225 100644 --- a/src/main/ephemeral-vm/workspace-removal.test.ts +++ b/src/main/ephemeral-vm/workspace-removal.test.ts @@ -1,6 +1,7 @@ -import { mkdtempSync, rmSync } from 'node:fs' +import { mkdtempSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { removeTempDirs } from '../../shared/testing/remove-temp-dirs.test-support' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { listEphemeralVmRuntimes, @@ -89,7 +90,7 @@ function makePorts( beforeEach(() => { root = mkdtempSync(join(tmpdir(), 'orca-recipe-remove-')) }) -afterEach(() => rmSync(root, { recursive: true, force: true })) +afterEach(() => removeTempDirs([root])) describe('recipe workspace removal on the provisioning host', () => { it('handles only removals that asked to destroy the environment', () => { diff --git a/src/main/ephemeral-vm/workspace-resume-paired-lost-contact.test.ts b/src/main/ephemeral-vm/workspace-resume-paired-lost-contact.test.ts index e7b1ca231b4..4f770ffefb5 100644 --- a/src/main/ephemeral-vm/workspace-resume-paired-lost-contact.test.ts +++ b/src/main/ephemeral-vm/workspace-resume-paired-lost-contact.test.ts @@ -1,9 +1,10 @@ // #34089 for VMs reached as paired Orca servers: a VM its provider stopped or reclaimed stays // recorded as running. Once Orca's own probes have failed for minutes, opening the workspace runs // the recipe's resume and keeps the device pairing unless the server came back with a new host key. -import { mkdtempSync, rmSync } from 'node:fs' +import { mkdtempSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { removeTempDirs } from '../../shared/testing/remove-temp-dirs.test-support' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' type MockState = { @@ -140,11 +141,8 @@ describe('opening a workspace whose paired VM server Orca could not reach for mi let environmentId: string let keyPair: KeyPair let now: number - const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform') beforeEach(async () => { - // Why: store contents are under test; secure-file tests cover Windows ACLs. - Object.defineProperty(process, 'platform', { configurable: true, value: 'linux' }) vi.useFakeTimers({ toFake: ['Date'] }) now = Date.parse('2026-11-08T12:00:00Z') vi.setSystemTime(now) @@ -178,11 +176,7 @@ describe('opening a workspace whose paired VM server Orca could not reach for mi mocks.reconnectControl.mockClear() mocks.refreshStatus.mockClear() mocks.updateStatus.mockClear() - if (originalPlatform) { - Object.defineProperty(process, 'platform', originalPlatform) - } - rmSync(state.desktopDataPath, { recursive: true, force: true }) - rmSync(serverDataPath, { recursive: true, force: true }) + await removeTempDirs([state.desktopDataPath, serverDataPath]) }) /** The VM goes away; Orca's probes keep failing for `forMs`. */ @@ -256,7 +250,7 @@ describe('opening a workspace whose paired VM server Orca could not reach for mi expect(listEnvironments(state.desktopDataPath)).toHaveLength(1) expect((await probe(environmentId)).ok).toBe(true) } finally { - rmSync(rebuiltServerDataPath, { recursive: true, force: true }) + await removeTempDirs([rebuiltServerDataPath]) } }) diff --git a/src/main/git/command-runner/gh-exec-file.ts b/src/main/git/command-runner/gh-exec-file.ts index dcc7a3c67d0..9eb9b7c973a 100644 --- a/src/main/git/command-runner/gh-exec-file.ts +++ b/src/main/git/command-runner/gh-exec-file.ts @@ -21,6 +21,7 @@ import { execFileCaptureToTermination } from './exec-file-capture' import { logHostedCliDeadlineKill } from './hosted-cli-deadline-log' import type { GitExecOptions } from './git-exec-options' import { argsLookIdempotent } from './gh-idempotency' +import { GhExecutableAbsenceBatch } from './gh-executable-absence-batch' import { applyGhHostToArgs, explicitGhHostname, explicitGhRepoHostname } from './gh-host-args' import { isGhBoundAccountError, resolveBoundGhExecEnv } from './gh-bound-account-env' import { @@ -178,6 +179,13 @@ export async function ghExecFileWithScopeAsync( if (lifetime) { await lifetime.waitPending(options.signal) } + const availability = GhExecutableAbsenceBatch.assertAvailable( + resolved, + boundEnv ?? options.env ?? process.env + ) + if (availability) { + await availability + } // gh may be a shim chain; terminate the whole tree so descendants cannot outlive the deadline. const { stdout, stderr } = await execFileCaptureToTermination( resolved.binary, @@ -198,6 +206,7 @@ export async function ghExecFileWithScopeAsync( if (lifetime) { await lifetime.waitPending(options.signal) } + GhExecutableAbsenceBatch.recordSuccess(resolved, boundEnv ?? options.env ?? process.env) return { // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: Capture decodes stdout with the requested string encoding above. stdout: stdout as string, @@ -277,6 +286,11 @@ export async function ghExecFileWithScopeAsync( await sleep(delayMs, options.signal) continue } + await GhExecutableAbsenceBatch.recordMissing( + resolved, + boundEnv ?? options.env ?? process.env, + err + ) throw err } finally { lifetime?.seal() diff --git a/src/main/git/command-runner/gh-executable-absence-batch.ts b/src/main/git/command-runner/gh-executable-absence-batch.ts new file mode 100644 index 00000000000..a2362641c3a --- /dev/null +++ b/src/main/git/command-runner/gh-executable-absence-batch.ts @@ -0,0 +1,116 @@ +import { AsyncLocalStorage } from 'node:async_hooks' +import { stat } from 'node:fs/promises' +import path from 'node:path' +import { + isCommandOnLocalPath, + resolveSelectedLocalCommand +} from '../../ipc/command-path/command-path-resolver' +import type { ResolvedCommand } from './wsl-command-resolution' + +const currentBatch = new AsyncLocalStorage() +const batches = new Set() + +function searchScope(command: ResolvedCommand, env: NodeJS.ProcessEnv): string | null { + if (command.wsl || command.binary !== 'gh' || !command.cwd) { + return null + } + const pathKey = Object.keys(env).find((key) => + process.platform === 'win32' ? key.toLowerCase() === 'path' : key === 'PATH' + ) + const searchPath = pathKey ? env[pathKey] : undefined + if (!searchPath || searchPath.split(path.delimiter).some((entry) => !path.isAbsolute(entry))) { + return null + } + const extensions = Object.entries(env).find(([key]) => key.toLowerCase() === 'pathext')?.[1] + return JSON.stringify([process.platform, command.binary, searchPath, extensions]) +} + +/** A finite recovery batch shares only proved native executable absence, never API failures. */ +export class GhExecutableAbsenceBatch { + private readonly missing = new Map() + + constructor() { + batches.add(this) + } + + run(operation: () => Promise): Promise { + return currentBatch.run(this, operation) + } + + close(): void { + batches.delete(this) + this.missing.clear() + } + + static assertAvailable(command: ResolvedCommand, env: NodeJS.ProcessEnv): Promise | null { + const batch = currentBatch.getStore() + if (!batch?.missing.size) { + return null + } + const scope = searchScope(command, env) + if (!scope || !batch.missing.has(scope)) { + return null + } + if (resolveSelectedLocalCommand('gh', { env, cwd: command.cwd }) !== 'gh') { + batch.missing.delete(scope) + return null + } + if (process.platform === 'win32') { + // Windows searches each checkout before PATH; a peer may have its own executable. + const localEnv = Object.fromEntries( + Object.entries(env).filter(([key]) => key.toLowerCase() !== 'path') + ) + return isCommandOnLocalPath('gh', { + env: { ...localEnv, PATH: '' }, + cwd: command.cwd + }).then((found) => { + if (!found) { + throw batch.missing.get(scope) + } + }) + } + throw batch.missing.get(scope) + } + + static async recordMissing( + command: ResolvedCommand, + env: NodeJS.ProcessEnv, + error: unknown + ): Promise { + const batch = currentBatch.getStore() + const scope = batch && searchScope(command, env) + if ( + !batch || + !scope || + !error || + typeof error !== 'object' || + !('code' in error) || + error.code !== 'ENOENT' || + batch.missing.get(scope) === error + ) { + return + } + try { + if ( + command.cwd && + (await stat(command.cwd)).isDirectory() && + resolveSelectedLocalCommand('gh', { env, cwd: command.cwd }) === 'gh' && + !(await isCommandOnLocalPath('gh', { env, cwd: command.cwd })) && + batches.has(batch) + ) { + batch.missing.set(scope, error) + } + } catch { + // A missing cwd or unreadable search environment proves nothing about peer checkouts. + } + } + + static recordSuccess(command: ResolvedCommand, env: NodeJS.ProcessEnv): void { + const scope = batches.size && searchScope(command, env) + if (scope) { + for (const batch of batches) { + batch.missing.delete(scope) + } + } + } +} diff --git a/src/main/git/remotes/hosted-remote-url.ts b/src/main/git/remotes/hosted-remote-url.ts index 9f10984fa05..5361b6ffac4 100644 --- a/src/main/git/remotes/hosted-remote-url.ts +++ b/src/main/git/remotes/hosted-remote-url.ts @@ -1,4 +1,5 @@ import { normalizeForgeWebHost } from '../../../shared/git/remotes/git-remote-host-alias' +import { getPublicForgeProviderForHost } from '../../../shared/git/remotes/public-forge-host' // Scoped local fork of the hosted-git-info@9.0.3 behavior Orca used. // Keep only the provider parsing and file/commit URL construction needed by source links. @@ -23,14 +24,14 @@ const shorthandHosts: Record { vi.useRealTimers() } }) + + it('reads a fine-grained token check from its Actions job when the check run is refused', async () => { + getOwnerRepoMock.mockResolvedValueOnce({ owner: 'acme', repo: 'widgets' }) + const job = { + id: 71, + run_id: 7, + name: 'pytest', + status: 'completed', + conclusion: 'success', + html_url: 'https://github.com/acme/widgets/actions/runs/7/job/71', + started_at: '2026-11-10T10:00:00Z', + completed_at: '2026-11-10T10:05:00Z', + steps: [] + } + ghExecFileAsyncMock.mockImplementation(async (args: string[]) => { + const path = args.at(-1) ?? '' + if (path.includes('/check-runs/71')) { + throw Object.assign(new Error(`Command failed: gh api ${path}`), { + stderr: 'gh: Resource not accessible by personal access token (HTTP 403)\n', + stdout: '' + }) + } + if (path.endsWith('/actions/jobs/71')) { + return { stdout: JSON.stringify(job), stderr: '' } + } + if (path.includes('/actions/runs/7/jobs')) { + return { stdout: JSON.stringify({ jobs: [job] }), stderr: '' } + } + throw new Error(`unexpected ${path}`) + }) + + const details = await getPRCheckDetails('/repo-root', { + checkRunId: 71, + workflowRunId: 7, + checkName: 'pytest' + }) + + expect(details).toMatchObject({ + name: 'pytest', + status: 'completed', + conclusion: 'success', + url: 'https://github.com/acme/widgets/actions/runs/7/job/71', + startedAt: '2026-11-10T10:00:00Z', + completedAt: '2026-11-10T10:05:00Z', + jobs: [{ id: 71, name: 'pytest', status: 'completed', conclusion: 'success' }] + }) + }) }) diff --git a/src/main/github/client/check/fine-grained-token-checks.test.ts b/src/main/github/client/check/fine-grained-token-checks.test.ts new file mode 100644 index 00000000000..2f95c2a1689 --- /dev/null +++ b/src/main/github/client/check/fine-grained-token-checks.test.ts @@ -0,0 +1,131 @@ +import { describe, expect, it, vi } from 'vitest' + +const { ghExecFileAsyncMock } = vi.hoisted(() => ({ ghExecFileAsyncMock: vi.fn() })) + +vi.mock('../../gh-utils', async (importOriginal) => ({ + ...(await importOriginal>()), + ghExecFileAsync: ghExecFileAsyncMock, + acquire: vi.fn(), + release: vi.fn() +})) +vi.mock('../../rate-limit', async (importOriginal) => ({ + ...(await importOriginal>()), + noteRepositoryRateLimitSpend: vi.fn() +})) +vi.mock('../lookup/pr-lookup-rate-limit', () => ({ assertRateLimitBudget: vi.fn() })) + +import { getPRChecksViaRestFallback } from './get-pr-checks' + +function forbidden(path: string): Error { + return Object.assign(new Error(`Command failed: gh api ${path}`), { + stderr: 'gh: Resource not accessible by personal access token (HTTP 403)\n', + stdout: '{"message":"Resource not accessible by personal access token","status":"403"}' + }) +} + +function reply(body: unknown): { stdout: string; stderr: string } { + return { stdout: JSON.stringify(body), stderr: '' } +} + +describe('PR checks for a token without the Checks permission', () => { + it('lists the head commit Actions jobs when check runs are refused', async () => { + ghExecFileAsyncMock.mockImplementation(async (args: string[]) => { + const path = args.at(-1) ?? '' + if (path.includes('/check-runs') || path.includes('/check-suites')) { + throw forbidden(path) + } + if (path.includes('/actions/runs?head_sha=sha-1&')) { + return reply({ + total_count: 2, + workflow_runs: [ + { id: 7, check_suite_id: 70, status: 'completed', conclusion: 'failure' }, + { id: 8, check_suite_id: 80, status: 'completed', conclusion: 'action_required' } + ] + }) + } + if (path.includes('/actions/runs/8/jobs?filter=latest&')) { + return reply({ total_count: 0, jobs: [] }) + } + if (path.includes('/actions/runs/7/jobs?filter=latest&')) { + return reply({ + total_count: 2, + jobs: [ + { + id: 71, + run_id: 7, + name: 'pytest', + status: 'completed', + conclusion: 'failure', + html_url: 'https://github.com/acme/widgets/actions/runs/7/job/71' + }, + { + id: 72, + run_id: 7, + name: 'compose', + status: 'queued', + conclusion: null, + html_url: 'https://github.com/acme/widgets/actions/runs/7/job/72' + } + ] + }) + } + if (path.includes('/status?')) { + return reply({ + total_count: 1, + statuses: [{ context: 'ci/jenkins', state: 'success', target_url: null }] + }) + } + throw new Error(`unexpected ${path}`) + }) + + const checks = await getPRChecksViaRestFallback( + { owner: 'acme', repo: 'widgets', host: 'github.com' }, + 'sha-1', + { cwd: '/repo-root' } + ) + + expect( + checks?.map(({ name, status, conclusion, url, checkRunId, workflowRunId }) => ({ + name, + status, + conclusion, + url, + checkRunId, + workflowRunId + })) + ).toEqual([ + { + name: 'pytest', + status: 'completed', + conclusion: 'failure', + url: 'https://github.com/acme/widgets/actions/runs/7/job/71', + checkRunId: 71, + workflowRunId: 7 + }, + { + name: 'compose', + status: 'queued', + conclusion: 'pending', + url: 'https://github.com/acme/widgets/actions/runs/7/job/72', + checkRunId: 72, + workflowRunId: 7 + }, + { + name: 'ci/jenkins', + status: 'completed', + conclusion: 'success', + url: null, + checkRunId: undefined, + workflowRunId: undefined + }, + { + name: 'GitHub Actions #80', + status: 'completed', + conclusion: 'action_required', + url: 'https://github.com/acme/widgets/commits/sha-1/checks#check-suite-80', + checkRunId: undefined, + workflowRunId: undefined + } + ]) + }) +}) diff --git a/src/main/github/client/check/get-pr-check-details.ts b/src/main/github/client/check/get-pr-check-details.ts index 7a80705dc37..94cd28a040f 100644 --- a/src/main/github/client/check/get-pr-check-details.ts +++ b/src/main/github/client/check/get-pr-check-details.ts @@ -23,6 +23,7 @@ import { runCheckDetailsCall } from './check-details-admission-lifetime' import { snapshotCheckJobLogExecution } from './check-job-log-execution' +import { isCheckRunsPermissionDenied } from './rest-pr-check-pages' export async function getPRCheckDetails( repoPath: string, args: { @@ -80,11 +81,20 @@ export async function getPRCheckDetails( let checkRun: Record | null = null let output: Record | null = null let annotations: PRCheckRunDetails['annotations'] = [] + let checkRunReadRefused = false if (args.checkRunId) { - const { stdout } = await fetchMetadata([ - 'api', - `repos/${ownerRepo.owner}/${ownerRepo.repo}/check-runs/${args.checkRunId}` - ]) + const checkRunPath = `repos/${ownerRepo.owner}/${ownerRepo.repo}/check-runs/${args.checkRunId}` + const { stdout } = await fetchMetadata(['api', checkRunPath]).catch((err: unknown) => { + if (!isCheckRunsPermissionDenied(err)) { + throw err + } + // Why: fine-grained tokens can't read check runs, but a job's id is its check run's id. + checkRunReadRefused = true + return fetchMetadata([ + 'api', + `repos/${ownerRepo.owner}/${ownerRepo.repo}/actions/jobs/${args.checkRunId}` + ]) + }) const parsed: unknown = JSON.parse(stdout) checkRun = parsed && typeof parsed === 'object' && !Array.isArray(parsed) @@ -94,7 +104,10 @@ export async function getPRCheckDetails( checkRun?.output && typeof checkRun.output === 'object' ? Object.fromEntries(Object.entries(checkRun.output)) : null - if (checkRun?.status !== 'completed' || output?.annotations_count !== 0) { + if ( + !checkRunReadRefused && + (checkRun?.status !== 'completed' || output?.annotations_count !== 0) + ) { try { const annotationsResult = await fetchMetadata([ 'api', diff --git a/src/main/github/client/check/rest-pr-check-pages.ts b/src/main/github/client/check/rest-pr-check-pages.ts index 82f89c9dc3c..cd02db6dfe6 100644 --- a/src/main/github/client/check/rest-pr-check-pages.ts +++ b/src/main/github/client/check/rest-pr-check-pages.ts @@ -1,4 +1,5 @@ import { z } from 'zod' +import { extractExecError } from '../../../git/exec-error' import { ghExecFileAsync } from '../../gh-utils' import { githubHostExecOptions, type GitHubApiRepository } from '../../github-api-repository' import { noteRepositoryRateLimitSpend } from '../../rate-limit' @@ -24,6 +25,12 @@ const commitStatusSchema = z.object({ target_url: z.string().nullish(), created_at: z.string().nullish() }) +const workflowRunSchema = z.object({ + id: z.number(), + check_suite_id: z.number().nullish(), + status: z.string().nullable(), + conclusion: z.string().nullable() +}) const checkSuiteSchema = z.object({ id: z.number().optional(), status: z.string().nullable(), @@ -33,7 +40,6 @@ const checkSuiteSchema = z.object({ async function readPages( repository: GitHubApiRepository, - headSha: string, options: GhExecOptions, endpoint: string, field: string, @@ -48,7 +54,8 @@ async function readPages( let total: number | undefined for (let page = 1; ; page++) { await assertRateLimitBudget('core', repository, options) - const path = `repos/${repository.owner}/${repository.repo}/commits/${encodeURIComponent(headSha)}/${endpoint}?per_page=100&page=${page}` + const separator = endpoint.includes('?') ? '&' : '?' + const path = `repos/${repository.owner}/${repository.repo}/${endpoint}${separator}per_page=100&page=${page}` const { stdout } = await ghExecFileAsync( ['api', ...(noCache ? [] : ['--cache', '60s']), path], { ...options, ...githubHostExecOptions(repository) } @@ -74,23 +81,89 @@ async function readPages( } } -export function readRestPRCheckRuns( +function commitEndpoint(headSha: string, endpoint: string): string { + return `commits/${encodeURIComponent(headSha)}/${endpoint}` +} + +// Why: fine-grained tokens cannot be granted the Checks permission, but can read Actions. +export function isCheckRunsPermissionDenied(err: unknown): boolean { + const { stderr, stdout } = extractExecError(err) + const message = `${stderr}\n${stdout}\n${err instanceof Error ? err.message : ''}` + return message.toLowerCase().includes('resource not accessible by personal access token') +} + +function readHeadWorkflowRuns( + repository: GitHubApiRepository, + headSha: string, + options: GhExecOptions, + noCache: boolean, + pageLimit?: number +) { + return readPages( + repository, + options, + `actions/runs?head_sha=${encodeURIComponent(headSha)}`, + 'workflow_runs', + workflowRunSchema, + noCache, + pageLimit + ) +} + +/** The head commit's Actions jobs as check runs; a job's id is its check run's id. */ +async function readActionsJobsAsCheckRuns( + repository: GitHubApiRepository, + headSha: string, + options: GhExecOptions, + noCache: boolean, + pageLimit?: number +): Promise[]> { + const runs = await readHeadWorkflowRuns(repository, headSha, options, noCache, pageLimit) + const checkRuns: z.infer[] = [] + for (const run of runs) { + const jobs = await readPages( + repository, + options, + `actions/runs/${run.id}/jobs?filter=latest`, + 'jobs', + checkRunSchema, + noCache, + pageLimit + ) + for (const job of jobs) { + checkRuns.push({ + ...job, + details_url: job.html_url, + check_suite: run.check_suite_id ? { id: run.check_suite_id } : null + }) + } + } + return checkRuns +} + +export async function readRestPRCheckRuns( repository: GitHubApiRepository, headSha: string, options: GhExecOptions, noCache = true, pageLimit?: number ) { - return readPages( - repository, - headSha, - options, - 'check-runs', - 'check_runs', - checkRunSchema, - noCache, - pageLimit - ) + try { + return await readPages( + repository, + options, + commitEndpoint(headSha, 'check-runs'), + 'check_runs', + checkRunSchema, + noCache, + pageLimit + ) + } catch (err) { + if (!isCheckRunsPermissionDenied(err)) { + throw err + } + return readActionsJobsAsCheckRuns(repository, headSha, options, noCache, pageLimit) + } } export function readRestPRCommitStatuses( @@ -102,9 +175,8 @@ export function readRestPRCommitStatuses( ) { return readPages( repository, - headSha, options, - 'status', + commitEndpoint(headSha, 'status'), 'statuses', commitStatusSchema, noCache, @@ -112,23 +184,36 @@ export function readRestPRCommitStatuses( ) } -export function readRestPRCheckSuites( +export async function readRestPRCheckSuites( repository: GitHubApiRepository, headSha: string, options: GhExecOptions, noCache = true, pageLimit?: number -) { - return readPages( - repository, - headSha, - options, - 'check-suites', - 'check_suites', - checkSuiteSchema, - noCache, - pageLimit - ) +): Promise[]> { + try { + return await readPages( + repository, + options, + commitEndpoint(headSha, 'check-suites'), + 'check_suites', + checkSuiteSchema, + noCache, + pageLimit + ) + } catch (err) { + if (!isCheckRunsPermissionDenied(err)) { + throw err + } + // Each workflow run is its own check suite, so approval blockers still surface. + const runs = await readHeadWorkflowRuns(repository, headSha, options, noCache, pageLimit) + return runs.map((run) => ({ + id: run.check_suite_id ?? undefined, + status: run.status, + conclusion: run.conclusion, + app: { name: 'GitHub Actions' } + })) + } } /** REST rows in the GraphQL rollup's field names, so both reads give a check the same identity. */ diff --git a/src/main/github/client/fetch/repo-slug-upstream.ts b/src/main/github/client/fetch/repo-slug-upstream.ts index 4cbf567f238..4184817e685 100644 --- a/src/main/github/client/fetch/repo-slug-upstream.ts +++ b/src/main/github/client/fetch/repo-slug-upstream.ts @@ -1,4 +1,12 @@ -import { ghExecFileAsync, acquire, release, type OwnerRepo } from '../../gh-utils' +import { + ghExecFileAsync, + acquire, + release, + getRemoteUrlForRepo, + githubRepoContext, + parseGitHubRemoteIdentity, + type OwnerRepo +} from '../../gh-utils' import { getHostedReviewLocalGitOptions, type HostedReviewExecutionOptions @@ -10,6 +18,17 @@ import { resolveGitHubRepoExecution, type GitHubApiRepository } from '../../github-api-repository' +import { withSharedRemoteUrlReads } from '../../../git/remotes/remote-url-probe' +import { isStableMissingGitRemoteError } from '../../../git/remotes/stable-missing-git-remote-error' +import { + normalizeForgeWebHost, + foldWwwHostAlias +} from '../../../../shared/git/remotes/git-remote-host-alias' +import { + gitHubSshConfigHostAlias, + effectiveGitHubRemoteHost +} from '../../github-remote-identity-parsing' +import { resolveSshConfigHostname } from '../../github-ssh-host-alias-resolution' import { hostedReviewLocalGitOptionArgs, sameOwnerRepo } from './../github-exec-scope' export async function getRepoSlug( repoPath: string, @@ -23,55 +42,122 @@ export async function getRepoSlug( ) } -/** Best-effort fork parent for indicators/avatar selection; failures return null. */ +export type RepoUpstreamProbe = { + // Undefined is unavailable evidence, never a durable non-fork verdict. + upstream: OwnerRepo | null | undefined + origin: GitHubApiRepository | null +} + +export async function probeRepoUpstream( + repoPath: string, + connectionId?: string | null, + options: HostedReviewExecutionOptions = {}, + resolveParent = true +): Promise { + return withSharedRemoteUrlReads(async () => { + let origin: GitHubApiRepository | null = null + try { + const localGitOptions = hostedReviewLocalGitOptionArgs(options)[0] ?? {} + const context = githubRepoContext(repoPath, connectionId, localGitOptions) + let url: string | null + try { + url = await getRemoteUrlForRepo(context, 'origin') + } catch (error) { + if (isStableMissingGitRemoteError(error)) { + return { upstream: null, origin } + } + throw error + } + // An unserved remote host is not evidence of a missing origin. + if (url === null) { + return { upstream: undefined, origin } + } + const parsed = parseGitHubRemoteIdentity(url) + if (!parsed) { + return { upstream: null, origin } + } + let host = parsed.host + let hostResolved = true + const alias = gitHubSshConfigHostAlias(url) + if (alias) { + const resolved = await resolveSshConfigHostname(alias, context) + if (resolved.resolved && resolved.hostname) { + host = effectiveGitHubRemoteHost(host, resolved.hostname) + } else { + hostResolved = false + } + } + const forgeHost = normalizeForgeWebHost(foldWwwHostAlias(host)) + if (hostResolved && (forgeHost === 'gitlab.com' || forgeHost === 'bitbucket.org')) { + return { upstream: null, origin } + } + const execution = await resolveGitHubRepoExecution( + repoPath, + undefined, + connectionId, + localGitOptions + ) + origin = execution.ownerRepo + // Missing auth for an arbitrary custom host does not prove it is another forge. + if (!origin || !resolveParent) { + return { upstream: undefined, origin } + } + const upstream = await getGitHubApiRepositoryForRemote( + repoPath, + 'upstream', + connectionId, + localGitOptions + ) + if (upstream && !sameOwnerRepo(upstream, origin)) { + return { upstream, origin } + } + const controller = new AbortController() + const timer = setTimeout(() => controller.abort(), 10_000) + let acquired = false + try { + await acquire(controller.signal) + acquired = true + const { stdout } = await ghExecFileAsync( + ['repo', 'view', githubRepositorySlugArg(origin), '--json', 'isFork,parent'], + { ...execution.ghOptions, timeout: 10_000, signal: controller.signal } + ) + const data = JSON.parse(stdout) as { + isFork?: boolean + parent?: { name?: string; owner?: { login?: string } } | null + } + if (data.isFork === false) { + return { upstream: null, origin } + } + const owner = data.parent?.owner?.login + const repo = data.parent?.name + return { + upstream: + data.isFork === true && + typeof owner === 'string' && + owner.trim() && + typeof repo === 'string' && + repo.trim() + ? { owner, repo, ...(origin.host ? { host: origin.host } : {}) } + : undefined, + origin + } + } finally { + clearTimeout(timer) + if (acquired) { + release() + } + } + } catch { + return { upstream: undefined, origin } + } + }) +} + +/** Compatibility callers receive null when optional metadata is unavailable. */ export async function getRepoUpstream( repoPath: string, connectionId?: string | null, options: HostedReviewExecutionOptions = {} ): Promise { - const localGitArgs = hostedReviewLocalGitOptionArgs(options) - const localGitOptions = localGitArgs[0] ?? {} - const { ownerRepo: origin, ghOptions } = await resolveGitHubRepoExecution( - repoPath, - undefined, - connectionId, - localGitOptions - ) - if (!origin) { - return null - } - const upstreamRemote = await getGitHubApiRepositoryForRemote( - repoPath, - 'upstream', - connectionId, - localGitOptions - ) - if (upstreamRemote && !sameOwnerRepo(upstreamRemote, origin)) { - return upstreamRemote - } - await acquire() - try { - // Positional slugs bypass --repo qualification, so include the Enterprise host directly. - const { stdout } = await ghExecFileAsync( - ['repo', 'view', githubRepositorySlugArg(origin), '--json', 'isFork,parent'], - // Do not let optional metadata stall repository creation. - { - ...ghOptions, - timeout: 10_000 - } - ) - const data = JSON.parse(stdout) as { - isFork?: boolean - parent?: { name?: string; owner?: { login?: string } } | null - } - const owner = data.parent?.owner?.login - const repo = data.parent?.name - return data.isFork && owner && repo - ? { owner, repo, ...(origin.host ? { host: origin.host } : {}) } - : null - } catch { - return null - } finally { - release() - } + return (await probeRepoUpstream(repoPath, connectionId, options)).upstream ?? null } diff --git a/src/main/github/github-enterprise-repository.test.ts b/src/main/github/github-enterprise-repository.test.ts index 025609e3880..6a97404c2b7 100644 --- a/src/main/github/github-enterprise-repository.test.ts +++ b/src/main/github/github-enterprise-repository.test.ts @@ -33,6 +33,8 @@ import { isGitHubHostAuthenticated } from './github-enterprise-repository' import { _resetSshHostnameResolutionCache } from './github-ssh-host-alias-resolution' +import { getRepoUpstream, probeRepoUpstream } from './client/fetch/repo-slug-upstream' +import { _resetOriginGitHubApiRepositoryCache } from './github-api-repository' function mockOriginRemote(url: string): void { gitExecFileAsyncMock.mockImplementation(async (args: string[]) => { @@ -65,6 +67,25 @@ describe('getEnterpriseGitHubRepoSlug', () => { resolveWithSshGMock.mockResolvedValue(null) _resetGitHubHostAuthCache() _resetSshHostnameResolutionCache() + _resetOriginGitHubApiRepositoryCache() + }) + + it.each([ + ['https://bitbucket.org/team/orca.git', 'bitbucket.org'], + ['ssh://git@altssh.gitlab.com:443/team/orca.git', 'altssh.gitlab.com'], + ['https://codeberg.org/team/orca.git', 'codeberg.org'] + ])('does not promote a foreign public remote from gh inventory: %s', async (url, host) => { + mockOriginRemote(url) + mockHostAuthenticated(host) + await expect(getEnterpriseGitHubRepoSlug('/repo')).resolves.toBeFalsy() + await expect(isGitHubHostAuthenticated(host, '/repo')).resolves.toBe(false) + }) + + it('uses the effective SSH hostname before admitting an Enterprise identity', async () => { + mockOriginRemote('git@work-forge:team/orca.git') + resolveWithSshGMock.mockResolvedValue({ hostname: 'bitbucket.org' }) + mockHostAuthenticated('bitbucket.org') + await expect(getEnterpriseGitHubRepoSlug('/repo')).resolves.toBeNull() }) it.each([ @@ -93,6 +114,29 @@ describe('getEnterpriseGitHubRepoSlug', () => { host: 'ghe.acme.com:8443' }) }) + + it.each([true, false])( + 'keeps the literal Enterprise host fallback when SSH expansion fails (authenticated=%s)', + async (authenticated) => { + mockOriginRemote('git@ghe.corp.example:org/app.git') + ghExecFileAsyncMock.mockImplementation(async (args: string[]) => ({ + stdout: + args[0] === 'auth' + ? authenticated + ? 'ghe.corp.example\n ✓ Logged in to ghe.corp.example account kelora (keyring)' + : '' + : JSON.stringify({ isFork: true, parent: { owner: { login: 'parent' }, name: 'app' } }), + stderr: '' + })) + const expected = { owner: 'parent', repo: 'app', host: 'ghe.corp.example' } + const result = await probeRepoUpstream('/repo') + expect(result.upstream).toEqual(authenticated ? expected : undefined) + await expect(getRepoUpstream('/repo')).resolves.toEqual(authenticated ? expected : null) + expect(ghExecFileAsyncMock.mock.calls.filter(([args]) => args[0] === 'repo')).toHaveLength( + authenticated ? 2 : 0 + ) + } + ) }) describe('isGitHubHostAuthenticated', () => { diff --git a/src/main/github/github-enterprise-repository.ts b/src/main/github/github-enterprise-repository.ts index a0d590a6fb7..89a50c28ef2 100644 --- a/src/main/github/github-enterprise-repository.ts +++ b/src/main/github/github-enterprise-repository.ts @@ -22,6 +22,7 @@ import { parseWslPath } from '../wsl/filesystem/unc-path-access' import { isStableMissingGitRemoteError } from '../git/remotes/stable-missing-git-remote-error' import { requireReachableGitRoute } from '../providers/execution-host-provider-dispatch' import { getConnectionExecutionHostId } from '../../shared/execution-host' +import { getPublicForgeProviderForHost } from '../../shared/git/remotes/public-forge-host' export type GitHubEnterpriseRepoSlug = GitHubOwnerRepo & { host: string } @@ -131,6 +132,10 @@ async function resolveAuthenticatedGitHubHost( connectionId?: string | null, localGitOptions: LocalGitExecOptions = {} ): Promise { + const owner = getPublicForgeProviderForHost(host) + if (owner && owner !== 'github') { + return null + } const normalizedHost = normalizeGitHubHost(host)?.authority ?? host.trim().toLowerCase() const execOptions = ghRepoExecOptions(githubRepoContext(repoPath, connectionId, localGitOptions)) const cacheKey = `${runtimeCacheKey(repoPath, connectionId, localGitOptions.wslDistro)}\0${normalizedHost}\0${githubReadExecutionScope(execOptions)}` diff --git a/src/main/github/github-issue-link-title-fill.test.ts b/src/main/github/github-issue-link-title-fill.test.ts new file mode 100644 index 00000000000..596fe38be6f --- /dev/null +++ b/src/main/github/github-issue-link-title-fill.test.ts @@ -0,0 +1,100 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' +import { mkdtempSync, rmSync } from 'node:fs' +import { join } from 'node:path' +import { tmpdir } from 'node:os' +import { + closeTestStores, + createStore, + makeRepo, + testState, + writeDataFile +} from '../persistence/persistence-test-harness' +import { getWorkspaceAttachments } from '../../shared/workspace-attachments/workspace-attachments' +import { hostWorktreeTarget } from '../../shared/worktree/host-qualified-identity' +import { installGitHubIssueLinkTitleFill } from './github-issue-link-title-fill' + +vi.mock('electron', () => ({ + app: { getPath: () => testState.dir }, + safeStorage: { isEncryptionAvailable: () => false } +})) +vi.mock('../telemetry/client', () => ({ track: vi.fn() })) +vi.mock('../telemetry/cohort-classifier', () => ({ getCohortAtEmit: vi.fn() })) + +const target = hostWorktreeTarget({ id: 'repo::/work', hostId: 'local' }) + +async function setup(readIssueTitle: () => Promise) { + writeDataFile({ repos: [makeRepo({ id: 'repo', path: '/work' })] }) + const store = await createStore() + const pending: (() => void)[] = [] + const publish = vi.fn() + installGitHubIssueLinkTitleFill({ + store, + readIssueTitle, + publish, + schedule: (run) => pending.push(run) + }) + const settle = async (): Promise => { + for (const run of pending.splice(0)) { + run() + } + await vi.waitFor(() => expect(readIssueTitle).toHaveBeenCalled()) + await new Promise((resolve) => setImmediate(resolve)) + } + return { store, settle, publish } +} + +describe('GitHub issue link title fill', () => { + beforeEach(() => { + testState.dir = mkdtempSync(join(tmpdir(), 'orca-issue-link-title-')) + }) + afterEach(async () => { + await closeTestStores() + rmSync(testState.dir, { recursive: true, force: true }) + }) + + it('titles a bare linked issue without re-selecting a review the user had cleared', async () => { + const { store, settle, publish } = await setup(vi.fn(async () => 'Repair authentication')) + // A kept merge request with no review selected, as after the user clears the selection. + store.setWorktreeMeta(target, { + linkedItems: [{ provider: 'gitlab', type: 'mr', number: 5 }], + linkedPR: null, + linkedGitLabMR: null, + linkedBitbucketPR: null, + linkedAzureDevOpsPR: null, + linkedGiteaPR: null + }) + store.setWorktreeMeta(target, { linkedIssue: 42 }) + expect(store.getWorktreeMetaForHost('repo::/work', 'local')?.linkedGitLabMR ?? null).toBeNull() + await settle() + + const meta = store.getWorktreeMetaForHost('repo::/work', 'local') + expect(getWorkspaceAttachments(meta)).toContainEqual( + expect.objectContaining({ + provider: 'github', + type: 'issue', + number: 42, + title: 'Repair authentication' + }) + ) + expect(meta?.linkedIssue).toBe(42) + expect(meta?.linkedGitLabMR ?? null).toBeNull() + expect(publish).toHaveBeenCalledWith( + expect.objectContaining({ worktreeId: 'repo::/work', hostId: 'local' }) + ) + }) + + it('does not bring back a link removed while its title was being read', async () => { + let finish: (title: string) => void = () => {} + const read = vi.fn(() => new Promise((resolve) => (finish = resolve))) + const { store, settle } = await setup(read) + store.setWorktreeMeta(target, { linkedIssue: 42 }) + const settled = settle() + await vi.waitFor(() => expect(read).toHaveBeenCalled()) + store.setWorktreeMeta(target, { linkedIssue: null }) + finish('Repair authentication') + await settled + + const links = getWorkspaceAttachments(store.getWorktreeMetaForHost('repo::/work', 'local')) + expect(links.filter((item) => item.provider === 'github' && item.type === 'issue')).toEqual([]) + }) +}) diff --git a/src/main/github/github-issue-link-title-fill.ts b/src/main/github/github-issue-link-title-fill.ts new file mode 100644 index 00000000000..bea7dcc0f3e --- /dev/null +++ b/src/main/github/github-issue-link-title-fill.ts @@ -0,0 +1,166 @@ +import type { ExecutionHostId } from '../../shared/execution-host' +import type { Repo } from '../../shared/repo-types' +import type { WorktreeMeta } from '../../shared/worktree/meta-types' +import type { WorkspaceAttachment } from '../../shared/worktree/types' +import type { WorkspaceAttachmentMutation } from '../../shared/workspace-attachments/workspace-attachment-mutation' +import { getWorkspaceAttachments } from '../../shared/workspace-attachments/workspace-attachments' +import { WORKSPACE_ATTACHMENT_NUMBER_SLOTS } from '../../shared/workspace-attachments/workspace-attachment-legacy' +import { getWorkspaceReferenceIdentity } from '../../shared/workspace-attachments/workspace-reference-identity' +import { + hostWorktreeTarget, + type HostWorktreeTarget +} from '../../shared/worktree/host-qualified-identity' +import { getRepoIdFromWorktreeId } from '../../shared/worktree/id' +import type { WorktreeMetaWriteListener } from '../persistence/loading-store/write-scheduling' +import { findRepoRowForHostScopedWrite } from '../persistence/tracking-repos/repo-update-operations' + +export type GitHubIssueLinkTitleFillStore = { + onWorktreeMetaWritten: (listener: WorktreeMetaWriteListener) => () => void + getWorktreeMetaForHost: (worktreeId: string, hostId: ExecutionHostId) => WorktreeMeta | undefined + setWorktreeMeta: ( + target: HostWorktreeTarget, + meta: Partial & WorkspaceAttachmentMutation + ) => WorktreeMeta + getRepos: () => Repo[] +} + +type Job = { + worktreeId: string + hostId: ExecutionHostId + instanceId: string | undefined + identity: string + link: WorkspaceAttachment +} + +function untitledGitHubIssues(meta: WorktreeMeta | undefined): WorkspaceAttachment[] { + return getWorkspaceAttachments(meta).filter( + (item) => item.provider === 'github' && item.type === 'issue' && !item.title?.trim() + ) +} + +/** + * Links made without a title (CLI `--issue N`, phones, typed numbers) get the issue's title once, on the + * host that owns the workspace, so search can match it without a client re-reading every linked issue. + */ +export function installGitHubIssueLinkTitleFill(deps: { + store: GitHubIssueLinkTitleFillStore + readIssueTitle: (repo: Repo, link: WorkspaceAttachment) => Promise + // Addressed to the one workspace whose links changed; never a repo-wide refresh. + publish: (change: { worktreeId: string; hostId: ExecutionHostId; meta: WorktreeMeta }) => void + schedule?: (run: () => void) => void +}): () => void { + const schedule = deps.schedule ?? ((run) => setImmediate(run)) + const queue = new Map() + let draining = false + let disposed = false + + // The job's link as it is now; null once removed, retitled or its workspace re-created. + const currentTarget = (job: Job) => { + const meta = deps.store.getWorktreeMetaForHost(job.worktreeId, job.hostId) + if (!meta || meta.instanceId !== job.instanceId) { + return null + } + const items = getWorkspaceAttachments(meta) + const index = items.findIndex( + (item) => getWorkspaceReferenceIdentity(item) === job.identity && !item.title?.trim() + ) + return index === -1 ? null : { meta, items, index } + } + + const apply = (job: Job, title: string): void => { + const target = currentTarget(job) + if (!target) { + return + } + const { meta, items, index } = target + const reviewSlots = WORKSPACE_ATTACHMENT_NUMBER_SLOTS.filter(([, , type]) => type !== 'issue') + // A cleared review selection must be restated or the merge re-picks one; a set one it keeps. + const keepClearedSelection = reviewSlots.every(([slot]) => (meta[slot] ?? null) === null) + ? Object.fromEntries(reviewSlots.map(([slot]) => [slot, null])) + : {} + const updated = deps.store.setWorktreeMeta( + hostWorktreeTarget({ id: job.worktreeId, hostId: job.hostId }), + { + ...keepClearedSelection, + linkedItemsBase: items, + linkedItems: items.map((item, i) => (i === index ? { ...item, title } : item)) + } + ) + deps.publish({ worktreeId: job.worktreeId, hostId: job.hostId, meta: updated }) + } + + const drain = async (): Promise => { + if (draining) { + return + } + draining = true + try { + for (const [key, job] of queue) { + queue.delete(key) + if (disposed) { + return + } + try { + const repo = currentTarget(job) + ? findRepoRowForHostScopedWrite( + deps.store.getRepos(), + getRepoIdFromWorktreeId(job.worktreeId), + job.hostId + ) + : undefined + const title = repo ? await deps.readIssueTitle(repo, job.link).catch(() => null) : null + if (title?.trim() && !disposed) { + apply(job, title.trim()) + } + } catch { + // One link whose target changed underneath it (e.g. an alias turned ambiguous) is skipped; + // the rest of the queue still drains. + } + } + } finally { + draining = false + } + } + + const unsubscribe = deps.store.onWorktreeMetaWritten(({ worktreeId, hostId, previous, next }) => { + // Most writes (stamps, flags, comments) leave links untouched; skip them without normalizing. + // linkedWorkItem is re-created on every write and always titled, so it is not compared. + if ( + previous && + previous.instanceId === next.instanceId && + previous.linkedItems === next.linkedItems && + previous.linkedIssue === next.linkedIssue + ) { + return + } + const known = new Set( + previous?.instanceId === next.instanceId + ? untitledGitHubIssues(previous).map(getWorkspaceReferenceIdentity) + : [] + ) + let added = false + for (const link of untitledGitHubIssues(next)) { + const identity = getWorkspaceReferenceIdentity(link) + if (known.has(identity)) { + continue + } + queue.set(JSON.stringify([hostId, worktreeId, next.instanceId, identity]), { + worktreeId, + hostId, + instanceId: next.instanceId, + identity, + link + }) + added = true + } + if (added) { + // Run after the caller's write returns; nothing the user asked for waits on GitHub. + schedule(() => void drain()) + } + }) + return () => { + disposed = true + queue.clear() + unsubscribe() + } +} diff --git a/src/main/github/github-issue-link-title-wiring.ts b/src/main/github/github-issue-link-title-wiring.ts new file mode 100644 index 00000000000..0c22857efcf --- /dev/null +++ b/src/main/github/github-issue-link-title-wiring.ts @@ -0,0 +1,103 @@ +import type { Repo } from '../../shared/repo-types' +import { composeWorktreeHostIdentity } from '../../shared/worktree/host-qualified-identity' +import { getRepoIdFromWorktreeId } from '../../shared/worktree/id' +import { + workspaceMetadataSetRow, + type WorkspaceMetadataSet +} from '../../shared/worktree/workspace-metadata-set' +import type { WorkspaceAttachment } from '../../shared/worktree/types' +import { getRepoRoutingConnectionId } from '../../shared/execution-host' +import type { Store } from '../persistence/loading-store/store' +import { getLocalProjectGhExecOptions } from '../workspaces/execution-host/project-runtime-git-options' +import { getIssue } from './issues' +import { getWorkItemByOwnerRepo } from './client/fetch/get-work-item' +import { installGitHubIssueLinkTitleFill } from './github-issue-link-title-fill' +import { readGitHubRepoUnlessWslStopped } from '../ipc/source-control/github-repo-routing' + +const GITHUB_ISSUE_PATH = /^\/([^/]+)\/([^/]+)\/issues\/(\d+)$/ + +function sameIssueUrl(left: string, right: string): boolean { + try { + const a = new URL(left) + const b = new URL(right) + return ( + a.hostname.toLowerCase() === b.hostname.toLowerCase() && + a.pathname.replace(/\/+$/, '').toLowerCase() === b.pathname.replace(/\/+$/, '').toLowerCase() + ) + } catch { + return false + } +} + +/** Reads a link's issue the way its display does: a URL names its repo; a bare number uses the card's lookup. */ +async function readGitHubIssueLinkTitle( + store: Store, + repo: Repo, + link: WorkspaceAttachment +): Promise { + const connectionId = getRepoRoutingConnectionId(repo) + const options = getLocalProjectGhExecOptions(store, repo) + if (link.url) { + const url = new URL(link.url) + const route = GITHUB_ISSUE_PATH.exec(url.pathname) + if (!route || Number(route[3]) !== link.number) { + return null + } + const item = await getWorkItemByOwnerRepo( + repo.path, + { owner: route[1], repo: route[2], host: url.hostname }, + link.number, + 'issue', + connectionId, + options, + { preview: true } + ) + return item?.type === 'issue' && item.number === link.number && sameIssueUrl(item.url, link.url) + ? item.title + : null + } + const issue = await getIssue(repo.path, link.number, connectionId, options) + // The issues endpoint also answers PR numbers; a PR's title must not label an issue link. + return issue && issue.number === link.number && !/\/pull\/\d+$/.test(issue.url) + ? issue.title + : null +} + +export function wireGitHubIssueLinkTitleFill( + store: Store, + runtime: { + invalidateResolvedWorktreeCache: () => void + publishWorkspaceMetadataSet: (set: WorkspaceMetadataSet) => void + } +): () => void { + return installGitHubIssueLinkTitleFill({ + store, + // Background reads never start a stopped WSL distro; the link just stays untitled. + readIssueTitle: (repo, link) => + readGitHubRepoUnlessWslStopped( + store, + repo, + () => readGitHubIssueLinkTitle(store, repo, link), + { + wake: false + } + ), + publish: ({ worktreeId, hostId, meta }) => { + // Resolved rows embed metadata; refresh them so the next listing read agrees. + runtime.invalidateResolvedWorktreeCache() + // Same turn as the title write, so a listing either read it or carries an older seq. + const { epoch, seq } = store.advanceWorkspaceMetadataCursor() + runtime.publishWorkspaceMetadataSet({ + kind: 'set', + domain: 'workspaceMetadata', + hostId, + epoch, + seq, + id: composeWorktreeHostIdentity(hostId, worktreeId), + repoId: getRepoIdFromWorktreeId(worktreeId), + worktreeId, + row: workspaceMetadataSetRow(meta) + }) + } + }) +} diff --git a/src/main/github/github-repository-identity.fork-owner-repo.test.ts b/src/main/github/github-repository-identity.fork-owner-repo.test.ts index c697801eb0a..5e194798172 100644 --- a/src/main/github/github-repository-identity.fork-owner-repo.test.ts +++ b/src/main/github/github-repository-identity.fork-owner-repo.test.ts @@ -1,6 +1,6 @@ import type * as GitExecFileModule from '../git/command-runner/git-exec-file' import type * as GhExecFileModule from '../git/command-runner/gh-exec-file' -import { beforeEach, describe, expect, it, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' // Fork PR reads prefer upstream while origin-only probes retain the checkout identity. @@ -29,7 +29,11 @@ vi.mock('./local-git-config-signature', () => ({ import { _resetRemoteNameListingCache } from '../git/remotes/remote-name-listing' import { getOwnerRepoForRemote, _resetOwnerRepoCache } from './github-repository-identity' import { getOwnerRepo } from './github-owner-repo-selection' -import { getRepoUpstream } from './client/fetch/repo-slug-upstream' +import { getRepoUpstream, probeRepoUpstream } from './client/fetch/repo-slug-upstream' + +import { acquire, release } from './gh-utils' + +afterEach(() => vi.useRealTimers()) const FORK_PATH = '/tmp/fork-checkout' const NON_FORK_PATH = '/tmp/plain-checkout' @@ -43,6 +47,8 @@ const REMOTE_URLS_BY_REPO: Record> = { [NON_FORK_PATH]: { origin: 'https://github.com/stablyai/orca.git' }, + '/tmp/gitlab': { origin: 'https://gitlab.com/group/widget.git' }, + '/tmp/custom': { origin: 'https://code.example.com/group/widget.git' }, [SSH_FORK_PATH]: { origin: 'git@github.com:fsdwen/orca.git', upstream: 'git@github.com:stablyai/orca.git' @@ -117,3 +123,59 @@ describe('issue #7331: fork PR owner/repo resolution', () => { expect(ghExecFileAsyncMock).not.toHaveBeenCalled() }) }) + +describe('optional parent evidence', () => { + it.each([ + ['{"isFork":false}', null], + [ + '{"isFork":true,"parent":{"owner":{"login":"acme"},"name":"widget"}}', + { owner: 'acme', repo: 'widget', host: 'github.com' } + ], + ['{"isFork":true,"parent":null}', undefined], + ['{}', undefined], + ['invalid', undefined] + ])('persists only successful fork evidence from %s', async (stdout, expected) => { + ghExecFileAsyncMock.mockResolvedValue({ stdout }) + expect((await probeRepoUpstream(NON_FORK_PATH)).upstream).toEqual(expected) + }) + + it('bounds global admission and leaves origin avatar evidence usable on failure', async () => { + vi.useFakeTimers() + for (let slot = 0; slot < 4; slot++) { + await acquire() + } + try { + const pending = probeRepoUpstream(NON_FORK_PATH) + await vi.advanceTimersByTimeAsync(10_000) + expect(await pending).toEqual({ + upstream: undefined, + origin: { owner: 'stablyai', repo: 'orca', host: 'github.com' } + }) + expect(ghExecFileAsyncMock).not.toHaveBeenCalled() + let nextStarted = false + const next = acquire().then(() => { + nextStarted = true + release() + }) + await Promise.resolve() + expect(nextStarted).toBe(false) + release() + await next + for (let slot = 0; slot < 3; slot++) { + release() + } + } catch (error) { + for (let slot = 0; slot < 4; slot++) { + release() + } + throw error + } + }) +}) + +it('settles proven missing/other-forge origins but leaves unclassified custom hosts unknown', async () => { + expect(await probeRepoUpstream('/tmp/no-origin')).toEqual({ upstream: null, origin: null }) + expect(await probeRepoUpstream('/tmp/gitlab')).toEqual({ upstream: null, origin: null }) + ghExecFileAsyncMock.mockRejectedValue(new Error('auth unavailable')) + expect(await probeRepoUpstream('/tmp/custom')).toEqual({ upstream: undefined, origin: null }) +}) diff --git a/src/main/gitlab/gitlab-project-ref-resolution.ts b/src/main/gitlab/gitlab-project-ref-resolution.ts index 3e3b57a90df..90d69bf6052 100644 --- a/src/main/gitlab/gitlab-project-ref-resolution.ts +++ b/src/main/gitlab/gitlab-project-ref-resolution.ts @@ -1,7 +1,6 @@ import { glabExecFileAsync } from '../git/runner' import type { GitAdmissionTier } from '../git/command-runner/git-exec-options' import { addWslEnvKeys } from '../../shared/wsl-env' -import { normalizeForgeWebHost } from '../../shared/git/remotes/git-remote-host-alias' import { isTransientGitProbeError, readRemoteUrl } from '../git/remotes/remote-url-probe' import { NEGATIVE_ENTRY_TTL_MS } from '../git/remotes/remote-ref-probe-cache' import { readLocalGitConfigSignature } from '../github/local-git-config-signature' @@ -19,7 +18,7 @@ import { DEFAULT_GITLAB_HOSTS, normalizeGitLabHost, parseGitLabProjectRef, - parseRemoteProjectRefCandidate, + parseGitLabProjectRefCandidate, type ProjectRef } from './project-ref-parser' @@ -154,19 +153,12 @@ async function resolveProjectRefForRemote( if (stdout === null) { return null } - // Stray glab host entries for GitHub/Bitbucket hosts must not claim their remotes (#40386). - // Match the real host only: `github:team/project` is an scp remote on an SSH alias named github. - const remoteCandidate = parseRemoteProjectRefCandidate(stdout) - const remoteHost = remoteCandidate && normalizeForgeWebHost(remoteCandidate.host) - if (remoteHost === 'github.com' || remoteHost === 'bitbucket.org') { - publish(null) - return null - } const result = parseGitLabProjectRef(stdout, knownHosts) if (result) { publish(result) return result } + const remoteCandidate = parseGitLabProjectRefCandidate(stdout) if ( remoteCandidate && (await isGlabConfiguredForRemoteHost( diff --git a/src/main/gitlab/project-ref-parser.test.ts b/src/main/gitlab/project-ref-parser.test.ts index 6550aa5e402..c83ef13fe26 100644 --- a/src/main/gitlab/project-ref-parser.test.ts +++ b/src/main/gitlab/project-ref-parser.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { parseGitLabProjectRef } from './project-ref-parser' +import { parseGitLabProjectRef, parseRemoteProjectRefCandidate } from './project-ref-parser' describe('gitlab project ref parsing', () => { it.each([ @@ -43,4 +43,31 @@ describe('gitlab project ref parsing', () => { parseGitLabProjectRef('http://gitea.example.com:3030/team/api.git', knownHosts) ).toBeNull() }) + + it('keeps public ownership authoritative without narrowing generic mirror parsing', () => { + for (const [remote, host] of [ + ['https://github.com:8443/team/project.git', 'github.com:8443'], + ['git@SSH.GITHUB.COM:team/project.git', 'ssh.github.com'], + ['git@acme.ghe.com:team/project.git', 'acme.ghe.com'], + ['git@ssh.bitbucket.org:team/project.git', 'ssh.bitbucket.org'], + ['https://dev.azure.com/acme/project/_git/repo', 'dev.azure.com'], + ['git@ssh.dev.azure.com:v3/acme/project/repo', 'ssh.dev.azure.com'], + ['https://acme.visualstudio.com/project/_git/repo', 'acme.visualstudio.com'], + ['https://codeberg.org/team/project.git', 'codeberg.org'] + ]) { + expect(parseGitLabProjectRef(remote, [host])).toBeNull() + } + expect(parseRemoteProjectRefCandidate('git@github.com:team/project.git')).toEqual({ + host: 'github.com', + path: 'team/project' + }) + expect( + parseGitLabProjectRef('https://git.bitbucket.acme.com/team/project.git', [ + 'git.bitbucket.acme.com' + ]) + ).toEqual({ + host: 'git.bitbucket.acme.com', + path: 'team/project' + }) + }) }) diff --git a/src/main/gitlab/project-ref-parser.ts b/src/main/gitlab/project-ref-parser.ts index 051fdf1d062..96f083a6783 100644 --- a/src/main/gitlab/project-ref-parser.ts +++ b/src/main/gitlab/project-ref-parser.ts @@ -1,5 +1,6 @@ import type { GitLabProjectRef } from '../../shared/gitlab-types' import { normalizeGitLabRemoteHost } from '../../shared/git/remotes/git-remote-host-alias' +import { getPublicForgeProviderForHost } from '../../shared/git/remotes/public-forge-host' export type ProjectRef = GitLabProjectRef @@ -47,19 +48,6 @@ function knownHostMatches(urlHost: string, knownHost: string): boolean { return false } -function makeProjectRef( - host: string, - path: string, - knownHosts: readonly string[] -): ProjectRef | null { - const normalizedHost = normalizeGitLabRemoteHost(host) - const normalizedKnownHosts = knownHosts.map(normalizeGitLabHost) - if (!normalizedKnownHosts.some((knownHost) => knownHostMatches(normalizedHost, knownHost))) { - return null - } - return makeProjectRefForTrustedHost(normalizedHost, path) -} - export function parseRemoteProjectRefCandidate(remoteUrl: string): ProjectRef | null { const trimmed = remoteUrl.trim() if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)) { @@ -80,25 +68,24 @@ export function parseRemoteProjectRefCandidate(remoteUrl: string): ProjectRef | } } +export function parseGitLabProjectRefCandidate(remoteUrl: string): ProjectRef | null { + const candidate = parseRemoteProjectRefCandidate(remoteUrl) + if (!candidate) { + return null + } + const owner = getPublicForgeProviderForHost(candidate.host) + return owner && owner !== 'gitlab' ? null : candidate +} + export function parseGitLabProjectRef( remoteUrl: string, knownHosts: readonly string[] = DEFAULT_GITLAB_HOSTS ): ProjectRef | null { - const trimmed = remoteUrl.trim() - if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)) { - const scpLike = trimmed.match(/^(?:[^@/:]+@)?([^:\s/]+):([^\s]+?)(?:\.git)?$/) - if (scpLike) { - return makeProjectRef(scpLike[1], scpLike[2], knownHosts) - } - } - - try { - const url = new URL(trimmed) - if (!['http:', 'https:', 'ssh:', 'git:', 'git+ssh:'].includes(url.protocol.toLowerCase())) { - return null - } - return makeProjectRef(hostIdentityFromUrl(url), url.pathname, knownHosts) - } catch { + const candidate = parseGitLabProjectRefCandidate(remoteUrl) + if (!candidate) { return null } + return knownHosts.some((host) => knownHostMatches(candidate.host, normalizeGitLabHost(host))) + ? candidate + : null } diff --git a/src/main/gitlab/task-project-eligibility.test.ts b/src/main/gitlab/task-project-eligibility.test.ts index 894a356e3d7..1844b499abb 100644 --- a/src/main/gitlab/task-project-eligibility.test.ts +++ b/src/main/gitlab/task-project-eligibility.test.ts @@ -25,6 +25,8 @@ vi.mock('../git/command-runner/gh-exec-file', async (importOriginal) => ({ })) import { listMergeRequests } from './merge-request-list' +import { isTaskRepositoryIneligible } from '../git/task-repository-eligibility' +import { rememberGlabKnownHosts } from './gitlab-known-host-probe' import { listIssues } from './issues' import { _resetProjectRefCache, _resetKnownHostsCache } from './gitlab-project-ref-resolution' import { _resetRemoteNameListingCache } from '../git/remotes/remote-name-listing' @@ -132,4 +134,9 @@ describe('GitLab task project admission', () => { expect(result.items).toEqual([]) expect(glab.mock.calls.filter(([args]) => args[0] !== 'auth')).toEqual([]) }) + + it('does not exclude GitHub tasks because glab remembers github.com', async () => { + rememberGlabKnownHosts(['github.com']) + await expect(isTaskRepositoryIneligible('/github', 'github')).resolves.toBe(false) + }) }) diff --git a/src/main/ipc/browser/desktop-browser-bridge-wiring.ts b/src/main/ipc/browser/desktop-browser-bridge-wiring.ts index e6f533b851a..cd40d4ad535 100644 --- a/src/main/ipc/browser/desktop-browser-bridge-wiring.ts +++ b/src/main/ipc/browser/desktop-browser-bridge-wiring.ts @@ -5,7 +5,9 @@ import { DESKTOP_BROWSER_BRIDGE_CANCEL_CAPABILITY, DESKTOP_BROWSER_BRIDGE_EXPECT_URL_CAPABILITY, DESKTOP_BROWSER_BRIDGE_RUNTIME_CAPABILITY, - isDesktopBrowserBridgeMethod + DESKTOP_BROWSER_BRIDGE_TAB_ANNOTATIONS_CAPABILITY, + isDesktopBrowserBridgeMethod, + isHostReachableDocument } from '../../../shared/desktop-browser-bridge-protocol' import { ELECTRON_REMOTE_RUNTIME_CLIENT_CAPABILITIES } from '../../../shared/electron-remote-runtime-client-capabilities' import '../../../shared/remote-runtime/requests/remote-runtime-request-socket' @@ -22,10 +24,7 @@ import { DesktopBrowserBridgeManager, type DesktopBrowserBridgeCandidate } from '../../browser/desktop-browser-bridge/desktop-browser-bridge-manager' -import { - executeDesktopBrowserBridgeRequest, - isHostReachableDocument -} from '../../browser/desktop-browser-bridge/desktop-browser-bridge-executor' +import { executeDesktopBrowserBridgeRequest } from '../../browser/desktop-browser-bridge/desktop-browser-bridge-executor' import { rendererResolveRemoteCliWorkspace } from '../../browser/desktop-browser-bridge/desktop-browser-bridge-renderer-scope' import type { OrcaRuntimeService } from '../../runtime/orca-runtime' import { RpcDispatcher } from '../../runtime/rpc/dispatcher' @@ -153,7 +152,8 @@ export function installDesktopBrowserBridge(options: { ...ELECTRON_REMOTE_RUNTIME_CLIENT_CAPABILITIES, DESKTOP_BROWSER_BRIDGE_RUNTIME_CAPABILITY, DESKTOP_BROWSER_BRIDGE_CANCEL_CAPABILITY, - DESKTOP_BROWSER_BRIDGE_EXPECT_URL_CAPABILITY + DESKTOP_BROWSER_BRIDGE_EXPECT_URL_CAPABILITY, + DESKTOP_BROWSER_BRIDGE_TAB_ANNOTATIONS_CAPABILITY ] } ) diff --git a/src/main/ipc/computer-use-permissions.ts b/src/main/ipc/computer-use-permissions.ts index 8919acc42c7..5284a649751 100644 --- a/src/main/ipc/computer-use-permissions.ts +++ b/src/main/ipc/computer-use-permissions.ts @@ -6,6 +6,7 @@ import type { ComputerUsePermissionStatusResult } from '../../shared/computer-use-permissions-types' import { computerUsePermissionStatusGate } from '../computer/macos-computer-use-permission-status-gate' +import { mainI18n } from '../i18n/main-i18n' export function registerComputerUsePermissionHandlers(): void { ipcMain.handle( @@ -16,7 +17,7 @@ export function registerComputerUsePermissionHandlers(): void { ): Promise => { const { openComputerUsePermissions } = await import('../computer/macos-computer-use-permissions') - return openComputerUsePermissions(args?.id) + return openComputerUsePermissions(args?.id, mainI18n.resolvedLanguage ?? mainI18n.language) } ) ipcMain.handle( diff --git a/src/main/ipc/ephemeral-vm-provision-cancel.test.ts b/src/main/ipc/ephemeral-vm-provision-cancel.test.ts index 5ffa3e55049..d265ccdedd7 100644 --- a/src/main/ipc/ephemeral-vm-provision-cancel.test.ts +++ b/src/main/ipc/ephemeral-vm-provision-cancel.test.ts @@ -1,6 +1,7 @@ -import { existsSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' +import { existsSync, mkdtempSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { removeTempDirs } from '../../shared/testing/remove-temp-dirs.test-support' import { afterEach, expect, it, vi } from 'vitest' const handlers = new Map unknown>() @@ -24,10 +25,8 @@ import { registerEphemeralVmHandlers } from './ephemeral-vm' const tempDirs: string[] = [] -afterEach(() => { - for (const dir of tempDirs.splice(0)) { - rmSync(dir, { recursive: true, force: true }) - } +afterEach(async () => { + await removeTempDirs(tempDirs.splice(0)) vi.clearAllMocks() }) diff --git a/src/main/ipc/ephemeral-vm-provisioned-root-ref.test.ts b/src/main/ipc/ephemeral-vm-provisioned-root-ref.test.ts index 190c3268bc4..857c841a9a2 100644 --- a/src/main/ipc/ephemeral-vm-provisioned-root-ref.test.ts +++ b/src/main/ipc/ephemeral-vm-provisioned-root-ref.test.ts @@ -1,7 +1,8 @@ import { execFileSync } from 'node:child_process' -import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' +import { mkdtempSync, readFileSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { removeTempDirs } from '../../shared/testing/remove-temp-dirs.test-support' import { afterEach, beforeEach, expect, it, vi } from 'vitest' const handlers = new Map unknown>() @@ -43,9 +44,8 @@ beforeEach(() => { }) }) -afterEach(() => { - rmSync(userDataPath, { recursive: true, force: true }) - rmSync(repoPath, { recursive: true, force: true }) +afterEach(async () => { + await removeTempDirs([userDataPath, repoPath]) vi.clearAllMocks() }) diff --git a/src/main/ipc/ephemeral-vm-recipe-context.ts b/src/main/ipc/ephemeral-vm-recipe-context.ts index 3990f9827bf..1595c87df44 100644 --- a/src/main/ipc/ephemeral-vm-recipe-context.ts +++ b/src/main/ipc/ephemeral-vm-recipe-context.ts @@ -110,11 +110,12 @@ export function getRuntimeRecipeContext( // holds the same recipe, so a different checkout later placed there can't run its scripts. const fallback = runtime.recipe && runtime.repoPath ? runtime.recipe : null if (fallback && runtime.repoPath) { - const sameRecipe = (loadHooks(runtime.repoPath)?.environmentRecipes ?? []).some( + const sameRecipe = (loadHooks(runtime.repoPath)?.environmentRecipes ?? []).find( (entry) => entry.id === fallback.id && entry.create === fallback.create ) if (sameRecipe) { - return { runtime, repoPath: runtime.repoPath, recipe: fallback } + const passEnv = sameRecipe.passEnv ? { passEnv: sameRecipe.passEnv } : {} + return { runtime, repoPath: runtime.repoPath, recipe: { ...fallback, ...passEnv } } } } throw new EphemeralVmFailureError( @@ -128,11 +129,15 @@ export function getRuntimeRecipeContext( // Snapshots never persist timeoutSeconds, so take the repo's current limits (lifecycle commands stay // snapshotted). Only when the repo recipe has the same create command, so a different recipe that // later took this id (e.g. a repo recipe shadowing a plugin one) cannot impose its limits. - const limits = - repoRecipe?.timeoutSeconds && repoRecipe.create === runtime.recipe?.create + // passEnv follows the same rule, so suspend/resume/destroy see the environment create saw. + const sameCreate = repoRecipe !== undefined && repoRecipe.create === runtime.recipe?.create + const fromRepo = { + ...(sameCreate && repoRecipe.timeoutSeconds ? { timeoutSeconds: repoRecipe.timeoutSeconds } - : {} - const recipe = runtime.recipe ? { ...runtime.recipe, ...limits } : repoRecipe + : {}), + ...(sameCreate && repoRecipe.passEnv ? { passEnv: repoRecipe.passEnv } : {}) + } + const recipe = runtime.recipe ? { ...runtime.recipe, ...fromRepo } : repoRecipe if (!recipe) { throw new EphemeralVmFailureError( ephemeralVmFailure('recipeNotFound', { recipeId: runtime.recipeId }) diff --git a/src/main/ipc/ephemeral-vm-runtime-handler-cleanup.test.ts b/src/main/ipc/ephemeral-vm-runtime-handler-cleanup.test.ts index 96a52a900b4..e88b1dc316d 100644 --- a/src/main/ipc/ephemeral-vm-runtime-handler-cleanup.test.ts +++ b/src/main/ipc/ephemeral-vm-runtime-handler-cleanup.test.ts @@ -1,6 +1,7 @@ -import { existsSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' +import { existsSync, mkdtempSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { removeTempDirs } from '../../shared/testing/remove-temp-dirs.test-support' import { afterEach, beforeEach, expect, it, vi } from 'vitest' import { upsertEphemeralVmRuntime } from '../../shared/ephemeral-vm-runtime-store' import type * as RuntimeEnvironmentStore from '../../shared/remote-runtime/host-store/runtime-environment-store' @@ -65,10 +66,8 @@ beforeEach(() => { ) }) -afterEach(() => { - for (const dir of tempDirs.splice(0)) { - rmSync(dir, { recursive: true, force: true }) - } +afterEach(async () => { + await removeTempDirs(tempDirs.splice(0)) }) it('removes the hidden SSH target when provider cleanup cannot start', async () => { diff --git a/src/main/ipc/ephemeral-vm-runtime-handlers.ts b/src/main/ipc/ephemeral-vm-runtime-handlers.ts index 8a721827c74..f06d1116771 100644 --- a/src/main/ipc/ephemeral-vm-runtime-handlers.ts +++ b/src/main/ipc/ephemeral-vm-runtime-handlers.ts @@ -1,5 +1,6 @@ import { app, BrowserWindow, ipcMain } from 'electron' import type { Store } from '../persistence/loading-store/store' +import { listCredentialLikeEnvNames } from '../../shared/ephemeral-vm-recipe-env' import { listEphemeralVmRuntimes, updateEphemeralVmRuntimeStatus @@ -112,9 +113,15 @@ export function registerEphemeralVmRuntimeHandlers(store: Store): void { ipcMain.removeHandler('ephemeralVm:stopCleanup') ipcMain.removeHandler('ephemeralVm:forgetRuntime') ipcMain.removeHandler('ephemeralVm:getCleanupCommand') + ipcMain.removeHandler('ephemeralVm:listCredentialEnvNames') stopRuntimesChangedBroadcast?.() stopRuntimesChangedBroadcast = onEphemeralVmRuntimesChanged(broadcastEphemeralVmRuntimesChanged) + // Names only: the recipe list warns which credentials scripts inherit, never their values. + ipcMain.handle('ephemeralVm:listCredentialEnvNames', () => + listCredentialLikeEnvNames(process.env) + ) + ipcMain.handle('ephemeralVm:listRuntimes', (): EphemeralVmRuntimeRecord[] => { return listEphemeralVmRuntimes(app.getPath('userData')) }) diff --git a/src/main/ipc/ephemeral-vm.test.ts b/src/main/ipc/ephemeral-vm.test.ts index 6dd61f6f944..22b8758ca87 100644 --- a/src/main/ipc/ephemeral-vm.test.ts +++ b/src/main/ipc/ephemeral-vm.test.ts @@ -1,6 +1,7 @@ import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { removeTempDirs } from '../../shared/testing/remove-temp-dirs.test-support' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { encodePairingOffer } from '../../shared/remote-runtime/pairing/pairing' import { PAIRING_OFFER_VERSION } from '../../shared/remote-runtime/pairing/mobile-relay-pairing-offer' @@ -57,10 +58,8 @@ import { toWorkspaceLifecycleResult } from '../ephemeral-vm/workspace-lifecycle- const tempDirs: string[] = [] -afterEach(() => { - for (const dir of tempDirs.splice(0)) { - rmSync(dir, { recursive: true, force: true }) - } +afterEach(async () => { + await removeTempDirs(tempDirs.splice(0)) }) function makeDir(prefix: string): string { @@ -111,10 +110,7 @@ function pluginServiceWithRecipes( } describe('registerEphemeralVmHandlers', () => { - const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform') - beforeEach(() => { - Object.defineProperty(process, 'platform', { configurable: true, value: 'linux' }) handlers.clear() handleMock.mockReset() removeHandlerMock.mockReset() @@ -140,12 +136,6 @@ describe('registerEphemeralVmHandlers', () => { }) }) - afterEach(() => { - if (originalPlatform) { - Object.defineProperty(process, 'platform', originalPlatform) - } - }) - it('uses an immutable plugin recipe snapshot after the plugin is removed', async () => { const userDataPath = makeDir('orca-ephemeral-vm-ipc-user-data-') const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') diff --git a/src/main/ipc/pty/ipc/spawn-types.ts b/src/main/ipc/pty/ipc/spawn-types.ts index 1a52a464b4c..08bd61db360 100644 --- a/src/main/ipc/pty/ipc/spawn-types.ts +++ b/src/main/ipc/pty/ipc/spawn-types.ts @@ -65,8 +65,6 @@ export type PtySpawnIpcArgs = { spawnIntent?: unknown // Only `true` counts: a window restore no user act asked for. wslPassiveRestore?: unknown - // Only `true` counts: the user just chose to let agents ask, even if saving that answer failed. - skipAgentWorkspaceTrust?: unknown // Validate untyped launch input through AgentLaunch.safeParse. agentLaunch?: unknown // Main validates renderer telemetry; retain unknown input types at the IPC boundary. diff --git a/src/main/ipc/pty/spawn-options-assembly.ts b/src/main/ipc/pty/spawn-options-assembly.ts index ba8e3d5b1a0..93fcecc7e12 100644 --- a/src/main/ipc/pty/spawn-options-assembly.ts +++ b/src/main/ipc/pty/spawn-options-assembly.ts @@ -93,7 +93,6 @@ export type PtySpawnLaunchOptionsInput = { connectionId?: string | null shellOverride?: string telemetry?: { agent_kind?: unknown } - skipAgentWorkspaceTrust?: unknown } env: Record | undefined /** Mutated: OpenCode prep may add the keys its launch must drop. */ @@ -210,7 +209,6 @@ export async function assemblePtySpawnLaunchOptions(input: PtySpawnLaunchOptions launchAgent: args.launchAgent, worktreeId: args.worktreeId, trustWorktreeId: args.trustWorktreeId, - skipForThisLaunch: args.skipAgentWorkspaceTrust === true, cwd: input.cwd, store: input.store, isFreshLaunch: !input.preAdoptedStablePane && launchCommand !== undefined, diff --git a/src/main/ipc/repos-nested-import.test.ts b/src/main/ipc/repos-nested-import.test.ts index f70d1a9bae3..155752334ef 100644 --- a/src/main/ipc/repos-nested-import.test.ts +++ b/src/main/ipc/repos-nested-import.test.ts @@ -70,7 +70,17 @@ describe('projectGroups IPC validation', () => { mockWindow.webContents.send.mockReset() resetProjectGroupMocks(reposMocks, { isGitRepo, getGitRepoRoot }) - registerRepoHandlers(mockWindow as never, mockStore as never, {} as never) + registerRepoHandlers( + mockWindow as never, + mockStore as never, + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: These IPC cases use only the metadata owner's enqueue method; other runtime handlers are not invoked. + { + repositoryForkBackfill: { + enqueue: vi.fn().mockResolvedValue(undefined), + resolve: vi.fn().mockResolvedValue(true) + } + } as never + ) }) const group = { @@ -119,7 +129,11 @@ describe('projectGroups IPC validation', () => { mode: 'group' }) - expect(result).toMatchObject({ importedCount: 0, failedCount: 1 }) + expect(result).toMatchObject({ + importedCount: 0, + failedCount: 1, + projects: [{ errorCode: 'not_in_scan' }] + }) expect(mockStore.addRepo).not.toHaveBeenCalled() }) }) diff --git a/src/main/ipc/repos.ts b/src/main/ipc/repos.ts index 68ae1b3aed9..24448a20635 100644 --- a/src/main/ipc/repos.ts +++ b/src/main/ipc/repos.ts @@ -66,14 +66,22 @@ export function registerRepoHandlers( ipcMain.removeHandler('sparsePresets:remove') registerRepoCatalogHandlers(mainWindow, store, runtime) - registerProjectHostSetupHandlers(mainWindow, store) - registerRepoCreationHandlers(mainWindow, store) + const metadata = { + enqueueRepositoryMetadata: ( + repos: Parameters[0] + ) => void runtime.repositoryForkBackfill.enqueue(repos), + resolveRepositoryMetadata: ( + repo: Parameters[0] + ) => runtime.repositoryForkBackfill.resolve(repo) + } + registerProjectHostSetupHandlers(mainWindow, store, metadata) + registerRepoCreationHandlers(mainWindow, store, metadata.enqueueRepositoryMetadata) registerProjectGroupHandlers(mainWindow, store) registerFolderWorkspaceHandlers(mainWindow, store, runtime) - registerNestedRepoImportHandler(mainWindow, store) + registerNestedRepoImportHandler(mainWindow, store, metadata.enqueueRepositoryMetadata) registerRepoUpdateHandler(mainWindow, store) registerSparsePresetHandlers(mainWindow, store) registerRepoFolderPickerHandlers(mainWindow) - registerRepoCloneHandlers(mainWindow, store) + registerRepoCloneHandlers(mainWindow, store, metadata.enqueueRepositoryMetadata) registerBaseRefQueryHandlers(store) } diff --git a/src/main/ipc/repos/local-repo-registration.test.ts b/src/main/ipc/repos/local-repo-registration.test.ts index 8cae231ea9d..53b854a0ab4 100644 --- a/src/main/ipc/repos/local-repo-registration.test.ts +++ b/src/main/ipc/repos/local-repo-registration.test.ts @@ -7,7 +7,7 @@ import type { Store } from '../../persistence/loading-store/store' import { addLocalRepoFromPath } from './local-repo-registration' vi.mock('../../repository-icons/repo-icon-autodetect', () => ({ - detectRepoIconAndUpstream: vi.fn().mockResolvedValue({}) + detectRepoLocalMetadata: vi.fn().mockResolvedValue({}) })) vi.mock('../../workspaces/creation/worktree-root-preparation', () => ({ prepareLocalWorktreeRootForRepo: vi.fn().mockResolvedValue(undefined) diff --git a/src/main/ipc/repos/local-repo-registration.ts b/src/main/ipc/repos/local-repo-registration.ts index 5f447575fd1..53f4c136704 100644 --- a/src/main/ipc/repos/local-repo-registration.ts +++ b/src/main/ipc/repos/local-repo-registration.ts @@ -10,7 +10,7 @@ import { } from '../../git/repo' import { getRepoExecutionHostId, LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' import { findProjectAtSameRealPath } from '../../workspaces/catalog/project-realpath-identity' -import { detectRepoIconAndUpstream } from '../../repository-icons/repo-icon-autodetect' +import { detectRepoLocalMetadata } from '../../repository-icons/repo-icon-autodetect' import { prepareLocalWorktreeRootForRepo } from '../../workspaces/creation/worktree-root-preparation' import { describeWslUncAccessDenied } from '../../wsl/filesystem/wsl-unc-access-denied' import { createLocalProjectRecord } from '../../workspaces/catalog/local-project-record' @@ -86,7 +86,7 @@ export async function addLocalRepoFromPath( } } - const detected = await detectRepoIconAndUpstream({ + const detected = await detectRepoLocalMetadata({ repoPath: resolvedPath, kind: repoKind, executionHostId: LOCAL_EXECUTION_HOST_ID diff --git a/src/main/ipc/repos/nested-repo-import-handler.ts b/src/main/ipc/repos/nested-repo-import-handler.ts index 84dc522b3c2..e2152f68d2e 100644 --- a/src/main/ipc/repos/nested-repo-import-handler.ts +++ b/src/main/ipc/repos/nested-repo-import-handler.ts @@ -4,6 +4,7 @@ import { randomUUID } from 'node:crypto' import { realpath } from 'node:fs/promises' import type { Store } from '../../persistence/loading-store/store' import type { Repo } from '../../../shared/repo-types' +import type { RepositoryMetadataOwner } from '../../workspaces/catalog/imported-folder-project-link' import type { ProjectGroupImportResult } from '../../../shared/project-group-types' import { DEFAULT_REPO_BADGE_COLOR } from '../../../shared/constants' import { normalizeRuntimePathForComparison } from '../../../shared/cross-platform-path' @@ -15,7 +16,7 @@ import { } from '../../project-groups/nested-repo-import' import { createNestedRepoImportTargetResolver } from '../../project-groups/nested-repo-import-target' import { getRepoExecutionHostId, LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import { detectRepoIconAndUpstream } from '../../repository-icons/repo-icon-autodetect' +import { detectRepoLocalMetadata } from '../../repository-icons/repo-icon-autodetect' import { prepareLocalWorktreeRootForRepo } from '../../workspaces/creation/worktree-root-preparation' import { invalidateAuthorizedRootsCache } from '../worktrees/removal/registered-worktree-roots-cache' import { emitRepoAdded } from './repo-added-telemetry' @@ -28,7 +29,11 @@ function sanitizeNestedRepoImportError(context: string, error: unknown): string return 'Repository could not be imported' } -export function registerNestedRepoImportHandler(mainWindow: BrowserWindow, store: Store): void { +export function registerNestedRepoImportHandler( + mainWindow: BrowserWindow, + store: Store, + enqueueMetadata: RepositoryMetadataOwner['enqueueRepositoryMetadata'] +): void { ipcMain.handle( 'projectGroups:importNested', async (_event, rawArgs: unknown): Promise => { @@ -59,17 +64,24 @@ export function registerNestedRepoImportHandler(mainWindow: BrowserWindow, store (repoPath) => ({ path: repoPath, status: 'failed', + errorCode: 'not_in_scan', error: 'Repository was not found in the nested repo scan result' }) ) const importedProjectIdsByRepoPath = new Map() const importTargetResolver = createNestedRepoImportTargetResolver() + const acceptedRepos: Repo[] = [] for (const [projectGroupOrder, repoPath] of selection.selectedPaths.entries()) { try { // This process cannot validate SSH paths with local Git. if (args.connectionId) { - results.push({ path: repoPath, status: 'failed', error: 'Not a valid git repository' }) + results.push({ + path: repoPath, + status: 'failed', + errorCode: 'not_git_repository', + error: 'Not a valid git repository' + }) continue } await awaitWindowsHostGitEnvironmentReady({ cwd: repoPath }) @@ -77,6 +89,7 @@ export function registerNestedRepoImportHandler(mainWindow: BrowserWindow, store results.push({ path: repoPath, status: 'failed', + errorCode: 'not_git_repository', error: 'Not a valid git repository' }) continue @@ -117,7 +130,7 @@ export function registerNestedRepoImportHandler(mainWindow: BrowserWindow, store results.push({ path: repoPath, projectId: existing.id, status: 'already-known' }) continue } - const detected = await detectRepoIconAndUpstream({ + const detected = await detectRepoLocalMetadata({ repoPath: importRepoPath, kind: 'git', executionHostId: LOCAL_EXECUTION_HOST_ID @@ -140,6 +153,7 @@ export function registerNestedRepoImportHandler(mainWindow: BrowserWindow, store : {}) } store.addRepo(repo) + acceptedRepos.push(repo) await prepareLocalWorktreeRootForRepo(store, repo) importedProjectIdsByRepoPath.set(normalizedImportRepoPath, repo.id) results.push({ path: repoPath, projectId: repo.id, status: 'imported' }) @@ -148,11 +162,13 @@ export function registerNestedRepoImportHandler(mainWindow: BrowserWindow, store results.push({ path: repoPath, status: 'failed', + errorCode: 'import_failed', error: sanitizeNestedRepoImportError('Failed to import nested repository', error) }) } } + enqueueMetadata(acceptedRepos) const importedCount = results.filter((entry) => entry.status === 'imported').length const alreadyKnownCount = results.filter((entry) => entry.status === 'already-known').length const failedCount = results.filter((entry) => entry.status === 'failed').length diff --git a/src/main/ipc/repos/project-host-setup-handlers.ts b/src/main/ipc/repos/project-host-setup-handlers.ts index 61f412d26cc..7326003eb2e 100644 --- a/src/main/ipc/repos/project-host-setup-handlers.ts +++ b/src/main/ipc/repos/project-host-setup-handlers.ts @@ -13,7 +13,10 @@ import type { ProjectHostSetupUpdateResult } from '../../../shared/project-types' import { getProjectHostSetupForRepo } from '../../../shared/project-host-setup-lookup' -import { resolveImportedFolderProjectLink } from '../../../shared/imported-folder-project-identity' +import { + linkImportedFolderToProject, + type RepositoryMetadataOwner +} from '../../workspaces/catalog/imported-folder-project-link' import { readCurrentGitRemoteIdentity } from '../../workspaces/catalog/repo-git-remote-identity' import { getRepoExecutionHostId, parseExecutionHostId } from '../../../shared/execution-host' import { prepareLocalWorktreeRootForRepo } from '../../workspaces/creation/worktree-root-preparation' @@ -45,48 +48,11 @@ function buildProjectHostSetupResult(store: Store, repo: Repo): ProjectHostSetup return { project, setup, repo } } -function alignRepoWithRequestedProject( +export function registerProjectHostSetupHandlers( + mainWindow: BrowserWindow, store: Store, - repo: Repo, - folderRemote: Pick, - projectId: string, - setupMethod: ProjectHostSetupExistingFolderArgs['setupMethod'] = 'imported-existing-folder', - requestedProviderIdentity?: ProjectHostSetupExistingFolderArgs['projectProviderIdentity'] -): ProjectHostSetupResult { - assertWslMoveHostSetupWritable(store, { - projectId, - hostId: getRepoExecutionHostId(repo), - repoId: repo.id - }) - let setup = getProjectHostSetupForRepo(store.getProjectHostSetups(), repo) - if (setup.projectId !== projectId) { - const project = store.getProjects().find((entry) => entry.id === projectId) - // Project identity must travel with the request when it exists only on the source host. - const updated = store.updateRepo( - repo, - resolveImportedFolderProjectLink( - { ...repo, ...folderRemote }, - projectId, - project?.providerIdentity ?? requestedProviderIdentity - ) - ) - if (!updated) { - throw new Error(`Project setup repo disappeared before it could be linked: ${repo.id}`) - } - repo = updated - setup = getProjectHostSetupForRepo(store.getProjectHostSetups(), repo) - } - const updated = store.updateRepo(repo, { projectHostSetupMethod: setupMethod }) - if (!updated) { - throw new Error( - `Project setup repo disappeared before setup metadata could be linked: ${repo.id}` - ) - } - repo = updated - return buildProjectHostSetupResult(store, repo) -} - -export function registerProjectHostSetupHandlers(mainWindow: BrowserWindow, store: Store): void { + metadata: RepositoryMetadataOwner +): void { ipcMain.handle( 'projectHostSetups:create', (_event, rawArgs: ProjectHostSetupCreateArgs): ProjectHostSetupCreateResult => { @@ -191,20 +157,21 @@ export function registerProjectHostSetupHandlers(mainWindow: BrowserWindow, stor : result.repo let aligned: ProjectHostSetupResult try { - aligned = alignRepoWithRequestedProject( - store, + const repo = await linkImportedFolderToProject( + () => store, result.repo, folderRemote, - args.projectId, - args.setupMethod, - args.projectProviderIdentity + { ...args, hostId: getRepoExecutionHostId(result.repo) }, + metadata ) + aligned = buildProjectHostSetupResult(store, repo) } catch (err) { // Failed linking must not leave a newly registered repo or authorization root. if (!result.alreadyExisted) { store.removeProjectForHost(result.repo) invalidateAuthorizedRootsCache() } + notifyReposChanged(mainWindow) throw err } invalidateAuthorizedRootsCache() diff --git a/src/main/ipc/repos/project-host-setup-wsl-move-fence.test.ts b/src/main/ipc/repos/project-host-setup-wsl-move-fence.test.ts index a450dcab9d3..98cdb340348 100644 --- a/src/main/ipc/repos/project-host-setup-wsl-move-fence.test.ts +++ b/src/main/ipc/repos/project-host-setup-wsl-move-fence.test.ts @@ -83,7 +83,10 @@ describe('project host setups under a WSL move', () => { store.addRepo(repo('repo-1')) store.addRepo(repo('repo-2')) seedWslMoveCutover(testState.dir, cutover('move-1', 'source-fenced')) - registerProjectHostSetupHandlers(new BrowserWindow(), store) + registerProjectHostSetupHandlers(new BrowserWindow(), store, { + enqueueRepositoryMetadata: vi.fn(), + resolveRepositoryMetadata: vi.fn().mockResolvedValue(true) + }) const moving = setupFor('repo-1') await expect( @@ -107,7 +110,10 @@ describe('project host setups under a WSL move', () => { it("keeps a setup's own repo frozen once the WSL host owns it", async () => { store.addRepo(repo('repo-1')) seedWslMoveCutover(testState.dir, cutover('move-1', 'destination-committed')) - registerProjectHostSetupHandlers(new BrowserWindow(), store) + registerProjectHostSetupHandlers(new BrowserWindow(), store, { + enqueueRepositoryMetadata: vi.fn(), + resolveRepositoryMetadata: vi.fn().mockResolvedValue(true) + }) const owned = setupFor('repo-1') await expect( @@ -129,6 +135,8 @@ describe('project host setups under a WSL move', () => { invalidateResolvedWorktrees: vi.fn(), invalidateWorktreeScan: vi.fn(), notifyReposChanged: vi.fn(), + enqueueRepositoryMetadata: vi.fn(), + resolveRepositoryMetadata: vi.fn().mockResolvedValue(true), countLiveTerminalsForRepo: () => 0 }) const setupId = setupFor('repo-1').id diff --git a/src/main/ipc/repos/repo-clone-lifecycle.ts b/src/main/ipc/repos/repo-clone-lifecycle.ts index bd68750b60e..422d3833f68 100644 --- a/src/main/ipc/repos/repo-clone-lifecycle.ts +++ b/src/main/ipc/repos/repo-clone-lifecycle.ts @@ -22,14 +22,16 @@ import { getSavedProjectPathKeys } from '../../git/repo-clone-path' import { getRepoExecutionHostId, LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import { detectRepoIconAndUpstream } from '../../repository-icons/repo-icon-autodetect' +import { detectRepoLocalMetadata } from '../../repository-icons/repo-icon-autodetect' import { prepareLocalWorktreeRootForRepo } from '../../workspaces/creation/worktree-root-preparation' import { invalidateAuthorizedRootsCache } from '../worktrees/removal/registered-worktree-roots-cache' import { emitRepoAdded } from './repo-added-telemetry' import { notifyReposChanged } from './repos-changed-notification' import { runWithClonePathLock } from './clone-path-lock' +import { emitCloneProgressFromText } from './repo-clone-progress' import { resolveClonedFolderConversion } from '../../workspaces/catalog/folder-repo-git-conversion' import { findExtraFolderWorkspaceIds } from '../../workspaces/catalog/folder-workspace-meta-presence' +import type { RepositoryMetadataOwner } from '../../workspaces/catalog/imported-folder-project-link' type ActiveCloneMetadata = { path: string @@ -49,18 +51,6 @@ let nextCloneGeneration = 1 const latestCloneGenerationByPath = new Map() const pendingAbortCleanupByPath = new Map>() -function emitCloneProgressFromText(mainWindow: BrowserWindow, text: string): void { - for (const line of text.split(/[\r\n]+/)) { - const match = line.match(/^([\w\s]+):\s+(\d+)%/) - if (match && !mainWindow.isDestroyed()) { - mainWindow.webContents.send('repos:clone-progress', { - phase: match[1].trim(), - percent: Number.parseInt(match[2], 10) - }) - } - } -} - async function cleanupOwnedCloneTarget(metadata: ActiveCloneMetadata): Promise { if (!metadata.claimedTarget.canCleanup || !metadata.claimedTarget.ownedDirectoryIdentity) { return @@ -102,7 +92,11 @@ function settleCloneAbortCleanup(metadata: ActiveCloneMetadata): void { metadata.resolvePendingAbortCleanup = null } -export function registerRepoCloneHandlers(mainWindow: BrowserWindow, store: Store): void { +export function registerRepoCloneHandlers( + mainWindow: BrowserWindow, + store: Store, + enqueueMetadata: RepositoryMetadataOwner['enqueueRepositoryMetadata'] +): void { ipcMain.handle('repos:cloneAbort', async () => { for (const controller of pendingLocalCloneControllers) { controller.abort() @@ -136,7 +130,7 @@ export function registerRepoCloneHandlers(mainWindow: BrowserWindow, store: Stor const clonePathKey = getClonePathComparisonKey(clonePath) let savedPathKeys: string[] = [] const findSaved = (): Repo | undefined => findLocalSaved(savedPathKeys) - return runWithClonePathLock(clonePathKey, async () => { + const repo = await runWithClonePathLock(clonePathKey, async () => { await pendingAbortCleanupByPath.get(clonePathKey) // Read after the lock so lookup sees what a queued clone of this path registered. savedPathKeys = await getSavedProjectPathKeys(clonePath) @@ -299,7 +293,7 @@ export function registerRepoCloneHandlers(mainWindow: BrowserWindow, store: Stor // Register Git's checkout path so the clone stays its own selected checkout. const repoPath = (await inspectGitRepoForRegistrationAsync(clonePath)).rootPath - const detected = await detectRepoIconAndUpstream({ + const detected = await detectRepoLocalMetadata({ repoPath, kind: 'git', executionHostId: LOCAL_EXECUTION_HOST_ID @@ -329,5 +323,7 @@ export function registerRepoCloneHandlers(mainWindow: BrowserWindow, store: Stor } } }) + enqueueMetadata([repo]) + return repo }) } diff --git a/src/main/ipc/repos/repo-clone-progress.ts b/src/main/ipc/repos/repo-clone-progress.ts new file mode 100644 index 00000000000..cce16fbcd9c --- /dev/null +++ b/src/main/ipc/repos/repo-clone-progress.ts @@ -0,0 +1,13 @@ +import type { BrowserWindow } from 'electron' + +export function emitCloneProgressFromText(mainWindow: BrowserWindow, text: string): void { + for (const line of text.split(/[\r\n]+/)) { + const match = line.match(/^([\w\s]+):\s+(\d+)%/) + if (match && !mainWindow.isDestroyed()) { + mainWindow.webContents.send('repos:clone-progress', { + phase: match[1].trim(), + percent: Number.parseInt(match[2], 10) + }) + } + } +} diff --git a/src/main/ipc/repos/repo-creation-handlers.ts b/src/main/ipc/repos/repo-creation-handlers.ts index 25aed3525a0..d17a56ee3ba 100644 --- a/src/main/ipc/repos/repo-creation-handlers.ts +++ b/src/main/ipc/repos/repo-creation-handlers.ts @@ -6,6 +6,7 @@ import { homedir } from 'node:os' import { isAbsolute, join } from 'node:path' import type { Store } from '../../persistence/loading-store/store' import type { Repo } from '../../../shared/repo-types' +import type { RepositoryMetadataOwner } from '../../workspaces/catalog/imported-folder-project-link' import { DEFAULT_REPO_BADGE_COLOR, getDefaultWorkspaceDir } from '../../../shared/constants' import { normalizeRuntimePathForComparison } from '../../../shared/cross-platform-path' import { getRepoExecutionHostId, LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' @@ -14,7 +15,7 @@ import { probeGitAvailability } from '../../git/git-availability' import { gitExecFileAsync } from '../../git/runner' import { inspectGitRepoForRegistrationAsync } from '../../git/repo' import { getClonePathComparisonKey, getSavedProjectPathKeys } from '../../git/repo-clone-path' -import { detectRepoIconAndUpstream } from '../../repository-icons/repo-icon-autodetect' +import { detectRepoLocalMetadata } from '../../repository-icons/repo-icon-autodetect' import { prepareLocalWorktreeRootForRepo } from '../../workspaces/creation/worktree-root-preparation' import { invalidateAuthorizedRootsCache } from '../worktrees/removal/registered-worktree-roots-cache' import { repoCreateFailure, type RepoCreateFailure } from '../../../shared/repo-create-failure-copy' @@ -51,7 +52,11 @@ function getDefaultCreateProjectParent(store: Store): string { return join(home, 'orca', 'projects') } -export function registerRepoCreationHandlers(mainWindow: BrowserWindow, store: Store): void { +export function registerRepoCreationHandlers( + mainWindow: BrowserWindow, + store: Store, + enqueueMetadata: RepositoryMetadataOwner['enqueueRepositoryMetadata'] +): void { ipcMain.handle('repos:isGitAvailable', () => probeLocalGitAvailability()) ipcMain.handle('repos:getDefaultCreateProjectParent', () => getDefaultCreateProjectParent(store)) @@ -70,6 +75,7 @@ export function registerRepoCreationHandlers(mainWindow: BrowserWindow, store: S } invalidateAuthorizedRootsCache() notifyReposChanged(mainWindow) + enqueueMetadata([result.repo]) emitRepoAdded('folder_picker', result.alreadyExisted, result.repo.kind === 'git') return { repo: result.repo } } @@ -222,7 +228,7 @@ export function registerRepoCreationHandlers(mainWindow: BrowserWindow, store: S repoKind === 'git' ? (await inspectGitRepoForRegistrationAsync(targetPath)).rootPath : targetPath - const detected = await detectRepoIconAndUpstream({ + const detected = await detectRepoLocalMetadata({ repoPath, kind: repoKind, executionHostId: LOCAL_EXECUTION_HOST_ID @@ -244,6 +250,7 @@ export function registerRepoCreationHandlers(mainWindow: BrowserWindow, store: S } store.addRepo(repo) + enqueueMetadata([repo]) await prepareLocalWorktreeRootForRepo(store, repo) invalidateAuthorizedRootsCache() notifyReposChanged(mainWindow) diff --git a/src/main/ipc/runtime-environments/runtime-environment-recipe-vm-wake.test.ts b/src/main/ipc/runtime-environments/runtime-environment-recipe-vm-wake.test.ts index 6e3c5b7f1bb..365f916716a 100644 --- a/src/main/ipc/runtime-environments/runtime-environment-recipe-vm-wake.test.ts +++ b/src/main/ipc/runtime-environments/runtime-environment-recipe-vm-wake.test.ts @@ -1,8 +1,9 @@ // #36923: a client reaches a recipe VM's workspace through the VM's own server, which is gone // while the VM sleeps. Opening the workspace wakes it; any other request leaves it asleep. -import { mkdtempSync, rmSync } from 'node:fs' +import { mkdtempSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { removeTempDirs } from '../../../shared/testing/remove-temp-dirs.test-support' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { encodePairingOffer } from '../../../shared/remote-runtime/pairing/pairing' import { PAIRING_OFFER_VERSION } from '../../../shared/remote-runtime/pairing/mobile-relay-pairing-offer' @@ -104,9 +105,9 @@ describe('a request to a recipe VM environment', () => { }) }) - afterEach(() => { + afterEach(async () => { registerRecipeVmWaker(null) - rmSync(userDataPath, { recursive: true, force: true }) + await removeTempDirs([userDataPath]) }) it.each(['suspended', 'resume_failed'] as const)( diff --git a/src/main/ipc/workspace-space/workspace-space-window.ts b/src/main/ipc/workspace-space/workspace-space-window.ts index cd00a4acf48..1c5443a91be 100644 --- a/src/main/ipc/workspace-space/workspace-space-window.ts +++ b/src/main/ipc/workspace-space/workspace-space-window.ts @@ -18,6 +18,7 @@ export function registerWorkspaceSpaceWindowHandlers(store: Store): void { 'workspaceSpace:requestWindowState', 'workspaceSpace:revealWorktree', 'workspaceSpace:requestWorktreeRefresh', + 'workspaceSpace:requestIssueRefresh', 'workspaceSpace:publishWindowAnalysis' ]) { ipcMain.removeHandler(channel) @@ -72,6 +73,27 @@ export function registerWorkspaceSpaceWindowHandlers(store: Store): void { getTrustedUIRendererWebContents()?.send('workspaceSpace:worktreeRefreshRequested') } }) + // Why: the main window owns issueCache and publishes it to the Space window; Space asks rather than writing its own copy. + ipcMain.handle( + 'workspaceSpace:requestIssueRefresh', + (event, worktreeId: unknown, hostId: unknown): void => { + if (!isWorkspaceSpaceWindowRenderer(event.sender) || typeof worktreeId !== 'string') { + return + } + if (hostId !== undefined && typeof hostId !== 'string') { + return + } + const executionHostId = normalizeExecutionHostId(hostId) + if (hostId !== undefined && executionHostId === null) { + return + } + getTrustedUIRendererWebContents()?.send( + 'workspaceSpace:issueRefreshRequested', + worktreeId, + executionHostId ?? undefined + ) + } + ) ipcMain.handle('workspaceSpace:publishWindowAnalysis', (event, analysis: unknown): void => { if (isWorkspaceSpaceWindowRenderer(event.sender) && analysis && typeof analysis === 'object') { getTrustedUIRendererWebContents()?.send('workspaceSpace:windowAnalysis', analysis) diff --git a/src/main/ipc/worktrees/listing/detected-provider-listing-catalog-version.test.ts b/src/main/ipc/worktrees/listing/detected-provider-listing-catalog-version.test.ts index 3ea51313aa2..4924c45d74a 100644 --- a/src/main/ipc/worktrees/listing/detected-provider-listing-catalog-version.test.ts +++ b/src/main/ipc/worktrees/listing/detected-provider-listing-catalog-version.test.ts @@ -28,10 +28,8 @@ vi.mock('./authoritative-local-worktree-metadata-pruning', () => ({ })) const { listDetectedWorktreesForCapturedRepo } = await import('./detected-provider-listing') -const { __resetDetectedWorktreeScanCacheForTests, invalidateDetectedWorktreeScanCache } = - await import('./detected-worktree-scan-cache') -const { getLocalWorktreeCatalogVersion, getLocalWorktreeScanGeneration } = - await import('../../../workspaces/catalog/local-worktree-scan-generation') +const { __resetDetectedWorktreeScanCacheForTests } = await import('./detected-worktree-scan-cache') +await import('../../../workspaces/catalog/local-worktree-scan-generation') const localRepo: Repo = { id: 'repo-local', @@ -41,7 +39,7 @@ const localRepo: Repo = { addedAt: 0 } -function createStore(repo: Repo) { +function createStore(repo: Repo, cursor?: { epoch: string; seq: number }) { // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the listing reads only these store methods; the pruning that would need more is mocked above. return { getRepo: () => repo, @@ -55,7 +53,8 @@ function createStore(repo: Repo) { getAllWorktreeLineage: () => ({}), getAllWorkspaceLineage: () => ({}), removeWorktreeLineage: vi.fn(), - captureNativeLocalWorktreeMetadataScanExpectation: () => undefined + captureNativeLocalWorktreeMetadataScanExpectation: () => undefined, + ...(cursor ? { getWorkspaceMetadataCursor: () => ({ ...cursor }) } : {}) } as never } @@ -63,10 +62,6 @@ function worktreeAt(repo: Repo, path: string): GitWorktreeInfo { return { path, head: 'abc', branch: 'main', isBare: false, isMainWorktree: path === repo.path } } -function listLocal() { - return listDetectedWorktreesForCapturedRepo(createStore(localRepo), localRepo, () => true) -} - // Clients order listing rows by scan-start generation against applied create/remove replies. describe('the catalog version a listing carries', () => { beforeEach(() => { @@ -74,36 +69,25 @@ describe('the catalog version a listing carries', () => { listRepoWorktreesMock.mockReset() }) - it('is the generation the local scan began at, and a change bumps the current one past it', async () => { - listRepoWorktreesMock.mockResolvedValue([worktreeAt(localRepo, localRepo.path)]) - const atScanStart = getLocalWorktreeScanGeneration(localRepo.id) + it('carries the metadata cursor it read with its metadata, not one advanced during the scan', async () => { + const cursor = { epoch: 'e1', seq: 4 } + // A title write lands while the scan is still running. + listRepoWorktreesMock.mockImplementation(async () => { + cursor.seq = 5 + return [worktreeAt(localRepo, localRepo.path)] + }) + const store = createStore(localRepo, cursor) - const listing = await listLocal() + const during = await listDetectedWorktreesForCapturedRepo(store, localRepo, () => true) + const after = await listDetectedWorktreesForCapturedRepo(store, localRepo, () => true) - expect(listing).toMatchObject({ authoritative: true }) - expect(listing && 'catalogVersion' in listing ? listing.catalogVersion : undefined).toEqual( - getLocalWorktreeCatalogVersion(localRepo.id) - ) - expect(listing && 'catalogVersion' in listing ? listing.catalogVersion?.sequence : -1).toBe( - atScanStart - ) - - invalidateDetectedWorktreeScanCache(localRepo.id) - const afterChange = getLocalWorktreeCatalogVersion(localRepo.id) - expect(afterChange.sequence).toBeGreaterThan(atScanStart) - expect(afterChange.epoch).toBe( - listing && 'catalogVersion' in listing ? listing.catalogVersion?.epoch : undefined - ) - }) - - it("is the cached scan's own generation when the cache answers", async () => { - listRepoWorktreesMock.mockResolvedValue([worktreeAt(localRepo, localRepo.path)]) - const first = await listLocal() - const second = await listLocal() - - expect(listRepoWorktreesMock).toHaveBeenCalledTimes(1) - expect(second && 'catalogVersion' in second ? second.catalogVersion : undefined).toEqual( - first && 'catalogVersion' in first ? first.catalogVersion : undefined - ) + expect(during && 'workspaceMetadata' in during ? during.workspaceMetadata : null).toEqual({ + epoch: 'e1', + seq: 4 + }) + expect(after && 'workspaceMetadata' in after ? after.workspaceMetadata : null).toEqual({ + epoch: 'e1', + seq: 5 + }) }) }) diff --git a/src/main/ipc/worktrees/listing/detected-provider-listing.ts b/src/main/ipc/worktrees/listing/detected-provider-listing.ts index 3344d22e1a6..7aa21b9e99a 100644 --- a/src/main/ipc/worktrees/listing/detected-provider-listing.ts +++ b/src/main/ipc/worktrees/listing/detected-provider-listing.ts @@ -46,6 +46,13 @@ import { wslDistroNotRunningForScanFailure } from './wsl-stopped-worktree-listing' +// Partial stores (tests, embedders) may not publish workspace metadata; their listings carry no stamp. +function readWorkspaceMetadataCursor(store: { + getWorkspaceMetadataCursor?: () => { epoch: string; seq: number } +}): { epoch: string; seq: number } | undefined { + return store.getWorkspaceMetadataCursor?.() +} + export async function listDetectedWorktreesForCapturedRepo( store: Store, repo: Repo, @@ -59,6 +66,8 @@ export async function listDetectedWorktreesForCapturedRepo( ? ({ providerAbortStatus: providerAbort.status() } as const) : undefined const allMeta = isFolderRepo(repo) ? undefined : readAllWorktreeMetaForRepo(store, repo) + // Read with the metadata, so clients can tell which published metadata records this listing includes. + const workspaceMetadata = readWorkspaceMetadataCursor(store) try { // Folder rows are read synchronously, leaving no mutation window that needs a re-scan. @@ -75,7 +84,8 @@ export async function listDetectedWorktreesForCapturedRepo( authoritative: false, source: 'metadata-fallback', worktrees: [], - catalogVersion: getLocalWorktreeCatalogVersion(repo.id) + catalogVersion: getLocalWorktreeCatalogVersion(repo.id), + ...(workspaceMetadata ? { workspaceMetadata } : {}) } } return { @@ -83,6 +93,7 @@ export async function listDetectedWorktreesForCapturedRepo( authoritative: true, source: 'git', catalogVersion: getLocalWorktreeCatalogVersion(repo.id), + ...(workspaceMetadata ? { workspaceMetadata } : {}), worktrees: projectWorktreeLineageWithHostPeers( store, repo, @@ -108,7 +119,8 @@ export async function listDetectedWorktreesForCapturedRepo( authoritative: false, source: 'metadata-fallback', worktrees: buildDisconnectedDetectedWorktrees(store, repo, worktrees), - catalogVersion: getLocalWorktreeCatalogVersion(repo.id) + catalogVersion: getLocalWorktreeCatalogVersion(repo.id), + ...(workspaceMetadata ? { workspaceMetadata } : {}) } } const pendingAtScan = snapshotPendingWorktreeRemovals() @@ -140,7 +152,8 @@ export async function listDetectedWorktreesForCapturedRepo( authoritative: false, source: 'metadata-fallback', worktrees: [], - catalogVersion: localWorktreeCatalogVersionAt(scan.generation) + catalogVersion: localWorktreeCatalogVersionAt(scan.generation), + ...(workspaceMetadata ? { workspaceMetadata } : {}) } } if (freshScan) { @@ -166,6 +179,7 @@ export async function listDetectedWorktreesForCapturedRepo( authoritative: true, source: 'git', catalogVersion: localWorktreeCatalogVersionAt(scan.generation), + ...(workspaceMetadata ? { workspaceMetadata } : {}), worktrees: projectPendingWorktreeRemovals( buildDetectedGitWorktrees(store, repo, localRows, allMeta), (worktree) => worktree.id, @@ -196,7 +210,8 @@ export async function listDetectedWorktreesForCapturedRepo( unavailableReason, failureKind, wslDistroStopped, - catalogVersion: getLocalWorktreeCatalogVersion(repo.id) + catalogVersion: getLocalWorktreeCatalogVersion(repo.id), + ...(workspaceMetadata ? { workspaceMetadata } : {}) } } warnOnce( @@ -212,7 +227,8 @@ export async function listDetectedWorktreesForCapturedRepo( worktrees: [], unavailableReason, failureKind, - catalogVersion: getLocalWorktreeCatalogVersion(repo.id) + catalogVersion: getLocalWorktreeCatalogVersion(repo.id), + ...(workspaceMetadata ? { workspaceMetadata } : {}) } } } diff --git a/src/main/linear/issue-relation-write.test.ts b/src/main/linear/issue-relation-write.test.ts new file mode 100644 index 00000000000..9eb2ba48ae5 --- /dev/null +++ b/src/main/linear/issue-relation-write.test.ts @@ -0,0 +1,54 @@ +import { describe, expect, it, vi } from 'vitest' + +const { rawRequest } = vi.hoisted(() => ({ rawRequest: vi.fn() })) + +vi.mock('./linear-request-concurrency', () => ({ + acquire: vi.fn().mockResolvedValue(undefined), + release: vi.fn() +})) + +vi.mock('./linear-token-store', () => ({ + clearToken: vi.fn() +})) + +vi.mock('./client', () => ({ + getClients: () => [{ workspace: { id: 'workspace-1' }, client: { client: { rawRequest } } }], + isAuthError: () => false +})) + +import { writeIssueRelation } from './issue-relation-write' + +describe('writeIssueRelation', () => { + it('does not create a relation when the duplicate lookup omits pageInfo', async () => { + rawRequest.mockImplementation(async (query: string) => + query.includes('issueRelationCreate') + ? { + data: { + issueRelationCreate: { + success: true, + issueRelation: { + id: 'rel-new', + type: 'blocks', + issue: { id: 'issue-1' }, + relatedIssue: { id: 'issue-2' } + } + } + } + } + : { data: { issue: { relations: { nodes: [] } } } } + ) + const issue = { id: 'issue-1', identifier: 'LIN-1', title: 'One', url: 'https://x/1' } + const relatedIssue = { id: 'issue-2', identifier: 'LIN-2', title: 'Two', url: 'https://x/2' } + + await expect( + writeIssueRelation({ + issue, + relatedIssue, + relationship: 'blocks', + operation: 'add', + workspaceId: 'workspace-1' + }) + ).rejects.toMatchObject({ code: 'linear_partial' }) + expect(rawRequest).toHaveBeenCalledTimes(1) + }) +}) diff --git a/src/main/linear/issue-relation-write.ts b/src/main/linear/issue-relation-write.ts index 9b340d28bd1..e63e26fdb70 100644 --- a/src/main/linear/issue-relation-write.ts +++ b/src/main/linear/issue-relation-write.ts @@ -9,6 +9,7 @@ import { acquire, release } from './linear-request-concurrency' import { clearToken } from './linear-token-store' import { getClients, isAuthError } from './client' import { linearError } from './issue-context/errors' +import { linearConnectionHasNextPage } from './issue-context/pagination' import { INVERSE_RELATIONS_QUERY, RELATIONS_QUERY, @@ -135,7 +136,7 @@ async function findRelationInDirection( } inspected += nodes.length - const hasMore = connection?.pageInfo?.hasNextPage === true + const hasMore = linearConnectionHasNextPage(connection) const nextCursor = connection?.pageInfo?.endCursor ?? undefined if (!hasMore) { return { relation: null, hasMore: false } diff --git a/src/main/linear/mcp-issue-list-page-info.test.ts b/src/main/linear/mcp-issue-list-page-info.test.ts deleted file mode 100644 index cd4e71b6e98..00000000000 --- a/src/main/linear/mcp-issue-list-page-info.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' - -const { rawRequest } = vi.hoisted(() => ({ rawRequest: vi.fn() })) - -vi.mock('./linear-request-concurrency', () => ({ - acquire: vi.fn().mockResolvedValue(undefined), - release: vi.fn() -})) - -vi.mock('./linear-token-store', () => ({ - clearToken: vi.fn() -})) - -vi.mock('./client', () => ({ - getClients: () => [ - { - workspace: { - id: 'workspace-1', - organizationId: 'workspace-1', - organizationName: 'Acme', - displayName: 'Ada', - email: 'ada@example.com' - }, - client: { client: { rawRequest } } - } - ], - getStatus: () => ({ workspaces: [] }), - isAuthError: () => false, - getPublicFileUrlClient: (entry: { client: unknown }) => entry.client -})) - -import { listMcpIssues } from './mcp-issue-list' - -function issueNode(id: string) { - return { - id, - identifier: id.toUpperCase(), - title: id, - url: `https://linear.app/acme/issue/${id}`, - labels: { nodes: [] }, - updatedAt: '2026-11-10T00:00:00.000Z' - } -} - -describe('Linear list pagination evidence', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - - it('does not report a complete list when a later page omits pageInfo', async () => { - rawRequest - .mockResolvedValueOnce({ - data: { - issues: { - nodes: [issueNode('lin-1'), issueNode('lin-2')], - pageInfo: { hasNextPage: true, endCursor: 'next' } - } - } - }) - .mockResolvedValueOnce({ - data: { issues: { nodes: [] } } - }) - - await expect(listMcpIssues({})).rejects.toMatchObject({ code: 'linear_partial' }) - expect(rawRequest).toHaveBeenCalledTimes(2) - }) -}) diff --git a/src/main/menu/app-menu-window.ts b/src/main/menu/app-menu-window.ts index c78e289fdb1..a1b939e5668 100644 --- a/src/main/menu/app-menu-window.ts +++ b/src/main/menu/app-menu-window.ts @@ -1,3 +1,5 @@ +import { labeledAppMenuRole } from './labeled-app-menu-role' + export function createAppWindowMenu( label: string, isMac: boolean @@ -6,11 +8,11 @@ export function createAppWindowMenu( label, submenu: [ { - // Electron's minimize role would steal Ctrl+M from terminal apps. - role: 'minimize', + ...labeledAppMenuRole('minimize', 'menu.minimize', 'Minimize'), + // Why: Electron's minimize role otherwise steals Ctrl+M from terminal apps. ...(isMac ? {} : { accelerator: '', registerAccelerator: false }) }, - { role: 'zoom' } + labeledAppMenuRole('zoom', 'menu.zoom', 'Zoom') ] } } diff --git a/src/main/menu/labeled-app-menu-role.ts b/src/main/menu/labeled-app-menu-role.ts new file mode 100644 index 00000000000..28d4c6f682b --- /dev/null +++ b/src/main/menu/labeled-app-menu-role.ts @@ -0,0 +1,9 @@ +import { translateMain } from '../i18n/main-i18n' + +export function labeledAppMenuRole( + role: Electron.MenuItemConstructorOptions['role'], + key: string, + fallback: string +): Electron.MenuItemConstructorOptions { + return { role, label: translateMain(key, fallback) } +} diff --git a/src/main/menu/register-app-menu.ts b/src/main/menu/register-app-menu.ts index 55c6b770f77..ab7117af9a6 100644 --- a/src/main/menu/register-app-menu.ts +++ b/src/main/menu/register-app-menu.ts @@ -10,6 +10,7 @@ import { translateMain } from '../i18n/main-i18n' import { createAppMenuSelectionItem, resolveNativeEditTarget } from './app-menu-selection-item' import { createAppMenuQuitItems, type AppMenuQuitHandlers } from './app-menu-quit-item' import { createAppMenuReloadAndDevToolsItems } from './app-menu-reload-devtools-items' +import { labeledAppMenuRole } from './labeled-app-menu-role' import { createAppWindowMenu } from './app-menu-window' export type AppearanceMenuState = { @@ -129,15 +130,15 @@ function buildAndApplyMenu(options: RegisterAppMenuOptions): void { const macAppMenu: Electron.MenuItemConstructorOptions = { label: options.appMenuLabel ?? app.name, submenu: [ - { role: 'about' }, + labeledAppMenuRole('about', 'menu.about', 'About Orca'), checkForUpdatesItem, settingsItem, { type: 'separator' }, - { role: 'services' }, + labeledAppMenuRole('services', 'menu.services', 'Services'), { type: 'separator' }, - { role: 'hide' }, - { role: 'hideOthers' }, - { role: 'unhide' }, + labeledAppMenuRole('hide', 'menu.hide', 'Hide Orca'), + labeledAppMenuRole('hideOthers', 'menu.hideOthers', 'Hide Others'), + labeledAppMenuRole('unhide', 'menu.unhide', 'Show All'), { type: 'separator' }, ...createAppMenuQuitItems(options, options.appMenuLabel ?? app.name) ] @@ -155,10 +156,10 @@ function buildAndApplyMenu(options: RegisterAppMenuOptions): void { const editMenu: Electron.MenuItemConstructorOptions = { label: translateMain('menu.edit', 'Edit'), submenu: [ - { role: 'undo', ...undoRedoOptions }, - { role: 'redo', ...undoRedoOptions }, + { role: 'undo', label: translateMain('menu.undo', 'Undo'), ...undoRedoOptions }, + { role: 'redo', label: translateMain('menu.redo', 'Redo'), ...undoRedoOptions }, { type: 'separator' }, - { role: 'cut' }, + labeledAppMenuRole('cut', 'menu.cut', 'Cut'), createAppMenuSelectionItem({ action: 'copy', label: translateMain('menu.copy', 'Copy'), @@ -268,7 +269,7 @@ function buildAndApplyMenu(options: RegisterAppMenuOptions): void { label: `${translateMain('menu.openWorktreePalette', 'Open Worktree Palette')}\t${shortcutLabel('worktree.palette')}` }, { type: 'separator' }, - { role: 'togglefullscreen' }, + labeledAppMenuRole('togglefullscreen', 'menu.toggleFullScreen', 'Toggle Full Screen'), { type: 'separator' }, appearanceSubmenu ] @@ -287,7 +288,7 @@ function buildAndApplyMenu(options: RegisterAppMenuOptions): void { ? [] : ([ { type: 'separator' }, - { role: 'about' }, + labeledAppMenuRole('about', 'menu.about', 'About Orca'), checkForUpdatesItem ] satisfies Electron.MenuItemConstructorOptions[])) ] diff --git a/src/main/native-chat/agent-model-catalog/agent-model-catalog-entry.test.ts b/src/main/native-chat/agent-model-catalog/agent-model-catalog-entry.test.ts index a7f586a5c91..9286e5f368a 100644 --- a/src/main/native-chat/agent-model-catalog/agent-model-catalog-entry.test.ts +++ b/src/main/native-chat/agent-model-catalog/agent-model-catalog-entry.test.ts @@ -74,14 +74,16 @@ describe('a model whose newer chat listing does not know its efforts', () => { expect(merged).not.toHaveProperty('defaultEffort') }) - it('keeps native suggestions unknown without a known model menu', () => { + it('drops an OMP menu an older build borrowed from the running model', () => { + const saved = unknownChat(1, menu('low', 'medium', 'max')) + expect(agentModelCatalogEntry('omp', 'fp', saved, null, null)?.models[0]).toMatchObject({ + efforts: [], + effortsKnown: false + }) + }) + + it('keeps an older unknown menu when the newer listing has none', () => { const older = unknownChat(1, menu('low', 'high')) - const newer = unknownChat(2, menu('off', 'auto')) - for (const discovered of [null, { ...older, origin: 'probe' as const }]) { - const merged = agentModelCatalogEntry('omp', 'fp', discovered, newer, null)?.models[0] - expect(merged).toMatchObject({ efforts: menu('off', 'auto'), effortsKnown: false }) - expect(merged).not.toHaveProperty('defaultEffort') - } expect(model({ ...older, origin: 'probe' }, unknownChat(2))).toMatchObject({ efforts: menu('low', 'high'), effortsKnown: false diff --git a/src/main/native-chat/agent-model-catalog/agent-model-catalog-models.ts b/src/main/native-chat/agent-model-catalog/agent-model-catalog-models.ts index d9945ac0782..3b6ffd9e712 100644 --- a/src/main/native-chat/agent-model-catalog/agent-model-catalog-models.ts +++ b/src/main/native-chat/agent-model-catalog/agent-model-catalog-models.ts @@ -28,7 +28,7 @@ export function mergedAgentModelCatalogModels( // Coarser probe menus must not discard a chat-confirmed effort unless a newer chat menu does. const keepsChatMenu = older === live && !offersConfigured(model.efforts) && offersConfigured(olderEfforts) - const { efforts, effortsKnown } = modelSpecificEfforts + const { efforts: keptEfforts, effortsKnown } = modelSpecificEfforts ? model.effortsKnown === false && olderModel ? olderModel : model @@ -39,6 +39,8 @@ export function mergedAgentModelCatalogModels( : model.efforts.length > 0 && !keepsChatMenu ? model : (olderModel ?? model) + // An unobserved per-model menu is another model's; older builds saved such copies. + const efforts = modelSpecificEfforts && effortsKnown === false ? [] : keptEfforts const defaultEffort = [configuredEffort, listed?.defaultEffort, reported?.defaultEffort].find( (effort) => effort !== undefined && efforts.some((choice) => choice.value === effort) ) diff --git a/src/main/native-chat/agent-model-catalog/agent-model-catalog-scope.ts b/src/main/native-chat/agent-model-catalog/agent-model-catalog-scope.ts index b90609fc5ed..37122867666 100644 --- a/src/main/native-chat/agent-model-catalog/agent-model-catalog-scope.ts +++ b/src/main/native-chat/agent-model-catalog/agent-model-catalog-scope.ts @@ -62,7 +62,8 @@ export async function resolveAgentModelCatalogScope( // The list belongs to the account and the CLI a chat here would launch, not to this folder: // resolve the executable where the chat runs, but list from an empty Orca-owned folder so the // listing reads only account settings (a home folder can hold another account's settings as - // project settings) and every workspace sharing that invocation shares one listing. + // project settings) and every workspace sharing that invocation shares one listing. A command + // line that may name files in the chat's folder lists there instead (`catalogListingDirectory`). let listIn: string try { listIn = resolveHiddenProbeCwd() diff --git a/src/main/native-chat/agent-model-catalog/agent-model-catalog-snapshot.ts b/src/main/native-chat/agent-model-catalog/agent-model-catalog-snapshot.ts index b737ff65017..55cb348482b 100644 --- a/src/main/native-chat/agent-model-catalog/agent-model-catalog-snapshot.ts +++ b/src/main/native-chat/agent-model-catalog/agent-model-catalog-snapshot.ts @@ -239,7 +239,10 @@ export function projectAgentModelCatalogSnapshot( ...(!params.savedOnly && !params.verifiedOnly && (deps.store.isListing(bound.fingerprint) || - (resolving && deps.store.probeDue(bound.fingerprint))) && + (resolving && + (deps.store.probeDue(bound.fingerprint) || + // The picked model's menu is listed by the refresh this read just asked for. + deps.store.efforts.due(bound.fingerprint, params.selectedModel)))) && (independent || !listed || usesModelSpecificAcpEfforts(params.agent)) ? { listingInProgress: true as const } : {}), diff --git a/src/main/native-chat/agent-session-journal/input-order/journal-input-obligations.ts b/src/main/native-chat/agent-session-journal/input-order/journal-input-obligations.ts index de62b758978..2e082b85a45 100644 --- a/src/main/native-chat/agent-session-journal/input-order/journal-input-obligations.ts +++ b/src/main/native-chat/agent-session-journal/input-order/journal-input-obligations.ts @@ -262,6 +262,10 @@ export function journalInputPresentationMember( state: JournalReducerState, itemId: string ): boolean { + // Renders ask this of every row on each commit; parsing each key froze main in big chats (#40682). + if (state.inputs.rejections.size === 0) { + return true + } const identity = parseAgentJournalItemKey(itemId) return ( identity?.provider !== 'orca' || diff --git a/src/main/native-chat/agent-session-wire/host/testing/structured-agent-session-option-refresh.test-fixture.ts b/src/main/native-chat/agent-session-wire/host/testing/structured-agent-session-option-refresh.test-fixture.ts index 7138dbedf82..856e071ee53 100644 --- a/src/main/native-chat/agent-session-wire/host/testing/structured-agent-session-option-refresh.test-fixture.ts +++ b/src/main/native-chat/agent-session-wire/host/testing/structured-agent-session-option-refresh.test-fixture.ts @@ -106,7 +106,8 @@ export function piOptionRefreshHost(sessionId = 'session-1') { }, serialize: (_sessionId: string, task: () => Promise) => task(), openConversation: async () => conversation, - conversation: async () => conversation + conversation: async () => conversation, + sessions: new Map([[sessionId, conversation]]) } as unknown as StructuredAgentSessionMutationContext return readStructuredAgentSessionOptions(context, sessionId, { readsWithoutModel: true }) }, diff --git a/src/main/native-chat/agent-session-wire/host/testing/structured-agent-session-options-read-report-freshness.test.ts b/src/main/native-chat/agent-session-wire/host/testing/structured-agent-session-options-read-report-freshness.test.ts new file mode 100644 index 00000000000..d6e7517d7ea --- /dev/null +++ b/src/main/native-chat/agent-session-wire/host/testing/structured-agent-session-options-read-report-freshness.test.ts @@ -0,0 +1,182 @@ +import { expect, it } from 'vitest' +import type { AgentSessionModelCatalogResult } from '../../../../../shared/agent-session/agent-session-wire' +import type { StructuredAgentSessionMutationContext } from '../../operations/structured-agent-session-mutation-context' +import type { + StructuredAgentSessionHostSession, + StructuredAgentSessionProviderChild +} from '../structured-agent-session-host-types' +import { readStructuredAgentSessionOptions } from '../../options/structured-agent-session-options-read' +import { noteStructuredAgentSessionOptionPick } from '../../options/structured-agent-session-option-intent' +import { + hostTestCatalogReadOperation, + hostTestOptionsReadStore, + hostTestRestingOptionsJournal, + hostTestRestingOptionsRecord, + HOST_TEST_NOW as NOW, + HOST_TEST_SESSION as SESSION, + hostTestOperationId +} from './structured-agent-session-host-test-data.test-fixture' +import { + createQueuedMessageTestRig, + QUEUED_RIG_CALLER +} from './structured-agent-session-queued-message-rig.test-fixture' +import { appendUsageLimitedTurn } from './structured-agent-session-rewind-usage-limit.test-fixture' + +const RESPONSE_REPORT = { model: 'opus[1m]', reportedModel: 'claude-opus-4-8' } +// Claude's confirmed init model stands in for a report when no response named one. +const CONFIRMED_INIT = { model: 'opus[1m]', confirmed: ['model'] } + +function claudeOptionsRead(answer: Record = RESPONSE_REPORT) { + const record = { + ...hostTestRestingOptionsRecord('session-1'), + provider: 'claude', + options: { model: 'opus[1m]' } + } + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the reader and pick counter use only the child's identity, fence and phase. + const child = { fence: 2, phase: 'ready' } as unknown as StructuredAgentSessionProviderChild + const conversation = { + child, + params: { provider: 'claude' }, + journal: hostTestRestingOptionsJournal() + } + // Picks serialize with the live read, so they can land only after it, as the answer is assembled. + const entered = Promise.withResolvers() + const assembled = Promise.withResolvers() + const home: AgentSessionModelCatalogResult = { origin: 'probe', fetchedAt: 1, models: [] } + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: picks and the reader read only the session's current child. + const session = { child } as unknown as StructuredAgentSessionHostSession + const sessions = new Map([['session-1', session]]) + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the real reader accesses only these injected ports; no provider process is launched. + const context = { + deps: { + adapter: { + readOptions: async () => ({ + models: [], + current: answer + }) + }, + agents: { definition: () => null, capabilities: () => null }, + store: hostTestOptionsReadStore(() => record), + modelCatalog: { + captureRead: hostTestCatalogReadOperation, + read: async () => home + } + }, + serialize: (_sessionId: string, task: () => Promise) => task(), + openConversation: async () => conversation, + conversation: async () => { + entered.resolve() + await assembled.promise + return conversation + }, + sessions + } as unknown as StructuredAgentSessionMutationContext + const pick = (model: string) => { + record.options.model = model + noteStructuredAgentSessionOptionPick( + { deps: { adapter: {} }, sessions }, + { sessionId: 'session-1', fence: 2 }, + { key: 'model', value: model }, + true + ) + } + /** Run `during` while the read is between its live snapshot and its answer. */ + const read = async (during: () => void = () => {}) => { + const answer = readStructuredAgentSessionOptions(context, 'session-1', { + readsWithoutModel: true + }) + await entered.promise + during() + assembled.resolve() + return (await answer).current + } + return { read, pick, sessions, session } +} + +it('keeps a live fallback report that no pick has replaced', async () => { + expect(await claudeOptionsRead(CONFIRMED_INIT).read()).toMatchObject({ + reportedModel: 'opus[1m]' + }) + expect(await claudeOptionsRead().read()).toMatchObject({ + model: 'opus[1m]', + reportedModel: 'claude-opus-4-8' + }) +}) + +it.each([ + ['picks back to the same model', ['sonnet', 'opus[1m]'], RESPONSE_REPORT], + ['re-picks the shown model', ['opus[1m]'], RESPONSE_REPORT], + ['picks back while only the init model confirms', ['sonnet', 'opus[1m]'], CONFIRMED_INIT] +])( + 'drops a report captured before the user %s while the read is in flight', + async (_, models, answer) => { + const host = claudeOptionsRead(answer) + const current = await host.read(() => models.forEach((model) => host.pick(model))) + expect(current.model).toBe('opus[1m]') + expect(current.reportedModel).toBeUndefined() + } +) + +it('drops a report from a child that ended or was replaced while the read was in flight', async () => { + for (const next of [null, { fence: 3, phase: 'ready' }]) { + const host = claudeOptionsRead() + const current = await host.read(() => { + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: only child identity matters to the reader. + host.sessions.set('session-1', { + ...host.session, + child: next + } as unknown as StructuredAgentSessionHostSession) + }) + expect(current.reportedModel).toBeUndefined() + } +}) + +it.each([ + [ + 'retires the report when the user picks back to it', + QUEUED_RIG_CALLER, + ['sonnet', 'opus[1m]'], + undefined + ], + [ + 'keeps the report through an old client empty no-op', + { ...QUEUED_RIG_CALLER, readsOptionsWithoutModel: false }, + [''], + 'claude-opus-4-8' + ] +] as const)( + 'after a usage-limited turn, a pick made while recovery choices load %s', + async (_, caller, models, reportedModel) => { + const rig = await createQueuedMessageTestRig({ agent: 'claude' }) + try { + const pick = async (value: string) => { + const fields = { key: 'model', value } + return rig.host.setOption(caller, { + envelope: rig.envelope(fields, 'agentSession.setOption', hostTestOperationId()), + ...fields + }) + } + expect(await pick('opus[1m]')).toMatchObject({ ok: true }) + rig.host.deps.adapter.readOptions = async () => ({ models: [], current: RESPONSE_REPORT }) + const journal = rig.host.collaboratorsForTests().sessions.get(SESSION)!.journal + await appendUsageLimitedTurn(journal, NOW, 'quota') + const recovering = Promise.withResolvers() + const released = Promise.withResolvers() + rig.host.deps.resolveLaunchEnv = () => { + recovering.resolve() + return released.promise + } + const answer = rig.host.readOptions(SESSION) + await recovering.promise + for (const model of models) { + expect(await pick(model)).toMatchObject({ ok: true }) + } + released.resolve(undefined) + const { current } = await answer + expect(current.model).toBe('opus[1m]') + expect(current.reportedModel).toBe(reportedModel) + } finally { + await rig.dispose() + } + } +) diff --git a/src/main/native-chat/agent-session-wire/operations/structured-agent-session-host-mutations.ts b/src/main/native-chat/agent-session-wire/operations/structured-agent-session-host-mutations.ts index adca12f049b..d8e7188f424 100644 --- a/src/main/native-chat/agent-session-wire/operations/structured-agent-session-host-mutations.ts +++ b/src/main/native-chat/agent-session-wire/operations/structured-agent-session-host-mutations.ts @@ -51,7 +51,10 @@ import { openWithReadyStructuredAgentSessionChild } from './structured-agent-ses import type { StructuredAgentSessionCaller } from '../host/structured-agent-session-host-types' import '../options/structured-agent-session-options-read' -import { recordStructuredAgentSessionOptionIntent } from '../options/structured-agent-session-option-intent' +import { + noteStructuredAgentSessionOptionPick, + recordStructuredAgentSessionOptionIntent +} from '../options/structured-agent-session-option-intent' import { confirmIdleStructuredAgentSessionOption } from '../options/structured-agent-session-idle-option' export function sendStructuredAgentSessionTurn( @@ -240,6 +243,7 @@ export async function setStructuredAgentSessionOption( readsWithoutModel: caller.readsOptionsWithoutModel !== false }) if (picked.ok) { + noteStructuredAgentSessionOptionPick(context, ctx, params, !noChoice) const confirming = confirmIdleStructuredAgentSessionOption(context, ctx, params) context.trackProviderOperation?.(confirming) void confirming.catch((error) => { diff --git a/src/main/native-chat/agent-session-wire/options/structured-agent-session-option-intent.ts b/src/main/native-chat/agent-session-wire/options/structured-agent-session-option-intent.ts index 6a42d64f690..54206b25ad7 100644 --- a/src/main/native-chat/agent-session-wire/options/structured-agent-session-option-intent.ts +++ b/src/main/native-chat/agent-session-wire/options/structured-agent-session-option-intent.ts @@ -18,6 +18,10 @@ import { structuredAgentSessionPickReply } from './structured-agent-session-pick-reply' import type { StructuredAgentSessionAdapter } from '../providers/structured-agent-session-adapter' +import type { + StructuredAgentSessionHostSession, + StructuredAgentSessionProviderChild +} from '../host/structured-agent-session-host-types' function acceptsOptionPick( agents: Pick, @@ -101,3 +105,34 @@ export async function recordStructuredAgentSessionOptionIntent( } } } + +const modelPicks = new WeakMap() + +/** Counts saved model picks per child, so a read can tell its captured report predates one. */ +export function structuredAgentSessionModelPicks( + child: StructuredAgentSessionProviderChild +): number { + return modelPicks.get(child) ?? 0 +} + +/** A saved pick retires the current child's earlier reports, including ones a read already captured. */ +export function noteStructuredAgentSessionOptionPick( + context: { + deps: { adapter: Pick } + sessions: ReadonlyMap + }, + ctx: Pick, + input: { key: string; value: string }, + saved: boolean +): void { + const { sessionId, fence } = ctx + // An old client's empty model clears nothing, so it retires no report. + if (!saved) { + return + } + const child = context.sessions.get(sessionId)?.child + if (input.key === 'model' && child?.fence === fence) { + modelPicks.set(child, structuredAgentSessionModelPicks(child) + 1) + } + context.deps.adapter.noteOptionPick?.({ sessionId, fence, ...input }) +} diff --git a/src/main/native-chat/agent-session-wire/options/structured-agent-session-options-read.ts b/src/main/native-chat/agent-session-wire/options/structured-agent-session-options-read.ts index 7fcc1712749..761d2594fe4 100644 --- a/src/main/native-chat/agent-session-wire/options/structured-agent-session-options-read.ts +++ b/src/main/native-chat/agent-session-wire/options/structured-agent-session-options-read.ts @@ -30,12 +30,13 @@ import { structuredAgentSessionImmediatePermission } from './structured-agent-se import type { StructuredAgentSessionMutationContext } from '../operations/structured-agent-session-mutation-context' import { readStructuredSessionRecovery } from '../recovery/structured-agent-session-recovery-read' import { fillUnknownModelEfforts } from '../../../../shared/agent-session/options/agent-session-model-efforts' +import { structuredAgentSessionModelPicks } from './structured-agent-session-option-intent' /** A live child's own answer, or the answer at rest; the goal, usage and rewind either way. */ export async function readStructuredAgentSessionOptions( context: Pick< StructuredAgentSessionMutationContext, - 'deps' | 'serialize' | 'openConversation' | 'conversation' + 'deps' | 'serialize' | 'openConversation' | 'conversation' | 'sessions' > & Partial>, sessionId: string, @@ -71,6 +72,7 @@ export async function readStructuredAgentSessionOptions( child && child.phase !== 'starting' ? await adapter.readOptions?.({ sessionId, fence: child.fence }) : undefined + const modelPicks = child ? structuredAgentSessionModelPicks(child) : 0 const scope = () => structuredAgentSessionCatalogScopeOwned( context.deps, @@ -93,7 +95,8 @@ export async function readStructuredAgentSessionOptions( records, session, child, - options: observed ?? null + options: observed ?? null, + modelPicks } }) let started = await readCurrent(true) @@ -130,6 +133,13 @@ export async function readStructuredAgentSessionOptions( const agent = session.params.provider const capabilities = agents.capabilities(agent) const restingOptions = await atRest() + const recovery = await readStructuredSessionRecovery(session, context, sessionId) + const [floor, goalSource, contextUsage] = await Promise.all([ + session.journal.reads.contextFloor(), + session.journal.reads.threadGoalSource(), + capabilities?.contextUsage ? session.journal.reads.contextUsage() : undefined + ]) + const contextFloor = floor ? { contextFloor: floor } : {} if (live && usesModelSpecificAcpEfforts(agent)) { options = { ...options, @@ -157,12 +167,17 @@ export async function readStructuredAgentSessionOptions( const model = saved.model ?? (options.current.model || selected.current.model || displayDefault) const projected = live?.projectCurrent?.({ ...saved, ...(model ? { model } : {}) }) const reportedEffort = projected?.confirmed?.includes('effort') ? projected.effort : undefined - const reportedModel = live - ? (options.current.reportedModel ?? - (agent === 'claude' && options.current.confirmed?.includes('model') - ? options.current.model - : undefined)) - : undefined + // After every await: a pick or a replaced child since the live read retires its report. + const reportedModel = + live && + started.kind === 'live' && + context.sessions.get(sessionId)?.child === started.child && + started.modelPicks === structuredAgentSessionModelPicks(started.child) + ? (options.current.reportedModel ?? + (agent === 'claude' && options.current.confirmed?.includes('model') + ? options.current.model + : undefined)) + : undefined const current = { ...selected.current, ...options.current, @@ -234,13 +249,6 @@ export async function readStructuredAgentSessionOptions( current.serviceTier = projected.options.serviceTier } } - const recovery = await readStructuredSessionRecovery(session, context, sessionId) - const [floor, goalSource, contextUsage] = await Promise.all([ - session.journal.reads.contextFloor(), - session.journal.reads.threadGoalSource(), - capabilities?.contextUsage ? session.journal.reads.contextUsage() : undefined - ]) - const contextFloor = floor ? { contextFloor: floor } : {} return { ...options, ...recovery, @@ -262,7 +270,7 @@ export async function readStructuredAgentSessionOptions( current: { ...current, acceptedInputSources, - ...(reportedModel ? { reportedModel } : {}), + reportedModel, ...(reportedEffort !== undefined ? { reportedEffort } : {}), defaulted, confirmed, diff --git a/src/main/native-chat/agent-session-wire/providers/structured-agent-session-adapter-router.ts b/src/main/native-chat/agent-session-wire/providers/structured-agent-session-adapter-router.ts index da43eee3fd1..b2b1ab2e8a5 100644 --- a/src/main/native-chat/agent-session-wire/providers/structured-agent-session-adapter-router.ts +++ b/src/main/native-chat/agent-session-wire/providers/structured-agent-session-adapter-router.ts @@ -205,6 +205,8 @@ export class StructuredAgentSessionAdapterRouter implements Adapter { this.liveOwnerOrNull(input.sessionId)?.captureMessageSteeringInputs?.(input) ?? { kind: 'codex-unavailable' } + noteOptionPick: Adapter['noteOptionPick'] = (input) => + this.liveOwnerOrNull(input.sessionId)?.noteOptionPick?.(input) projectOptions: Adapter['projectOptions'] = (sessionId, options) => this.liveOwnerOrNull(sessionId)?.projectOptions?.(sessionId, options) diff --git a/src/main/native-chat/agent-session-wire/providers/structured-agent-session-adapter.ts b/src/main/native-chat/agent-session-wire/providers/structured-agent-session-adapter.ts index 0a21fdac9d4..1ebe2aa9600 100644 --- a/src/main/native-chat/agent-session-wire/providers/structured-agent-session-adapter.ts +++ b/src/main/native-chat/agent-session-wire/providers/structured-agent-session-adapter.ts @@ -305,6 +305,8 @@ export type StructuredAgentSessionAdapter = StructuredAgentSessionAdapterStop & ): Promise>> /** Opt in only when setOption can update idle metadata without a provider turn. */ canSetOptionWhileIdle?(input: StructuredAgentSessionSetOptionInput): boolean + /** A saved pick retires this child's earlier execution reports until a turn carries it. */ + noteOptionPick?(input: { sessionId: string; fence: number; key: string; value: string }): void /** Finite live compiler facts for this exact child, without a proposed card. */ captureMessageSteeringInputs?(input: { sessionId: string diff --git a/src/main/native-chat/agent-session-wire/publication/subscribers/testing/structured-agent-session-subscriber-failed-frame.test.ts b/src/main/native-chat/agent-session-wire/publication/subscribers/testing/structured-agent-session-subscriber-failed-frame.test.ts deleted file mode 100644 index 79fd84206b7..00000000000 --- a/src/main/native-chat/agent-session-wire/publication/subscribers/testing/structured-agent-session-subscriber-failed-frame.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { mkdtemp, rm } from 'node:fs/promises' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, beforeEach, expect, it, vi } from 'vitest' -import { AGENT_JOURNAL_THREAD_SCOPE } from '../../../../../../shared/agent-session/journal/agent-session-journal-types' -import { claudeProviderHandle } from '../../../../../../shared/agent-session/lifecycle/agent-session-provider-handle-encoding' -import type { AgentSessionSubscribeEvent } from '../../../../../../shared/agent-session/agent-session-wire' -import { createTrackedJournalOpener } from '../../../../agent-session-journal/store-lifecycle/journal-host-database-test-support' -import { AgentSessionSubscribers } from '../structured-agent-session-subscribers' - -const SESSION = 'failed-frame-session' -let root: string -const journals = createTrackedJournalOpener() - -beforeEach(async () => { - root = await mkdtemp(join(tmpdir(), 'orca-subscriber-failed-frame-')) - vi.spyOn(console, 'warn').mockImplementation(() => {}) -}) - -afterEach(async () => { - vi.restoreAllMocks() - await journals.closeAll() - await rm(root, { recursive: true, force: true }) -}) - -// #39926: a frame that failed to send dropped the subscriber but left its stream open, so the chat -// view sat on a healthy-looking, silent stream until the tab was reopened. -it('ends the stream of a subscriber dropped after a frame fails to send', async () => { - const journal = await journals.open({ - identity: { - sessionId: SESSION, - workspaceId: 'workspace-1', - hostId: 'local', - agent: 'claude', - providerHandle: claudeProviderHandle('provider-1', null) - }, - stateDirectory: join(root, 'journal') - }) - const subscribers = new AgentSessionSubscribers() - const received: AgentSessionSubscribeEvent['type'][] = [] - const initial = Promise.withResolvers() - const ended = Promise.withResolvers() - const end = vi.fn(() => ended.resolve()) - subscribers.open({ - id: 'chat-pane', - sessionId: SESSION, - journal, - fence: 1, - end, - emit: (event) => { - if (event.type === 'batch') { - throw new Error('frame could not be sent') - } - received.push(event.type) - initial.resolve() - } - }) - await initial.promise - expect(received).toEqual(['snapshot']) - - await journal.appendItem( - { provider: 'orca', clientMessageId: 'reply' }, - { kind: 'status', text: 'reply' }, - { fence: 1, turnScope: AGENT_JOURNAL_THREAD_SCOPE } - ) - subscribers.publish(SESSION, journal) - await ended.promise - - expect(subscribers.subscriberCountForTests(SESSION)).toBe(0) - expect(end).toHaveBeenCalledTimes(1) -}) diff --git a/src/main/native-chat/agent-session-wire/startup/structured-agent-session-startup-attempt.ts b/src/main/native-chat/agent-session-wire/startup/structured-agent-session-startup-attempt.ts index ecdaeb17872..6e05a41e237 100644 --- a/src/main/native-chat/agent-session-wire/startup/structured-agent-session-startup-attempt.ts +++ b/src/main/native-chat/agent-session-wire/startup/structured-agent-session-startup-attempt.ts @@ -24,6 +24,7 @@ import { type StructuredAgentSessionTrackedStartup } from './structured-agent-session-startup-tracking' +import { awakeNow } from '../../../power/awake-clock' import './structured-agent-session-startup-attempt-mint' type Tracked = StructuredAgentSessionTrackedStartup @@ -44,12 +45,13 @@ export class StructuredAgentSessionStartupAttempts { breach?: (breached: StructuredAgentSessionExpiredStartup & { agent: string }) => void settled?: (settled: StructuredAgentSessionStartupSettled) => void limits?: Partial - /** Use elapsed time; host clocks may be pinned. */ + /** Use elapsed time; host clocks may be pinned. Defaults to the awake clock, so time the + * machine spends asleep never counts toward the ceiling. */ now?: () => number } ) { this.limits = { ...STRUCTURED_AGENT_SESSION_STARTUP_LIMITS, ...deps.limits } - this.now = deps.now ?? Date.now + this.now = deps.now ?? awakeNow } /** A start registered before its first wait: its ceiling runs from now. */ diff --git a/src/main/native-chat/agent-session-wire/startup/structured-agent-session-startup-sleep.test.ts b/src/main/native-chat/agent-session-wire/startup/structured-agent-session-startup-sleep.test.ts new file mode 100644 index 00000000000..915c6c7f902 --- /dev/null +++ b/src/main/native-chat/agent-session-wire/startup/structured-agent-session-startup-sleep.test.ts @@ -0,0 +1,53 @@ +// The startup ceiling measures awake time: a machine that sleeps while an agent starts must not +// expire the start the moment it wakes. These run on the production default clock. + +import { afterEach, beforeEach, expect, it, vi } from 'vitest' +import { STRUCTURED_AGENT_SESSION_STARTUP_CEILING_MS } from './structured-agent-session-startup-attempt-contract' +import type * as SystemPowerLifecycle from '../../../power/system-power-lifecycle' +import type * as StartupAttempt from './structured-agent-session-startup-attempt' + +let power: typeof SystemPowerLifecycle +let Attempts: typeof StartupAttempt.StructuredAgentSessionStartupAttempts + +beforeEach(async () => { + vi.useFakeTimers({ + toFake: ['Date', 'performance', 'setTimeout', 'clearTimeout'] + }) + vi.setSystemTime(new Date('2026-11-09T09:08:32-08:00')) + // A fresh process-wide awake clock and power state for each test. + vi.resetModules() + power = await import('../../../power/system-power-lifecycle') + ;({ StructuredAgentSessionStartupAttempts: Attempts } = + await import('./structured-agent-session-startup-attempt')) +}) + +afterEach(() => { + vi.useRealTimers() +}) + +/** The machine sleeps: wall time passes while no timers run; then the system reports the wake. */ +function sleepFor(ms: number): void { + power.publishSystemSuspend() + vi.setSystemTime(Date.now() + ms) + power.publishSystemResume() +} + +async function awakeFor(ms: number): Promise { + await vi.advanceTimersByTimeAsync(ms) +} + +it('still expires once the start has been awake for the whole ceiling', async () => { + const expire = vi.fn() + const startup = new Attempts({ expire }) + const { registeredAt } = startup.begin('session', 'attempt') + + await awakeFor(2_000) + sleepFor(665_000) + await awakeFor(STRUCTURED_AGENT_SESSION_STARTUP_CEILING_MS - 3_000) + expect(expire).not.toHaveBeenCalled() + + await awakeFor(1_000) + expect(startup.pastCeiling(registeredAt)).toBe(true) + await vi.waitFor(() => expect(expire).toHaveBeenCalledOnce()) + startup.dispose() +}) diff --git a/src/main/native-chat/transcript-line-decoders-claude-queued-prompt.test.ts b/src/main/native-chat/transcript-line-decoders-claude-queued-prompt.test.ts index 543d923f845..392b5533a74 100644 --- a/src/main/native-chat/transcript-line-decoders-claude-queued-prompt.test.ts +++ b/src/main/native-chat/transcript-line-decoders-claude-queued-prompt.test.ts @@ -37,4 +37,18 @@ describe('Claude queued_command attachment', () => { parentId: 'tool-result-row' }) }) + + it('keeps inline images from a prompt absorbed mid-turn, which have no source row', () => { + const line = queuedCommand({ + prompt: [ + { type: 'image', source: { type: 'base64', media_type: 'image/png', data: 'iVBORw0K' } }, + { type: 'text', text: '[Image #3]' } + ], + commandMode: 'prompt' + }) + expect(decodeClaudeTranscriptLine(line, 'fallback')?.blocks).toEqual([ + { type: 'image-ref', url: 'data:image/png;base64,iVBORw0K' }, + { type: 'text', text: '[Image #3]' } + ]) + }) }) diff --git a/src/main/native-chat/transcript-line-decoders-claude.ts b/src/main/native-chat/transcript-line-decoders-claude.ts index 2e256af18e4..095e183e1d4 100644 --- a/src/main/native-chat/transcript-line-decoders-claude.ts +++ b/src/main/native-chat/transcript-line-decoders-claude.ts @@ -13,6 +13,7 @@ import { } from '../ai-vault/session-scanner-values' import { imageSourcePathFromText } from '../../shared/native-chat/transcript/native-chat-image-transcript-markers' import { claudeContentBlocks } from './transcript-record-blocks' +import { isKnownRasterImageMimeType } from '../../shared/file-preview/raster-image-preview-limits' import { unwrapClaudePastedContentBlock } from '../../shared/claude-pasted-content' import { unwrapClaudeBashInputBlock } from '../../shared/claude-bash-input' import { claudeInterruptedMessageId } from './transcript-turn-markers' @@ -161,7 +162,25 @@ function claudeQueuedPromptAsUserRecord( if (typeof prompt !== 'string' && !Array.isArray(prompt)) { return null } - return { ...record, type: 'user', message: { role: 'user', content: prompt } } + const content = Array.isArray(prompt) ? prompt.map(queuedPromptImageAsDataUrl) : prompt + return { ...record, type: 'user', message: { role: 'user', content } } +} + +// Queued prompts get no image-source companion row; their inline base64 is the only image record. +function queuedPromptImageAsDataUrl(item: unknown): unknown { + const record = asRecord(item) + const source = asRecord(record?.source) + const mediaType = extractString(source?.media_type) ?? undefined + const data = extractString(source?.data) + if ( + record?.type !== 'image' || + source?.type !== 'base64' || + !data || + !isKnownRasterImageMimeType(mediaType) + ) { + return item + } + return { ...record, source: { url: `data:${mediaType};base64,${data}` } } } function claudeStopHookFeedbackMessage( diff --git a/src/main/orca-profiles/profile-cloud-client.test.ts b/src/main/orca-profiles/profile-cloud-client.test.ts new file mode 100644 index 00000000000..bfd9ef8b54a --- /dev/null +++ b/src/main/orca-profiles/profile-cloud-client.test.ts @@ -0,0 +1,36 @@ +import { afterEach, describe, expect, it, vi } from 'vitest' +import type { OrcaCloudAuthConfig } from './profile-cloud-auth-config' +import { createOrcaCloudProfile, OrcaCloudRequestError } from './profile-cloud-client' +import type { OrcaCloudSession } from './profile-cloud-session-store' + +afterEach(() => { + vi.unstubAllGlobals() +}) + +describe('createOrcaCloudProfile', () => { + it('proves the sign-in with its refresh token alongside the access token', async () => { + const fetchImpl = vi.fn( + async () => new Response(null, { status: 403 }) + ) + vi.stubGlobal('fetch', fetchImpl) + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the call reads only this endpoint. + const config = { + profileEndpoint: 'https://login.test/v1/desktop/auth/profile' + } as OrcaCloudAuthConfig + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the call reads only the two tokens. + const session = { accessToken: 'access-1', refreshToken: 'refresh-1' } as OrcaCloudSession + + await expect( + createOrcaCloudProfile(config, session, { orgId: 'org-1', name: 'Work' }) + ).rejects.toBeInstanceOf(OrcaCloudRequestError) + + const [url, init] = fetchImpl.mock.calls[0]! + expect(url).toBe('https://login.test/v1/desktop/auth/profile') + expect(new Headers(init?.headers).get('authorization')).toBe('Bearer access-1') + expect(JSON.parse(String(init?.body))).toEqual({ + orgId: 'org-1', + name: 'Work', + refreshToken: 'refresh-1' + }) + }) +}) diff --git a/src/main/orca-profiles/profile-cloud-client.ts b/src/main/orca-profiles/profile-cloud-client.ts index baa4cf1e471..a8835d167ce 100644 --- a/src/main/orca-profiles/profile-cloud-client.ts +++ b/src/main/orca-profiles/profile-cloud-client.ts @@ -157,8 +157,8 @@ function normalizeSessionResponse(value: unknown): OrcaCloudSessionExchangeRespo const CLOUD_REQUEST_TIMEOUT_MS = 30_000 -// A lost rotating-token response makes retries ambiguous; one longer attempt avoids replay. -const CLOUD_REFRESH_TIMEOUT_MS = 60_000 +// Two attempts plus the replay delay must settle inside the server's 60s rotation grace. +const CLOUD_REFRESH_TIMEOUT_MS = 20_000 type PostJsonOptions = { accessToken?: string @@ -170,6 +170,22 @@ export function isAmbiguousCloudRequestFailure(error: unknown): boolean { return !(error instanceof OrcaCloudRequestError) } +// Proxies, CDNs and gateways answer with HTML; only the auth server's JSON carries a verdict. +async function readCloudErrorCode(response: Response): Promise { + if (!response.headers.get('content-type')?.toLowerCase().includes('application/json')) { + await cancelUnreadResponseBody(response) + return undefined + } + try { + const body: unknown = await response.json() + return body && typeof body === 'object' && 'error' in body && typeof body.error === 'string' + ? body.error + : undefined + } catch { + return undefined + } +} + async function postJson(url: string, body: unknown, options?: PostJsonOptions): Promise { const response = await fetch(url, { method: 'POST', @@ -183,8 +199,7 @@ async function postJson(url: string, body: unknown, options?: PostJsonOptions signal: AbortSignal.timeout(options?.timeoutMs ?? CLOUD_REQUEST_TIMEOUT_MS) }) if (!response.ok) { - await cancelUnreadResponseBody(response) - throw new OrcaCloudRequestError(response.status) + throw new OrcaCloudRequestError(response.status, await readCloudErrorCode(response)) } return (await response.json()) as T } @@ -242,10 +257,8 @@ export async function createOrcaCloudProfile( return normalizeSessionResponse( await postJson( config.profileEndpoint, - { - orgId: args.orgId, - name: args.name - }, + // The refresh token proves the long-lived sign-in, not just a short-lived access token. + { orgId: args.orgId, name: args.name, refreshToken: session.refreshToken }, { accessToken: session.accessToken } ) ) diff --git a/src/main/orca-profiles/profile-cloud-refresh-replay-guard.ts b/src/main/orca-profiles/profile-cloud-refresh-replay-guard.ts index 5290fe347c8..0efc33c094a 100644 --- a/src/main/orca-profiles/profile-cloud-refresh-replay-guard.ts +++ b/src/main/orca-profiles/profile-cloud-refresh-replay-guard.ts @@ -1,7 +1,7 @@ // Lost refresh replies may have rotated the token; replay can revoke the entire token family. // Briefly block retry loops after ambiguous rotation to avoid replay storms. -export const AMBIGUOUS_REFRESH_REPLAY_DELAY_MS = 30_000 +export const AMBIGUOUS_REFRESH_REPLAY_DELAY_MS = 10_000 const AMBIGUOUS_REFRESH_ATTEMPTS_MAX_ENTRIES = 512 type AmbiguousRefreshAttempt = { diff --git a/src/main/orca-profiles/profile-cloud-session-refresh.test.ts b/src/main/orca-profiles/profile-cloud-session-refresh.test.ts new file mode 100644 index 00000000000..137b335b0da --- /dev/null +++ b/src/main/orca-profiles/profile-cloud-session-refresh.test.ts @@ -0,0 +1,275 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import type { OrcaCloudAuthConfig } from './profile-cloud-auth-config' +import type { ActiveOrcaProfileState } from './profile-index-store' +import type { OrcaCloudSession } from './profile-cloud-session-store' +import type { OrcaProfileSummary } from '../../shared/orca-profiles' + +const store = vi.hoisted(() => { + const state: { session: OrcaCloudSession | null; signedOut: number } = { + session: null, + signedOut: 0 + } + return state +}) + +vi.mock('./profile-cloud-session-owner', () => ({ + readCloudSession: () => + store.session ? { status: 'found', session: store.session } : { status: 'missing' }, + takeCloudSessionTicket: () => 1, + commitCloudSessionRotation: ( + _profileId: string, + _userDataPath: string, + _ticket: number, + _previous: OrcaCloudSession, + next: OrcaCloudSession + ) => { + store.session = { + accessToken: next.accessToken, + refreshToken: next.refreshToken, + expiresAt: next.expiresAt, + capabilities: next.capabilities + } + return store.session + }, + signOutRevokedCloudSession: ( + _profileId: string, + _userDataPath: string, + failed: OrcaCloudSession + ) => { + if (store.session?.refreshToken !== failed.refreshToken) { + return false + } + store.session = null + store.signedOut += 1 + return true + } +})) + +import { OrcaCloudRequestError } from './profile-cloud-client' +import { + readFreshOrcaCloudSession, + runWithFreshOrcaCloudSession +} from './profile-cloud-session-refresh' + +const HOUR_MS = 3_600_000 +const SERVER_ROTATION_GRACE_MS = 60_000 +const HTML_403 = '

403 Forbidden

' +const HTML_502 = '

502 Bad Gateway

' + +const AUTH = 'https://auth.example.test' +const config: OrcaCloudAuthConfig = { + apiBaseUrl: AUTH, + authorizeEndpoint: `${AUTH}/authorize`, + sessionEndpoint: `${AUTH}/session`, + refreshEndpoint: `${AUTH}/refresh`, + capabilitiesEndpoint: `${AUTH}/capabilities`, + profileEndpoint: `${AUTH}/profile`, + orgEndpoint: `${AUTH}/org`, + logoutEndpoint: `${AUTH}/logout`, + relayTokenEndpoint: `${AUTH}/relay-token`, + connectorTokenEndpoint: `${AUTH}/connector-token`, + relayDirectorUrl: AUTH, + clientId: 'client-1', + scope: 'openid' +} + +let seq = 0 +let refreshCalls = 0 +let answerRefresh: (refreshToken: string) => Promise + +function reply(status: number, body: string, type = 'application/json'): Response { + return new Response(body, { status, headers: { 'content-type': type } }) +} + +function sessionReply(refreshToken: string): Response { + return reply( + 200, + JSON.stringify({ + accessToken: `access-${refreshToken}`, + refreshToken, + expiresAt: Date.now() + HOUR_MS, + cloud: { cloudProfileId: 'cloud-profile-1', userId: 'user-1', email: 'a@example.com' }, + capabilities: { flags: {}, refreshedAt: 1 } + }) + ) +} + +function signedIn(expired = true): ActiveOrcaProfileState { + seq += 1 + store.signedOut = 0 + store.session = { + accessToken: 'access-old', + refreshToken: `refresh-old-${seq}`, + expiresAt: expired ? Date.now() - 1 : Date.now() + HOUR_MS, + capabilities: { flags: {}, refreshedAt: 1 } + } + // A fresh profile id keeps the module's single-flight and replay-guard state per test. + const profile: OrcaProfileSummary = { + id: `profile-${seq}`, + name: 'Profile', + avatar: { kind: 'initials', initials: 'P', color: 'neutral' }, + kind: 'cloud-linked', + createdAt: 1, + updatedAt: 1, + lastOpenedAt: 1, + cloud: { + userId: 'user-1', + cloudProfileId: 'cloud-profile-1', + email: 'a@example.com', + linkedAt: 1 + } + } + return { + index: { schemaVersion: 1, activeProfileId: profile.id, profiles: [profile] }, + profile, + dataFile: '', + stateDatabaseFile: '', + profileDirectory: '' + } +} + +async function settle(promise: Promise): Promise { + const settled = promise.catch(() => 'threw') + await vi.advanceTimersByTimeAsync(5 * 60_000) + return settled +} + +beforeEach(() => { + // Response body streams schedule on real immediates; only the request clock is faked. + vi.useFakeTimers({ now: 1_000_000, toFake: ['setTimeout', 'clearTimeout', 'Date'] }) + vi.spyOn(console, 'warn').mockImplementation(() => undefined) + // Route request timeouts through fake timers so the timeout chain runs on the test clock. + vi.spyOn(AbortSignal, 'timeout').mockImplementation((ms) => { + const controller = new AbortController() + setTimeout(() => controller.abort(new DOMException('timed out', 'TimeoutError')), ms) + return controller.signal + }) + refreshCalls = 0 + vi.stubGlobal('fetch', (_url: string, init: RequestInit) => { + refreshCalls += 1 + const body: { refreshToken?: unknown } = JSON.parse(String(init.body)) + const refreshToken = String(body.refreshToken) + return Promise.race([ + answerRefresh(refreshToken), + new Promise((_, reject) => + init.signal?.addEventListener('abort', () => reject(init.signal?.reason)) + ) + ]) + }) +}) + +afterEach(() => { + vi.unstubAllGlobals() + vi.restoreAllMocks() + vi.useRealTimers() +}) + +describe('refresh failures that must keep the sign-in', () => { + it.each([ + ['403 HTML from a proxy, CDN, WAF or IAM layer', () => reply(403, HTML_403, 'text/html')], + ['403 JSON', () => reply(403, '{"error":"forbidden"}')], + ['401 HTML from a proxy', () => reply(401, HTML_403, 'text/html')], + ['401 JSON without the refresh-token verdict', () => reply(401, '{"error":"invalid_token"}')], + [ + '401 JSON verdict served as HTML', + () => reply(401, '{"error":"invalid_refresh_token"}', 'text/html') + ], + ['429 rate limited', () => reply(429, '{"error":"rate_limited"}')], + ['502 HTML', () => reply(502, HTML_502, 'text/html')], + ['503 JSON', () => reply(503, '{"error":"unavailable"}')] + ])('%s', async (_name, response) => { + const active = signedIn() + answerRefresh = async () => response() + + await settle(readFreshOrcaCloudSession(config, active, '/user-data')) + + expect(store.signedOut).toBe(0) + expect(store.session).not.toBeNull() + }) +}) + +describe('refresh rejections that end the sign-in', () => { + it.each(['signed_out', 'revoked', 'expired', 'reused', undefined])( + '401 invalid_refresh_token, reason %s', + async (reason) => { + const active = signedIn() + answerRefresh = async () => + reply(401, JSON.stringify({ error: 'invalid_refresh_token', reason })) + + const result = await settle(readFreshOrcaCloudSession(config, active, '/user-data')) + + expect(result).toEqual({ status: 'reconnect-required' }) + expect(store.signedOut).toBe(1) + } + ) +}) + +describe('a refresh the server committed but answered too slowly', () => { + it('resolves inside the rotation grace instead of replaying the token after it', async () => { + const active = signedIn() + const rotations = new Map() + answerRefresh = async (refreshToken) => { + const prior = rotations.get(refreshToken) + if (prior) { + return Date.now() - prior.at < SERVER_ROTATION_GRACE_MS + ? sessionReply(prior.next) + : reply(401, '{"error":"invalid_refresh_token","reason":"reused"}') + } + rotations.set(refreshToken, { at: Date.now(), next: 'refresh-next' }) + return new Promise(() => undefined) + } + + const result = await settle(readFreshOrcaCloudSession(config, active, '/user-data')) + + expect(result).toMatchObject({ status: 'found', session: { refreshToken: 'refresh-next' } }) + expect(store.signedOut).toBe(0) + expect(refreshCalls).toBe(2) + }) +}) + +describe('operations wrapped in a fresh session', () => { + it('keeps the sign-in when the operation still answers 401 after a successful refresh', async () => { + const active = signedIn(false) + answerRefresh = async () => sessionReply('refresh-next') + + const result = runWithFreshOrcaCloudSession(config, active, '/user-data', async () => { + throw new OrcaCloudRequestError(401) + }) + + await expect(result).rejects.toBeInstanceOf(OrcaCloudRequestError) + expect(store.signedOut).toBe(0) + expect(store.session?.refreshToken).toBe('refresh-next') + }) + + it('does not rotate the token when the operation answers 403', async () => { + const active = signedIn(false) + answerRefresh = async () => sessionReply('refresh-next') + + const result = runWithFreshOrcaCloudSession(config, active, '/user-data', async () => { + throw new OrcaCloudRequestError(403) + }) + + await expect(result).rejects.toMatchObject({ statusCode: 403 }) + expect(refreshCalls).toBe(0) + }) + + it('rotates once for concurrent and repeated 401s within the backoff window', async () => { + const active = signedIn(false) + let rotation = 0 + answerRefresh = async () => sessionReply(`refresh-next-${++rotation}`) + const rejectedCall = (): Promise => + runWithFreshOrcaCloudSession(config, active, '/user-data', async () => { + throw new OrcaCloudRequestError(401) + }).catch((error: unknown) => error) + + const concurrent = await Promise.all([rejectedCall(), rejectedCall(), rejectedCall()]) + await vi.advanceTimersByTimeAsync(60_000) + const repeated = [await rejectedCall(), await rejectedCall()] + + for (const error of [...concurrent, ...repeated]) { + expect(error).toMatchObject({ statusCode: 401 }) + } + expect(refreshCalls).toBe(1) + expect(store.signedOut).toBe(0) + }) +}) diff --git a/src/main/orca-profiles/profile-cloud-session-refresh.ts b/src/main/orca-profiles/profile-cloud-session-refresh.ts index 3008dcaecd9..77b7cfa11de 100644 --- a/src/main/orca-profiles/profile-cloud-session-refresh.ts +++ b/src/main/orca-profiles/profile-cloud-session-refresh.ts @@ -8,6 +8,7 @@ import { } from './profile-cloud-client' import type { OrcaCloudSessionExchangeResponse } from './profile-cloud-session-exchange' import { + AMBIGUOUS_REFRESH_REPLAY_DELAY_MS, AmbiguousRefreshReplayBlockedError, blocksAmbiguousRefreshReplay, forgetAmbiguousRefreshAttempt, @@ -36,9 +37,31 @@ function shouldRefreshCloudSession(session: OrcaCloudSession, now = Date.now()): return session.expiresAt <= now + CLOUD_SESSION_REFRESH_SKEW_MS } -export function isOrcaCloudAuthFailure(error: unknown): boolean { +// A 403 is a permission answer, never an expired token, so only a 401 may force a refresh. +function isAccessTokenRejected(error: unknown): boolean { + return error instanceof OrcaCloudRequestError && error.statusCode === 401 +} + +// An operation that keeps answering 401 must not rotate the token on every call. +const FORCED_REFRESH_BACKOFF_MS = 5 * 60_000 +const lastForcedRefreshAt = new Map() + +function takeForcedRefreshSlot(key: string, now = Date.now()): boolean { + const last = lastForcedRefreshAt.get(key) + // A clock rollback must not stretch the backoff. + if (last !== undefined && now >= last && now - last < FORCED_REFRESH_BACKOFF_MS) { + return false + } + lastForcedRefreshAt.set(key, now) + return true +} + +// Only the auth server's own verdict may discard a sign-in; proxies, outages and limits never do. +function isRefreshTokenRejected(error: unknown): boolean { return ( - error instanceof OrcaCloudRequestError && (error.statusCode === 401 || error.statusCode === 403) + error instanceof OrcaCloudRequestError && + error.statusCode === 401 && + error.errorCode === 'invalid_refresh_token' ) } @@ -67,12 +90,8 @@ function clearCloudSessionIfUnchanged( function warnIfPossibleRefreshReplay( profileId: string, userDataPath: string, - failed: OrcaCloudSession, - error: unknown + failed: OrcaCloudSession ): void { - if (!(error instanceof OrcaCloudRequestError) || error.statusCode !== 401) { - return - } const key = orcaCloudSessionKey(profileId, userDataPath) if (!wasRefreshTokenAmbiguouslyAttempted(key, failed.refreshToken)) { return @@ -107,19 +126,19 @@ async function attemptCloudSessionRefresh( if (ambiguous) { recordAmbiguousRefreshAttempt(key, session.refreshToken) } - // Retry only explicit 5xx rejection; ambiguous failures may have spent the token. - const retryable = !ambiguous && attempt === 0 && isRetryableCloudRefreshRejection(error) - if (!ambiguous && !retryable) { + if (attempt > 0 || (!ambiguous && !isRetryableCloudRefreshRejection(error))) { throw error } + // An unanswered attempt may have rotated the token; replay it once while the server's + // rotation grace still returns the successor, instead of after the grace treats it as reuse. + if (ambiguous) { + await new Promise((resolve) => setTimeout(resolve, AMBIGUOUS_REFRESH_REPLAY_DELAY_MS)) + } // Reuse concurrent rotations instead of replaying the now-spent token. const current = readCloudSession(active.profile.id, userDataPath) if (current.status === 'found' && current.session.refreshToken !== session.refreshToken) { return { status: 'rotated-elsewhere', session: current.session } } - if (ambiguous) { - throw error - } } } } @@ -198,8 +217,8 @@ export async function readFreshOrcaCloudSession( session: await refreshStoredCloudSession(config, active, userDataPath, session.session) } } catch (error) { - if (isOrcaCloudAuthFailure(error)) { - warnIfPossibleRefreshReplay(active.profile.id, userDataPath, session.session, error) + if (isRefreshTokenRejected(error)) { + warnIfPossibleRefreshReplay(active.profile.id, userDataPath, session.session) clearCloudSessionIfUnchanged(active.profile.id, userDataPath, session.session) return { status: 'reconnect-required' } } @@ -219,8 +238,8 @@ export async function forceRefreshOrcaCloudSession( session: await refreshStoredCloudSession(config, active, userDataPath, session) } } catch (error) { - if (isOrcaCloudAuthFailure(error)) { - warnIfPossibleRefreshReplay(active.profile.id, userDataPath, session, error) + if (isRefreshTokenRejected(error)) { + warnIfPossibleRefreshReplay(active.profile.id, userDataPath, session) clearCloudSessionIfUnchanged(active.profile.id, userDataPath, session) return { status: 'reconnect-required' } } @@ -241,7 +260,15 @@ export async function runWithFreshOrcaCloudSession( try { return { status: 'ok', value: await operation(session.session) } } catch (error) { - if (!isOrcaCloudAuthFailure(error)) { + if (!isAccessTokenRejected(error)) { + throw error + } + // Reuse a rotation that already happened or is in flight; start a new one only once per backoff. + const key = orcaCloudSessionKey(active.profile.id, userDataPath) + const stored = readCloudSession(active.profile.id, userDataPath) + const rotatedSince = + stored.status === 'found' && stored.session.refreshToken !== session.session.refreshToken + if (!rotatedSince && !inflightCloudSessionRefreshes.has(key) && !takeForcedRefreshSlot(key)) { throw error } const refreshed = await forceRefreshOrcaCloudSession( @@ -253,15 +280,7 @@ export async function runWithFreshOrcaCloudSession( if (refreshed.status !== 'found') { return { status: 'reconnect-required' } } - try { - return { status: 'ok', value: await operation(refreshed.session) } - } catch (retryError) { - // Post-refresh 401 rejects the session; permission-only 403 must preserve it. - if (retryError instanceof OrcaCloudRequestError && retryError.statusCode === 401) { - clearCloudSessionIfUnchanged(active.profile.id, userDataPath, refreshed.session) - return { status: 'reconnect-required' } - } - throw retryError - } + // The auth server just accepted this session, so a second rejection is the operation's error. + return { status: 'ok', value: await operation(refreshed.session) } } } diff --git a/src/main/orca-profiles/profile-project-domain-transfer.test.ts b/src/main/orca-profiles/profile-project-domain-transfer.test.ts index bc731f54317..b1fc06965da 100644 --- a/src/main/orca-profiles/profile-project-domain-transfer.test.ts +++ b/src/main/orca-profiles/profile-project-domain-transfer.test.ts @@ -178,6 +178,12 @@ afterEach(() => { }) describe('profile domain transfers', () => { + it('moves a project without granting publishing permission to either older profile', () => { + expect(transfer()).toMatchObject({ status: 'transferred' }) + expect(JSON.parse(raw('source').json).settings).not.toHaveProperty('artifactSharingEnabled') + expect(JSON.parse(raw('target').json).settings).not.toHaveProperty('artifactSharingEnabled') + }) + it('refuses independently hashed malformed unrelated data before a copy writes anything', () => { const before = raw('target').json withDatabase('source', (db) => diff --git a/src/main/orca-profiles/profile-project-state-file.ts b/src/main/orca-profiles/profile-project-state-file.ts index ec017b0f920..e85b6ffc680 100644 --- a/src/main/orca-profiles/profile-project-state-file.ts +++ b/src/main/orca-profiles/profile-project-state-file.ts @@ -121,6 +121,7 @@ export function normalizeProfileProjectState( const { uiLanguagePortugueseMigrationApplied: _migrationApplied, nestedWorkerMaxDepthDefaultedToFour: _depthMigrated, + artifactSharingEnabled: _artifactSharingEnabled, ...settingsDefaults } = defaults.settings return rebuildRepoBackedProjectState({ diff --git a/src/main/orcad/orcad-client-page-commands.ts b/src/main/orcad/orcad-client-page-commands.ts index 9afc3d95ab7..11e8e8e4a1e 100644 --- a/src/main/orcad/orcad-client-page-commands.ts +++ b/src/main/orcad/orcad-client-page-commands.ts @@ -28,6 +28,11 @@ import { type BrowserEngineTabs } from '../runtime/browser/client-pages/browser-client-page-queries' +import { + findListedBrowserTab, + readBrowserTabAnnotations +} from '../runtime/browser/tabs/browser-tab-annotations' + type Forward = (args: unknown[], name?: string) => unknown const LOGICAL_TAB_QUERIES = [ @@ -70,6 +75,16 @@ export function orcadClientPageCommand( : closeBrowserPageWithoutEngine(host, params, browserUnavailableError) } } + if (name === 'browserTabAnnotations') { + return async (...args: Parameters) => { + const { page, worktree } = args[0] ?? {} + // The engine's active flags are global, so a worktree's current tab needs its own query. + const tab = page + ? findListedBrowserTab((await logicalTabs().browserTabList({ worktree })).tabs, page) + : (await logicalTabs().browserTabCurrent({ worktree })).tab + return readBrowserTabAnnotations(host, tab) + } + } const query = LOGICAL_TAB_QUERIES.find((candidate) => candidate === name) if (query) { return (...args: unknown[]) => { diff --git a/src/main/orcad/orcad-entry.ts b/src/main/orcad/orcad-entry.ts index 0f463081e63..da51c916fe2 100644 --- a/src/main/orcad/orcad-entry.ts +++ b/src/main/orcad/orcad-entry.ts @@ -226,6 +226,8 @@ async function startOrcadRuntime( paneGridsForShutdown = runtime accountLaunch?.attachToRuntime(runtime) + const { wireGitHubIssueLinkTitleFill } = await import('../github/github-issue-link-title-wiring') + registerCleanup(wireGitHubIssueLinkTitleFill(profileStore, runtime)) const { installOrcadEmulatorBridge } = await import('./orcad-emulator-bridge') installOrcadEmulatorBridge(runtime, registerCleanup) diff --git a/src/main/persistence/applying-settings/feature-interaction-recording.ts b/src/main/persistence/applying-settings/feature-interaction-recording.ts index a383f83340a..9bc970c8dfb 100644 --- a/src/main/persistence/applying-settings/feature-interaction-recording.ts +++ b/src/main/persistence/applying-settings/feature-interaction-recording.ts @@ -12,7 +12,7 @@ import { getCohortAtEmit } from '../../telemetry/cohort-classifier' export type FeatureInteractionOperations = { state: PersistedState - scheduleSave: (domains?: readonly string[]) => void + scheduleSave: (domains: readonly string[]) => void notifyUIChanged: () => void getUI: () => PersistedState['ui'] } diff --git a/src/main/persistence/applying-settings/terminal-settings-migrations.ts b/src/main/persistence/applying-settings/terminal-settings-migrations.ts index ae54a94349e..9264e9db532 100644 --- a/src/main/persistence/applying-settings/terminal-settings-migrations.ts +++ b/src/main/persistence/applying-settings/terminal-settings-migrations.ts @@ -108,6 +108,8 @@ type RetiredGlobalSettings = { orchestrationHeartbeatIntervalMinutes?: unknown // Full-access plugins now need only their own approval. pluginFullAccessEnabled?: unknown + // Extensions left Experimental and default on; browserExtensionsEnabled replaces this. + experimentalBrowserExtensions?: unknown } export function stripRetiredGlobalSettings( @@ -127,6 +129,7 @@ export function stripRetiredGlobalSettings( orchestrationHeartbeatsEnabled: _retiredHeartbeatsEnabled, orchestrationHeartbeatIntervalMinutes: _retiredHeartbeatInterval, pluginFullAccessEnabled: _retiredPluginFullAccessSwitch, + experimentalBrowserExtensions: _retiredBrowserExtensionsExperiment, ...rest } = (settings ?? {}) as Partial & RetiredGlobalSettings void _retiredChatPermissionCopies @@ -142,6 +145,7 @@ export function stripRetiredGlobalSettings( void _retiredHeartbeatsEnabled void _retiredHeartbeatInterval void _retiredPluginFullAccessSwitch + void _retiredBrowserExtensionsExperiment return rest } diff --git a/src/main/persistence/applying-settings/ui-state-read.ts b/src/main/persistence/applying-settings/ui-state-read.ts index 238f6ab67b3..a550fb1cf37 100644 --- a/src/main/persistence/applying-settings/ui-state-read.ts +++ b/src/main/persistence/applying-settings/ui-state-read.ts @@ -13,6 +13,7 @@ import { } from '../../../shared/workspace-statuses' import { normalizeUsagePercentageDisplay } from '../../../shared/usage-percentage-display' import { normalizeStatusBarUsageMode } from '../../../shared/status-bar-usage-mode' +import { normalizeStatusBarUsageFormat } from '../../../shared/status-bar-usage-format' import { clampMarkdownTocPanelWidth } from '../../../shared/markdown-toc-panel-width' import { clampCombinedDiffFileTreeWidth } from '../../../shared/combined-diff-file-tree-width' import { @@ -59,6 +60,7 @@ export function getPersistedUI( syncTaskStatusFromWorkspaceBoard: state.ui?.syncTaskStatusFromWorkspaceBoard === true, usagePercentageDisplay: normalizeUsagePercentageDisplay(state.ui?.usagePercentageDisplay), statusBarUsageMode: normalizeStatusBarUsageMode(state.ui?.statusBarUsageMode), + statusBarUsageFormat: normalizeStatusBarUsageFormat(state.ui?.statusBarUsageFormat), statusBarCompactChangeNoticeDismissed: state.ui?.statusBarCompactChangeNoticeDismissed !== false, trayMinimizeNoticeShown: state.ui?.trayMinimizeNoticeShown === true, diff --git a/src/main/persistence/applying-settings/ui-state-update.ts b/src/main/persistence/applying-settings/ui-state-update.ts index 5d954d8ff2e..eb282c1c973 100644 --- a/src/main/persistence/applying-settings/ui-state-update.ts +++ b/src/main/persistence/applying-settings/ui-state-update.ts @@ -13,6 +13,7 @@ import { } from '../../../shared/workspace-statuses' import { normalizeUsagePercentageDisplay } from '../../../shared/usage-percentage-display' import { normalizeStatusBarUsageMode } from '../../../shared/status-bar-usage-mode' +import { normalizeStatusBarUsageFormat } from '../../../shared/status-bar-usage-format' import { clampMarkdownTocPanelWidth } from '../../../shared/markdown-toc-panel-width' import { clampCombinedDiffFileTreeWidth } from '../../../shared/combined-diff-file-tree-width' import { @@ -153,6 +154,9 @@ export function updatePersistedUI( statusBarUsageMode: normalizeStatusBarUsageMode( sanitizedUpdates.statusBarUsageMode ?? operations.state.ui?.statusBarUsageMode ), + statusBarUsageFormat: normalizeStatusBarUsageFormat( + sanitizedUpdates.statusBarUsageFormat ?? operations.state.ui?.statusBarUsageFormat + ), markdownTocPanelWidth: clampMarkdownTocPanelWidth( sanitizedUpdates.markdownTocPanelWidth ?? operations.state.ui?.markdownTocPanelWidth ), diff --git a/src/main/persistence/leasing-ssh-ptys/ssh-target-state.ts b/src/main/persistence/leasing-ssh-ptys/ssh-target-state.ts index e3991435bd4..6e12216406f 100644 --- a/src/main/persistence/leasing-ssh-ptys/ssh-target-state.ts +++ b/src/main/persistence/leasing-ssh-ptys/ssh-target-state.ts @@ -1,3 +1,4 @@ +import type { ProfileSaveDomains } from '../profile-save-domains' import type { PersistedState } from '../../../shared/persisted-state-types' import type { RemovedSshTargetTombstone, SshTarget } from '../../../shared/ssh-types' import type { ProtectedSecretPersistence } from '../../credentials/protected-secret-persistence' @@ -17,7 +18,7 @@ import { export type SshTargetStateOperations = { state: PersistedState protectedSecrets: Pick - scheduleSave: () => void + scheduleSave: (domains: ProfileSaveDomains) => void } export function getSshTargets(state: PersistedState): SshTarget[] { @@ -32,7 +33,7 @@ export function getSshTarget(state: PersistedState, id: string): SshTarget | und export function addSshTarget(operations: SshTargetStateOperations, target: SshTarget): void { // Replace the array to invalidate identity-cached automation projections. operations.state.sshTargets = [...(operations.state.sshTargets ?? []), normalizeSshTarget(target)] - operations.scheduleSave() + operations.scheduleSave(['sshTargets']) } export function updateSshTarget( @@ -64,7 +65,7 @@ export function updateSshTarget( } // Invalidate identity-cached lists after mutating the shared row. operations.state.sshTargets = [...(operations.state.sshTargets ?? [])] - operations.scheduleSave() + operations.scheduleSave(['sshTargets', 'retiredWorktreeNamesByNamespace']) return { ...target } } @@ -79,7 +80,7 @@ export function removeSshTarget(operations: SshTargetStateOperations, id: string operations.state.sshTargets = nextTargets operations.state.sshPtyConsumerRecoveries = nextRecoveries operations.protectedSecrets.removeRetainedBlob(sshPtyOwnerLeaseSecretSlot(id)) - operations.scheduleSave() + operations.scheduleSave(['sshTargets', 'sshPtyConsumerRecoveries']) } export function getDeletedSshConfigAliases(state: PersistedState): string[] { @@ -93,7 +94,7 @@ export function addDeletedSshConfigAlias( operations.state.deletedSshConfigAliases ??= [] if (!operations.state.deletedSshConfigAliases.includes(alias)) { operations.state.deletedSshConfigAliases.push(alias) - operations.scheduleSave() + operations.scheduleSave(['deletedSshConfigAliases']) } } @@ -106,7 +107,7 @@ export function removeDeletedSshConfigAlias( return } operations.state.deletedSshConfigAliases = current.filter((entry) => entry !== alias) - operations.scheduleSave() + operations.scheduleSave(['deletedSshConfigAliases']) } export function clearDeletedSshConfigAliases(operations: SshTargetStateOperations): void { @@ -115,7 +116,7 @@ export function clearDeletedSshConfigAliases(operations: SshTargetStateOperation operations.state.deletedSshConfigAliases.length > 0 ) { operations.state.deletedSshConfigAliases = [] - operations.scheduleSave() + operations.scheduleSave(['deletedSshConfigAliases']) } } @@ -134,7 +135,7 @@ export function addRemovedSshTargetTombstone( sshTargetRemovalEvidenceDependencies(operations.state), MAX_REMOVED_SSH_TARGET_TOMBSTONES ) - operations.scheduleSave() + operations.scheduleSave(['removedSshTargetTombstones']) } function sshTargetRemovalEvidenceDependencies(state: PersistedState): Set { @@ -169,5 +170,5 @@ export function removeRemovedSshTargetTombstone( operations.state.removedSshTargetTombstones = existing.filter( (entry) => entry.oldTargetId !== oldTargetId ) - operations.scheduleSave() + operations.scheduleSave(['removedSshTargetTombstones']) } diff --git a/src/main/persistence/loading-store/automation-enablement-transitions.ts b/src/main/persistence/loading-store/automation-enablement-transitions.ts new file mode 100644 index 00000000000..32e45925acb --- /dev/null +++ b/src/main/persistence/loading-store/automation-enablement-transitions.ts @@ -0,0 +1,24 @@ +import type { Automation } from '../../../shared/automations/automation-definition' + +/** In-memory count of pause and re-enable transitions per automation, for the scheduler's wake + * gate: a pause and re-enable can restore every field, even `updatedAt` within one ms, and run + * bookkeeping moves `updatedAt` without any user change. Every re-enable goes through + * `updateAutomation`; `disableAutomations` need not count, since the gate only holds enabled + * rows and coming back needs a re-enable. Not persisted: holds do not survive a restart. */ +export class AutomationEnablementTransitions { + private readonly counts = new Map() + + revision(id: string): number { + return this.counts.get(id) ?? 0 + } + + /** Runs an update of `id`, counting it when it flips the automation's `enabled`. */ + track(stored: readonly Automation[], id: string, update: () => Automation): Automation { + const wasEnabled = stored.find((entry) => entry.id === id)?.enabled + const updated = update() + if (wasEnabled !== undefined && updated.enabled !== wasEnabled) { + this.counts.set(id, this.revision(id) + 1) + } + return updated + } +} diff --git a/src/main/persistence/loading-store/automation-persistence.ts b/src/main/persistence/loading-store/automation-persistence.ts index 996b515ea45..13ed2137b73 100644 --- a/src/main/persistence/loading-store/automation-persistence.ts +++ b/src/main/persistence/loading-store/automation-persistence.ts @@ -58,6 +58,7 @@ import { import type { StoreRuntimeState } from './store-runtime-state' import type { WriteFlushBarrierOperations } from './write-flush-barriers' import type { ProfilePreferences } from './profile-preferences' +import { AutomationEnablementTransitions } from './automation-enablement-transitions' type AutomationPersistenceRuntime = Pick< StoreRuntimeState, @@ -69,6 +70,7 @@ type AutomationPersistenceRuntime = Pick< > const automationPersistenceContext = Symbol('AutomationPersistence') +const automationEnablement = Symbol('AutomationEnablement') type AutomationPersistenceContext = { runtime: AutomationPersistenceRuntime flushBarriers: WriteFlushBarrierOperations @@ -77,6 +79,7 @@ type AutomationPersistenceContext = { export class AutomationPersistence { readonly [automationPersistenceContext]: AutomationPersistenceContext + readonly [automationEnablement] = new AutomationEnablementTransitions() constructor( runtime: AutomationPersistenceRuntime, @@ -159,7 +162,15 @@ export class AutomationPersistence { updates: AutomationUpdateInput, options?: AutomationUpdatePreconditions & { resolvedRepo?: Repo } ): Automation { - return updateAutomationOperation(getAutomationDefinitionOperations(this), id, updates, options) + const stored = this[automationPersistenceContext].runtime.state.automations ?? [] + return this[automationEnablement].track(stored, id, () => + updateAutomationOperation(getAutomationDefinitionOperations(this), id, updates, options) + ) + } + + /** Changes when an update pauses or re-enables the automation, never on run bookkeeping. */ + automationEnablementRevision(id: string): number { + return this[automationEnablement].revision(id) } stampLegacyAutomationRunContext(automationId: string, runContext: WorkspaceRunContext): boolean { diff --git a/src/main/persistence/loading-store/cross-store-lineage-persistence.ts b/src/main/persistence/loading-store/cross-store-lineage-persistence.ts index 6ed378546cf..e253ca9caea 100644 --- a/src/main/persistence/loading-store/cross-store-lineage-persistence.ts +++ b/src/main/persistence/loading-store/cross-store-lineage-persistence.ts @@ -1,4 +1,5 @@ import type { ExecutionHostId } from '../../../shared/execution-host' +import { WORKSPACE_LINEAGE_DOMAINS } from '../profile-save-domains' import type { WorkspaceKey } from '../../../shared/workspace-scope' import type { CrossStoreWorkspaceLineage } from '../../../shared/worktree/lineage-types' import { hostWorktreeTarget } from '../../../shared/worktree/host-qualified-identity' @@ -61,7 +62,7 @@ export class CrossStoreLineagePersistence { delete state.workspaceLineageByChildKey[lineage.childWorkspaceKey] state.crossStoreLineageByChildKey ??= {} state.crossStoreLineageByChildKey[lineage.childWorkspaceKey] = lineage - scheduleSave(this[crossStoreLineagePersistenceContext].scheduling) + scheduleSave(this[crossStoreLineagePersistenceContext].scheduling, WORKSPACE_LINEAGE_DOMAINS) return lineage } } diff --git a/src/main/persistence/loading-store/folder-parent-lineage-persistence.ts b/src/main/persistence/loading-store/folder-parent-lineage-persistence.ts index e3cb0676133..dcd384c3f69 100644 --- a/src/main/persistence/loading-store/folder-parent-lineage-persistence.ts +++ b/src/main/persistence/loading-store/folder-parent-lineage-persistence.ts @@ -1,4 +1,5 @@ import type { HostWorktreeTarget } from '../../../shared/worktree/host-qualified-identity' +import { WORKSPACE_LINEAGE_DOMAINS } from '../profile-save-domains' import { parseWorkspaceKey, worktreeWorkspaceKey } from '../../../shared/workspace-scope' import type { WorkspaceLineage, WorktreeLineage } from '../../../shared/worktree/lineage-types' import { ownsRawIdBucket } from './metadata-lineage-operations' @@ -33,7 +34,7 @@ export class FolderParentLineagePersistence { delete state.worktreeLineageById[target.id] delete state.crossStoreLineageByChildKey?.[worktreeWorkspaceKey(target.id)] state.workspaceLineageByChildKey[worktreeWorkspaceKey(target.id)] = lineage - scheduleSave(this[folderParentLineageContext].scheduling) + scheduleSave(this[folderParentLineageContext].scheduling, WORKSPACE_LINEAGE_DOMAINS) return lineage } } diff --git a/src/main/persistence/loading-store/metadata-lineage-operations.ts b/src/main/persistence/loading-store/metadata-lineage-operations.ts index eab6c2d96ab..b24f707bb92 100644 --- a/src/main/persistence/loading-store/metadata-lineage-operations.ts +++ b/src/main/persistence/loading-store/metadata-lineage-operations.ts @@ -33,9 +33,9 @@ import { getWorktreeMetaForHost as getWorktreeMetaForHostOperation, migrateWorktreeMetadataLocator, removeWorktreeMetadataForHost, - setWorktreeMetaForHost as setWorktreeMetaForHostOperation, - WORKTREE_METADATA_DOMAINS + setWorktreeMetaForHost as setWorktreeMetaForHostOperation } from './worktree-identity-metadata' +import * as saved from '../profile-save-domains' import { captureNativeLocalWorktreeMetadataScanExpectation as captureNativeLocalWorktreeMetadataScanExpectationOperation, pruneSessionlessMissingLocalWorktreeMetadataForRepo as pruneSessionlessMissingLocalWorktreeMetadataForRepoOperation, @@ -53,6 +53,10 @@ type MetadataLineageOperationsContext = { sessions: SessionHostPartitionOperations } +function saveDomains(owner: MetadataLineageOperations, domains: readonly string[]): void { + scheduleSave(owner[metadataLineageOperationsContext].scheduling, domains) +} + export class MetadataLineageOperations { readonly [metadataLineageOperationsContext]: MetadataLineageOperationsContext @@ -198,7 +202,7 @@ export class MetadataLineageOperations { } // Removal may release identity collisions that previously blocked unrelated metadata pruning. invalidateLocalWorktreeMetadataPruneInputs() - scheduleSave(this[metadataLineageOperationsContext].scheduling) + saveDomains(this, saved.WORKTREE_METADATA_REMOVAL_DOMAINS) } selectProbeableLocalWorktreeMetadataCandidates( @@ -220,7 +224,7 @@ export class MetadataLineageOperations { missingMetadata ) if (removed.length > 0) { - scheduleSave(this[metadataLineageOperationsContext].scheduling) + saveDomains(this, saved.WORKTREE_METADATA_PRUNE_DOMAINS) } return removed } @@ -247,7 +251,7 @@ export class MetadataLineageOperations { state.workspaceLineageByChildKey[worktreeWorkspaceKey(target.id)] = toWorkspaceLineageRow(lineage) delete state.crossStoreLineageByChildKey?.[worktreeWorkspaceKey(target.id)] - scheduleSave(this[metadataLineageOperationsContext].scheduling) + saveDomains(this, saved.WORKSPACE_LINEAGE_DOMAINS) return lineage } @@ -259,7 +263,7 @@ export class MetadataLineageOperations { delete state.worktreeLineageById[target.id] delete state.workspaceLineageByChildKey[worktreeWorkspaceKey(target.id)] delete state.crossStoreLineageByChildKey?.[worktreeWorkspaceKey(target.id)] - scheduleSave(this[metadataLineageOperationsContext].scheduling) + saveDomains(this, saved.WORKSPACE_LINEAGE_DOMAINS) } migrateWorktreeIdentity(target: HostWorktreeTarget, newWorktreeId: string): void { @@ -275,9 +279,9 @@ export class MetadataLineageOperations { ) if (legacyChanged || canonicalChanged) { // Legacy identity moves also touch sessions, lineage, mobile selections and UI state. - scheduleSave( - this[metadataLineageOperationsContext].scheduling, - legacyChanged ? undefined : WORKTREE_METADATA_DOMAINS + saveDomains( + this, + legacyChanged ? saved.WORKTREE_IDENTITY_MIGRATION_DOMAINS : saved.WORKTREE_METADATA_DOMAINS ) } } @@ -298,7 +302,7 @@ export class MetadataLineageOperations { const state = this[metadataLineageOperationsContext].runtime.state state.workspaceLineageByChildKey[lineage.childWorkspaceKey] = lineage delete state.crossStoreLineageByChildKey?.[lineage.childWorkspaceKey] - scheduleSave(this[metadataLineageOperationsContext].scheduling) + saveDomains(this, ['workspaceLineageByChildKey', 'crossStoreLineageByChildKey']) return lineage } } diff --git a/src/main/persistence/loading-store/mobile-tab-selection-persistence.ts b/src/main/persistence/loading-store/mobile-tab-selection-persistence.ts index 2002fc8ca40..e0173d5350a 100644 --- a/src/main/persistence/loading-store/mobile-tab-selection-persistence.ts +++ b/src/main/persistence/loading-store/mobile-tab-selection-persistence.ts @@ -28,6 +28,8 @@ export class MobileTabSelectionPersistence { setMobileClientTabSelections(next: PersistedMobileClientTabSelections): void { this[mobileTabSelectionPersistenceContext].runtime.state.mobileClientTabSelectionsByDeviceId = next - scheduleSave(this[mobileTabSelectionPersistenceContext].scheduling) + scheduleSave(this[mobileTabSelectionPersistenceContext].scheduling, [ + 'mobileClientTabSelectionsByDeviceId' + ]) } } diff --git a/src/main/persistence/loading-store/normalize-loaded-global-settings.ts b/src/main/persistence/loading-store/normalize-loaded-global-settings.ts index c75ab18a38c..a29713ace36 100644 --- a/src/main/persistence/loading-store/normalize-loaded-global-settings.ts +++ b/src/main/persistence/loading-store/normalize-loaded-global-settings.ts @@ -98,6 +98,8 @@ export function normalizeLoadedGlobalSettings( ), worktreeVisibilityDefaults: migratedExternalVisibility.defaults, prBotAuthorOverrides: normalizePRBotAuthorOverrides(parsed.settings?.prBotAuthorOverrides), + // Only fresh profiles take the on default; a stored profile saved before the key existed was off. + artifactSharingEnabled: parsed.settings?.artifactSharingEnabled === true, // Carry the retired sidekick flag into pet settings. experimentalPet: parsed.settings?.experimentalPet ?? readLegacySidekickFlag(parsed) ?? false, // Migrate old platform defaults once; retain later opt-outs. diff --git a/src/main/persistence/loading-store/primary-state-write-worker.ts b/src/main/persistence/loading-store/primary-state-write-worker.ts index 6a67aa73cb2..de3cef861c9 100644 --- a/src/main/persistence/loading-store/primary-state-write-worker.ts +++ b/src/main/persistence/loading-store/primary-state-write-worker.ts @@ -23,7 +23,15 @@ export async function writeProfileStateInWorker( runtime.dirtyProfileStateDomains.add(domain) } } - runtime.pendingAutomationRunsAfter ??= automationRuns + if (automationRuns === undefined || runtime.pendingAutomationRunsAfter !== undefined) { + return + } + // A run list replaced while this write was in flight is newer; save it as a whole row instead. + if (automationRuns === runtime.state.automationRuns) { + runtime.pendingAutomationRunsAfter = automationRuns + } else { + runtime.dirtyProfileStateDomains?.add('automationRuns') + } } try { diff --git a/src/main/persistence/loading-store/profile-preferences.ts b/src/main/persistence/loading-store/profile-preferences.ts index 4be94581122..86bd0f6529d 100644 --- a/src/main/persistence/loading-store/profile-preferences.ts +++ b/src/main/persistence/loading-store/profile-preferences.ts @@ -186,7 +186,7 @@ export class ProfilePreferences { ...updates.checklist } } - scheduleSave(this[profilePreferencesContext].scheduling) + scheduleSave(this[profilePreferencesContext].scheduling, ['onboarding']) return this.getOnboarding() } @@ -267,7 +267,7 @@ export function getUIUpdateOperations(owner: ProfilePreferences): UIUpdateOperat setActiveView: (activeView) => owner[profilePreferencesContext].runtime.activeViewPreference.set(activeView), getUI: () => owner.getUI(), - scheduleSave: () => scheduleSave(owner[profilePreferencesContext].scheduling), + scheduleSave: () => scheduleSave(owner[profilePreferencesContext].scheduling, ['ui']), notifyUIChanged: () => notifyUIChanged(owner) } } diff --git a/src/main/persistence/loading-store/profile-state-checkpoints.test.ts b/src/main/persistence/loading-store/profile-state-checkpoints.test.ts index 3b69c23ac3e..97764f71c7d 100644 --- a/src/main/persistence/loading-store/profile-state-checkpoints.test.ts +++ b/src/main/persistence/loading-store/profile-state-checkpoints.test.ts @@ -80,7 +80,7 @@ describe('complete profile state checkpoints', () => { try { other.readSerializedState() other.writeSerializedDomains([{ domain: 'futureDomain', payload: '{"external":true}' }]) - scheduleSave(store) + scheduleSave(store, ['ui']) if (mode === 'sync') { expect(() => store.flushOrThrow()).toThrow(/Profile state revision changed/) } else { diff --git a/src/main/persistence/loading-store/profile-state-maintenance.ts b/src/main/persistence/loading-store/profile-state-maintenance.ts index 3f04eba8e92..20efca42f63 100644 --- a/src/main/persistence/loading-store/profile-state-maintenance.ts +++ b/src/main/persistence/loading-store/profile-state-maintenance.ts @@ -4,7 +4,7 @@ import type { StoreDomains } from './store-domain-composition' import type { StoreRuntimeState } from './store-runtime-state' import { drainProfileStateOperations } from './profile-state-flush-lifetime' import { flushCurrentStateAsync } from './write-flush-barriers' -import { scheduleSave } from './write-scheduling' +import { scheduleFullProfileSave } from './write-scheduling' import { persistGithubCache, suspendGithubCachePersistence } from './github-cache-persistence' export type ProfileStateMaintenanceOptions = { @@ -66,7 +66,7 @@ export function beginProfileStateMaintenance( runtime.profileMaintenancePending = false runtime.pendingProfileMaintenance = null resumePreference() - scheduleSave(domains.scheduling) + scheduleFullProfileSave(domains.scheduling) // Updates admitted while paused (or a retry it skipped) resume their routine save. persistGithubCache(runtime, 'routine') } diff --git a/src/main/persistence/loading-store/project-collection-operations.ts b/src/main/persistence/loading-store/project-collection-operations.ts index 2e67007eefc..90c7cc1ee6e 100644 --- a/src/main/persistence/loading-store/project-collection-operations.ts +++ b/src/main/persistence/loading-store/project-collection-operations.ts @@ -186,7 +186,7 @@ export class ProjectCollectionOperations { const { runtime, scheduling } = this[projectCollectionOperationsContext] const changed = applyWslMoveRetainedMarks(runtime.state, marks) if (changed > 0) { - scheduleSave(scheduling) + scheduleSave(scheduling, ['repos', 'folderWorkspaces']) } return changed } @@ -216,7 +216,8 @@ export function getProjectHostOperations( ), removeProjectForHost: (target) => owner[projectCollectionOperationsContext].repos.removeProjectForHost(target), - scheduleSave: () => scheduleSave(owner[projectCollectionOperationsContext].scheduling) + scheduleSave: (domains) => + scheduleSave(owner[projectCollectionOperationsContext].scheduling, domains) }) return owner[projectCollectionOperationsContext].runtime.projectHostOperations } @@ -227,7 +228,8 @@ export function getProjectGroupOperations( owner[projectCollectionOperationsContext].runtime.projectGroupOperations ??= new ProjectGroupPersistenceOperations({ state: owner[projectCollectionOperationsContext].runtime.state, - scheduleSave: () => scheduleSave(owner[projectCollectionOperationsContext].scheduling), + scheduleSave: (domains) => + scheduleSave(owner[projectCollectionOperationsContext].scheduling, domains), removeWorkspaceLineageForRemovedFolder: (folderWorkspaceId) => removeWorkspaceLineageForRemovedFolder( owner[projectCollectionOperationsContext].metadata, @@ -248,7 +250,8 @@ export function getFolderWorkspaceOperations( owner[projectCollectionOperationsContext].runtime.folderWorkspaceOperations ??= new FolderWorkspacePersistenceOperations({ state: owner[projectCollectionOperationsContext].runtime.state, - scheduleSave: () => scheduleSave(owner[projectCollectionOperationsContext].scheduling), + scheduleSave: (domains) => + scheduleSave(owner[projectCollectionOperationsContext].scheduling, domains), removeWorkspaceLineageForRemovedFolder: (folderWorkspaceId) => removeWorkspaceLineageForRemovedFolder( owner[projectCollectionOperationsContext].metadata, diff --git a/src/main/persistence/loading-store/repo-lifecycle-operations.ts b/src/main/persistence/loading-store/repo-lifecycle-operations.ts index ea15fa64885..98a791a0316 100644 --- a/src/main/persistence/loading-store/repo-lifecycle-operations.ts +++ b/src/main/persistence/loading-store/repo-lifecycle-operations.ts @@ -1,4 +1,5 @@ import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' +import { REMOVE_PROJECT_DOMAINS, REPO_CATALOG_DOMAINS } from '../profile-save-domains' import type { ProjectHostSetup, ProjectHostSetupUpdateArgs } from '../../../shared/project-types' import type { Repo } from '../../../shared/repo-types' import type { RepoHostTarget } from '../../../shared/repo-host-identity' @@ -80,7 +81,7 @@ export class RepoLifecycleOperations { getRepoOrderOperations(this).addRepo(repo) const context = this[repoLifecycleOperationsContext] if (applyNewWindowsDriveProjectDefault(context.runtime.state, repo)) { - scheduleSave(context.scheduling) + scheduleSave(context.scheduling, ['projects']) } } @@ -138,7 +139,7 @@ export class RepoLifecycleOperations { } } } - scheduleSave(this[repoLifecycleOperationsContext].scheduling) + scheduleSave(this[repoLifecycleOperationsContext].scheduling, REMOVE_PROJECT_DOMAINS) } /** Sweep unregistered local repos at load; unpaired remote absence cannot prove deletion. */ @@ -226,7 +227,8 @@ export function getRepoOrderOperations( new RepoOrderPersistenceOperations({ state: owner[repoLifecycleOperationsContext].runtime.state, syncProjectHostSetupCompatibilityState: () => syncProjectHostSetupCompatibilityState(owner), - scheduleSave: () => scheduleSave(owner[repoLifecycleOperationsContext].scheduling) + scheduleSave: () => + scheduleSave(owner[repoLifecycleOperationsContext].scheduling, REPO_CATALOG_DOMAINS) }) return owner[repoLifecycleOperationsContext].runtime.repoOrderOperations } @@ -272,7 +274,8 @@ export function getRepoUpdateOperations( state: owner[repoLifecycleOperationsContext].runtime.state, bumpLocalWorktreeScanGeneration, syncProjectHostSetupCompatibilityState: () => syncProjectHostSetupCompatibilityState(owner), - scheduleSave: () => scheduleSave(owner[repoLifecycleOperationsContext].scheduling), + scheduleSave: () => + scheduleSave(owner[repoLifecycleOperationsContext].scheduling, REPO_CATALOG_DOMAINS), hydrateRepo: (repo) => hydrateRepo(owner, repo) }) return owner[repoLifecycleOperationsContext].runtime.repoUpdateOperations @@ -295,7 +298,8 @@ export function getProjectHostSetupOperations( new ProjectHostSetupPersistenceOperations({ state: owner[repoLifecycleOperationsContext].runtime.state, updateRepo: (target, updates) => owner.updateRepo(target, updates), - scheduleSave: () => scheduleSave(owner[repoLifecycleOperationsContext].scheduling) + scheduleSave: () => + scheduleSave(owner[repoLifecycleOperationsContext].scheduling, ['projectHostSetups']) }) return owner[repoLifecycleOperationsContext].runtime.projectHostSetupOperations } diff --git a/src/main/persistence/loading-store/retired-worktree-name-persistence.ts b/src/main/persistence/loading-store/retired-worktree-name-persistence.ts index 8a86e5f5540..c32b50ed0ab 100644 --- a/src/main/persistence/loading-store/retired-worktree-name-persistence.ts +++ b/src/main/persistence/loading-store/retired-worktree-name-persistence.ts @@ -88,7 +88,9 @@ export class RetiredWorktreeNamePersistence { namespaceKey, next ) - scheduleSave(this[retiredWorktreeNamePersistenceContext].scheduling) + scheduleSave(this[retiredWorktreeNamePersistenceContext].scheduling, [ + 'retiredWorktreeNamesByNamespace' + ]) return true } } @@ -105,6 +107,8 @@ export function applyRetiredWorktreeNames( owner[retiredWorktreeNamePersistenceContext].runtime.state.retiredWorktreeNamesByRepo ??= {} owner[retiredWorktreeNamePersistenceContext].runtime.state.retiredWorktreeNamesByRepo[repoId] = next - scheduleSave(owner[retiredWorktreeNamePersistenceContext].scheduling) + scheduleSave(owner[retiredWorktreeNamePersistenceContext].scheduling, [ + 'retiredWorktreeNamesByRepo' + ]) return true } diff --git a/src/main/persistence/loading-store/sparse-preset-persistence.ts b/src/main/persistence/loading-store/sparse-preset-persistence.ts index 3a9ed632e66..3f7fae052b2 100644 --- a/src/main/persistence/loading-store/sparse-preset-persistence.ts +++ b/src/main/persistence/loading-store/sparse-preset-persistence.ts @@ -32,7 +32,7 @@ export class SparsePresetPersistence { index === -1 ? [...existing, preset] : existing.map((entry, entryIndex) => (entryIndex === index ? preset : entry)) - scheduleSave(this[sparsePresetPersistenceContext].scheduling) + scheduleSave(this[sparsePresetPersistenceContext].scheduling, ['sparsePresetsByRepo']) return preset } @@ -41,6 +41,6 @@ export class SparsePresetPersistence { this[sparsePresetPersistenceContext].runtime.state.sparsePresetsByRepo[repoId] ?? [] this[sparsePresetPersistenceContext].runtime.state.sparsePresetsByRepo[repoId] = existing.filter((entry) => entry.id !== presetId) - scheduleSave(this[sparsePresetPersistenceContext].scheduling) + scheduleSave(this[sparsePresetPersistenceContext].scheduling, ['sparsePresetsByRepo']) } } diff --git a/src/main/persistence/loading-store/ssh-lease-recovery-operations.ts b/src/main/persistence/loading-store/ssh-lease-recovery-operations.ts index efbc1afa4a0..75324fc74a8 100644 --- a/src/main/persistence/loading-store/ssh-lease-recovery-operations.ts +++ b/src/main/persistence/loading-store/ssh-lease-recovery-operations.ts @@ -1,3 +1,4 @@ +import { WORKSPACE_SESSION_DOMAINS } from '../workspace-session-domains' import type { SshPendingPtyKill } from '../../../shared/ssh-pending-pty-kill' import type { SshRemotePtyLease } from '../../../shared/ssh-types' import type { PtyRetirementEvidence } from '../../pty/process-retirement/pty-exit-proof' @@ -89,7 +90,8 @@ function getSshPtyBindingCleanupOperations( targetId, ptyId ), - scheduleSave: () => scheduleSave(owner[sshLeaseRecoveryOperationsContext].scheduling) + scheduleSave: () => + scheduleSave(owner[sshLeaseRecoveryOperationsContext].scheduling, WORKSPACE_SESSION_DOMAINS) } } diff --git a/src/main/persistence/loading-store/ssh-profile-operations.ts b/src/main/persistence/loading-store/ssh-profile-operations.ts index f236db609ba..8f7ee60bf24 100644 --- a/src/main/persistence/loading-store/ssh-profile-operations.ts +++ b/src/main/persistence/loading-store/ssh-profile-operations.ts @@ -1,4 +1,6 @@ import type { RemovedSshTargetTombstone, SshTarget } from '../../../shared/ssh-types' +import { WORKSPACE_SESSION_DOMAINS } from '../workspace-session-domains' +import { WORKTREE_METADATA_DOMAINS } from '../profile-save-domains' import { type SshTargetStateOperations, addDeletedSshConfigAlias as addDeletedSshConfigAliasOperation, @@ -37,6 +39,23 @@ type SshProfileOperationsContext = { repos: RepoLifecycleOperations } +/** Re-adopting an SSH target rewrites every record that names the old target. */ +const SSH_TARGET_REASSIGNMENT_DOMAINS = [ + 'repos', + 'projects', + 'projectHostSetups', + ...WORKTREE_METADATA_DOMAINS, + ...WORKSPACE_SESSION_DOMAINS, + 'ui', + 'retiredWorktreeNamesByNamespace', + 'folderWorkspaces', + 'projectGroups', + 'automations', + 'automationRuns', + 'sshRemotePtyLeases', + 'sshPtyConsumerRecoveries' +] + export class SshProfileOperations { readonly [sshProfileOperationsContext]: SshProfileOperationsContext @@ -75,7 +94,7 @@ export class SshProfileOperations { allocateSshTargetGeneration(): number { const context = this[sshProfileOperationsContext] return allocateSshTargetGenerationOperation(context.runtime.state, () => - scheduleSave(context.scheduling) + scheduleSave(context.scheduling, ['sshTargetGenerationCounter']) ) } @@ -117,7 +136,8 @@ export class SshProfileOperations { protectedSecrets: this[sshProfileOperationsContext].runtime.protectedSecrets, syncProjectHostSetupCompatibilityState: () => syncProjectHostSetupCompatibilityState(this[sshProfileOperationsContext].repos), - scheduleSave: () => scheduleSave(this[sshProfileOperationsContext].scheduling) + scheduleSave: () => + scheduleSave(this[sshProfileOperationsContext].scheduling, SSH_TARGET_REASSIGNMENT_DOMAINS) } return reassignSshTargetIdOperation(operations, oldTargetId, newTargetId) } @@ -127,6 +147,6 @@ export function getSshTargetStateOperations(owner: SshProfileOperations): SshTar return { state: owner[sshProfileOperationsContext].runtime.state, protectedSecrets: owner[sshProfileOperationsContext].runtime.protectedSecrets, - scheduleSave: () => scheduleSave(owner[sshProfileOperationsContext].scheduling) + scheduleSave: (domains) => scheduleSave(owner[sshProfileOperationsContext].scheduling, domains) } } diff --git a/src/main/persistence/loading-store/state-serialization-secret-handling.test.ts b/src/main/persistence/loading-store/state-serialization-secret-handling.test.ts new file mode 100644 index 00000000000..b36b4d4f4fe --- /dev/null +++ b/src/main/persistence/loading-store/state-serialization-secret-handling.test.ts @@ -0,0 +1,90 @@ +import { describe, it, expect, vi } from 'vitest' +import { getDefaultPersistedState } from '../../../shared/constants' +import { folderWorkspaceKey } from '../../../shared/workspace-scope' +import type { WorktreeMeta } from '../../../shared/worktree/meta-types' +import { ProtectedSecretPersistence } from '../../credentials/protected-secret-persistence' +import { StateSerializationSecretHandlingOperations } from './state-serialization-secret-handling' + +vi.mock('electron', () => ({ + safeStorage: { + isEncryptionAvailable: () => true, + encryptString: (plaintext: string) => Buffer.from(`encrypted:${plaintext}`, 'utf-8'), + decryptString: (ciphertext: Buffer) => ciphertext.toString('utf-8').slice('encrypted:'.length) + } +})) + +describe('profile save serialization', () => { + it('saves every named domain exactly as a whole save does', () => { + const state = getDefaultPersistedState('/home/user') + state.settings.httpProxyUrl = 'http://proxy.example:8080' + state.ui.browserKagiSessionLink = 'https://kagi.example/session' + state.folderWorkspaces = [ + { + id: 'fw-1', + projectGroupId: 'group-1', + name: 'Refund fix', + folderPath: '/workspace/platform', + linkedTask: null, + comment: '', + isArchived: false, + isUnread: false, + isPinned: false, + sortOrder: 0, + lastActivityAt: 1, + createdAt: 1, + updatedAt: 1, + diffComments: [ + { + id: 'note-1', + worktreeId: folderWorkspaceKey('fw-1'), + filePath: 'README.md', + source: 'markdown', + lineNumber: 1, + body: 'Review this', + createdAt: 100, + side: 'modified' + } + ] + } + ] + const row: WorktreeMeta = { + instanceId: 'instance-1', + hostId: 'local', + displayName: 'wt-1', + comment: 'pinned', + linkedIssue: null, + linkedPR: null, + linkedLinearIssue: null, + isArchived: false, + isUnread: false, + isPinned: false, + sortOrder: 0, + lastActivityAt: 1 + } + state.worktreeMeta = { 'repo-1::/work/wt-1': row } + state.worktreeMetaByIdentity = { 'wt2:local:instance-1': row } + state.worktreeIdentityAliases = { 'local::repo-1::/work/wt-1': ['wt2:local:instance-1'] } + state.sshPtyConsumerRecoveries = [ + { + targetId: 'ssh-1', + clientInstanceId: 'client-1', + serverBuildId: 'server-1', + clientGeneration: 1, + ownerGeneration: 1, + ownerLease: 'lease-secret' + } + ] + const serialization = new StateSerializationSecretHandlingOperations({ + protectedSecrets: new ProtectedSecretPersistence(), + state + }) + + const whole = serialization.buildStateToSave(true).domains! + const named = serialization.buildStateDomainsToSave(new Set(whole.map(({ domain }) => domain))) + + expect(named).toBeDefined() + expect(new Map(named!.replacements.map(({ domain, payload }) => [domain, payload]))).toEqual( + new Map(whole.map(({ domain, payload }) => [domain, payload])) + ) + }) +}) diff --git a/src/main/persistence/loading-store/state-serialization-secret-handling.ts b/src/main/persistence/loading-store/state-serialization-secret-handling.ts index 05d859c8cae..f97760b3c57 100644 --- a/src/main/persistence/loading-store/state-serialization-secret-handling.ts +++ b/src/main/persistence/loading-store/state-serialization-secret-handling.ts @@ -16,6 +16,7 @@ import { LEGACY_OPENCODE_GO_API_KEY_SLOT } from './legacy-opencode-go-api-key-mi import { omitDefaultWorktreeMetaFieldsInMap } from '../../../shared/worktree/meta-persisted-defaults' import { projectWorktreeMetaByIdentityOntoLocators } from './worktree-meta-alias-projection' import { withoutRedundantPartitionGlobals } from '../../../shared/workspace-session/workspace-session-host-field-ownership' +import { WORKTREE_METADATA_DOMAINS } from '../profile-save-domains' import { applySecretSentinelSubstitutions, @@ -23,6 +24,42 @@ import { } from './secret-sentinel-substitution' import type { StoreRuntimeState } from './store-runtime-state' +/** Domains whose saved form differs from state; whole saves keep this order after the durable spread. */ +const PROJECTED_SAVE_DOMAINS = [ + 'worktreeMeta', + 'worktreeMetaByIdentity', + 'workspaceSessionsByHostId', + 'folderWorkspaces', + 'folderWorkspaceDiffComments', + 'sshPtyConsumerRecoveries', + 'settings', + 'ui' +] as const + +/** Saved domains derived from another domain's state must be written with it. */ +const DEPENDENT_SAVE_DOMAINS = new Map([ + ['folderWorkspaces', ['folderWorkspaceDiffComments']], + ...WORKTREE_METADATA_DOMAINS.map((domain): [string, readonly string[]] => [ + domain, + WORKTREE_METADATA_DOMAINS + ]) +]) + +function withDependentSaveDomains(domains: ReadonlySet): ReadonlySet { + const saved = new Set() + for (const domain of domains) { + // Memory-only state never reaches disk. + if (domain === 'githubCache') { + continue + } + saved.add(domain) + for (const dependent of DEPENDENT_SAVE_DOMAINS.get(domain) ?? []) { + saved.add(dependent) + } + } + return saved +} + type StateSerializationSecretHandlingOperationsRuntime = Pick< StoreRuntimeState, 'protectedSecrets' | 'state' | 'originalExperimentalNativeChat' @@ -36,7 +73,7 @@ export class StateSerializationSecretHandlingOperations { return durable } - /** Unknown domains require full serialization so secret retention stays complete. */ + /** Pending encryption requires full serialization so secret retention stays complete. */ buildStateDomainsToSave(domains: ReadonlySet): | { replacements: ProfileStateDomainReplacement[] @@ -47,7 +84,6 @@ export class StateSerializationSecretHandlingOperations { if (this.runtime.protectedSecrets.hasPendingEncryption()) { return undefined } - const stateToSave: Record = {} const protectedSecretUpdates: ProtectedSecretRetentionUpdate[] = [] const encrypt = (slot: string, plaintext: string): string => { const encrypted = this.runtime.protectedSecrets.encrypt(slot, plaintext) @@ -56,70 +92,13 @@ export class StateSerializationSecretHandlingOperations { } return encrypted.blob } - for (const domain of domains) { - switch (domain) { - case 'settings': - stateToSave[domain] = this.buildSettingsToSave(encrypt) - break - case 'workspaceSession': - stateToSave[domain] = this.runtime.state.workspaceSession - break - case 'automations': - case 'automationRuns': - stateToSave[domain] = this.runtime.state[domain] - break - case 'featureInteractionTelemetryBuckets': - stateToSave[domain] = this.runtime.state.featureInteractionTelemetryBuckets - break - case 'ui': - stateToSave[domain] = { - ...this.runtime.state.ui, - browserKagiSessionLink: - encrypt( - PROTECTED_SECRET_SLOT.browserKagiSessionLink, - this.runtime.state.ui.browserKagiSessionLink ?? '' - ) || null - } - break - case 'worktreeMeta': - stateToSave[domain] = omitDefaultWorktreeMetaFieldsInMap(this.runtime.state.worktreeMeta) - break - case 'worktreeMetaByIdentity': - if (this.runtime.state.worktreeMetaByIdentity !== undefined) { - stateToSave[domain] = omitDefaultWorktreeMetaFieldsInMap( - projectWorktreeMetaByIdentityOntoLocators( - this.runtime.state.worktreeMetaByIdentity, - this.runtime.state - ) - ) - } - break - case 'worktreeIdentityAliases': - if (this.runtime.state.worktreeIdentityAliases !== undefined) { - stateToSave[domain] = this.runtime.state.worktreeIdentityAliases - } - break - case 'workspaceSessionsByHostId': - if (this.runtime.state.workspaceSessionsByHostId !== undefined) { - stateToSave[domain] = withoutRedundantPartitionGlobals( - this.runtime.state.workspaceSessionsByHostId, - this.runtime.state.workspaceSession - ) - } - break - case 'sshRemotePtyLeases': - case 'remoteLayoutSnapshots': - case 'hostRepoCatalogSnapshots': - case 'legacyPaneKeyAliasEntries': - case 'migrationUnsupportedPtyEntries': - stateToSave[domain] = this.runtime.state[domain] - break - default: - return undefined - } + const saved = withDependentSaveDomains(domains) + const stateToSave: Record = {} + for (const domain of saved) { + stateToSave[domain] = this.projectDomainToSave(domain, encrypt) } return { - replacements: serializeSelectiveProfileStateDomains(stateToSave, domains), + replacements: serializeSelectiveProfileStateDomains(stateToSave, saved), protectedSecretUpdates } } @@ -148,67 +127,10 @@ export class StateSerializationSecretHandlingOperations { secretSubs.push({ sentinel, blob, hashValue }) return sentinel } - const encryptOptionalToSentinel = ( - slot: string, - plaintext: string | null | undefined - ): string | null => { - const encrypted = encryptToSentinel(slot, plaintext ?? '') - return encrypted || null - } - // Project shared aliases before default omission clones rows, avoiding per-row deep comparisons. - const projectedWorktreeMetaByIdentity = - this.runtime.state.worktreeMetaByIdentity === undefined - ? undefined - : projectWorktreeMetaByIdentityOntoLocators( - this.runtime.state.worktreeMetaByIdentity, - this.runtime.state - ) // Clone before encryption to keep in-memory state plaintext. - const stateToSave = { - ...this.getDurableState(), - // Load normalization restores omitted default metadata fields. - worktreeMeta: omitDefaultWorktreeMetaFieldsInMap(this.runtime.state.worktreeMeta), - ...(projectedWorktreeMetaByIdentity !== undefined - ? { - worktreeMetaByIdentity: omitDefaultWorktreeMetaFieldsInMap( - projectedWorktreeMetaByIdentity - ) - } - : {}), - // Local owns these globals; host partitions restore defaults on load. - ...(this.runtime.state.workspaceSessionsByHostId !== undefined - ? { - workspaceSessionsByHostId: withoutRedundantPartitionGlobals( - this.runtime.state.workspaceSessionsByHostId, - this.runtime.state.workspaceSession - ) - } - : {}), - // Override both spread keys to relocate notes without mutating in-memory workspace rows. - // Undefined omits the map entirely when no notes exist. - folderWorkspaces: (this.runtime.state.folderWorkspaces ?? []).map( - ({ diffComments: _relocated, ...rest }) => rest - ), - folderWorkspaceDiffComments: collectFolderWorkspaceDiffComments( - this.runtime.state.folderWorkspaces - ), - sshPtyConsumerRecoveries: (this.runtime.state.sshPtyConsumerRecoveries ?? []).map( - (record) => ({ - ...record, - ownerLease: encryptToSentinel( - sshPtyOwnerLeaseSecretSlot(record.targetId), - record.ownerLease - ) - }) - ), - settings: this.buildSettingsToSave(encryptToSentinel), - ui: { - ...this.runtime.state.ui, - browserKagiSessionLink: encryptOptionalToSentinel( - PROTECTED_SECRET_SLOT.browserKagiSessionLink, - this.runtime.state.ui.browserKagiSessionLink - ) - } + const stateToSave: Record = { ...this.getDurableState() } + for (const domain of PROJECTED_SAVE_DOMAINS) { + stateToSave[domain] = this.projectDomainToSave(domain, encryptToSentinel) } if ( serializeDomains && @@ -238,6 +160,60 @@ export class StateSerializationSecretHandlingOperations { return { payload, stateHash, protectedSecretUpdates } } + /** The one saved form of each domain, shared by selective and whole saves. */ + private projectDomainToSave( + domain: string, + encrypt: (slot: string, plaintext: string) => string + ): unknown { + const { state } = this.runtime + switch (domain) { + case 'githubCache': + return undefined + case 'settings': + return this.buildSettingsToSave(encrypt) + case 'ui': + return { + ...state.ui, + browserKagiSessionLink: + encrypt( + PROTECTED_SECRET_SLOT.browserKagiSessionLink, + state.ui.browserKagiSessionLink ?? '' + ) || null + } + // Load normalization restores omitted default metadata fields. + case 'worktreeMeta': + return omitDefaultWorktreeMetaFieldsInMap(state.worktreeMeta) + // Project shared aliases before default omission clones rows, avoiding per-row deep comparisons. + case 'worktreeMetaByIdentity': + return state.worktreeMetaByIdentity === undefined + ? undefined + : omitDefaultWorktreeMetaFieldsInMap( + projectWorktreeMetaByIdentityOntoLocators(state.worktreeMetaByIdentity, state) + ) + // Local owns these globals; host partitions restore defaults on load. + case 'workspaceSessionsByHostId': + return state.workspaceSessionsByHostId === undefined + ? undefined + : withoutRedundantPartitionGlobals( + state.workspaceSessionsByHostId, + state.workspaceSession + ) + // Relocate notes without mutating in-memory workspace rows; undefined omits the map when none exist. + case 'folderWorkspaces': + return (state.folderWorkspaces ?? []).map(({ diffComments: _relocated, ...rest }) => rest) + case 'folderWorkspaceDiffComments': + return collectFolderWorkspaceDiffComments(state.folderWorkspaces) + case 'sshPtyConsumerRecoveries': + return (state.sshPtyConsumerRecoveries ?? []).map((record) => ({ + ...record, + ownerLease: encrypt(sshPtyOwnerLeaseSecretSlot(record.targetId), record.ownerLease) + })) + default: + // Own properties only, including domains this build doesn't know. + return Object.getOwnPropertyDescriptor(state, domain)?.value + } + } + private buildSettingsToSave(encrypt: (slot: string, plaintext: string) => string) { return { ...stripRetiredGlobalSettings(this.runtime.state.settings), diff --git a/src/main/persistence/loading-store/store-domain-composition.ts b/src/main/persistence/loading-store/store-domain-composition.ts index 0381ec482c8..eab60b4b077 100644 --- a/src/main/persistence/loading-store/store-domain-composition.ts +++ b/src/main/persistence/loading-store/store-domain-composition.ts @@ -1,4 +1,5 @@ import type { StoreRuntimeState } from './store-runtime-state' +import { WORKSPACE_SESSION_DOMAINS } from '../workspace-session-domains' import type { Store } from './store' import { LoadedStateAdaptationOperations } from './loaded-state-adaptation' import { LoadedCohortMigrationOperations } from './loaded-cohort-migrations' @@ -185,8 +186,10 @@ export function createStoreDomains(runtime: StoreRuntimeState): StoreDomains { layoutCommands: new LayoutCommandPersistence( runtime, sessions, - // Retry persistence for terminal closes retained after failed writes. - ORCA_LAYOUT_OWNER_IS_MAIN ? () => scheduleSave(scheduling) : undefined + // Retry persistence for terminal closes retained after failed writes; a close edits sessions only. + ORCA_LAYOUT_OWNER_IS_MAIN + ? () => scheduleSave(scheduling, WORKSPACE_SESSION_DOMAINS) + : undefined ), sshProfiles, retiredWorktreeNames, diff --git a/src/main/persistence/loading-store/store-runtime-state.ts b/src/main/persistence/loading-store/store-runtime-state.ts index 951187da47b..d089fa159a4 100644 --- a/src/main/persistence/loading-store/store-runtime-state.ts +++ b/src/main/persistence/loading-store/store-runtime-state.ts @@ -1,3 +1,4 @@ +import { randomUUID } from 'node:crypto' import { removeStaleDurableWriteTempFiles } from '../../filesystem/durable-file-write' import type { GlobalSettings } from '../../../shared/global-settings-types' import type { PersistedState } from '../../../shared/persisted-state-types' @@ -6,7 +7,7 @@ import type { WorkspaceSessionWriteListener } from './workspace-session-write-listeners' import type { ExecutionHostId } from '../../../shared/execution-host' -import type { StateWriteListener } from './write-scheduling' +import type { StateWriteListener, WorktreeMetaWriteListener } from './write-scheduling' import type { PartitionEditorViews } from './layout-editor-views' import type { ActiveViewPreference } from '../preferences/active-view-preference' import { @@ -114,6 +115,9 @@ export class StoreRuntimeState { /** In-memory editor views by partition; layout-owner builds only. */ readonly layoutEditorViews = new Map() readonly stateWriteListeners = new Set() + readonly worktreeMetaWriteListeners = new Set() + // This store's workspaceMetadata position: a new epoch per process, one seq per published record. + readonly workspaceMetadataCursor = { epoch: randomUUID(), seq: 0 } projectHostOperations: ProjectHostPersistenceOperations | null = null projectGroupOperations: ProjectGroupPersistenceOperations | null = null folderWorkspaceOperations: FolderWorkspacePersistenceOperations | null = null diff --git a/src/main/persistence/loading-store/store.ts b/src/main/persistence/loading-store/store.ts index 0deffce5565..c25eecde0b5 100644 --- a/src/main/persistence/loading-store/store.ts +++ b/src/main/persistence/loading-store/store.ts @@ -23,7 +23,7 @@ import { bindPersistedTabTerminalPanes, sweepPersistedUnattachedTerminalRows } from '../restoring-sessions/tab-terminal-pane-binding-repair' -import { scheduleSave } from './write-scheduling' +import { scheduleFullProfileSave, scheduleSave } from './write-scheduling' import { migrateLegacyOpenCodeGoApiKey, type OpenCodeGoApiKeyTarget @@ -177,7 +177,7 @@ export class Store { adaptedProjectGroups || sweptRepoIds.length > 0 ) { - scheduleSave(this.domains.scheduling) + scheduleFullProfileSave(this.domains.scheduling) } } } @@ -185,7 +185,7 @@ export class Store { /** Retain the legacy settings key until migration to the main-owned store succeeds. */ migrateLegacyOpenCodeGoApiKey(target: OpenCodeGoApiKeyTarget): void { if (migrateLegacyOpenCodeGoApiKey(this.runtime.protectedSecrets, target)) { - scheduleSave(this.domains.scheduling) + scheduleSave(this.domains.scheduling, ['settings']) } } diff --git a/src/main/persistence/loading-store/workspace-session-snapshot-publication.ts b/src/main/persistence/loading-store/workspace-session-snapshot-publication.ts index 5dbd4e1077f..2a0e2222c5a 100644 --- a/src/main/persistence/loading-store/workspace-session-snapshot-publication.ts +++ b/src/main/persistence/loading-store/workspace-session-snapshot-publication.ts @@ -1,4 +1,5 @@ import type { PersistedState } from '../../../shared/persisted-state-types' +import { WORKSPACE_SESSION_DOMAINS } from '../workspace-session-domains' import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' import { sanitizeWorkspaceSessionTerminalRetirements } from '../../runtime/terminal/surface/mobile-session-terminal-persistence-retirement' import { LOCAL_EXECUTION_HOST_ID, type ExecutionHostId } from '../../../shared/execution-host' @@ -121,7 +122,11 @@ export function setLocalWorkspaceSession( remappedManualUnread.changed ) { // UI remaps include protected fields, so keep the complete serializer boundary. - scheduleSave(context.scheduling, undefined, LOCAL_EXECUTION_HOST_ID) + scheduleSave( + context.scheduling, + [WORKSPACE_SESSION_DOMAINS[0], 'ui', 'sshRemotePtyLeases'], + LOCAL_EXECUTION_HOST_ID + ) } else { scheduleSave( context.scheduling, diff --git a/src/main/persistence/loading-store/worktree-identity-metadata.ts b/src/main/persistence/loading-store/worktree-identity-metadata.ts index 8a9a78369b8..4dace783a0c 100644 --- a/src/main/persistence/loading-store/worktree-identity-metadata.ts +++ b/src/main/persistence/loading-store/worktree-identity-metadata.ts @@ -14,23 +14,19 @@ import type { StoreRuntimeState } from './store-runtime-state' import { type WriteSchedulingOperations, scheduleSave } from './write-scheduling' import { mergeWorktreeMetaForWrite } from './worktree-meta-write-normalization' +import { WORKTREE_METADATA_DOMAINS } from '../profile-save-domains' import { isLocalOnlyWorktreeMetaId, worktreeMetaHostFor } from '../../../shared/worktree/local-only-worktree-meta-ids' -type MetadataRuntime = Pick +type MetadataRuntime = Pick & + Partial> type WorktreeMetaState = Pick< PersistedState, 'worktreeMeta' | 'worktreeMetaByIdentity' | 'worktreeIdentityAliases' > -export const WORKTREE_METADATA_DOMAINS = [ - 'worktreeMeta', - 'worktreeMetaByIdentity', - 'worktreeIdentityAliases' -] as const - export function resolveAliasIdentityKey( state: WorktreeMetaState, alias: string @@ -265,5 +261,13 @@ export function setWorktreeMetaForHost( state.worktreeMeta[worktreeId] = updated } scheduleSave(scheduling, WORKTREE_METADATA_DOMAINS) + for (const listener of runtime.worktreeMetaWriteListeners ?? []) { + try { + listener({ worktreeId, hostId: executionHostId, previous: existing, next: updated }) + } catch (error) { + // The row is already written; an observer's failure must not report the write as failed. + console.error('[worktree-meta] write listener failed:', error) + } + } return updated } diff --git a/src/main/persistence/loading-store/worktree-meta-write-normalization.ts b/src/main/persistence/loading-store/worktree-meta-write-normalization.ts index 638623f5202..e98a0e2e7f7 100644 --- a/src/main/persistence/loading-store/worktree-meta-write-normalization.ts +++ b/src/main/persistence/loading-store/worktree-meta-write-normalization.ts @@ -49,7 +49,7 @@ export function mergeWorktreeMetaForWrite( const normalizedUpdates = normalizeWorkspaceAttachmentUpdate(existing, metaUpdates) const updated = { ...(existing ?? createDefaultWorktreeMeta()), - ...normalizeGitHubPRSuppressionUpdate(normalizedUpdates), + ...normalizeGitHubPRSuppressionUpdate(normalizedUpdates, existing?.linkedPR), ...identity } updated.linkedWorkItem = normalizeWorkspaceLinkedItem(updated.linkedWorkItem) diff --git a/src/main/persistence/loading-store/write-scheduling.ts b/src/main/persistence/loading-store/write-scheduling.ts index a5bd9ccd810..e84f9d71485 100644 --- a/src/main/persistence/loading-store/write-scheduling.ts +++ b/src/main/persistence/loading-store/write-scheduling.ts @@ -9,9 +9,18 @@ import { } from './workspace-session-write-listeners' import { ptyBindingGenerationOf } from './pty-binding-generations' import type { PartitionEditorViews } from './layout-editor-views' +import type { ProfileSaveDomains } from '../profile-save-domains' +import type { WorktreeMeta } from '../../../shared/worktree/meta-types' /** Undefined means any domain may have changed. */ export type StateWriteListener = (dirtyDomains: readonly string[] | undefined) => void +/** One host's worktree metadata row before and after a write. */ +export type WorktreeMetaWriteListener = (write: { + worktreeId: string + hostId: ExecutionHostId + previous: WorktreeMeta | undefined + next: WorktreeMeta +}) => void const SAVE_DEBOUNCE_MS = 1_000 const SAVE_MAX_WAIT_MS = 5_000 @@ -20,6 +29,7 @@ type WriteSchedulingOperationsRuntime = Pick< StoreRuntimeState, | 'activeViewPreference' | 'automationListProjectionCache' + | 'pendingAutomationRunsAfter' | 'dirtyProfileStateDomains' | 'firstPendingSaveAt' | 'pendingWrite' @@ -31,6 +41,8 @@ type WriteSchedulingOperationsRuntime = Pick< | 'workspaceSessionWriteListeners' | 'workspaceSessionOperationListeners' | 'stateWriteListeners' + | 'worktreeMetaWriteListeners' + | 'workspaceMetadataCursor' | 'ptyBindingGenerations' | 'layoutEditorViews' | 'state' @@ -88,11 +100,47 @@ export class WriteSchedulingOperations { runtime.stateWriteListeners.delete(listener) } } + + /** The workspaceMetadata position a listing records when it reads metadata. */ + getWorkspaceMetadataCursor(): { epoch: string; seq: number } { + const { epoch, seq } = this[writeSchedulingOperationsContext].runtime.workspaceMetadataCursor + return { epoch, seq } + } + + /** Advances the position for one published record; call in the same turn as its metadata write. */ + advanceWorkspaceMetadataCursor(): { epoch: string; seq: number } { + const cursor = this[writeSchedulingOperationsContext].runtime.workspaceMetadataCursor + cursor.seq += 1 + return { epoch: cursor.epoch, seq: cursor.seq } + } + + /** Observe each host-qualified worktree metadata write; callbacks must not throw, block or write. */ + onWorktreeMetaWritten(listener: WorktreeMetaWriteListener): () => void { + const { runtime } = this[writeSchedulingOperationsContext] + runtime.worktreeMetaWriteListeners.add(listener) + return () => { + runtime.worktreeMetaWriteListeners.delete(listener) + } + } } +/** Saves the rows of the domains a mutation changed. */ export function scheduleSave( owner: WriteSchedulingOperations, - dirtyDomains?: readonly string[], + domains: ProfileSaveDomains, + writtenHostId?: ExecutionHostId +): void { + scheduleDomainSave(owner, domains, writtenHostId) +} + +/** Startup load, migration and maintenance resume only: their changes span the profile. */ +export function scheduleFullProfileSave(owner: WriteSchedulingOperations): void { + scheduleDomainSave(owner, undefined) +} + +function scheduleDomainSave( + owner: WriteSchedulingOperations, + dirtyDomains: readonly string[] | undefined, writtenHostId?: ExecutionHostId ): void { const { runtime, writes } = owner[writeSchedulingOperationsContext] @@ -101,6 +149,13 @@ export function scheduleSave( listener(dirtyDomains) } runtime.automationListProjectionCache = null + // A run list replaced outside the run-delta path saves as a whole row; an older pending delta is stale. + if ( + dirtyDomains?.includes('automationRuns') && + runtime.pendingAutomationRunsAfter !== runtime.state.automationRuns + ) { + runtime.pendingAutomationRunsAfter = undefined + } const trackedDomains = runtime.dirtyProfileStateDomains if (dirtyDomains === undefined) { runtime.dirtyProfileStateDomains = null diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-commit-automation-runs.test.ts b/src/main/persistence/migrating-orcad-catalog/orcad-catalog-commit-automation-runs.test.ts new file mode 100644 index 00000000000..bcb119f5f04 --- /dev/null +++ b/src/main/persistence/migrating-orcad-catalog/orcad-catalog-commit-automation-runs.test.ts @@ -0,0 +1,56 @@ +import { describe, it, expect, vi } from 'vitest' +import { + createWorkerMaintenanceFixture, + maintenanceBarrier +} from '../loading-store/profile-state-maintenance-fixture' +import { ProfileStateWriterError } from '../profile-state/profile-state-writer-errors' +import { hostWorktreeTarget } from '../../../shared/worktree/host-qualified-identity' +import { + DORMANT_AUTOMATION_RUN, + dormantState, + manifest +} from './persistence-orcad-migration-catalog-fixture' + +vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) +vi.mock('../../telemetry/cohort-classifier', () => ({ + getCohortAtEmit: () => ({ nth_repo_added: 1 }) +})) +vi.mock('../../ssh/config/ssh-config-parser', () => ({ + loadUserSshConfig: () => ({ hosts: [] }), + sshConfigHostsToTargets: () => [] +})) + +describe('catalog commit and automation run saves', () => { + it('keeps imported runs when an older run write fails while the import is saved', async () => { + const { store, authority, readState } = await createWorkerMaintenanceFixture() + vi.spyOn(console, 'error').mockImplementation(() => {}) + const base = manifest() + const input = manifest({ payload: { ...base.payload, dormantState: dormantState() } }) + store.stageOrcadMigrationCatalog(input) + await store.flushPendingOrThrowAsync() + + const started = maintenanceBarrier() + const finish = maintenanceBarrier() + vi.spyOn(authority, 'writeSerializedAutomationRuns').mockImplementationOnce(async () => { + started.resolve() + await finish.promise + throw new ProfileStateWriterError('disk-refused', 'disk refused', 'known-failure') + }) + // An unrelated run edit leaves its run list pending and starts a write that stays in flight. + expect( + store.snapshotAutomationRunWorkspaceDisplayName( + hostWorktreeTarget({ id: 'repo-local::/fixture/local', hostId: 'local' }), + 'Renamed workspace' + ) + ).toBeGreaterThan(0) + await started.promise + + store.commitStagedOrcadMigrationCatalog(input) + finish.resolve() + await store.flushPendingOrThrowAsync() + + expect(readState().automationRuns.map(({ id }: { id: string }) => id)).toContain( + DORMANT_AUTOMATION_RUN.id + ) + }) +}) diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-commit-domains.ts b/src/main/persistence/migrating-orcad-catalog/orcad-catalog-commit-domains.ts new file mode 100644 index 00000000000..2abbc3f8b71 --- /dev/null +++ b/src/main/persistence/migrating-orcad-catalog/orcad-catalog-commit-domains.ts @@ -0,0 +1,26 @@ +import { WORKTREE_METADATA_DOMAINS } from '../profile-save-domains' +import { WORKSPACE_SESSION_DOMAINS } from '../workspace-session-domains' + +/** An imported catalog adds repos, workspaces and their dormant state, and records its receipts. */ +export const ORCAD_CATALOG_COMMIT_DOMAINS = [ + 'projectGroups', + 'repos', + 'folderWorkspaces', + 'projects', + 'projectHostSetups', + ...WORKTREE_METADATA_DOMAINS, + 'worktreeLineageById', + 'workspaceLineageByChildKey', + 'sparsePresetsByRepo', + 'retiredWorktreeNamesByRepo', + 'retiredWorktreeNamesByNamespace', + // The import writes the local session only. + WORKSPACE_SESSION_DOMAINS[0], + 'automations', + 'automationRuns', + 'mobileClientTabSelectionsByDeviceId', + 'ui', + 'orcadMigrationStagedCatalogs', + 'orcadMigrationImportReceipts', + 'orcadMigrationEvictedReceipts' +] diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-import.ts b/src/main/persistence/migrating-orcad-catalog/orcad-catalog-import.ts index a011d604cea..941323ecbbd 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-import.ts +++ b/src/main/persistence/migrating-orcad-catalog/orcad-catalog-import.ts @@ -1,4 +1,5 @@ import { MAX_ORCAD_MIGRATION_STAGED_CATALOGS } from '../../../shared/orcad-migration/orcad-migration-staged-catalog-validation' +import { ORCAD_CATALOG_COMMIT_DOMAINS } from './orcad-catalog-commit-domains' import { ORCAD_MIGRATION_MANIFEST_VERSION } from '../../../shared/orcad-migration/orcad-migration-manifest-validation' import type { OrcadMigrationCatalogAbortResult, @@ -72,6 +73,7 @@ type OrcadCatalogImportContext = { } // Manifests arrive parsed; the RPC boundary verified the digest over the bytes as sent. + export class OrcadCatalogImportPersistence { readonly [orcadCatalogImportContext]: OrcadCatalogImportContext @@ -90,7 +92,7 @@ export class OrcadCatalogImportPersistence { const context = this[orcadCatalogImportContext] const now = options.now ?? (() => new Date()) if (expireOrcadMigrationStages(context.runtime.state, now().getTime())) { - scheduleSave(context.scheduling) + scheduleSave(context.scheduling, ['orcadMigrationStagedCatalogs']) } pruneOrcadMigrationSnapshotStaging( stagedManifests(context.runtime.state), @@ -122,7 +124,7 @@ export class OrcadCatalogImportPersistence { stagedAt } ] - scheduleSave(context.scheduling) + scheduleSave(context.scheduling, ['orcadMigrationStagedCatalogs']) return stagedCatalogState(manifest, stagedAt, context.runtime) } @@ -182,7 +184,7 @@ export class OrcadCatalogImportPersistence { commitOrcadMigrationBlobs(manifest, blobRoot) const receipt = commitPreparedCatalog(context, manifest, prepared, options.now) const generationBefore = context.runtime.writeGeneration - scheduleSave(context.scheduling) + scheduleSave(context.scheduling, ORCAD_CATALOG_COMMIT_DOMAINS) recordOrcadMigrationCommitWriteGeneration(context.runtime, manifest, generationBefore) return committedCatalogState(receipt) } @@ -201,7 +203,7 @@ export class OrcadCatalogImportPersistence { ).filter((entry) => entry.manifest.migrationId !== manifest.migrationId) abortOrcadMigrationSnapshots(manifest, context.runtime.terminalScrollbackSnapshotStorage) abortOrcadMigrationBlobs(manifest, context.runtime.orcadMigrationBlobRoot) - scheduleSave(context.scheduling) + scheduleSave(context.scheduling, ['orcadMigrationStagedCatalogs']) return { ...absentCatalogState(manifest), aborted: true } } diff --git a/src/main/persistence/persistence-async-write-syscalls.test.ts b/src/main/persistence/persistence-async-write-syscalls.test.ts index 499df38a519..8cbb7a85024 100644 --- a/src/main/persistence/persistence-async-write-syscalls.test.ts +++ b/src/main/persistence/persistence-async-write-syscalls.test.ts @@ -141,9 +141,8 @@ describe('worker persistence avoids synchronous profile filesystem calls', () => it('retains dirty state when a SQL commit fails and persists an explicit retry', async () => { const { store, authority, readState } = await createWorkerMaintenanceFixture() vi.spyOn(console, 'error').mockImplementation(() => {}) - vi.spyOn(authority, 'writeCompleteSerializedDomains').mockRejectedValueOnce( - new Error('disk refused') - ) + // A UI change saves only the ui domain. + vi.spyOn(authority, 'writeSerializedDomains').mockRejectedValueOnce(new Error('disk refused')) const original = readState().ui.sidebarWidth store.updateUI({ sidebarWidth: 511 }) await store.flushPendingAsync() diff --git a/src/main/persistence/persistence-loading-store-write-risks.test.ts b/src/main/persistence/persistence-loading-store-write-risks.test.ts index 109aa999a65..384738ce360 100644 --- a/src/main/persistence/persistence-loading-store-write-risks.test.ts +++ b/src/main/persistence/persistence-loading-store-write-risks.test.ts @@ -18,14 +18,13 @@ describe('loading Store write-risk characterization', () => { const { store, authority, readState } = await createWorkerMaintenanceFixture() const committed = maintenanceBarrier() const acknowledge = maintenanceBarrier() - const writeDomains = authority.writeCompleteSerializedDomains.bind(authority) - vi.spyOn(authority, 'writeCompleteSerializedDomains').mockImplementationOnce( - async (replacements) => { - await writeDomains(replacements) - committed.resolve() - await acknowledge.promise - } - ) + // A UI change saves only the ui domain. + const writeDomains = authority.writeSerializedDomains.bind(authority) + vi.spyOn(authority, 'writeSerializedDomains').mockImplementationOnce(async (replacements) => { + await writeDomains(replacements) + committed.resolve() + await acknowledge.promise + }) const close = vi.spyOn(authority, 'close') store.updateUI({ sidebarWidth: 712 }) diff --git a/src/main/persistence/profile-save-domains.ts b/src/main/persistence/profile-save-domains.ts new file mode 100644 index 00000000000..2d758338742 --- /dev/null +++ b/src/main/persistence/profile-save-domains.ts @@ -0,0 +1,92 @@ +import { WORKSPACE_SESSION_DOMAINS } from './workspace-session-domains' + +/** The profile domains a mutation changed; its save writes only their rows. */ +export type ProfileSaveDomains = readonly string[] + +export const WORKTREE_METADATA_DOMAINS = [ + 'worktreeMeta', + 'worktreeMetaByIdentity', + 'worktreeIdentityAliases' +] as const + +export const WORKSPACE_LINEAGE_DOMAINS = [ + 'worktreeLineageById', + 'workspaceLineageByChildKey', + 'crossStoreLineageByChildKey' +] as const + +/** Records that carry sort stamps and unread flags: worktree metadata and folder workspaces. */ +export const WORKSPACE_RECORD_DOMAINS: readonly string[] = [ + ...WORKTREE_METADATA_DOMAINS, + 'folderWorkspaces' +] + +/** Repo, project, folder, lineage and SSH catalog domains; listeners read these as a catalog change. */ +export const WORKSPACE_CATALOG_SAVE_DOMAINS: readonly string[] = [ + 'repos', + 'projects', + 'projectHostSetups', + 'projectGroups', + 'folderWorkspaces', + 'folderWorkspaceDiffComments', + ...WORKSPACE_LINEAGE_DOMAINS, + 'sparsePresetsByRepo', + 'retiredWorktreeNamesByRepo', + 'retiredWorktreeNamesByNamespace', + 'sshTargets', + 'sshTargetGenerationCounter', + 'deletedSshConfigAliases', + 'removedSshTargetTombstones', + 'sshPtyConsumerRecoveries', + 'orcadMigrationStagedCatalogs' +] + +/** Undefined means a whole save, which may have changed any catalog domain. */ +export function savedWorkspaceCatalog(dirtyDomains: readonly string[] | undefined): boolean { + return ( + dirtyDomains === undefined || + dirtyDomains.some((domain) => WORKSPACE_CATALOG_SAVE_DOMAINS.includes(domain)) + ) +} + +/** Repo writes also re-derive the project catalog compatibility rows. */ +export const REPO_CATALOG_DOMAINS: readonly string[] = ['repos', 'projects', 'projectHostSetups'] + +/** Removing a project prunes its workspaces' metadata, lineage, sessions and phone selections. */ +export const REMOVE_PROJECT_DOMAINS: readonly string[] = [ + ...REPO_CATALOG_DOMAINS, + 'sparsePresetsByRepo', + 'retiredWorktreeNamesByRepo', + ...WORKTREE_METADATA_DOMAINS, + ...WORKSPACE_LINEAGE_DOMAINS, + ...WORKSPACE_SESSION_DOMAINS, + 'mobileClientTabSelectionsByDeviceId' +] + +/** Removing a folder workspace drops its sessions, lineage and phone selections. */ +export const FOLDER_WORKSPACE_REMOVAL_DOMAINS: readonly string[] = [ + 'folderWorkspaces', + 'workspaceLineageByChildKey', + 'crossStoreLineageByChildKey', + ...WORKSPACE_SESSION_DOMAINS, + 'mobileClientTabSelectionsByDeviceId' +] + +/** Pruning missing worktrees drops their metadata and lineage. */ +export const WORKTREE_METADATA_PRUNE_DOMAINS: readonly string[] = [ + ...WORKTREE_METADATA_DOMAINS, + ...WORKSPACE_LINEAGE_DOMAINS +] + +/** Removing worktree metadata also drops its lineage and saved session tabs. */ +export const WORKTREE_METADATA_REMOVAL_DOMAINS: readonly string[] = [ + ...WORKTREE_METADATA_PRUNE_DOMAINS, + ...WORKSPACE_SESSION_DOMAINS +] + +/** A worktree locator move rewrites its metadata, lineage, sessions, phone selections and UI keys. */ +export const WORKTREE_IDENTITY_MIGRATION_DOMAINS: readonly string[] = [ + ...WORKTREE_METADATA_REMOVAL_DOMAINS, + 'mobileClientTabSelectionsByDeviceId', + 'ui' +] diff --git a/src/main/persistence/profile-state/profile-state-domain-writes.test.ts b/src/main/persistence/profile-state/profile-state-domain-writes.test.ts index f1fae0aa8ce..49040ffecb9 100644 --- a/src/main/persistence/profile-state/profile-state-domain-writes.test.ts +++ b/src/main/persistence/profile-state/profile-state-domain-writes.test.ts @@ -71,6 +71,32 @@ describe('profile state dirty-domain writes', () => { } }) + it('saves a run list per-run rows cannot hold as one replacement row', () => { + const db = openTestDatabase() + try { + const fixtureRun = buildProfileStateCutoverFixture().automationRuns[0] + if (!fixtureRun) { + throw new Error('Expected automation run fixture') + } + importProfileStateJson(db, JSON.stringify({ automationRuns: [fixtureRun] }), { + now: () => 100 + }) + // Legacy histories can keep duplicate run ids, which the per-run rows refuse. + const duplicated = [fixtureRun, { ...fixtureRun, title: 'Duplicate id' }] + + expect( + writeProfileStateDomains(db, { + expectedRevision: 1, + replacements: [], + automationRunsAfter: duplicated + }) + ).toMatchObject({ changed: true, revision: 2 }) + expect(JSON.parse(exportProfileStateJson(db)).automationRuns).toEqual(duplicated) + } finally { + db.close() + } + }) + it('rolls back every domain when a later mutation fails', () => { const db = openTestDatabase() try { diff --git a/src/main/persistence/profile-state/profile-state-domain-writes.ts b/src/main/persistence/profile-state/profile-state-domain-writes.ts index 44314d9ab3b..2d69dd70ce3 100644 --- a/src/main/persistence/profile-state/profile-state-domain-writes.ts +++ b/src/main/persistence/profile-state/profile-state-domain-writes.ts @@ -97,7 +97,7 @@ export function writeProfileStateDomains( const updates: PreparedProfileStateMutation[] = [] const splitStates = new Map>() - for (const mutation of prepared) { + const admit = (mutation: PreparedProfileStateMutation): void => { const splitState = readSplitDomainWriteState(db, mutation.domain) splitStates.set(mutation.domain, splitState) if (splitState.kind === 'parts') { @@ -106,7 +106,7 @@ export function writeProfileStateDomains( if (mutation.payload === null || mutation.payloadHash !== splitState.contentHash) { updates.push(mutation) } - continue + return } const existing = db .prepare( @@ -131,7 +131,7 @@ export function writeProfileStateDomains( mutation.payload?.startsWith('[') && currentAutomationRuns.contentHash === mutation.payloadHash ) { - continue + return } const normalized = prepareProfileStateAutomationRunsReplacement( db, @@ -142,7 +142,7 @@ export function writeProfileStateDomains( if (normalized.changed) { updates.push({ ...mutation, automationRuns: normalized }) } - continue + return } } const unchanged = @@ -152,6 +152,9 @@ export function writeProfileStateDomains( updates.push(mutation) } } + for (const mutation of prepared) { + admit(mutation) + } if (transaction.automationRunsAfter !== undefined) { const delta = prepareProfileStateAutomationRunsDelta( db, @@ -161,9 +164,15 @@ export function writeProfileStateDomains( actualRevision ) if (delta === undefined) { - throw new Error('Normalized automationRuns delta is unsupported') - } - if (delta.changed) { + // Histories per-run rows can't hold (e.g. duplicate run ids) save as one replacement row. + admit( + prepareProfileStateDomainMutation({ + domain: 'automationRuns', + payload: JSON.stringify(transaction.automationRunsAfter), + domainVersion: PROFILE_STATE_DOCUMENT_VERSION + }) + ) + } else if (delta.changed) { updates.push({ domain: 'automationRuns', payload: null, diff --git a/src/main/persistence/profile-state/profile-state-offline-settings.test.ts b/src/main/persistence/profile-state/profile-state-offline-settings.test.ts new file mode 100644 index 00000000000..5055445bc59 --- /dev/null +++ b/src/main/persistence/profile-state/profile-state-offline-settings.test.ts @@ -0,0 +1,38 @@ +import { mkdtempSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { expect, it } from 'vitest' +import { openProfileStateDatabase } from './profile-state-database' +import { importProfileStateJson, readProfileStateSnapshot } from './profile-state-documents' +import { updateAgentHookSettingsFromProfileState } from './profile-state-offline-settings' + +it('changes agent hooks offline without granting publishing permission to an older profile', () => { + const root = mkdtempSync(join(tmpdir(), 'orca-offline-sharing-')) + const location = { + profileId: 'older-profile', + dataFile: join(root, 'orca-data.json'), + databaseFile: join(root, 'profile-state.db') + } + try { + const opened = openProfileStateDatabase(location.databaseFile, location.profileId) + try { + importProfileStateJson(opened.db, '{"settings":{"agentStatusHooksEnabled":true}}') + } finally { + opened.db.close() + } + + updateAgentHookSettingsFromProfileState(location, false) + updateAgentHookSettingsFromProfileState(location, true) + + const reopened = openProfileStateDatabase(location.databaseFile, location.profileId) + try { + const { settings } = JSON.parse(readProfileStateSnapshot(reopened.db).json) + expect(settings.agentStatusHooksEnabled).toBe(true) + expect(settings).not.toHaveProperty('artifactSharingEnabled') + } finally { + reopened.db.close() + } + } finally { + rmSync(root, { recursive: true, force: true }) + } +}) diff --git a/src/main/persistence/profile-state/profile-state-offline-settings.ts b/src/main/persistence/profile-state/profile-state-offline-settings.ts index 186d3724f9c..ef06fb01542 100644 --- a/src/main/persistence/profile-state/profile-state-offline-settings.ts +++ b/src/main/persistence/profile-state/profile-state-offline-settings.ts @@ -79,6 +79,7 @@ export function updateAgentHookSettingsInProfileState( uiLanguagePortugueseMigrationApplied: _migrationApplied, nestedWorkerMaxDepthDefaultedToFour: _depthMigrated, agentLaunchChoices: _launchChoices, + artifactSharingEnabled: _artifactSharingEnabled, ...settingsDefaults } = getDefaultPersistedState(homedir()).settings const settings = { diff --git a/src/main/persistence/restoring-sessions/folder-workspace-operations.ts b/src/main/persistence/restoring-sessions/folder-workspace-operations.ts index 72f7bad70eb..1b656595777 100644 --- a/src/main/persistence/restoring-sessions/folder-workspace-operations.ts +++ b/src/main/persistence/restoring-sessions/folder-workspace-operations.ts @@ -1,3 +1,4 @@ +import { FOLDER_WORKSPACE_REMOVAL_DOMAINS, type ProfileSaveDomains } from '../profile-save-domains' import { randomUUID } from 'node:crypto' import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' import type { PersistedState } from '../../../shared/persisted-state-types' @@ -19,7 +20,7 @@ import { ORCA_SIDEBAR_INPUTS_IS_MAIN } from '../../../shared/sidebar-inputs-swit export type FolderWorkspaceMutationOperations = { state: PersistedState - scheduleSave: () => void + scheduleSave: (domains: ProfileSaveDomains) => void removeWorkspaceLineageForRemovedFolder: (folderWorkspaceId: string) => void pruneMobileClientTabSelections: (matchesWorktreeId: (worktreeId: string) => boolean) => void hydrateRepo: (repo: Repo) => Repo @@ -32,8 +33,8 @@ export class FolderWorkspacePersistenceOperations { return this.operations.state } - private scheduleSave(): void { - this.operations.scheduleSave() + private scheduleSave(domains: ProfileSaveDomains): void { + this.operations.scheduleSave(domains) } private removeWorkspaceLineageForRemovedFolder(folderWorkspaceId: string): void { @@ -121,7 +122,7 @@ export class FolderWorkspacePersistenceOperations { updatedAt: now } this.state.folderWorkspaces = [workspace, ...(this.state.folderWorkspaces ?? [])] - this.scheduleSave() + this.scheduleSave(['folderWorkspaces']) return workspace } @@ -266,7 +267,7 @@ export class FolderWorkspacePersistenceOperations { workspace.externalConversations = updates.externalConversations } workspace.updatedAt = Date.now() - this.scheduleSave() + this.scheduleSave(['folderWorkspaces']) return workspace } @@ -281,7 +282,7 @@ export class FolderWorkspacePersistenceOperations { removeWorkspaceSessionOwnerEverywhere(this.state, folderWorkspaceKey(id)) this.removeWorkspaceLineageForRemovedFolder(id) this.pruneMobileClientTabSelections((worktreeId) => worktreeId === folderWorkspaceKey(id)) - this.scheduleSave() + this.scheduleSave(FOLDER_WORKSPACE_REMOVAL_DOMAINS) return true } @@ -304,7 +305,7 @@ export class FolderWorkspacePersistenceOperations { typeof order === 'number' && Number.isFinite(order) ? order : getNextProjectGroupOrder(siblingRepos, normalizedGroupId) - this.scheduleSave() + this.scheduleSave(['repos']) return this.hydrateRepo(repo) } } diff --git a/src/main/persistence/tracking-repos/persistence-folder-workspace-notes.test.ts b/src/main/persistence/tracking-repos/persistence-folder-workspace-notes.test.ts index f2f51cf1191..bedd559e19f 100644 --- a/src/main/persistence/tracking-repos/persistence-folder-workspace-notes.test.ts +++ b/src/main/persistence/tracking-repos/persistence-folder-workspace-notes.test.ts @@ -297,4 +297,19 @@ describe('Store', () => { 'fw-1': [editedNote] }) }) + it('drops the saved note map when the last note is cleared', async () => { + writeFolderWorkspaceProfile({ + workspaces: [folderWorkspaceRecord()], + diffCommentsMap: { 'fw-1': [makeFolderNote('note-1', 'Old note')] } + }) + + const store = await createStore() + // Drain the load's whole save so the edit below saves only what it names. + store.flush() + store.updateFolderWorkspace('fw-1', { diffComments: [] }) + store.flush() + + expect((readDataFile() as PersistedState).folderWorkspaceDiffComments).toBeUndefined() + expect((await createStore()).getFolderWorkspace('fw-1')?.diffComments ?? []).toEqual([]) + }) }) diff --git a/src/main/persistence/tracking-repos/persistence-repo-lifecycle.test.ts b/src/main/persistence/tracking-repos/persistence-repo-lifecycle.test.ts index 82490eacc6e..d0b4fd71541 100644 --- a/src/main/persistence/tracking-repos/persistence-repo-lifecycle.test.ts +++ b/src/main/persistence/tracking-repos/persistence-repo-lifecycle.test.ts @@ -101,6 +101,28 @@ describe('Store', () => { ]) }) + it('removing a project saves the repo, metadata and session removal with only those domains dirty', async () => { + const store = await createStore() + store.addRepo(makeRepo({ id: 'r1', path: '/repo' })) + store.setWorktreeMeta(at('r1::/repo/wt', 'local'), { displayName: 'wt' }) + store.setWorkspaceSession({ + ...getDefaultWorkspaceSession(), + lastVisitedAtByWorktreeId: { 'r1::/repo/wt': 111 } + }) + // Drain earlier saves so the removal's own save is the one under test. + store.flush() + + store.removeProjectForHost({ id: 'r1', executionHostId: 'local' }) + store.flush() + + const reloaded = await createStore() + expect(reloaded.getRepos()).toEqual([]) + expect(reloaded.getWorktreeMeta('r1::/repo/wt')).toBeUndefined() + expect( + reloaded.getWorkspaceSession().lastVisitedAtByWorktreeId?.['r1::/repo/wt'] + ).toBeUndefined() + }) + it('removeProjectForHost on the local host keeps a surviving SSH host session', async () => { const store = await createStore() store.addRepo(makeRepo({ id: 'shared', path: '/repo' })) diff --git a/src/main/persistence/tracking-repos/project-group-operations.ts b/src/main/persistence/tracking-repos/project-group-operations.ts index cd7d55bf99c..4ee2fc9aa87 100644 --- a/src/main/persistence/tracking-repos/project-group-operations.ts +++ b/src/main/persistence/tracking-repos/project-group-operations.ts @@ -1,3 +1,5 @@ +import type { ProfileSaveDomains } from '../profile-save-domains' +import { WORKSPACE_SESSION_DOMAINS } from '../workspace-session-domains' import type { PersistedState } from '../../../shared/persisted-state-types' import type { ProjectGroup, @@ -15,7 +17,7 @@ import { removeWorkspaceSessionOwnersEverywhere } from '../restoring-sessions/se export type ProjectGroupMutationOperations = { state: PersistedState - scheduleSave: () => void + scheduleSave: (domains: ProfileSaveDomains) => void removeWorkspaceLineageForRemovedFolder: (folderWorkspaceId: string) => void pruneMobileClientTabSelections: (matchesWorktreeId: (worktreeId: string) => boolean) => void } @@ -27,8 +29,8 @@ export class ProjectGroupPersistenceOperations { return this.operations.state } - private scheduleSave(): void { - this.operations.scheduleSave() + private scheduleSave(domains: ProfileSaveDomains): void { + this.operations.scheduleSave(domains) } private removeWorkspaceLineageForRemovedFolder(folderWorkspaceId: string): void { @@ -68,7 +70,7 @@ export class ProjectGroupPersistenceOperations { group.rootProjectOrder = rootProjectOrder } this.state.projectGroups = [...(this.state.projectGroups ?? []), group] - this.scheduleSave() + this.scheduleSave(['projectGroups']) return group } @@ -78,7 +80,7 @@ export class ProjectGroupPersistenceOperations { return null } this.applyGroupUpdate(group, updates) - this.scheduleSave() + this.scheduleSave(['projectGroups']) return group } @@ -93,7 +95,7 @@ export class ProjectGroupPersistenceOperations { return group }) if (updated.length > 0) { - this.scheduleSave() + this.scheduleSave(['projectGroups']) } return updated } @@ -150,7 +152,15 @@ export class ProjectGroupPersistenceOperations { (workspace) => !deletedGroupIds.has(workspace.projectGroupId) ) this.pruneMobileClientTabSelections((worktreeId) => removedFolderWorkspaceKeys.has(worktreeId)) - this.scheduleSave() + this.scheduleSave([ + 'projectGroups', + 'repos', + 'folderWorkspaces', + 'workspaceLineageByChildKey', + 'crossStoreLineageByChildKey', + ...WORKSPACE_SESSION_DOMAINS, + 'mobileClientTabSelectionsByDeviceId' + ]) return true } } diff --git a/src/main/persistence/tracking-repos/project-host-operations.ts b/src/main/persistence/tracking-repos/project-host-operations.ts index 89b18608c9c..b0577b7867f 100644 --- a/src/main/persistence/tracking-repos/project-host-operations.ts +++ b/src/main/persistence/tracking-repos/project-host-operations.ts @@ -1,3 +1,4 @@ +import type { ProfileSaveDomains } from '../profile-save-domains' import type { Project, ProjectHostSetup, @@ -33,7 +34,7 @@ export type ProjectHostMutationOperations = { updates: ProjectHostSetupUpdateArgs['updates'] ) => ProjectHostSetup removeProjectForHost: (target: RepoHostTarget) => void - scheduleSave: () => void + scheduleSave: (domains: ProfileSaveDomains) => void } export class ProjectHostPersistenceOperations { @@ -70,8 +71,8 @@ export class ProjectHostPersistenceOperations { this.operations.removeProjectForHost(target) } - private scheduleSave(): void { - this.operations.scheduleSave() + private scheduleSave(domains: ProfileSaveDomains): void { + this.operations.scheduleSave(domains) } getRepos(): Repo[] { @@ -100,7 +101,7 @@ export class ProjectHostPersistenceOperations { } } project.updatedAt = Date.now() - this.scheduleSave() + this.scheduleSave(['projects']) return { ...project } } @@ -142,7 +143,7 @@ export class ProjectHostPersistenceOperations { } // Independent setup persistence survives future repo projection sync. this.state.projectHostSetups.push(setup) - this.scheduleSave() + this.scheduleSave(['projectHostSetups']) return { project, setup } } @@ -197,7 +198,7 @@ export class ProjectHostPersistenceOperations { return { project, setup, repo: this.hydrateRepo(repo) } } this.state.projectHostSetups = this.state.projectHostSetups.filter((entry) => entry !== setup) - this.scheduleSave() + this.scheduleSave(['projectHostSetups']) return { project, setup } } @@ -234,7 +235,7 @@ export class ProjectHostPersistenceOperations { } else { delete repo.gitUsername } - this.scheduleSave() + this.scheduleSave(['repos']) return true } } diff --git a/src/main/plugins/plugin-runtime-binding.test.ts b/src/main/plugins/plugin-runtime-binding.test.ts index 8c26efb5829..9bf34c08122 100644 --- a/src/main/plugins/plugin-runtime-binding.test.ts +++ b/src/main/plugins/plugin-runtime-binding.test.ts @@ -268,6 +268,7 @@ describe('workspace.changed', () => { written = listener return () => undefined }, + onStateWritten: () => () => undefined, delayMs: 10 }) written() @@ -301,4 +302,35 @@ describe('workspace.changed', () => { vi.useRealTimers() } }) + + it('re-reads the context after a catalog save such as a folder rename, not a UI save', async () => { + vi.useFakeTimers() + try { + const delegate = pluginRuntimeDelegate( + runtime([{ handle: 'term_a', title: 'zsh' }]), + () => [] + ) + const events = { wantsEvent: vi.fn(() => true), emitEvent: vi.fn() } + let saved: (domains: readonly string[] | undefined) => void = () => undefined + const stop = watchPluginWorkspaceContext({ + delegate, + events, + onSessionWritten: () => () => undefined, + onStateWritten: (listener) => { + saved = listener + return () => undefined + }, + delayMs: 10 + }) + saved(['ui']) + await vi.advanceTimersByTimeAsync(20) + expect(events.emitEvent).not.toHaveBeenCalled() + saved(['folderWorkspaces']) + await vi.advanceTimersByTimeAsync(20) + expect(events.emitEvent).toHaveBeenCalledWith('workspace.changed', expect.anything()) + stop() + } finally { + vi.useRealTimers() + } + }) }) diff --git a/src/main/plugins/plugin-runtime-binding.ts b/src/main/plugins/plugin-runtime-binding.ts index 279a2872e15..9b31e8e38bb 100644 --- a/src/main/plugins/plugin-runtime-binding.ts +++ b/src/main/plugins/plugin-runtime-binding.ts @@ -1,4 +1,5 @@ import type { PluginEventName } from '../../shared/plugins/manifest/plugin-manifest' +import { savedWorkspaceCatalog } from '../persistence/profile-save-domains' import type { PluginAgentStatusChangedPayload } from '../../shared/plugins/events/plugin-events' import { PLUGIN_WORKSPACE_TERMINAL_LIMIT } from '../../shared/plugins/workers/plugin-host-api' import type { PluginRuntimeDelegate } from './workers/plugin-host-service-bindings' @@ -166,6 +167,7 @@ export function watchPluginWorkspaceContext(input: { delegate: PluginRuntimeDelegate events: PluginEvents onSessionWritten: (listener: () => void) => () => void + onStateWritten: (listener: (domains: readonly string[] | undefined) => void) => () => void delayMs?: number }): () => void { let timer: ReturnType | null = null @@ -183,11 +185,19 @@ export function watchPluginWorkspaceContext(input: { input.events.emitEvent('workspace.changed', change) } } - const stop = input.onSessionWritten(() => { + const schedule = (): void => { timer ??= setTimeout(() => void check(), input.delayMs ?? WORKSPACE_CHANGE_DEBOUNCE_MS) + } + const stopSession = input.onSessionWritten(schedule) + // A folder workspace rename reaches the context through the catalog, not the session. + const stopCatalog = input.onStateWritten((domains) => { + if (savedWorkspaceCatalog(domains)) { + schedule() + } }) return () => { - stop() + stopSession() + stopCatalog() if (timer) { clearTimeout(timer) } diff --git a/src/main/power/awake-clock.test.ts b/src/main/power/awake-clock.test.ts new file mode 100644 index 00000000000..a219521c127 --- /dev/null +++ b/src/main/power/awake-clock.test.ts @@ -0,0 +1,109 @@ +import { describe, expect, it } from 'vitest' +import { AWAKE_CLOCK_HEARTBEAT_MS, createAwakeClock } from './awake-clock' + +type CounterModel = 'counts sleep (macOS/Windows Node)' | 'stops in sleep (Linux)' + +/** Wall and monotonic clocks the test moves. Awake time fires the heartbeat (an overdue beat fires + * on wake); sleep fires nothing, and advances the monotonic counter only where that runtime's + * counter counts sleep. */ +function testClocks(model: CounterModel) { + const time = { wall: 1_794_244_112_215, monotonic: 0 } + let pending: (() => void) | null = null + let beatOverdue = false + const beat = (): void => { + const due = pending + pending = null + due?.() + } + return { + time, + sources: { + wallNow: () => time.wall, + monotonicNow: () => time.monotonic, + after: (onBeat: () => void) => { + pending = onBeat + } + }, + awake(ms: number) { + if (beatOverdue) { + beatOverdue = false + beat() + } + for (let left = ms; left > 0; left -= AWAKE_CLOCK_HEARTBEAT_MS) { + const step = Math.min(left, AWAKE_CLOCK_HEARTBEAT_MS) + time.wall += step + time.monotonic += step + if (step === AWAKE_CLOCK_HEARTBEAT_MS) { + beat() + } + } + }, + asleep(ms: number) { + beatOverdue = true + time.wall += ms + if (model === 'counts sleep (macOS/Windows Node)') { + time.monotonic += ms + } + } + } +} + +const MODELS: CounterModel[] = ['counts sleep (macOS/Windows Node)', 'stops in sleep (Linux)'] +const SETTLE = 120_000 + +describe.each(MODELS)('awake clock on a monotonic counter that %s', (model) => { + it('does not count the time between suspend and resume', () => { + const clocks = testClocks(model) + const clock = createAwakeClock(clocks.sources) + const start = clock.now() + clocks.awake(2_000) + clock.suspend() + clocks.asleep(665_000) + // A timer that fires on wake before the resume event is delivered still reads the frozen clock. + expect(clock.now() - start).toBe(2_000) + clock.resume() + clocks.awake(3_000) + expect(clock.now() - start).toBe(5_000) + }) + + it('does not count a sleep that no power event reported', () => { + const clocks = testClocks(model) + const clock = createAwakeClock(clocks.sources) + const start = clock.now() + clocks.awake(AWAKE_CLOCK_HEARTBEAT_MS) + clocks.asleep(600_000) + clocks.awake(2_000) + expect(clock.now() - start).toBe(AWAKE_CLOCK_HEARTBEAT_MS + 2_000) + }) + + it('resumes by itself once the process has run for minutes after a lost resume event', () => { + const clocks = testClocks(model) + const clock = createAwakeClock(clocks.sources) + clock.suspend() + clocks.asleep(600_000) + const frozen = clock.now() + clocks.awake(100_000) + expect(clock.now()).toBe(frozen) + expect(clock.settled(SETTLE)).toBe(false) + clocks.awake(20_000) + // The two minutes it ran count as awake; the sleep before them does not. + expect(clock.now()).toBe(frozen + 120_000) + expect(clock.settled(SETTLE)).toBe(true) + }) +}) + +describe.each(MODELS)('awake clock settling on a monotonic counter that %s', (model) => { + it('settles on schedule when the wall clock is corrected backward after a resume', () => { + const clocks = testClocks(model) + const clock = createAwakeClock(clocks.sources) + clock.suspend() + clocks.asleep(600_000) + clock.resume() + clocks.awake(30_000) + clocks.time.wall -= 60 * 60_000 + clocks.awake(80_000) + expect(clock.settled(SETTLE)).toBe(false) + clocks.awake(10_000) + expect(clock.settled(SETTLE)).toBe(true) + }) +}) diff --git a/src/main/power/awake-clock.ts b/src/main/power/awake-clock.ts new file mode 100644 index 00000000000..e14d54ddc79 --- /dev/null +++ b/src/main/power/awake-clock.ts @@ -0,0 +1,164 @@ +import { subscribeSystemPowerLifecycle } from './system-power-lifecycle' + +/** How often the clock samples itself while in use, so a stretch with no samples means the + * process was not running (system sleep, or an App Nap-sized stall). */ +export const AWAKE_CLOCK_HEARTBEAT_MS = 20_000 + +/** A sample gap this long means the process did not run in between. Sleeps shorter than this go + * unnoticed without a power event. */ +export const AWAKE_CLOCK_SLEEP_GAP_MS = 3 * AWAKE_CLOCK_HEARTBEAT_MS + +/** The heartbeat stops after this long without a read. It outlasts the agent startup ceiling, and + * the automation scheduler reads every tick only while an automation is enabled. */ +export const AWAKE_CLOCK_IDLE_MS = 15 * 60_000 + +/** Uninterrupted running while still marked suspended after which a resume event was evidently + * lost. Dark wakes run for seconds, so this never ends a real suspension early. */ +const LOST_RESUME_MS = 2 * 60_000 + +export type AwakeClockSources = { + wallNow: () => number + /** Never runs backward or follows wall corrections. It may count sleep (macOS and Windows + * Node clocks do) or not (Linux CLOCK_MONOTONIC); the clock is correct either way. */ + monotonicNow: () => number + /** Runs `beat` once after `ms`. Timers do not fire while the machine sleeps. */ + after: (beat: () => void, ms: number) => void +} + +export type AwakeClock = { + /** Milliseconds of awake time, anchored to the wall clock at creation: it stands still while + * suspended or in a stretch the process did not run, and ignores wall-clock corrections. */ + now(): number + /** Not suspended, and awake for at least `settleMs` since the last wake. */ + settled(settleMs: number): boolean + suspend(): void + resume(): void +} + +const SYSTEM_SOURCES: AwakeClockSources = { + // Read through the globals each time so test fake timers apply. + wallNow: () => Date.now(), + monotonicNow: () => globalThis.performance.now(), + after: (beat, ms) => { + setTimeout(beat, ms).unref() + } +} + +/** Why: a wall-clock deadline expires the moment a laptop wakes from a sleep that outlasted it, + * so anything that times out an active process must not count the time the machine slept. + * Limit: reads more than AWAKE_CLOCK_IDLE_MS apart, with no power event, cannot tell a sleep + * between them from idle time on a counter that counts sleep. */ +export function createAwakeClock(sources: AwakeClockSources = SYSTEM_SOURCES): AwakeClock { + const { wallNow, monotonicNow } = sources + const createdAt = { wall: wallNow(), monotonic: monotonicNow() } + /** Monotonic time excluded from awake time. */ + let slept = 0 + let suspendedAt: number | null = null + /** Monotonic start of the current stretch the process has run without a gap. */ + let runningSince = createdAt.monotonic + /** Awake reading at the last wake; null until the machine is seen to wake. */ + let lastWakeAt: number | null = null + let sample = { ...createdAt } + let lastReadAt = createdAt.monotonic + let beating = false + + const awake = (monotonic: number): number => + monotonic - createdAt.monotonic - slept - (suspendedAt === null ? 0 : monotonic - suspendedAt) + + const endSuspension = (resumedAt: number): void => { + if (suspendedAt === null) { + return + } + slept += Math.max(0, resumedAt - suspendedAt) + suspendedAt = null + lastWakeAt = awake(resumedAt) + } + + /** Reads both clocks and records any stretch the process did not run as a wake. */ + const observe = (afterIdle: boolean): number => { + const wall = wallNow() + const monotonic = monotonicNow() + const sinceMonotonic = monotonic - sample.monotonic + // A counter that counts sleep shows the gap itself; one that excludes it shows only on the + // wall. After an unsampled idle stretch, only the wall gap is evidence of sleep. + const counterGap = + !afterIdle && (sinceMonotonic < 0 || sinceMonotonic > AWAKE_CLOCK_SLEEP_GAP_MS) + const wallGap = wall - sample.wall - sinceMonotonic > AWAKE_CLOCK_SLEEP_GAP_MS + sample = { wall, monotonic } + if (counterGap || wallGap) { + runningSince = monotonic + if (suspendedAt === null) { + // A suspension's span is excluded on resume; outside one, exclude the gap now. + slept += counterGap ? sinceMonotonic : 0 + lastWakeAt = awake(monotonic) + } + } + if (suspendedAt !== null && monotonic - runningSince >= LOST_RESUME_MS) { + endSuspension(Math.max(suspendedAt, runningSince)) + } + return monotonic + } + + const beat = (): void => { + const monotonic = observe(false) + beating = monotonic - lastReadAt < AWAKE_CLOCK_IDLE_MS + if (beating) { + sources.after(beat, AWAKE_CLOCK_HEARTBEAT_MS) + } + } + + const read = (): number => { + const monotonic = observe(!beating) + lastReadAt = monotonic + if (!beating) { + beating = true + sources.after(beat, AWAKE_CLOCK_HEARTBEAT_MS) + } + return monotonic + } + + return { + now: () => createdAt.wall + awake(read()), + settled(settleMs) { + const monotonic = read() + return ( + suspendedAt === null && (lastWakeAt === null || awake(monotonic) - lastWakeAt >= settleMs) + ) + }, + suspend() { + // Dark wake can re-suspend without a resume; keep the earliest stamp. + const monotonic = read() + if (suspendedAt === null) { + suspendedAt = monotonic + runningSince = monotonic + } + }, + resume() { + const monotonic = read() + runningSince = monotonic + endSuspension(monotonic) + } + } +} + +let systemAwakeClock: AwakeClock | null = null + +/** The process-wide awake clock, driven by the system's suspend and resume events where a + * publisher exists (desktop) and by its own sampling everywhere (including orcad). */ +export function getSystemAwakeClock(): AwakeClock { + if (!systemAwakeClock) { + const clock = createAwakeClock() + systemAwakeClock = clock + // Lives for the process; subscribing replays the current state, which is harmless here. + subscribeSystemPowerLifecycle({ + onSuspend: () => clock.suspend(), + onResume: () => clock.resume() + }) + } + return systemAwakeClock +} + +/** The awake clock's reading; a drop-in for `Date.now` in startup deadlines. */ +export function awakeNow(): number { + return getSystemAwakeClock().now() +} diff --git a/src/main/pty/process-retirement/pty-master-foreground-observation.ts b/src/main/pty/process-retirement/pty-master-foreground-observation.ts index 70eeb61b08a..f2114a14a1b 100644 --- a/src/main/pty/process-retirement/pty-master-foreground-observation.ts +++ b/src/main/pty/process-retirement/pty-master-foreground-observation.ts @@ -137,7 +137,7 @@ export async function observePtyForeground( ) { return unknown('terminal_unavailable') } - const rows = await readPtyTerminalRows(tty, deadlineMs - Date.now()) + const rows = await readPtyTerminalRows(tty, proc.pid, deadlineMs - Date.now()) if (!alive()) { return unknown('session_changed') } diff --git a/src/main/pty/process-retirement/terminal-process-rows.ts b/src/main/pty/process-retirement/terminal-process-rows.ts index 9dbbf66acd7..60d88fa4d27 100644 --- a/src/main/pty/process-retirement/terminal-process-rows.ts +++ b/src/main/pty/process-retirement/terminal-process-rows.ts @@ -83,20 +83,57 @@ export async function readTerminalTty( return output === null ? null : normalizePtyTty(output) } +/** A container's private pts/N reuses the host's terminal number while its processes keep their own session, so + * ps -t lists them beside the terminal's own (#39488). Strip the sid column ps prefixes and keep only the anchor + * process's session; a missing anchor row keeps every row. */ +function parseTerminalSessionRows(stdout: string, anchorPid: number): ProcessTableRow[] { + const sidByPid = new Map() + const body = stdout + .split(/\r?\n/) + .map((line) => { + const match = line.trim().match(/^(\d+)\s+(\d+)\s+(.*)$/) + if (!match) { + return line.trim() + } + sidByPid.set(Number(match[2]), Number(match[1])) + return `${match[2]} ${match[3]}` + }) + .join('\n') + const rows = parseShellForegroundRows(body, { strict: true }) + const anchorSid = sidByPid.get(anchorPid) + return anchorSid === undefined ? rows : rows.filter((row) => sidByPid.get(row.pid) === anchorSid) +} + export async function readPtyTerminalRows( tty: string, + anchorPid: number, timeoutMs = PS_TIMEOUT_MS ): Promise { const normalized = normalizePtyTty(tty) if (!normalized || timeoutMs <= 0) { return null } + // macOS ps has no sid keyword. + const withSid = process.platform === 'linux' const stdout = await readTerminalPs( - ['-ww', '-o', 'pid=,ppid=,pgid=,tpgid=,stat=,command=', '-t', normalized], + [ + '-ww', + '-o', + withSid + ? 'sid=,pid=,ppid=,pgid=,tpgid=,stat=,command=' + : 'pid=,ppid=,pgid=,tpgid=,stat=,command=', + '-t', + normalized + ], timeoutMs ) try { - return stdout === null ? null : parseShellForegroundRows(stdout, { strict: true }) + if (stdout === null) { + return null + } + return withSid + ? parseTerminalSessionRows(stdout, anchorPid) + : parseShellForegroundRows(stdout, { strict: true }) } catch { return null } @@ -106,7 +143,7 @@ export async function readPtyTerminalRows( export async function readTerminalProcessRows(rootPid: number): Promise { const deadline = Date.now() + PS_TIMEOUT_MS const tty = await readTerminalTty(rootPid, deadline - Date.now()) - const rows = tty ? await readPtyTerminalRows(tty, deadline - Date.now()) : null + const rows = tty ? await readPtyTerminalRows(tty, rootPid, deadline - Date.now()) : null if (!rows?.some((row) => row.pid === rootPid) || Date.now() >= deadline) { return null } diff --git a/src/main/rate-limits/providers/minimax/minimax-request-context.test.ts b/src/main/rate-limits/providers/minimax/minimax-request-context.test.ts index c4addf7a72c..68fc9ef7b35 100644 --- a/src/main/rate-limits/providers/minimax/minimax-request-context.test.ts +++ b/src/main/rate-limits/providers/minimax/minimax-request-context.test.ts @@ -1,27 +1,6 @@ -import { describe, expect, it, vi } from 'vitest' -import type { Session } from 'electron' -import { setMainHttpClient } from '../../../network/http-client' - -const { fetchMock, sessionFromPartitionMock } = vi.hoisted(() => { - const fetchMock = vi.fn() - const cookiesSetMock = vi.fn(() => Promise.resolve()) - const clearStorageDataMock = vi.fn(() => Promise.resolve()) - const sessionFromPartitionMock = vi.fn(() => ({ - clearStorageData: clearStorageDataMock, - cookies: { set: cookiesSetMock }, - fetch: fetchMock - })) - return { clearStorageDataMock, cookiesSetMock, fetchMock, sessionFromPartitionMock } -}) +import { describe, expect, it } from 'vitest' import { redactMiniMaxSecret } from './minimax-request-context' -setMainHttpClient({ - fetch: fetchMock, - proxySession: () => null, - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the code under test only calls clearStorageData, cookies.set and fetch, which the fake provides. - partitionSession: sessionFromPartitionMock as unknown as (partition: string) => Session -}) - describe('redactMiniMaxSecret', () => { it('redacts _token values in header and quoted syntax', () => { const redacted = redactMiniMaxSecret('cookie _token=eyJhABCDEF and _token:"x.y"') diff --git a/src/main/remote-layout-snapshot/remote-layout-snapshot-persistence.test.ts b/src/main/remote-layout-snapshot/remote-layout-snapshot-persistence.test.ts index 9b80228c4c3..560749b1c21 100644 --- a/src/main/remote-layout-snapshot/remote-layout-snapshot-persistence.test.ts +++ b/src/main/remote-layout-snapshot/remote-layout-snapshot-persistence.test.ts @@ -153,5 +153,5 @@ it('keeps a title-only change without arming a save, and writes it with the next // Another domain's save writes only the domains marked dirty, which must include this one. store.updateSettings({ opencodeSessionCookie: 'cookie' }) store.flushOrThrow() - expect(open().getRemoteLayoutSnapshot('env')?.workspaces[workspace.worktree]).toEqual(retitled) + expect(open().getRemoteLayoutSnapshots().env?.workspaces[workspace.worktree]).toEqual(retitled) }) diff --git a/src/main/remote-layout-snapshot/remote-layout-snapshot-persistence.ts b/src/main/remote-layout-snapshot/remote-layout-snapshot-persistence.ts index 04560570a45..45186efd4dd 100644 --- a/src/main/remote-layout-snapshot/remote-layout-snapshot-persistence.ts +++ b/src/main/remote-layout-snapshot/remote-layout-snapshot-persistence.ts @@ -1,4 +1,7 @@ -import type { RemoteLayoutSnapshot } from '../../shared/remote-layout-snapshot' +import type { + RemoteLayoutSnapshot, + RemoteLayoutSnapshotWorkspace +} from '../../shared/remote-layout-snapshot' import type { StoreRuntimeState } from '../persistence/loading-store/store-runtime-state' import type { WriteSchedulingOperations } from '../persistence/loading-store/write-scheduling' import { scheduleSave } from '../persistence/loading-store/write-scheduling' @@ -11,6 +14,28 @@ type RemoteLayoutSnapshotPersistenceContext = { scheduling: WriteSchedulingOperations } +function writeSnapshotEntry(entries: Record, id: string, value: T): void { + // Admitted string identities must remain own keys even when named __proto__. + Object.defineProperty(entries, id, { + value, + configurable: true, + enumerable: true, + writable: true + }) +} + +function saveRemoteLayoutSnapshots( + { runtime, scheduling }: RemoteLayoutSnapshotPersistenceContext, + save: 'now' | 'later' +): void { + if (save === 'later') { + runtime.dirtyProfileStateDomains?.add('remoteLayoutSnapshots') + return + } + // Save only this domain without waking workspace-session listeners. + scheduleSave(scheduling, ['remoteLayoutSnapshots']) +} + export class RemoteLayoutSnapshotPersistence { readonly [remoteLayoutSnapshotPersistenceContext]: RemoteLayoutSnapshotPersistenceContext @@ -18,10 +43,18 @@ export class RemoteLayoutSnapshotPersistence { this[remoteLayoutSnapshotPersistenceContext] = { runtime, scheduling } } - getRemoteLayoutSnapshot(environmentId: string): RemoteLayoutSnapshot | undefined { - return this[remoteLayoutSnapshotPersistenceContext].runtime.state.remoteLayoutSnapshots?.[ - environmentId - ] + /** Recorder-only lookup; workspace values are replaced, never mutated. */ + getRemoteLayoutSnapshotWorkspace( + environmentId: string, + worktreeId: string + ): RemoteLayoutSnapshotWorkspace | undefined { + const snapshots = + this[remoteLayoutSnapshotPersistenceContext].runtime.state.remoteLayoutSnapshots + const snapshot = + snapshots && Object.hasOwn(snapshots, environmentId) ? snapshots[environmentId] : undefined + return snapshot && Object.hasOwn(snapshot.workspaces, worktreeId) + ? snapshot.workspaces[worktreeId] + : undefined } getRemoteLayoutSnapshots(): Record { @@ -31,7 +64,7 @@ export class RemoteLayoutSnapshotPersistence { return Object.fromEntries( Object.entries(stored).map(([environmentId, { workspaces }]) => [ environmentId, - { workspaces } + { workspaces: structuredClone(workspaces) } ]) ) } @@ -42,19 +75,36 @@ export class RemoteLayoutSnapshotPersistence { snapshot: RemoteLayoutSnapshot | null, save: 'now' | 'later' ): void { - const { runtime, scheduling } = this[remoteLayoutSnapshotPersistenceContext] - const { [environmentId]: previous, ...others } = runtime.state.remoteLayoutSnapshots ?? {} - if (snapshot === null && previous === undefined) { + const context = this[remoteLayoutSnapshotPersistenceContext] + const snapshots = (context.runtime.state.remoteLayoutSnapshots ??= {}) + if (snapshot === null && !Object.hasOwn(snapshots, environmentId)) { return } - runtime.state.remoteLayoutSnapshots = snapshot - ? { ...others, [environmentId]: snapshot } - : others - if (save === 'later') { - runtime.dirtyProfileStateDomains?.add('remoteLayoutSnapshots') - return + if (snapshot) { + writeSnapshotEntry(snapshots, environmentId, snapshot) + } else { + delete snapshots[environmentId] } - // Save only this domain without waking workspace-session listeners. - scheduleSave(scheduling, ['remoteLayoutSnapshots']) + saveRemoteLayoutSnapshots(context, save) + } + + setRemoteLayoutSnapshotWorkspace( + environmentId: string, + worktreeId: string, + workspace: RemoteLayoutSnapshotWorkspace | null, + save: 'now' | 'later' + ): void { + const context = this[remoteLayoutSnapshotPersistenceContext] + const snapshots = (context.runtime.state.remoteLayoutSnapshots ??= {}) + const workspaces = Object.hasOwn(snapshots, environmentId) + ? snapshots[environmentId].workspaces + : {} + if (workspace) { + writeSnapshotEntry(workspaces, worktreeId, workspace) + } else { + delete workspaces[worktreeId] + } + writeSnapshotEntry(snapshots, environmentId, { workspaces }) + saveRemoteLayoutSnapshots(context, save) } } diff --git a/src/main/remote-layout-snapshot/remote-layout-snapshot-recorder.test.ts b/src/main/remote-layout-snapshot/remote-layout-snapshot-recorder.test.ts index 516d53f820b..20f8ac06316 100644 --- a/src/main/remote-layout-snapshot/remote-layout-snapshot-recorder.test.ts +++ b/src/main/remote-layout-snapshot/remote-layout-snapshot-recorder.test.ts @@ -13,7 +13,18 @@ function memoryStore() { const snapshots = new Map() const saves: ('now' | 'later')[] = [] const store: RemoteLayoutSnapshotStore = { - getRemoteLayoutSnapshot: (environmentId) => snapshots.get(environmentId), + getRemoteLayoutSnapshotWorkspace: (environmentId, worktreeId) => + snapshots.get(environmentId)?.workspaces[worktreeId], + setRemoteLayoutSnapshotWorkspace: (environmentId, worktreeId, workspace, save) => { + saves.push(save) + const snapshot = snapshots.get(environmentId) ?? { workspaces: {} } + if (workspace) { + snapshot.workspaces[worktreeId] = workspace + } else { + delete snapshot.workspaces[worktreeId] + } + snapshots.set(environmentId, snapshot) + }, setRemoteLayoutSnapshot: (environmentId, snapshot, save) => { saves.push(save) if (snapshot) { diff --git a/src/main/remote-layout-snapshot/remote-layout-snapshot-recorder.ts b/src/main/remote-layout-snapshot/remote-layout-snapshot-recorder.ts index 36bec681970..78c3e040212 100644 --- a/src/main/remote-layout-snapshot/remote-layout-snapshot-recorder.ts +++ b/src/main/remote-layout-snapshot/remote-layout-snapshot-recorder.ts @@ -8,7 +8,16 @@ import type { RuntimeRpcResponse } from '../../shared/runtime-rpc-envelope' import type { RuntimeMobileSessionTabsResult } from '../../shared/runtime-session-contracts' export type RemoteLayoutSnapshotStore = { - getRemoteLayoutSnapshot(environmentId: string): RemoteLayoutSnapshot | undefined + getRemoteLayoutSnapshotWorkspace( + environmentId: string, + worktreeId: string + ): RemoteLayoutSnapshotWorkspace | undefined + setRemoteLayoutSnapshotWorkspace( + environmentId: string, + worktreeId: string, + workspace: RemoteLayoutSnapshotWorkspace | null, + save: 'now' | 'later' + ): void setRemoteLayoutSnapshot( environmentId: string, snapshot: RemoteLayoutSnapshot | null, @@ -77,16 +86,16 @@ export function recordRemoteLayoutFrame( return } const { type: _type, removed, ...result } = frame - const { [frame.worktree]: previous, ...others } = - store.getRemoteLayoutSnapshot(environmentId)?.workspaces ?? {} + const previous = store.getRemoteLayoutSnapshotWorkspace(environmentId, frame.worktree) if (removed) { - store.setRemoteLayoutSnapshot(environmentId, { workspaces: others }, 'now') + store.setRemoteLayoutSnapshotWorkspace(environmentId, frame.worktree, null, 'now') return } const workspace = displayed(result) - store.setRemoteLayoutSnapshot( + store.setRemoteLayoutSnapshotWorkspace( environmentId, - { workspaces: { ...others, [frame.worktree]: workspace } }, + frame.worktree, + workspace, structure(previous) === structure(workspace) ? 'later' : 'now' ) } diff --git a/src/main/repository-icons/repo-icon-autodetect.ts b/src/main/repository-icons/repo-icon-autodetect.ts index 64dce61e202..393672a9ef9 100644 --- a/src/main/repository-icons/repo-icon-autodetect.ts +++ b/src/main/repository-icons/repo-icon-autodetect.ts @@ -8,7 +8,7 @@ import { githubAvatarSlug, type RepoIcon } from '../../shared/repo-icon' -import { getRepoSlug, getRepoUpstream } from '../github/client/fetch/repo-slug-upstream' +import { getRepoSlug } from '../github/client/fetch/repo-slug-upstream' import { resolveFilesystemRouteForHost, resolveGitRouteForHost @@ -92,6 +92,24 @@ export async function detectGitHubAvatarIcon( } } +async function detectRepoLocalIcon( + repoPath: string, + executionHostId: ExecutionHostId +): Promise { + try { + const route = resolveFilesystemRouteForHost(executionHostId) + const fileIcon = await detectRepoFileIcon(repoPath, route) + if (fileIcon) { + return fileIcon + } + return ( + (route.kind === 'local' ? await detectLocalPackageHomepageIcon(repoPath) : null) ?? undefined + ) + } catch { + return undefined + } +} + export async function detectRepoIcon({ repoPath, kind, @@ -103,30 +121,15 @@ export async function detectRepoIcon({ executionHostId: ExecutionHostId upstream?: GitHubRepositoryIdentity | null }): Promise { - try { - const route = resolveFilesystemRouteForHost(executionHostId) - const fileIcon = await detectRepoFileIcon(repoPath, route) - if (fileIcon) { - return fileIcon - } - - const homepageIcon = - route.kind === 'local' ? await detectLocalPackageHomepageIcon(repoPath) : null - if (homepageIcon) { - return homepageIcon - } - - if (kind === 'git') { - return (await detectGitHubAvatarIcon(repoPath, executionHostId, upstream)) ?? undefined - } - } catch { - // Icon failures must not prevent repo creation. - } - return undefined + return ( + (await detectRepoLocalIcon(repoPath, executionHostId)) ?? + (kind === 'git' + ? ((await detectGitHubAvatarIcon(repoPath, executionHostId, upstream)) ?? undefined) + : undefined) + ) } -// A null upstream marks a resolved non-fork and prevents repeated probes. -export async function detectRepoIconAndUpstream({ +export async function detectRepoLocalMetadata({ repoPath, kind, executionHostId @@ -135,22 +138,13 @@ export async function detectRepoIconAndUpstream({ kind: RepoKind executionHostId: ExecutionHostId }) { - const remoteRead = repoRemoteReadConnection(executionHostId) - const upstream = - kind === 'git' && remoteRead.kind === 'dial' - ? await getRepoUpstream(repoPath, remoteRead.connectionId) - : null const gitRemoteIdentity = kind === 'git' - ? await detectGitRemoteIdentity(repoPath, executionHostId, { - // Host Git on purpose: this runs while the project is being added, before it exists. - hostGit: true - }) + ? await detectGitRemoteIdentity(repoPath, executionHostId, { hostGit: true }) : null - const repoIcon = await detectRepoIcon({ repoPath, kind, executionHostId, upstream }) + const repoIcon = await detectRepoLocalIcon(repoPath, executionHostId) return { ...(repoIcon ? { repoIcon } : {}), - ...(gitRemoteIdentity ? { gitRemoteIdentity } : {}), - ...(kind === 'git' ? { upstream: upstream ?? null } : {}) + ...(gitRemoteIdentity ? { gitRemoteIdentity } : {}) } } diff --git a/src/main/runtime/agent-senders/runtime-agent-sender-history-triggers.ts b/src/main/runtime/agent-senders/runtime-agent-sender-history-triggers.ts index f2247f0d6c0..bc4a2a4f6a2 100644 --- a/src/main/runtime/agent-senders/runtime-agent-sender-history-triggers.ts +++ b/src/main/runtime/agent-senders/runtime-agent-sender-history-triggers.ts @@ -1,4 +1,5 @@ import { z } from 'zod' +import { projectionMutationTriggers } from '../orchestration/db/projection-mutation-triggers' import type { OrchestrationDb } from '../orchestration/db/orchestration-db' import { tolerant } from './agent-sender-row-decoding' @@ -65,26 +66,15 @@ CREATE TEMP TABLE IF NOT EXISTS agent_sender_tracked ( kind TEXT NOT NULL, key TEXT NOT NULL, PRIMARY KEY (kind, key)) WITHOUT ROWID; CREATE TEMP TABLE IF NOT EXISTS agent_sender_dirty ( kind TEXT NOT NULL, key TEXT NOT NULL, PRIMARY KEY (kind, key)) WITHOUT ROWID; -${HISTORY_TRIGGERS.flatMap((trigger) => { - const events: { name: string; event: string; marks: string[] }[] = [ - { name: 'insert', event: 'AFTER INSERT', marks: [markDirty('NEW', trigger)] }, - { name: 'delete', event: 'AFTER DELETE', marks: [markDirty('OLD', trigger)] }, - { - name: 'update', - event: `AFTER UPDATE OF ${trigger.columns}`, - marks: [markDirty('OLD', trigger), markDirty('NEW', trigger)] - } - ] - return events.map( - ({ - name, - event, - marks - }) => `CREATE TEMP TRIGGER IF NOT EXISTS agent_sender_${trigger.table}_${name} -${event} ON main.${trigger.table} -BEGIN UPDATE temp.agent_sender_generation SET history = history + 1; ${marks.join(' ')} END;` - ) -}).join('\n')} +${projectionMutationTriggers( + 'agent_sender', + HISTORY_TRIGGERS.map((trigger) => ({ + table: trigger.table, + columns: trigger.columns, + mark: (row) => markDirty(row, trigger) + })), + 'UPDATE temp.agent_sender_generation SET history = history + 1;' +)} ${['insert', 'delete', 'update'] .map( (name) => `CREATE TEMP TRIGGER IF NOT EXISTS agent_sender_federated_dispatches_${name} diff --git a/src/main/runtime/agent-session/structured-agent-session-codex-start-deadline.test.ts b/src/main/runtime/agent-session/structured-agent-session-codex-start-deadline.test.ts index 8bf7a3f8597..b3287654d4d 100644 --- a/src/main/runtime/agent-session/structured-agent-session-codex-start-deadline.test.ts +++ b/src/main/runtime/agent-session/structured-agent-session-codex-start-deadline.test.ts @@ -17,6 +17,8 @@ import { createStructuredAgentSessionLogger } from '../../native-chat/agent-sess import { recordAgentSessionStartup } from '../../observability/agent-session-instrumentation' import { STRUCTURED_AGENT_SESSION_STARTUP_CEILING_MS } from '../../native-chat/agent-session-wire/startup/structured-agent-session-startup-attempt-contract' import { readWholeAgentSessionFailureFact } from '../../../shared/agent-session/failures/agent-session-failure' +import { awakeNow, createAwakeClock } from '../../power/awake-clock' +import type * as AwakeClockModule from '../../power/awake-clock' import type { ScriptedAgentChild } from './installation/structured-agent-scripted-child.test-fixture' import { stopStructuredAgentSessionRuntime } from './structured-agent-session-runtime' import { ensureTestStructuredAgentSessionHost as ensureStructuredAgentSessionHost } from './records/agent-session-record-store-test-harness' @@ -26,16 +28,27 @@ vi.mock('../../observability/agent-session-instrumentation', async (importOrigin recordAgentSessionStartup: vi.fn() })) +// The startup ceiling runs on the process-wide awake clock, which outlives a test: its heartbeat +// is a fake timer that useRealTimers drops, after which a jump reads as a sleep and never counts. +// Each test gets its own production awake clock, built on that test's fake time. +vi.mock('../../power/awake-clock', async (importOriginal) => ({ + ...(await importOriginal()), + awakeNow: vi.fn() +})) + let root: string | undefined const caller = { callerKey: 'codex-start-deadline-test' } let operation = 0 beforeEach(() => { - // Real time still passes, so file and database work settles; the test jumps the clock. + // Real time still passes, so file and database work settles; the test jumps the clock. The + // awake clock reads performance as well as Date, so both move together. vi.useFakeTimers({ shouldAdvanceTime: true, - toFake: ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'Date'] + toFake: ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'Date', 'performance'] }) + const clock = createAwakeClock() + vi.mocked(awakeNow).mockImplementation(() => clock.now()) vi.mocked(recordAgentSessionStartup).mockClear() }) diff --git a/src/main/runtime/agent-session/structured-agent-session-startup-reconcile.test.ts b/src/main/runtime/agent-session/structured-agent-session-startup-reconcile.test.ts index 2d12af6088b..646946e49ae 100644 --- a/src/main/runtime/agent-session/structured-agent-session-startup-reconcile.test.ts +++ b/src/main/runtime/agent-session/structured-agent-session-startup-reconcile.test.ts @@ -17,6 +17,7 @@ import { closeTestJournalHostDatabases } from '../../native-chat/agent-session-j import { OrcaRuntimeService } from '../orca-runtime' import { stopStructuredAgentSessionRuntime } from './structured-agent-session-runtime' import { recordingStructuredAgentSessionLogger } from '../../native-chat/agent-session-wire/host/testing/structured-agent-session-logger.test-fixture' +import { observeStructuredSession } from '../orchestration/terminal-authority/structured-sessions/structured-worker-authority' let root: string @@ -42,8 +43,11 @@ async function seedChat(options: { newer?: boolean } = {}) { return { path: journalDomainDatabasePath(root), sessionId: record.sessionId } } -function startupRuntime(log = recordingStructuredAgentSessionLogger()) { - const runtime = new OrcaRuntimeService() +function startupRuntime( + log = recordingStructuredAgentSessionLogger(), + deps?: ConstructorParameters[2] +) { + const runtime = new OrcaRuntimeService(undefined, undefined, deps) // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: these are the runtime's own protected members; the test roots the host at `root` and stubs the PTY daemon. const internal = runtime as unknown as { hasPersistedStructuredAgentSessionStore(): boolean @@ -147,3 +151,13 @@ it('closes a chat tab over records a newer Orca wrote, reporting the index it ca }) expect(close).toHaveBeenCalledWith(sessionId, 'user-close') }) + +it('settles a chat worker that died with the last run when orchestration restores its workers', async () => { + const { sessionId } = await seedChat() + // A host without recoverable PTYs restores no terminal workers, only chats. + const runtime = startupRuntime(undefined, { canRecoverPersistentLocalPtys: () => false }) + + await runtime.refreshRestoredOrchestrationAuthority() + + expect(observeStructuredSession(sessionId).status).toBe('exited') +}) diff --git a/src/main/runtime/browser/commands/browser-command-contracts.ts b/src/main/runtime/browser/commands/browser-command-contracts.ts index 9d5367bf3b9..09d04d459ce 100644 --- a/src/main/runtime/browser/commands/browser-command-contracts.ts +++ b/src/main/runtime/browser/commands/browser-command-contracts.ts @@ -9,6 +9,7 @@ import type { BrowserBackend } from '../../../browser/browser-backend' import type { BrowserSessionTabSelectionOptions } from '../tabs/browser-tab-create-publication' import type { ServeBrowserTabs } from '../headless/serve-browser-tabs' import type { BrowserTabBarEntry } from '../tabs/browser-tab-listing' +import type { BrowserPageAnnotation } from '../../../../shared/browser/element-grab/browser-grab-types' export type BrowserCommandTargetParams = { worktree?: string @@ -60,6 +61,8 @@ export type RuntimeBrowserCommandHost = { options?: BrowserSessionTabSelectionOptions ): void notifyHeadlessBrowserSessionTabsChanged?(worktreeId: string): void + /** A page's unsent notes; see readSavedBrowserPageAnnotations. */ + readBrowserPageAnnotations?(browserPageId: string): BrowserPageAnnotation[] /** The tab bar's browser tabs, loaded or not, from the published session snapshot. */ readBrowserTabBar?(worktreeId: string | undefined): BrowserTabBarEntry[] retireRuntimeOwnedBrowserSessionTab?(worktreeId: string, browserPageId: string): boolean | void diff --git a/src/main/runtime/browser/commands/browser-commands.ts b/src/main/runtime/browser/commands/browser-commands.ts index acdda731ff6..4f8e0cb11a8 100644 --- a/src/main/runtime/browser/commands/browser-commands.ts +++ b/src/main/runtime/browser/commands/browser-commands.ts @@ -81,6 +81,7 @@ export class RuntimeBrowserCommands { readonly browserProceedCertificate: RuntimeBrowserTabQueries['browserProceedCertificate'] readonly browserTabShow: RuntimeBrowserTabQueries['browserTabShow'] readonly browserTabCurrent: RuntimeBrowserTabQueries['browserTabCurrent'] + readonly browserTabAnnotations: RuntimeBrowserTabQueries['browserTabAnnotations'] readonly browserTabSwitch: RuntimeBrowserTabQueries['browserTabSwitch'] readonly browserTabCreate: RuntimeBrowserTabCreation['browserTabCreate'] readonly browserOpenUrlOnClient: RuntimeBrowserTabCreation['browserOpenUrlOnClient'] @@ -187,6 +188,7 @@ export class RuntimeBrowserCommands { this.browserProceedCertificate = queries.browserProceedCertificate.bind(queries) this.browserTabShow = queries.browserTabShow.bind(queries) this.browserTabCurrent = queries.browserTabCurrent.bind(queries) + this.browserTabAnnotations = queries.browserTabAnnotations.bind(queries) this.browserTabSwitch = queries.browserTabSwitch.bind(queries) this.browserTabCreate = creation.browserTabCreate.bind(creation) this.browserOpenUrlOnClient = creation.browserOpenUrlOnClient.bind(creation) diff --git a/src/main/runtime/browser/screencast/browser-screencasts.ts b/src/main/runtime/browser/screencast/browser-screencasts.ts index 192aa7412ed..d8a97faa304 100644 --- a/src/main/runtime/browser/screencast/browser-screencasts.ts +++ b/src/main/runtime/browser/screencast/browser-screencasts.ts @@ -2,6 +2,7 @@ import type { BrowserScreencastResult } from '../../../../shared/browser/runtime import { BrowserError } from '../../../browser/browser-error' import { randomUUID } from 'node:crypto' import { startBrowserScreencast } from '../../../browser/cdp/screencast/browser-screencast-stream' +import { browserManager } from '../../../browser/guest-lifecycle/manager/browser-manager' import { rendererPublicationThrottle } from '../../../window/renderer-publication-throttle' import { mintBrowserScreencastSubscriptionId } from './browser-screencast-subscription-id' import { @@ -102,6 +103,7 @@ export class RuntimeBrowserScreencasts { format: params.format, ...budget, ...viewport, + holdPaint: () => browserManager.holdPaintForCapture(guest.id), onFrame: (bytes) => { const ghosts: string[] = [] for (const [subscriptionId, subscriber] of pendingRecord.subscribers) { diff --git a/src/main/runtime/browser/screencast/remote-browser-screencast-frame-admission.test.ts b/src/main/runtime/browser/screencast/remote-browser-screencast-frame-admission.test.ts index 6e5d0b3db0c..c87652a7309 100644 --- a/src/main/runtime/browser/screencast/remote-browser-screencast-frame-admission.test.ts +++ b/src/main/runtime/browser/screencast/remote-browser-screencast-frame-admission.test.ts @@ -92,6 +92,7 @@ describe('sendRemoteBrowserScreencastFrame', () => { maxHeight: 2160, everyNthFrame: 1, minFrameIntervalMs: 0, + holdPaint: () => () => {}, onFrame: (bytes) => sendRemoteBrowserScreencastFrame(transport.sendBinary, bytes) !== 'refused' }) diff --git a/src/main/runtime/browser/tabs/browser-tab-annotations.ts b/src/main/runtime/browser/tabs/browser-tab-annotations.ts new file mode 100644 index 00000000000..c58ceffb5ab --- /dev/null +++ b/src/main/runtime/browser/tabs/browser-tab-annotations.ts @@ -0,0 +1,67 @@ +import type { BrowserPageAnnotation } from '../../../../shared/browser/element-grab/browser-grab-types' +import type { + BrowserTabAnnotationsResult, + BrowserTabInfo +} from '../../../../shared/browser/runtime/runtime-browser-contracts' +import { isHostReachableDocument } from '../../../../shared/desktop-browser-bridge-protocol' +import { BrowserError } from '../../../browser/browser-error' +import type { RuntimeStore } from '../../construction/runtime-store-contract' +import type { RuntimeBrowserCommandHost } from '../commands/browser-command-contracts' +import { remoteCliBrowserScopeWorkspaceId } from '../../desktop-browser-bridge/remote-cli-browser-scope' + +/** A page's unsent notes from the saved session, which the window keeps current. */ +export function readSavedBrowserPageAnnotations( + store: + | Pick + | null + | undefined, + browserPageId: string +): BrowserPageAnnotation[] { + // Page ids are unique across hosts, and a bridged SSH page has no worktree row here. + for (const hostId of store?.getWorkspaceSessionHostIds?.() ?? []) { + const pages = store?.getWorkspaceSession?.(hostId)?.browserPagesByWorkspace ?? {} + for (const workspacePages of Object.values(pages)) { + const page = workspacePages.find((candidate) => candidate.id === browserPageId) + if (page) { + return page.annotations ?? [] + } + } + } + return [] +} + +export function findListedBrowserTab( + tabs: readonly BrowserTabInfo[], + page: string +): BrowserTabInfo { + const tab = tabs.find((candidate) => candidate.browserPageId === page) + if (!tab) { + throw new BrowserError('browser_tab_not_found', `Browser page ${page} was not found`) + } + return tab +} + +export function readBrowserTabAnnotations( + host: Pick< + RuntimeBrowserCommandHost, + 'getRuntimeBrowserPageRegistry' | 'readBrowserPageAnnotations' + >, + tab: BrowserTabInfo +): BrowserTabAnnotationsResult { + // A paired desktop draws this page and keeps its notes; this host would wrongly report none. + if (host.getRuntimeBrowserPageRegistry().getPage(tab.browserPageId)) { + throw new BrowserError( + 'browser_annotations_unavailable', + `Tab ${tab.browserPageId} is drawn by a paired desktop, which keeps its unsent notes. Ask the user to send them from that tab.` + ) + } + const annotations = host.readBrowserPageAnnotations?.(tab.browserPageId) ?? [] + return { + tab, + // An SSH host may not read what a note captured from a desktop-local document. + annotations: + remoteCliBrowserScopeWorkspaceId() === undefined + ? annotations + : annotations.filter((note) => isHostReachableDocument(note.payload.page.sanitizedUrl)) + } +} diff --git a/src/main/runtime/browser/tabs/browser-tab-queries.ts b/src/main/runtime/browser/tabs/browser-tab-queries.ts index 5aaab4a5a66..51f31bdbe76 100644 --- a/src/main/runtime/browser/tabs/browser-tab-queries.ts +++ b/src/main/runtime/browser/tabs/browser-tab-queries.ts @@ -1,4 +1,5 @@ import type { + BrowserTabAnnotationsResult, BrowserTabCurrentResult, BrowserTabListResult, BrowserTabShowResult, @@ -17,6 +18,7 @@ import type { } from '../commands/browser-command-contracts' import type { RuntimeBrowserCommandTargets } from '../commands/browser-command-targets' import type { RuntimeBrowserTabCatalog } from './browser-tab-catalog' +import { findListedBrowserTab, readBrowserTabAnnotations } from './browser-tab-annotations' export class RuntimeBrowserTabQueries { constructor( @@ -27,6 +29,7 @@ export class RuntimeBrowserTabQueries { | 'getRuntimeBrowserPageRegistry' | 'markHeadlessBrowserSessionTabActive' | 'notifyHeadlessBrowserSessionTabsChanged' + | 'readBrowserPageAnnotations' >, private readonly targets: Pick< RuntimeBrowserCommandTargets, @@ -89,6 +92,22 @@ export class RuntimeBrowserTabQueries { return { tab: this.catalog.describeBrowserTab(params.page, target.worktreeId) } } + async browserTabAnnotations(params: { + page?: string + worktree?: string + }): Promise { + if (!params.page) { + return readBrowserTabAnnotations(this.host, (await this.browserTabCurrent(params)).tab) + } + // A named page's notes are saved state: list the tab bar as saved rather than waking a browser. + const workspaceId = params.worktree + ? (await this.host.resolveBrowserWorkspace(params.worktree)).id + : undefined + const clientPages = this.host.getRuntimeBrowserPageRegistry().listPages(workspaceId) + const tabs = this.catalog.listLogicalBrowserTabs(workspaceId, clientPages) + return readBrowserTabAnnotations(this.host, findListedBrowserTab(tabs, params.page)) + } + async browserTabCurrent(params: { worktree?: string }): Promise { const tab = (await this.browserTabList(params)).tabs.find((candidate) => candidate.active) if (!tab) { diff --git a/src/main/runtime/client/events/runtime-notifier-contract.ts b/src/main/runtime/client/events/runtime-notifier-contract.ts index aeaacdf7d83..0715c88c511 100644 --- a/src/main/runtime/client/events/runtime-notifier-contract.ts +++ b/src/main/runtime/client/events/runtime-notifier-contract.ts @@ -1,3 +1,4 @@ +import type { WorkspaceMetadataSet } from '../../../../shared/worktree/workspace-metadata-set' import type { RuntimeEditorTabReveal, RuntimeFileOpenPosition @@ -49,6 +50,7 @@ export type RuntimeNotifier = { // Why: false for metadata-only changes (sort order) that leave Git scan results valid. options?: { invalidateGitScans?: boolean } ): void + workspaceMetadataSet?(set: WorkspaceMetadataSet): void worktreeBaseStatus?(event: WorktreeBaseStatusEvent): void worktreeRemoteBranchConflict?(event: WorktreeRemoteBranchConflictEvent): void reposChanged(): void @@ -136,7 +138,8 @@ export type RuntimeNotifier = { focusTerminal(tabId: string, worktreeId: string, leafId?: string | null): void /** Raises the window onto a pane it shows; resolves false when the window does not know the worktree. */ revealTerminalPane?(target: TerminalPaneRevealTarget): Promise - focusEditorTab?(tabId: string, worktreeId: string): void + /** `userInitiated` lets a chat tab move the window to another worktree. */ + focusEditorTab?(tabId: string, worktreeId: string, options?: { userInitiated: true }): void closeSessionTab?(tabId: string, worktreeId: string): void | Promise moveSessionTab?(worktreeId: string, move: RuntimeMobileSessionTabMove): void /** The window moves a client's pane to a new tab, since it owns the layout; rejects when it cannot answer. */ diff --git a/src/main/runtime/construction/runtime-construction-dependencies.ts b/src/main/runtime/construction/runtime-construction-dependencies.ts index c1dd0251255..e7d30136582 100644 --- a/src/main/runtime/construction/runtime-construction-dependencies.ts +++ b/src/main/runtime/construction/runtime-construction-dependencies.ts @@ -33,6 +33,7 @@ export type RuntimeConstructionDependencies = { onClaudeTerminalEvidence?: (paneKey: string, evidence: ClaudeTerminalEvidence) => void getAgentStatusSnapshot?: () => AgentStatusIpcPayload[] getAgentStatusSnapshotForPane?: (paneKey: string) => AgentStatusIpcPayload[] + getPublicAgentStatusSnapshotForPane?: (paneKey: string) => AgentStatusIpcPayload[] structuredAgentStatusSink?: StructuredAgentSessionStatusSink readObservedAgentStatusPaneIdentity?: (paneKey: string) => ObservedAgentStatusPaneIdentity getAgentProviderSessionSnapshot?: (tabId?: string) => AgentStatusIpcPayload[] diff --git a/src/main/runtime/construction/runtime-construction-services.ts b/src/main/runtime/construction/runtime-construction-services.ts index d3ea3a29649..6c1c4baadcd 100644 --- a/src/main/runtime/construction/runtime-construction-services.ts +++ b/src/main/runtime/construction/runtime-construction-services.ts @@ -277,6 +277,7 @@ export abstract class RuntimeConstructionServices { protected abstract readonly getAgentStatusSnapshotForPaneFn: | ((paneKey: string) => AgentStatusIpcPayload[]) | null + protected abstract readonly publicPaneStatusFn?: (paneKey: string) => AgentStatusIpcPayload[] abstract readonly getAgentStatusSnapshotFn: (() => AgentStatusIpcPayload[]) | null protected abstract getTrackedDisplayTitleForPty(ptyId: string): string | null protected abstract getLeavesForPty(ptyId: string): readonly RuntimeLeafRecord[] diff --git a/src/main/runtime/construction/runtime-construction.ts b/src/main/runtime/construction/runtime-construction.ts index dfffdd783c4..797bbb1e977 100644 --- a/src/main/runtime/construction/runtime-construction.ts +++ b/src/main/runtime/construction/runtime-construction.ts @@ -1,7 +1,7 @@ import { collectSavedStructuredAgentSessionIds } from '../agent-session/lifecycle/saved-structured-agent-session-restoration' import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' import type { - RuntimeConstructionBindings, + RuntimeConstructionBindings as Bindings, RuntimeConstructionDependencies } from './runtime-construction-dependencies' import type { OrcaRuntimeWithRuntimeId as IdentityState } from './runtime-identity-state' @@ -75,11 +75,11 @@ export abstract class OrcaRuntimeWithStateFields extends OrcaRuntimeWithLinearCo declare protected readonly attestAgentHookCompatibilityAuthorityFn: HostServices['attestAgentHookCompatibilityAuthorityFn'] declare protected readonly retireAgentHookCompatibilityAuthorityFn: HostServices['retireAgentHookCompatibilityAuthorityFn'] declare protected readonly readHookCliWriterObservationFn: - | RuntimeConstructionBindings['readHookCliWriterObservation'] + | Bindings['readHookCliWriterObservation'] | null declare protected readonly checkHookAgentPresenceFn: HostServices['checkHookAgentPresenceFn'] declare readonly subscribeAgentProviderSessionChangesFn: - | RuntimeConstructionBindings['subscribeAgentProviderSessionChanges'] + | Bindings['subscribeAgentProviderSessionChanges'] | null declare protected readonly reconcileAgentStatusForEndedProcessFn: HostServices['reconcileAgentStatusForEndedProcessFn'] declare protected readonly forgetHookAgentExitFn: HostServices['forgetHookAgentExitFn'] @@ -115,14 +115,14 @@ export abstract class OrcaRuntimeWithStateFields extends OrcaRuntimeWithLinearCo readonly workspaceSleepPlatform: WorkspaceSleepPlatform | null - protected readonly getAgentStatusSnapshotForPaneFn: - | RuntimeConstructionBindings['getAgentStatusSnapshotForPane'] - | null + declare protected readonly getAgentStatusSnapshotForPaneFn: HostServices['getAgentStatusSnapshotForPaneFn'] + + protected readonly publicPaneStatusFn?: Bindings['getPublicAgentStatusSnapshotForPane'] /** The agent's full final reply for that finished lead turn; status rows carry only a capped preview. */ - readonly getAcceptedAgentReply: RuntimeConstructionBindings['getAcceptedAgentReply'] + readonly getAcceptedAgentReply: Bindings['getAcceptedAgentReply'] /** Synchronous on every hook status row change, including clears. */ - readonly subscribeAgentStatusRowChanges: RuntimeConstructionBindings['subscribeAgentStatusRowChanges'] + readonly subscribeAgentStatusRowChanges: Bindings['subscribeAgentStatusRowChanges'] protected readonly machineName = new RuntimeMachineName( () => this.store?.getSettings?.().machineName @@ -253,6 +253,7 @@ export abstract class OrcaRuntimeWithStateFields extends OrcaRuntimeWithLinearCo } this.getAgentStatusSnapshotFn = deps?.getAgentStatusSnapshot ?? null this.getAgentStatusSnapshotForPaneFn = deps?.getAgentStatusSnapshotForPane ?? null + this.publicPaneStatusFn = deps?.getPublicAgentStatusSnapshotForPane this.structuredAgentStatusSinkFn = deps?.structuredAgentStatusSink ?? null this.readObservedAgentStatusPaneIdentityFn = deps?.readObservedAgentStatusPaneIdentity ?? (() => ({ kind: 'unobserved' })) diff --git a/src/main/runtime/construction/runtime-edge-command-controller.ts b/src/main/runtime/construction/runtime-edge-command-controller.ts index 933c812272c..6d6b7fac4ec 100644 --- a/src/main/runtime/construction/runtime-edge-command-controller.ts +++ b/src/main/runtime/construction/runtime-edge-command-controller.ts @@ -47,6 +47,7 @@ const BROWSER_COMMAND_NAMES = [ 'browserProceedCertificate', 'browserTabShow', 'browserTabCurrent', + 'browserTabAnnotations', 'browserTabSwitch', 'browserHover', 'browserDrag', diff --git a/src/main/runtime/construction/runtime-host-services.ts b/src/main/runtime/construction/runtime-host-services.ts index b1515e72345..38403c91120 100644 --- a/src/main/runtime/construction/runtime-host-services.ts +++ b/src/main/runtime/construction/runtime-host-services.ts @@ -1,8 +1,6 @@ import type * as Calls from './runtime-host-service-calls' import type { RuntimeConstructionBindings as HostBindings } from './runtime-construction-dependencies' -import type { RuntimeRepositoryCommandSurface } from '../repositories/runtime-repository-command-surface' - import type { LegacyWorkerRecoveryCandidate } from '../orchestration/terminal-authority/structured-sessions/runtime-legacy-worker-terminal-recovery-types' import type { LegacyWorkerTerminalRecoveryPlan } from '../orchestration/terminal-authority/release/orchestration-legacy-worker-terminal-recovery' @@ -46,8 +44,6 @@ import { teardownFolderWorkspacePtys } from '../workspaces/removal/folder-worksp import { countRepoTerminalsNotKnownExited } from '../workspaces/removal/project-removal-impact' export abstract class OrcaRuntimeWithPreservedBranchCleanup extends OrcaRuntimeWithTerminalDrivers { - declare addRepo: RuntimeRepositoryCommandSurface['addRepo'] - declare cloneRepo: RuntimeRepositoryCommandSurface['cloneRepo'] declare acquireFileWatcherRemoval: ConstructorParameters< typeof RuntimeProjectGroupController >[0]['acquireFileWatcherRemoval'] @@ -279,8 +275,11 @@ export abstract class OrcaRuntimeWithPreservedBranchCleanup extends OrcaRuntimeW protected readonly projectHostSetups = new RuntimeProjectHostSetupController({ getStore: () => this.store, listRepos: () => this.listRepos(), - addRepo: (path, kind, hostId) => this.addRepo(path, kind, hostId), - cloneRepo: (args) => this.cloneRepo(args.url, args.destination, args.hostId, args.folderName), + addRepo: (path, kind, hostId) => this.repositoryRegistrations.add(path, kind, hostId), + cloneRepo: (args) => + this.repositoryClones.clone(args.url, args.destination, args.hostId, args.folderName), + resolveRepositoryMetadata: (repo) => this.repositoryForkBackfill.resolve(repo), + enqueueRepositoryMetadata: (repos) => void this.repositoryForkBackfill.enqueue(repos), invalidateResolvedWorktrees: () => this.invalidateResolvedWorktreeCache(), invalidateWorktreeScan: (repoId) => this.invalidateWorktreeScanCacheForRepo(repoId), notifyReposChanged: () => this.notifyReposChanged(), @@ -353,7 +352,7 @@ export abstract class OrcaRuntimeWithPreservedBranchCleanup extends OrcaRuntimeW protected readonly serverEnvironment = new RuntimeServerEnvironmentCommands() - protected readonly repositoryForkBackfill = new RuntimeRepositoryForkBackfill( + readonly repositoryForkBackfill = new RuntimeRepositoryForkBackfill( () => this.store, () => this.notifyReposChanged() ) diff --git a/src/main/runtime/construction/runtime-store-contract.ts b/src/main/runtime/construction/runtime-store-contract.ts index e65b65778b7..4847daa5909 100644 --- a/src/main/runtime/construction/runtime-store-contract.ts +++ b/src/main/runtime/construction/runtime-store-contract.ts @@ -32,6 +32,7 @@ export type RuntimeStore = { removeProjectForHost?: Store['removeProjectForHost'] reorderRepos?: Store['reorderRepos'] getAllWorktreeMeta: Store['getAllWorktreeMeta'] + getWorkspaceMetadataCursor?: Store['getWorkspaceMetadataCursor'] getAllWorktreeMetaForHost?: Store['getAllWorktreeMetaForHost'] captureNativeLocalWorktreeMetadataScanExpectation?: Store['captureNativeLocalWorktreeMetadataScanExpectation'] pruneSessionlessMissingLocalWorktreeMetadataForRepo?: Store['pruneSessionlessMissingLocalWorktreeMetadataForRepo'] diff --git a/src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-registry.test.ts b/src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-registry.test.ts index cc2170d60e7..4338bf8352b 100644 --- a/src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-registry.test.ts +++ b/src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-registry.test.ts @@ -6,6 +6,28 @@ import { } from './desktop-browser-bridge-registry' import { routeDesktopBrowserBridgeRpc } from './desktop-browser-bridge-route' +describe('tab annotations through the desktop bridge', () => { + it('never sends them to an older desktop, which would drop its whole bridge', async () => { + const registry = new DesktopBrowserBridgeRegistry() + const emit = vi.fn() + registry.attach({ connectionId: 'new', pairedDeviceId: 'd', readsTabAnnotations: true, emit }) + registry.attach({ connectionId: 'old', pairedDeviceId: 'd', emit }) + + await expect( + routeDesktopBrowserBridgeRpc({ + method: 'browser.tabAnnotations', + params: { page: 'page-1' }, + caller: { kind: 'local-cli' }, + hostEnabled: true, + registry, + localBrowserAvailable: false, + resolveWorkspace: async (selector) => ({ id: selector }) + }) + ).rejects.toMatchObject({ code: 'desktop_browser_bridge_not_forwarded' }) + expect(emit).not.toHaveBeenCalled() + }) +}) + describe('--expect-url through the desktop bridge', () => { const route = (registry: DesktopBrowserBridgeRegistry) => routeDesktopBrowserBridgeRpc({ diff --git a/src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-registry.ts b/src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-registry.ts index b0c561e52ef..b297f8e6d2b 100644 --- a/src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-registry.ts +++ b/src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-registry.ts @@ -19,6 +19,7 @@ type Attachment = { pairedDeviceId: string acceptsCancel?: boolean enforcesExpectUrl?: boolean + readsTabAnnotations?: boolean emit: (event: DesktopBrowserBridgeEvent) => void } @@ -57,6 +58,10 @@ export class DesktopBrowserBridgeRegistry { return this.attachments.at(-1)?.enforcesExpectUrl === true } + newestAttachmentReadsTabAnnotations(): boolean { + return this.attachments.at(-1)?.readsTabAnnotations === true + } + forward( request: DesktopBrowserBridgeForward, options: { timeoutMs: number; signal?: AbortSignal } diff --git a/src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-route.ts b/src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-route.ts index ae0f6a6aaa5..2f472b5f36e 100644 --- a/src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-route.ts +++ b/src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-route.ts @@ -75,6 +75,15 @@ export async function routeDesktopBrowserBridgeRpc(options: { 'The Orca desktop sharing its browser cannot check --expect-url. Update Orca on that desktop or drop the flag.' ) } + if ( + forwardedMethod === 'browser.tabAnnotations' && + !options.registry.newestAttachmentReadsTabAnnotations() + ) { + throw new BrowserError( + DESKTOP_BROWSER_BRIDGE_NOT_FORWARDED_CODE, + 'The Orca desktop sharing its browser cannot read tab notes. Update Orca on that desktop.' + ) + } const result = await options.registry.forward( { method: forwardedMethod, params, ...(workspaceId ? { workspaceId } : {}) }, { timeoutMs: forwardTimeoutMs(forwardedMethod, params), signal: options.signal } diff --git a/src/main/runtime/hosts/runtime-status.ts b/src/main/runtime/hosts/runtime-status.ts index 7800d47fea3..73dc3dea758 100644 --- a/src/main/runtime/hosts/runtime-status.ts +++ b/src/main/runtime/hosts/runtime-status.ts @@ -45,7 +45,7 @@ import { TERMINAL_PERSISTENCE_UNAVAILABLE_MESSAGE } from '../../../shared/runtime-capability-degradation' import { MOBILE_WEB_BUNDLE_CAPABILITY } from '../../../shared/mobile-web-bundle/mobile-web-bundle-capability' -import { loadBundledMobileWebBundle } from '../rpc/methods/mobile-delivery/bundled-mobile-web-bundle' +import { getBundledMobileWebBundleRoot } from '../rpc/methods/mobile-delivery/bundled-mobile-web-bundle' import { runtimeTerminalDegradation } from '../terminal/launch/native-terminal-availability' import { isWindowsProcessStartTimeAvailable } from '../../windows/windows-process-table' import { WORKTREE_CREATE_RESULT_TTL_MS } from '../workspaces/creation/worktree-create-idempotency' @@ -120,8 +120,8 @@ export abstract class OrcaRuntimeWithGetStatus extends RuntimeWorkspaceChangeEve capabilities.push(DESKTOP_BROWSER_BRIDGE_RUNTIME_CAPABILITY) } capabilities.push(...darkSwitchRuntimeCapabilities()) - // Dev/serve installs may lack out/mobile-web; never advertise downloads this install cannot produce. - if (loadBundledMobileWebBundle()) { + // Dev/serve installs may lack out/mobile-web; advertise downloads only where the install ships it. + if (getBundledMobileWebBundleRoot()) { capabilities.push(MOBILE_WEB_BUNDLE_CAPABILITY) } // Report the actual failure so operators are not told to fix already-correct configuration. diff --git a/src/main/runtime/mobile-cloud-relay/relay-session-broker.ts b/src/main/runtime/mobile-cloud-relay/relay-session-broker.ts index 78f99af7c05..d7be7f45381 100644 --- a/src/main/runtime/mobile-cloud-relay/relay-session-broker.ts +++ b/src/main/runtime/mobile-cloud-relay/relay-session-broker.ts @@ -19,6 +19,7 @@ import { relayIdentityKey } from './relay-auth-identity' import { RelayOriginPool } from './relay-origin-pool' import { RelayRegionRefresh } from './relay-region-refresh' import { relayRenewalDelayMs } from './relay-renewal-jitter' +import { RelayWallClockTimer } from './relay-wall-clock-timer' export class RelaySessionBroker { private readonly options: RelaySessionBrokerOptions @@ -26,11 +27,12 @@ export class RelaySessionBroker { private readonly originPool: RelayOriginPool private readonly regionRefresh: RelayRegionRefresh | null private authorization: RelayAuthorization | null = null - private refreshTimer: ReturnType | null = null + private readonly refreshTimer: RelayWallClockTimer private closed = false private constructor(options: RelaySessionBrokerOptions) { this.options = options + this.refreshTimer = new RelayWallClockTimer(options.now) this.relayHostId = deriveRelayHostId(options.keypair.publicKey) this.originPool = new RelayOriginPool({ directorUrl: options.authConfig.relayDirectorUrl, @@ -199,10 +201,7 @@ export class RelaySessionBroker { } const publishOffline = this.options.isCurrent() this.closed = true - if (this.refreshTimer) { - clearTimeout(this.refreshTimer) - this.refreshTimer = null - } + this.refreshTimer.cancel() this.originPool.closeNow(hostCloseReason) this.regionRefresh?.close() if (publishOffline) { @@ -259,11 +258,10 @@ export class RelaySessionBroker { const now = (this.options.now ?? Date.now)() const random = this.options.random ?? Math.random const delay = relayRenewalDelayMs(authorization.expiresAt, now, random) - this.refreshTimer = setTimeout(() => void this.refreshAuthorization(), delay) + this.refreshTimer.schedule(delay, () => void this.refreshAuthorization()) } private async refreshAuthorization(): Promise { - this.refreshTimer = null try { const refresh = await this.options.refreshAccessToken() this.assertCurrent() @@ -287,9 +285,9 @@ export class RelaySessionBroker { const now = (this.options.now ?? Date.now)() if (!this.closed && this.options.isCurrent() && now <= expiry + 60_000) { const random = this.options.random ?? Math.random - this.refreshTimer = setTimeout( - () => void this.refreshAuthorization(), - 5_000 + Math.floor(random() * 10_001) + this.refreshTimer.schedule( + 5_000 + Math.floor(random() * 10_001), + () => void this.refreshAuthorization() ) return } diff --git a/src/main/runtime/mobile-cloud-relay/relay-wall-clock-timer.test.ts b/src/main/runtime/mobile-cloud-relay/relay-wall-clock-timer.test.ts new file mode 100644 index 00000000000..a5461458549 --- /dev/null +++ b/src/main/runtime/mobile-cloud-relay/relay-wall-clock-timer.test.ts @@ -0,0 +1,45 @@ +import { afterEach, describe, expect, it, vi } from 'vitest' +import { RelayWallClockTimer } from './relay-wall-clock-timer' + +function resumeSource(): { + subscribe: (onResume: () => void) => () => void + resume: () => void + count: () => number +} { + const listeners = new Set<() => void>() + return { + subscribe: (onResume) => { + listeners.add(onResume) + onResume() + return () => listeners.delete(onResume) + }, + resume: () => { + for (const listener of Array.from(listeners)) { + listener() + } + }, + count: () => listeners.size + } +} + +describe('RelayWallClockTimer', () => { + afterEach(() => { + vi.useRealTimers() + }) + + it('runs a task that fell due during a sleep as soon as the machine resumes', () => { + vi.useFakeTimers() + let wall = 1_000_000 + const source = resumeSource() + const timer = new RelayWallClockTimer(() => wall, source.subscribe) + const task = vi.fn() + timer.schedule(180_000, task) + // Asleep: the wall clock moves, the timer clock does not. + wall += 200_000 + source.resume() + expect(task).toHaveBeenCalledTimes(1) + vi.advanceTimersByTime(180_000) + expect(task).toHaveBeenCalledTimes(1) + expect(source.count()).toBe(0) + }) +}) diff --git a/src/main/runtime/mobile-cloud-relay/relay-wall-clock-timer.ts b/src/main/runtime/mobile-cloud-relay/relay-wall-clock-timer.ts new file mode 100644 index 00000000000..da84d170f86 --- /dev/null +++ b/src/main/runtime/mobile-cloud-relay/relay-wall-clock-timer.ts @@ -0,0 +1,68 @@ +import { subscribeSystemPowerLifecycle } from '../../power/system-power-lifecycle' + +type SubscribeResume = (onResume: () => void) => () => void + +const subscribeResume: SubscribeResume = (onResume) => + subscribeSystemPowerLifecycle({ onSuspend: () => {}, onResume }) + +// A one-shot timer due at a wall-clock time. Node timers run on a clock that stops while the +// machine sleeps, so a relay token renewal due during a sleep would fire that much later after +// wake, after the token's wall-clock expiry: the relay then closes the still-live control 4401. +// On resume, a task already due runs at once; one not yet due is re-armed from the wall clock. +export class RelayWallClockTimer { + private timer: ReturnType | null = null + private unsubscribe: (() => void) | null = null + private dueAt = 0 + private task: (() => void) | null = null + + constructor( + private readonly now: () => number = Date.now, + private readonly onResume: SubscribeResume = subscribeResume + ) {} + + schedule(delayMs: number, task: () => void): void { + this.cancel() + this.dueAt = this.now() + delayMs + this.task = task + this.arm(delayMs) + // The lifecycle reports the current state on subscribe; only later resumes count. On each + // resume a due task runs, and one not yet due is re-armed for the time left on the wall clock + // (the timer clock lost the whole sleep). + let subscribed = false + this.unsubscribe = this.onResume(() => { + if (!subscribed || this.task !== task) { + return + } + const left = this.dueAt - this.now() + if (left <= 0) { + this.fire() + } else { + this.arm(left) + } + }) + subscribed = true + } + + cancel(): void { + if (this.timer) { + clearTimeout(this.timer) + this.timer = null + } + this.unsubscribe?.() + this.unsubscribe = null + this.task = null + } + + private arm(delayMs: number): void { + if (this.timer) { + clearTimeout(this.timer) + } + this.timer = setTimeout(() => this.fire(), delayMs) + } + + private fire(): void { + const task = this.task + this.cancel() + task?.() + } +} diff --git a/src/main/runtime/orca-runtime-tests/orca-runtime-test-scenario-builders.spec.ts b/src/main/runtime/orca-runtime-tests/orca-runtime-test-scenario-builders.spec.ts index 0054a769df0..2bab325844f 100644 --- a/src/main/runtime/orca-runtime-tests/orca-runtime-test-scenario-builders.spec.ts +++ b/src/main/runtime/orca-runtime-tests/orca-runtime-test-scenario-builders.spec.ts @@ -218,6 +218,7 @@ function makePostRevealWorkerRecoveryHarness( // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: This recovery fixture reaches only the listed planner, terminal settlement and authority lookup methods. runtime.setOrchestrationDb({ crewChanges: new CrewChanges(), + hasAnyDispatchContexts: () => true, listSessionDispatchesForPresentation: () => [], reconcileMissingWorkerTerminal: vi.fn(), getActiveDispatchForTerminal: () => undefined, diff --git a/src/main/runtime/orca-runtime-tests/project-setup-folder-remote-identity.spec.ts b/src/main/runtime/orca-runtime-tests/project-setup-folder-remote-identity.spec.ts index a141ece1665..6251a4fca06 100644 --- a/src/main/runtime/orca-runtime-tests/project-setup-folder-remote-identity.spec.ts +++ b/src/main/runtime/orca-runtime-tests/project-setup-folder-remote-identity.spec.ts @@ -1,9 +1,9 @@ import { realpathSync } from 'node:fs' -import { describe, expect, it } from 'vitest' +import { beforeEach, describe, expect, it, vi } from 'vitest' import './runtime-test-module-registration.spec' import { OrcaRuntimeService } from '../orca-runtime' import { execFileSync } from 'node:child_process' -import { getRepoUpstreamMock } from '../orca-runtime-test-mocks/setup.spec' +import * as forkMetadata from '../../github/client/fetch/repo-slug-upstream' import { join } from 'node:path' import { mkdtemp, rm } from 'node:fs/promises' import { projectHostSetupProjectionFromRepos } from '../../../shared/project-host-setup-projection' @@ -12,6 +12,11 @@ import { store } from './orca-runtime-test-fixtures.spec' import type { Repo } from '../../../shared/repo-types' import type { RuntimeStore } from '../construction/runtime-store-contract' +const parentProbe = vi.spyOn(forkMetadata, 'probeRepoUpstream') +beforeEach(() => { + parentProbe.mockReset().mockResolvedValue({ upstream: undefined, origin: null }) +}) + function createRuntime(repos: Repo[]): OrcaRuntimeService { const runtimeStore: RuntimeStore = { ...store, @@ -61,7 +66,6 @@ const repoA = { provider: 'github' as const, owner: 'acme', repo: 'repo-a' } describe('OrcaRuntimeService project setup of an existing folder (#30663)', () => { it('refuses to relabel a folder whose own GitHub remote names another repository', async () => { const repos: Repo[] = [] - getRepoUpstreamMock.mockResolvedValueOnce(null) const runtime = createRuntime(repos) await withGitFolder({ origin: 'https://github.com/acme/repo-b.git' }, async (path) => { @@ -118,3 +122,447 @@ describe('OrcaRuntimeService project setup of an existing folder (#30663)', () = ) }) }) + +describe('explicit fork project setup with deferred ordinary metadata', () => { + it.each([ + ['git@gh-personal:me/repo-a.git', 'github:me/repo-a', undefined, null], + [ + 'https://code.corp.example/me/repo-a.git', + 'github:code.corp.example/me/repo-a', + 'code.corp.example', + undefined + ] + ] as const)( + 'keeps a resolved origin nonfork through setup when its local hostname needs resolution: %s', + async (url, projectId, host, upstream) => { + const repos: Repo[] = [] + const origin = { owner: 'me', repo: 'repo-a', ...(host ? { host } : {}) } + parentProbe.mockResolvedValue({ upstream, origin }) + const runtime = createRuntime(repos) + await withGitFolder({ origin: url }, async (path) => { + const result = await runtime.setupProjectExistingFolder({ + projectId, + projectProviderIdentity: { provider: 'github', ...origin }, + hostId: 'runtime:env-1', + path, + kind: 'git' + }) + expect(result.project.id).toBe(projectId) + expect(result.repo.upstream).toBeNull() + expect( + projectHostSetupProjectionFromRepos(JSON.parse(JSON.stringify(repos))).setups[0].projectId + ).toBe(projectId) + expect(parentProbe).toHaveBeenCalledTimes(1) + }) + } + ) + + it.each([ + ['github:acme/repo-a', { owner: 'acme', repo: 'repo-a' }], + ['github:me/repo-a', { owner: 'me', repo: 'repo-a' }] + ] as const)( + 'preserves selected project %s when a hosted parent is known', + async (projectId, upstream) => { + const repos: Repo[] = [] + parentProbe.mockResolvedValue({ + upstream: { owner: 'acme', repo: 'repo-a' }, + origin: { owner: 'me', repo: 'repo-a' } + }) + const runtime = createRuntime(repos) + await withGitFolder({ origin: 'https://github.com/me/repo-a.git' }, async (path) => { + const result = await runtime.setupProjectExistingFolder({ + projectId, + projectProviderIdentity: { provider: 'github', ...upstream }, + hostId: 'runtime:env-1', + path, + kind: 'git' + }) + expect(result.project.id).toBe(projectId) + expect(result.repo.upstream).toEqual(upstream) + expect( + projectHostSetupProjectionFromRepos(JSON.parse(JSON.stringify(repos))).setups[0].projectId + ).toBe(projectId) + expect(parentProbe).toHaveBeenCalledTimes(1) + }) + } + ) + + it.each([null, undefined])( + 'keeps a matching origin nonfork when parent evidence is %s', + async (upstream) => { + const repos: Repo[] = [] + parentProbe.mockResolvedValue({ upstream, origin: { owner: 'me', repo: 'repo-a' } }) + const runtime = createRuntime(repos) + await withGitFolder({ origin: 'https://github.com/me/repo-a.git' }, async (path) => { + const result = await runtime.setupProjectExistingFolder({ + projectId: 'github:me/repo-a', + projectProviderIdentity: { provider: 'github', owner: 'me', repo: 'repo-a' }, + hostId: 'runtime:env-1', + path, + kind: 'git' + }) + expect(result.project.id).toBe('github:me/repo-a') + expect(result.repo.upstream).toBeNull() + expect( + projectHostSetupProjectionFromRepos(JSON.parse(JSON.stringify(repos))).setups[0].projectId + ).toBe('github:me/repo-a') + expect(parentProbe).toHaveBeenCalledTimes(1) + const again = await runtime.setupProjectExistingFolder({ + projectId: 'github:me/repo-a', + projectProviderIdentity: { provider: 'github', owner: 'me', repo: 'repo-a' }, + hostId: 'runtime:env-1', + path, + kind: 'git' + }) + expect(again.repo.upstream).toBeNull() + expect(parentProbe).toHaveBeenCalledTimes(1) + }) + } + ) +}) + +it('completes parent-selected setup while unrelated background metadata remains pending', async () => { + await withGitFolder({ origin: 'https://github.com/me/repo-a.git' }, async (path) => { + const repos: Repo[] = [ + { + id: 'blocker', + path: '/blocked', + displayName: 'blocker', + badgeColor: 'blue', + addedAt: 1, + kind: 'git' + } + ] + const runtime = createRuntime(repos) + const gate = Promise.withResolvers() + parentProbe + .mockImplementationOnce(() => gate.promise) + .mockResolvedValue({ + upstream: { owner: 'acme', repo: 'repo-a' }, + origin: { owner: 'me', repo: 'repo-a' } + }) + const background = runtime.repositoryForkBackfill.enqueue(repos) + try { + const result = await runtime.setupProjectExistingFolder({ + projectId: 'github:acme/repo-a', + projectProviderIdentity: repoA, + hostId: 'runtime:env-1', + path, + kind: 'git' + }) + expect(result.project.id).toBe('github:acme/repo-a') + expect(repos[0].upstream).toBeUndefined() + expect(parentProbe).toHaveBeenCalledTimes(2) + } finally { + gate.resolve({ upstream: null, origin: null }) + await background + } + }) +}) + +it.each([false, true])( + 'refuses changed current origin after an unavailable lookup (pre-existing=%s)', + async (existing) => { + await withGitFolder({ origin: 'https://github.com/me/repo-a.git' }, async (path) => { + const repos: Repo[] = [] + if (existing) { + repos.push({ + id: 'selected', + path: realpathSync(path), + displayName: 'repo-a', + badgeColor: 'blue', + addedAt: 1, + kind: 'git', + executionHostId: 'runtime:env-1', + gitRemoteIdentity: { + canonicalKey: 'github.com/me/repo-a', + remoteName: 'origin', + remoteUrl: 'https://github.com/me/repo-a.git' + } + }) + } + const runtime = createRuntime(repos) + const gate = Promise.withResolvers() + const started = Promise.withResolvers() + parentProbe.mockImplementationOnce(() => { + started.resolve() + return gate.promise + }) + const setup = runtime.setupProjectExistingFolder({ + projectId: 'github:me/repo-a', + projectProviderIdentity: { provider: 'github', owner: 'me', repo: 'repo-a' }, + hostId: 'runtime:env-1', + path, + kind: 'git' + }) + const rejection = expect(setup).rejects.toThrow(/points at other\/repo-a, not me\/repo-a/) + await started.promise + execFileSync('git', ['remote', 'set-url', 'origin', 'https://github.com/other/repo-a.git'], { + cwd: path, + stdio: 'ignore' + }) + gate.resolve({ upstream: undefined, origin: { owner: 'me', repo: 'repo-a' } }) + await rejection + expect(repos).toHaveLength(existing ? 1 : 0) + expect(parentProbe).toHaveBeenCalledTimes(1) + }) + } +) + +it.each([ + [ + 'older automatic avatar', + { + type: 'image', + source: 'github', + src: 'https://ghe.corp.example/old.png?size=64', + label: 'old/repo-a' + }, + { host: 'ghe.corp.example', owner: 'new', repo: 'repo-a' } + ], + [ + 'protected image', + { + type: 'image', + source: 'file', + src: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=' + }, + null + ] +] as const)( + 'links a current enterprise remote despite unavailable metadata and a retained %s', + async (_label, repoIcon, upstream) => { + await withGitFolder({ origin: 'https://ghe.corp.example/new/repo-a.git' }, async (path) => { + const repos: Repo[] = [ + { + id: 'selected', + path: realpathSync(path), + displayName: 'repo-a', + badgeColor: 'blue', + addedAt: 1, + kind: 'git', + executionHostId: 'runtime:env-1', + gitRemoteIdentity: { + canonicalKey: 'ghe.corp.example/old/repo-a', + remoteName: 'origin', + remoteUrl: 'https://ghe.corp.example/old/repo-a.git' + }, + repoIcon + } + ] + const runtime = createRuntime(repos) + const result = await runtime.setupProjectExistingFolder({ + projectId: 'github:ghe.corp.example/new/repo-a', + projectProviderIdentity: { + provider: 'github', + host: 'ghe.corp.example', + owner: 'new', + repo: 'repo-a' + }, + hostId: 'runtime:env-1', + path, + kind: 'git' + }) + expect(result.project.id).toBe('github:ghe.corp.example/new/repo-a') + expect(repos[0].upstream).toEqual(upstream) + expect(repos[0].repoIcon).toEqual(repoIcon) + expect( + projectHostSetupProjectionFromRepos(JSON.parse(JSON.stringify(repos))).setups[0].projectId + ).toBe('github:ghe.corp.example/new/repo-a') + }) + } +) + +it('retains matching null authority when a nonfork result settles during setup', async () => { + await withGitFolder({ origin: 'https://github.com/me/repo-a.git' }, async (path) => { + const repos: Repo[] = [] + const runtime = createRuntime(repos) + const gate = Promise.withResolvers() + const started = Promise.withResolvers() + parentProbe.mockImplementationOnce(() => { + started.resolve() + return gate.promise + }) + const setup = runtime.setupProjectExistingFolder({ + projectId: 'github:me/repo-a', + projectProviderIdentity: { provider: 'github', owner: 'me', repo: 'repo-a' }, + hostId: 'runtime:env-1', + path, + kind: 'git' + }) + await started.promise + execFileSync('git', ['remote', 'set-url', 'origin', 'https://github.com/other/repo-a.git'], { + cwd: path, + stdio: 'ignore' + }) + gate.resolve({ upstream: null, origin: { owner: 'me', repo: 'repo-a' } }) + const result = await setup + expect(result.project.id).toBe('github:me/repo-a') + expect(result.repo.upstream).toBeNull() + expect( + projectHostSetupProjectionFromRepos(JSON.parse(JSON.stringify(repos))).setups[0].projectId + ).toBe('github:me/repo-a') + }) +}) + +it('publishes metadata retained on a pre-existing row after explicit setup fails', async () => { + await withGitFolder({ origin: 'https://github.com/me/repo-a.git' }, async (path) => { + const repos: Repo[] = [ + { + id: 'selected', + path: realpathSync(path), + displayName: 'repo-a', + badgeColor: 'blue', + addedAt: 1, + kind: 'git', + executionHostId: 'runtime:env-1' + } + ] + const runtime = createRuntime(repos) + parentProbe.mockResolvedValue({ + upstream: { owner: 'acme', repo: 'repo-a' }, + origin: { owner: 'me', repo: 'repo-a' } + }) + const notifications: string[] = [] + const unsubscribe = runtime.onClientEvent((event) => { + if (event.type === 'reposChanged') { + notifications.push(event.type) + } + }) + try { + await expect( + runtime.setupProjectExistingFolder({ + projectId: 'github:elsewhere/repo-a', + projectProviderIdentity: { provider: 'github', owner: 'elsewhere', repo: 'repo-a' }, + hostId: 'runtime:env-1', + path, + kind: 'git' + }) + ).rejects.toThrow(/points at me\/repo-a, not elsewhere\/repo-a/) + expect(repos).toHaveLength(1) + expect(repos[0].upstream).toEqual({ owner: 'acme', repo: 'repo-a' }) + expect(notifications).toEqual(['reposChanged']) + expect(parentProbe).toHaveBeenCalledTimes(1) + } finally { + unsubscribe() + } + }) +}) + +it.each(['recovered parent', 'unavailable'] as const)( + 'settles an explicit origin after ordinary alias enrichment: %s', + async (evidence) => { + await withGitFolder({ origin: 'git@gh-personal:me/repo-a.git' }, async (path) => { + const repos: Repo[] = [] + const runtime = createRuntime(repos) + const origin = { owner: 'me', repo: 'repo-a' } + const ordinary = Promise.withResolvers() + const ordinaryStarted = Promise.withResolvers() + const ordinaryFinished = Promise.withResolvers() + const required = Promise.withResolvers() + const requiredStarted = Promise.withResolvers() + parentProbe + .mockImplementationOnce(() => { + ordinaryStarted.resolve() + return ordinary.promise + }) + .mockImplementationOnce(() => { + requiredStarted.resolve() + return required.promise + }) + const unsubscribe = runtime.onClientEvent((event) => { + if (event.type === 'reposChanged' && repos[0]?.repoIcon?.type === 'image') { + ordinaryFinished.resolve() + } + }) + try { + const added = await runtime.addRepo(path, 'git', 'runtime:env-1') + await ordinaryStarted.promise + ordinary.resolve({ upstream: undefined, origin }) + await ordinaryFinished.promise + expect(added.id).toBe(repos[0].id) + expect(repos[0].gitRemoteIdentity).toEqual({ + canonicalKey: 'gh-personal/me/repo-a', + remoteName: 'origin', + remoteUrl: 'git@gh-personal:me/repo-a.git' + }) + expect(repos[0].repoIcon).toEqual({ + type: 'image', + source: 'github', + src: 'https://github.com/me.png?size=64', + label: 'me/repo-a' + }) + expect(repos[0].upstream).toBeUndefined() + + const setup = runtime.setupProjectExistingFolder({ + projectId: 'github:me/repo-a', + projectProviderIdentity: { provider: 'github', ...origin }, + hostId: 'runtime:env-1', + path, + kind: 'git' + }) + await requiredStarted.promise + const completion = runtime.repositoryForkBackfill.resolve(repos[0]) + required.resolve({ + upstream: evidence === 'recovered parent' ? { owner: 'acme', repo: 'repo-a' } : undefined, + origin + }) + const result = await setup + await completion + expect(result.project.id).toBe('github:me/repo-a') + expect(result.repo.upstream).toEqual(evidence === 'recovered parent' ? origin : null) + parentProbe.mockResolvedValue({ upstream: { owner: 'acme', repo: 'repo-a' }, origin }) + await runtime.repositoryForkBackfill.run() + expect(repos[0].upstream).toEqual(evidence === 'recovered parent' ? origin : null) + expect( + projectHostSetupProjectionFromRepos(JSON.parse(JSON.stringify(repos))).setups[0].projectId + ).toBe('github:me/repo-a') + } finally { + ordinary.resolve({ upstream: undefined, origin }) + required.resolve({ upstream: undefined, origin }) + unsubscribe() + } + }) + } +) + +it('accepts remote-less saved-avatar equality without a required probe or new stamp', async () => { + await withGitFolder({}, async (path) => { + const repos: Repo[] = [ + { + id: 'legacy', + path: realpathSync(path), + displayName: 'repo-a', + badgeColor: 'blue', + addedAt: 1, + kind: 'git', + executionHostId: 'runtime:env-1', + repoIcon: { + type: 'image', + source: 'github', + src: 'https://github.com/me.png?size=64', + label: 'me/repo-a' + } + } + ] + const runtime = createRuntime(repos) + const background = Promise.withResolvers() + parentProbe.mockImplementationOnce(() => background.promise) + try { + const result = await runtime.setupProjectExistingFolder({ + projectId: 'github:me/repo-a', + projectProviderIdentity: { provider: 'github', owner: 'me', repo: 'repo-a' }, + hostId: 'runtime:env-1', + path, + kind: 'git' + }) + expect(result.project.id).toBe('github:me/repo-a') + expect(result.repo.upstream).toBeUndefined() + } finally { + const completion = runtime.repositoryForkBackfill.resolve(repos[0]) + background.resolve({ upstream: undefined, origin: null }) + await completion + } + expect(repos[0].upstream).toBeUndefined() + }) +}) diff --git a/src/main/runtime/orca-runtime-tests/worker-recovery-releases-conversation.test.ts b/src/main/runtime/orca-runtime-tests/worker-recovery-releases-conversation.test.ts new file mode 100644 index 00000000000..eb2bdf71f46 --- /dev/null +++ b/src/main/runtime/orca-runtime-tests/worker-recovery-releases-conversation.test.ts @@ -0,0 +1,94 @@ +import { describe, expect, it, vi } from 'vitest' +import './runtime-test-module-registration.spec' +import './orca-runtime-test-lifecycle.spec' +import { OrcaRuntimeService } from '../orca-runtime' +import { OrchestrationDb } from '../orchestration/db/orchestration-db' +import { withDurableRuntimeStore } from './runtime-durable-store-fixture' +import { + TEST_WORKTREE_ID, + makeRuntimeStoreWithWorkspaceSession, + makeWorkspaceSessionWithHeadlessTerminal +} from './orca-runtime-test-fixtures.spec' +import type { AgentStatusIpcPayload } from '../../../shared/agent-status/contracts/agent-status-ipc-payload' + +const SESSION = { key: 'session_id', id: 'grok-session-1' } as const +const DEAD_PANE_KEY = 'crashed-reopen-tab:44444444-4444-4444-8444-444444444444' + +describe('worker terminal recovery after a crash', () => { + it('lets the conversation of a worker whose terminal died with Orca be reopened', async () => { + // A restored hook row from before the crash; this agent reports no process to probe. + const hookRows = new Map([ + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the resume guards read only paneKey, providerSession and the observation clocks. + [DEAD_PANE_KEY, { paneKey: DEAD_PANE_KEY, providerSession: SESSION, receivedAt: 1 } as never] + ]) + const { runtimeStore } = makeRuntimeStoreWithWorkspaceSession( + makeWorkspaceSessionWithHeadlessTerminal() + ) + const runtime = new OrcaRuntimeService( + withDurableRuntimeStore({ ...runtimeStore, flushOrThrow: vi.fn() }), + undefined, + { + canRecoverPersistentLocalPtys: () => true, + getDesktopWindowStatus: () => 'openable', + getAgentProviderSessionSnapshot: () => [...hookRows.values()], + checkHookAgentPresence: async () => null, + reconcileAgentStatusForEndedProcess: (paneKeys) => { + for (const paneKey of paneKeys) { + hookRows.delete(paneKey) + } + } + } + ) + const db = new OrchestrationDb(':memory:') + try { + const run = db.createRun({ + objective: 'crash', + coordinatorHandle: 'term_coordinator', + coordinatorPaneKey: 'tab_c:leaf_c' + }) + const task = db.createTask({ spec: 'follow up', runId: run.id }) + const started = db.createStartingWorkerDispatch({ + creator: { kind: 'system' }, + maxDepth: Number.MAX_SAFE_INTEGER, + taskId: task.id, + startOptions: { topology: 'current', agent: 'grok' } + }) + db.prepareStartingWorkerAuthority({ + dispatchId: started.dispatch.id, + handle: 'term_crashed_reopen', + paneKey: DEAD_PANE_KEY, + processIncarnation: 'pty-crashed:55555555-5555-4555-8555-555555555555', + worktreeId: TEST_WORKTREE_ID, + setupState: 'not_applicable', + effects: [] + }) + db.markWorkerDispatchReady(started.dispatch.id) + runtime.setOrchestrationDb(db) + runtime.setPtyController({ + spawn: vi.fn(async () => ({ id: 'resumed-pty' })), + write: () => true, + kill: () => true, + getForegroundProcess: async () => null, + hasPty: () => false, + listProcesses: async () => [] + }) + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: recovery calls only this notifier method. + runtime.setNotifier({ resolveLegacyWorkerTerminalRecovery: vi.fn() } as never) + + await expect(runtime.reconcileLegacyWorkerTerminals()).resolves.toMatchObject({ + exitedDispatchIds: [started.dispatch.id] + }) + + await expect( + runtime.resumeAgentSessionInWorkspace(TEST_WORKTREE_ID, { + agent: 'grok', + providerSession: SESSION, + captureHostId: 'local', + mutationId: 'next-follow-up' + }) + ).resolves.toMatchObject({ ok: true }) + } finally { + db.close() + } + }) +}) diff --git a/src/main/runtime/orca-runtime.ts b/src/main/runtime/orca-runtime.ts index aeebd8bad02..456f346a079 100644 --- a/src/main/runtime/orca-runtime.ts +++ b/src/main/runtime/orca-runtime.ts @@ -62,6 +62,7 @@ import { getHostDisplayLabelOverrides } from '../../shared/host-setting-override import type { OrchestrationDb } from './orchestration/db/orchestration-db' import { continueRestoredWorkerMailSoon } from './rpc/methods/orchestration/messaging/settled-worker-follow-through' import { PeerMailRelay } from './orchestration/federation/peer-mail/peer-mail-relay' +import { structuredAgentSessionHostTabId } from '../../shared/agent-session/view/structured-agent-session-host-tab-id' const OrcaRuntimeSidebarBase: typeof OrcaRuntimeWithAgentTransitions = ORCA_SIDEBAR_INPUTS_IS_MAIN ? OrcaRuntimeWithSidebarTemporal @@ -222,6 +223,13 @@ class OrcaRuntimeService extends OrcaRuntimeSidebarBase { return this.notifier.publishAgentLaunchTab(request) } + /** The window follows a listed active chat only on its own intent (#5435), so a focused launch names it. */ + focusLaunchedChatInHostWindow(worktreeId: string, sessionId: string): void { + this.notifier?.focusEditorTab?.(structuredAgentSessionHostTabId(sessionId), worktreeId, { + userInitiated: true + }) + } + /** Retain final verdicts, clear settled ones, and remove withdrawn panes without removing split siblings. */ reportAgentLaunchPaneVerdict( pane: AgentLaunchPaneAddress, diff --git a/src/main/runtime/orchestration/addressing/orchestration-caller-identity.ts b/src/main/runtime/orchestration/addressing/orchestration-caller-identity.ts index 5d5c12dd857..232428348e0 100644 --- a/src/main/runtime/orchestration/addressing/orchestration-caller-identity.ts +++ b/src/main/runtime/orchestration/addressing/orchestration-caller-identity.ts @@ -1,4 +1,5 @@ import type { RunRow } from '../db/orchestration-records' +import type { PeerRunRow } from '../db/peer-runs/peer-run-store' import { isEquivalentPaneKey } from '../db/pane-key-match' import { currentRunCoordinatorOrcaSessionId } from '../db/runs/run-coordinator-orca-session' import { @@ -16,6 +17,7 @@ export type OrchestrationCoordinatorKey = Pick< /** A caller the dispatch entry resolved from the Orca session id in its injected environment. */ export type OrchestrationSessionCaller = OrchestrationCallerIdentity & Readonly<{ + kind?: undefined orcaSessionId: OrcaSessionId /** The session record the request came from. */ sessionId: OrcaSessionId @@ -23,6 +25,50 @@ export type OrchestrationSessionCaller = OrchestrationCallerIdentity & workspaceId: string }> +/** A paired Orca acting as the coordinator of its Run here, as its authenticated frame names it. + * Its handle and binding key are its address, which no terminal or session here can have. */ +export type OrchestrationPeerCaller = OrchestrationCallerIdentity & + Readonly<{ + kind: 'peer' + terminalHandle: string + paneKey: string + orcaSessionId: null + peerRun: PeerRunRow + }> + +/** The caller the dispatch entry resolved, which wins over any declared handle: a session from + * its environment, or a paired Orca from its pairing. */ +export type OrchestrationEntryCaller = OrchestrationSessionCaller | OrchestrationPeerCaller + +/** The address, and Run binding key, of the paired Orca coordinating a conversation's Run here. */ +export function peerCoordinatorAddress(conversationId: string): string { + return `${PEER_ADDRESS_PREFIX}${conversationId}` +} + +const PEER_ADDRESS_PREFIX = 'peer:' + +export function isPeerCoordinatorAddress(value: string | null | undefined): boolean { + return !!value?.startsWith(PEER_ADDRESS_PREFIX) +} + +export function peerCoordinatorCaller(peerRun: PeerRunRow): OrchestrationPeerCaller { + const address = peerCoordinatorAddress(peerRun.conversation_id) + return Object.freeze({ + kind: 'peer', + address, + terminalHandle: address, + paneKey: address, + orcaSessionId: null, + peerRun + }) +} + +export function isPeerCaller( + caller: OrchestrationCallerIdentity | null | undefined +): caller is OrchestrationPeerCaller { + return !!caller && 'kind' in caller && caller.kind === 'peer' +} + /** A caller with neither a pane nor an Orca session id can never be bound to a Run. */ export function hasRunBindingKey(caller: OrchestrationCoordinatorKey): boolean { return caller.paneKey !== null || caller.orcaSessionId !== null diff --git a/src/main/runtime/orchestration/addressing/orchestration-fleet-agent-status-snapshot.ts b/src/main/runtime/orchestration/addressing/orchestration-fleet-agent-status-snapshot.ts index 946aab137ce..8b04deb002d 100644 --- a/src/main/runtime/orchestration/addressing/orchestration-fleet-agent-status-snapshot.ts +++ b/src/main/runtime/orchestration/addressing/orchestration-fleet-agent-status-snapshot.ts @@ -1,3 +1,4 @@ +import { orchestrationProjectionFacts } from '../crew/orchestration-projection-facts' import type { TerminalIdentityReadContext } from '../../terminal/query/terminal-identity-read-context' import { conversationRecordReader } from './session-lineage/structured-session-lineage' import { getStructuredAgentSessionHost } from '../../../native-chat/agent-session-wire/host/structured-agent-session-registry' @@ -39,17 +40,22 @@ export function readCapturedOrchestrationFleetAgentStatusSnapshot( dependencies: RuntimeAgentOrchestrationDependencies ): readonly FleetAgentStatusEvidence[] { const projection = new RuntimeAgentOrchestrationProjection(dependencies) + const raw = dependencies.getDb() + const sourceFacts = raw?.db ? orchestrationProjectionFacts(raw) : undefined + const db = sourceFacts?.view ?? raw let scope: ReturnType | undefined return readOrchestrationFleetAgentStatusSnapshot({ ...source, getAgentStatusOrchestrationContextForPaneKey: (paneKey) => { + if (raw?.db && !sourceFacts) { + return undefined + } const handle = source.getAgentStatusTerminalHandleForPaneKey?.(paneKey) if (!handle) { return undefined } - const db = dependencies.getDb() scope ??= createOrchestrationProjectionScope(db, dependencies) - return projection.getForHandle(handle, db, { paneKey }, scope) + return projection.getForHandle(handle, db, { paneKey, deferAttention: true }, scope) } }) } diff --git a/src/main/runtime/orchestration/crew/crew-host-derivation.ts b/src/main/runtime/orchestration/crew/crew-host-derivation.ts index a7e24cc5b20..e42c44f6d4c 100644 --- a/src/main/runtime/orchestration/crew/crew-host-derivation.ts +++ b/src/main/runtime/orchestration/crew/crew-host-derivation.ts @@ -9,12 +9,10 @@ import { readCrewAssignments, type CrewAssignmentRow } from './crew-query' import { createCrewSourceInputs } from './crew-source-inputs' import type { CrewReadDependencies } from './crew-read-dependencies' -export function createCrewHostDerivation( - deps: CrewReadDependencies, - now: number, - capacity?: () => number -) { +export function createCrewHostDerivation(deps: CrewReadDependencies, capacity?: () => number) { const { statuses, ...sources } = captureCrewIdentityInputs(deps) + // Reading statuses can refresh the same source; capture its cutoff afterwards. + const now = deps.now ?? Date.now() const registry = createCrewPartyRegistry({ ...sources, statuses }) const { alias } = registry const identity = deps.openIdentityRead?.() diff --git a/src/main/runtime/orchestration/crew/crew-party-snapshot.ts b/src/main/runtime/orchestration/crew/crew-party-snapshot.ts index 5138af1f54a..a29e6e4aaa2 100644 --- a/src/main/runtime/orchestration/crew/crew-party-snapshot.ts +++ b/src/main/runtime/orchestration/crew/crew-party-snapshot.ts @@ -39,7 +39,7 @@ function preview(body: string): string { export function buildCrewSnapshot( address: string, deps: CrewReadDependencies, - host = createCrewHostDerivation(deps, deps.now ?? Date.now()) + host = createCrewHostDerivation(deps) ): OrchestrationCrewSnapshot { deps = { ...host.deps, now: deps.now } const db = deps.db diff --git a/src/main/runtime/orchestration/crew/crew-read-model.ts b/src/main/runtime/orchestration/crew/crew-read-model.ts index 34ca2b7a173..f861a2becb9 100644 --- a/src/main/runtime/orchestration/crew/crew-read-model.ts +++ b/src/main/runtime/orchestration/crew/crew-read-model.ts @@ -86,9 +86,7 @@ export class CrewReadModel { deps = { ...deps, records: previous.deps.records } } // A one-shot read has no watch to keep captured truth current. - const host = createCrewHostDerivation(deps, deps.now ?? now, () => - Math.max(32, this.listeners.size * 2) - ) + const host = createCrewHostDerivation(deps, () => Math.max(32, this.listeners.size * 2)) if (this.listeners.size === 0) { return buildCrewSnapshot(address, { ...host.deps, now }, host) } @@ -104,10 +102,8 @@ export class CrewReadModel { previous.registry.refreshRecordNames(deps.records, renamed) this.host = isDeepStrictEqual(identities(previous.deps.statuses), identities(statuses)) ? refreshCrewStatuses(previous, statuses) - : createCrewHostDerivation( - { ...sources, records: previous.deps.records, statuses }, - now, - () => Math.max(32, this.listeners.size * 2) + : createCrewHostDerivation({ ...sources, records: previous.deps.records, statuses }, () => + Math.max(32, this.listeners.size * 2) ) } else { this.host = previous diff --git a/src/main/runtime/orchestration/crew/dispatch-presentation-deadlines.ts b/src/main/runtime/orchestration/crew/dispatch-presentation-deadlines.ts new file mode 100644 index 00000000000..e8a7961419e --- /dev/null +++ b/src/main/runtime/orchestration/crew/dispatch-presentation-deadlines.ts @@ -0,0 +1,13 @@ +import { DispatchPresentationPriority } from './dispatch-presentation-priority' + +/** One addressable deadline per eligible dispatch; removing its owner also removes its deadline. */ +export class DispatchPresentationDeadlines extends DispatchPresentationPriority { + *expired(now: number): Iterable { + let next = this.peek() + while (next && next.priority < now) { + this.delete(next.id) + yield next.id + next = this.peek() + } + } +} diff --git a/src/main/runtime/orchestration/crew/dispatch-presentation-priority.ts b/src/main/runtime/orchestration/crew/dispatch-presentation-priority.ts new file mode 100644 index 00000000000..009fc22302d --- /dev/null +++ b/src/main/runtime/orchestration/crew/dispatch-presentation-priority.ts @@ -0,0 +1,79 @@ +/** Addressable dispatch priorities; arbitrary removal leaves no stale entries. */ +export class DispatchPresentationPriority { + private readonly positions = new Map() + private readonly items: { id: string; priority: number }[] = [] + + set(id: string, priority: number): void { + this.delete(id) + this.items.push({ id, priority }) + this.positions.set(id, this.items.length - 1) + this.up(this.items.length - 1) + } + + delete(id: string): void { + const index = this.positions.get(id) + if (index === undefined) { + return + } + const last = this.items.pop()! + this.positions.delete(id) + if (index >= this.items.length) { + return + } + this.items[index] = last + this.positions.set(last.id, index) + const moved = this.up(index) + if (moved === index) { + this.down(index) + } + } + + get size(): number { + return this.items.length + } + + peek(): Readonly<{ id: string; priority: number }> | undefined { + return this.items[0] + } + + clear(): void { + this.items.length = 0 + this.positions.clear() + } + + private swap(a: number, b: number): void { + const entry = this.items[a] + this.items[a] = this.items[b] + this.items[b] = entry + this.positions.set(this.items[a].id, a) + this.positions.set(this.items[b].id, b) + } + + private up(index: number): number { + while (index > 0) { + const parent = (index - 1) >> 1 + if (this.items[parent].priority <= this.items[index].priority) { + break + } + this.swap(index, parent) + index = parent + } + return index + } + + private down(index: number): void { + for (;;) { + const left = index * 2 + 1 + const right = left + 1 + const child = + right < this.items.length && this.items[right].priority < this.items[left].priority + ? right + : left + if (child >= this.items.length || this.items[index].priority <= this.items[child].priority) { + return + } + this.swap(index, child) + index = child + } + } +} diff --git a/src/main/runtime/orchestration/crew/orchestration-dispatch-context.ts b/src/main/runtime/orchestration/crew/orchestration-dispatch-context.ts new file mode 100644 index 00000000000..b16edee66b2 --- /dev/null +++ b/src/main/runtime/orchestration/crew/orchestration-dispatch-context.ts @@ -0,0 +1,140 @@ +import type { AgentStatusOrchestrationContext } from '../../../../shared/agent-status/contracts/agent-status-types' +import { creatorFirstParent, crewTaskDisplay } from './crew-rules' +import { parsePaneKey } from '../../../../shared/workspace-layout/stable-pane-id' +import type { OrchestrationDb } from '../db/orchestration-db' +import { buildWorkerAttentionContext } from '../workers/reports/worker-attention-context' +import { worktreeIdsEqual } from '../../../../shared/worktree/id' +import type { createOrchestrationProjectionScope } from './runtime-agent-orchestration-scope' +import { currentRunCoordinatorOrcaSessionId } from '../db/runs/run-coordinator-orca-session' +import type { DispatchContextRow } from '../db/orchestration-records' +import type { + DispatchProjectionOptions, + RuntimeAgentOrchestrationDependencies +} from './runtime-agent-orchestration-projection' + +export function composeOrchestrationDispatch( + deps: RuntimeAgentOrchestrationDependencies, + dispatch: DispatchContextRow, + handle: string, + db: OrchestrationDb | null, + options: DispatchProjectionOptions, + scope: ReturnType +): AgentStatusOrchestrationContext { + const { paneKey, evidence, deferAttention = false } = options + const session = options.observeSession?.(dispatch) + const task = scope.task(dispatch.task_id, dispatch.run_id) + const display = crewTaskDisplay(task) + const owningRun = + task?.run_id && task.run_id === dispatch.run_id ? scope.run(dispatch.run_id) : undefined + const runCoordinatorHandle = owningRun?.coordinator_handle ?? undefined + const legacyActiveRun = + owningRun?.legacy === 1 && (dispatch.status === 'pending' || dispatch.status === 'dispatched') + ? db?.getActiveCoordinatorRun?.() + : undefined + const handleWorktreeId = legacyActiveRun ? deps.getWorktreeId(handle) : null + const coordinatorWorktreeId = legacyActiveRun + ? deps.getWorktreeId(legacyActiveRun.coordinator_handle) + : null + const scopedLegacyRun = + legacyActiveRun && + handleWorktreeId && + coordinatorWorktreeId && + worktreeIdsEqual(coordinatorWorktreeId, handleWorktreeId) + ? legacyActiveRun + : undefined + const coordinatorHandle = runCoordinatorHandle ?? scopedLegacyRun?.coordinator_handle + const orchestrationRunId = owningRun?.legacy === 0 ? owningRun.id : scopedLegacyRun?.id + const creatorPaneKey = task?.created_by_pane_key + const creatorPaneHandle = creatorPaneKey ? deps.getHandleForPaneKey(creatorPaneKey) : null + const creatorAuthority = creatorPaneHandle ? deps.getDispatchAuthority(creatorPaneHandle) : null + const storedCreatorPane = creatorPaneKey ? parsePaneKey(creatorPaneKey) : null + const currentCreatorPane = creatorAuthority?.paneKey + ? parsePaneKey(creatorAuthority.paneKey) + : null + const sameCreatorPane = Boolean( + creatorPaneKey && + creatorAuthority?.paneKey && + (creatorPaneKey === creatorAuthority.paneKey || + (storedCreatorPane && + currentCreatorPane && + storedCreatorPane.leafId === currentCreatorPane.leafId)) + ) + const paneRuns = creatorPaneKey ? scope.paneRuns(creatorPaneKey) : [] + const paneRun = paneRuns.find((run) => run.id === owningRun?.id) ?? paneRuns[0] + const sameRunCreatorDispatch = Boolean( + task?.creator_dispatch_id && + task.creator_dispatch_run_id === owningRun?.id && + task.creator_dispatch_pane_key && + task.creator_dispatch_process_incarnation === task.created_by_process_incarnation && + parsePaneKey(task.creator_dispatch_pane_key)?.leafId === storedCreatorPane?.leafId + ) + // Durable Run membership identifies the creator; live incarnation/handle checks only decide mutation authority. + const creatorLineageInRun = Boolean( + owningRun?.legacy === 0 && + task?.created_by_run_generation === owningRun.consumer_generation && + creatorPaneKey && + (paneRun + ? paneRun.id === owningRun.id && + paneRun.consumer_generation === task.created_by_run_generation + : sameRunCreatorDispatch) + ) + const currentCreatorHandle = + creatorLineageInRun && + task?.created_by_process_incarnation === creatorAuthority?.processIncarnation && + sameCreatorPane + ? (creatorPaneHandle ?? undefined) + : undefined + const selfSession = dispatch.assignee_orca_session_id + const selfPane = selfSession ? scope.resolve(selfSession) : paneKey + const coordinatorSession = + owningRun?.legacy === 0 ? currentRunCoordinatorOrcaSessionId(owningRun) : null + // Why: a chat party nests by its visible row; its handle and minted pane key match no row. + const coordinator: { handle?: string; paneKey?: string } = coordinatorSession + ? { paneKey: scope.resolve(coordinatorSession) } + : scope.resolveTerminal( + coordinatorHandle, + owningRun?.legacy === 0 ? owningRun.coordinator_pane_key : null + ) + const creatorSession = + dispatch.creator_orca_session_id && dispatch.creator_orca_session_id !== selfSession + ? dispatch.creator_orca_session_id + : null + const creator: { handle?: string; paneKey?: string } | undefined = creatorSession + ? { paneKey: scope.resolve(creatorSession) } + : currentCreatorHandle + ? scope.resolveTerminal(currentCreatorHandle, creatorAuthority?.paneKey ?? null) + : creatorLineageInRun + ? scope.resolveTerminal(creatorPaneHandle, creatorPaneKey ?? null) + : undefined + const coordinatorIsSelf = + coordinator.handle === handle || + (coordinatorSession !== null && coordinatorSession === selfSession) || + (paneKey !== undefined && coordinator.paneKey !== undefined && coordinator.paneKey === paneKey) + // Why: a creator whose pane is gone still has a coordinator to nest under. + const parent = + creatorFirstParent( + (creator?.handle || (creatorSession && creator?.paneKey)) && + (!selfPane || creator?.paneKey !== selfPane) && + creator?.handle !== handle + ? creator + : undefined, + coordinator, + coordinatorIsSelf || coordinator.paneKey === selfPane + ) ?? {} + const attention = + !deferAttention && db && typeof db.getWorkerAttentionFacts === 'function' + ? buildWorkerAttentionContext({ db, dispatch, task, evidence, session, now: scope.now }) + : undefined + return { + taskId: dispatch.task_id, + dispatchId: dispatch.id, + dispatchStatus: dispatch.status, + ...(display.taskTitle ? { taskTitle: display.taskTitle } : {}), + ...(display.displayName ? { displayName: display.displayName } : {}), + ...(parent.handle ? { parentTerminalHandle: parent.handle } : {}), + ...(parent.paneKey ? { parentPaneKey: parent.paneKey } : {}), + ...(coordinator.handle ? { coordinatorHandle: coordinator.handle } : {}), + ...(orchestrationRunId ? { orchestrationRunId } : {}), + ...(attention ? { attention } : {}) + } +} diff --git a/src/main/runtime/orchestration/crew/orchestration-projection-debt.ts b/src/main/runtime/orchestration/crew/orchestration-projection-debt.ts new file mode 100644 index 00000000000..386a6e9aedd --- /dev/null +++ b/src/main/runtime/orchestration/crew/orchestration-projection-debt.ts @@ -0,0 +1,37 @@ +import type { OrchestrationDb } from '../db/orchestration-db' + +const state = 'orchestration_projection_state' +const dirty = 'orchestration_projection_dirty' +const MIN_CANDIDATE_CAPACITY = 64 + +export const projectionDebtSchema = `CREATE TEMP TABLE IF NOT EXISTS ${state}( + id INTEGER PRIMARY KEY CHECK(id = 1), queued INTEGER NOT NULL, + capacity INTEGER NOT NULL, rebuild INTEGER NOT NULL); + INSERT OR IGNORE INTO ${state} VALUES(1, 0, ${MIN_CANDIDATE_CAPACITY}, 0);` + +export function markProjectionCandidate(row: string): string { + return `INSERT OR IGNORE INTO ${dirty}(key) + SELECT 'candidate:' || ${row}.id FROM ${state} WHERE id = 1 AND rebuild = 0; + UPDATE ${state} SET queued = queued + changes(), + rebuild = (queued + changes() > capacity) WHERE id = 1 AND rebuild = 0;` +} + +export function projectionNeedsRebuild(db: OrchestrationDb): boolean { + return db.db.prepare(`SELECT rebuild FROM temp.${state} WHERE id = 1`).get()?.rebuild === 1 +} + +/** Retire debt only after current source facts have loaded successfully. */ +export function acknowledgeProjectionDebt(db: OrchestrationDb, candidates: number): void { + db.db.exec('SAVEPOINT orchestration_projection_ack') + try { + db.db.prepare(`DELETE FROM temp.${dirty}`).run() + db.db + .prepare(`UPDATE temp.${state} SET queued = 0, rebuild = 0, capacity = ? WHERE id = 1`) + .run(Math.max(MIN_CANDIDATE_CAPACITY, candidates)) + db.db.exec('RELEASE orchestration_projection_ack') + } catch (error) { + db.db.exec('ROLLBACK TO orchestration_projection_ack') + db.db.exec('RELEASE orchestration_projection_ack') + throw error + } +} diff --git a/src/main/runtime/orchestration/crew/orchestration-projection-facts.ts b/src/main/runtime/orchestration/crew/orchestration-projection-facts.ts new file mode 100644 index 00000000000..14b2d857666 --- /dev/null +++ b/src/main/runtime/orchestration/crew/orchestration-projection-facts.ts @@ -0,0 +1,294 @@ +import type { OrchestrationDb } from '../db/orchestration-db' +import { paneKeyMatchSuffix } from '../db/pane-key-match' +import { + readWorkerAttentionInputs, + projectWorkerAttentionInput +} from '../db/worker-terminal/worker-terminal-attention-query' +import { + installProjectionInvalidations, + projectionDirtyKeys, + trackProjectionKey +} from './orchestration-projection-invalidations' +import { projectionNeedsRebuild, acknowledgeProjectionDebt } from './orchestration-projection-debt' +import { PresentationDispatchIndex } from './presentation-dispatch-index' +import { withPresentationCompletionSource } from '../db/dispatch-context/presentation-completion-source' +type Fact = { value: unknown; dependencies: readonly string[]; owners: Set } +const sources = new WeakMap() +const views = new WeakMap() + +/** The connection owns persisted facts; every presentation still reads live identities and time. */ +export class OrchestrationProjectionFacts { + readonly view: OrchestrationDb + private readonly candidates: PresentationDispatchIndex + private readonly facts = new Map() + private readonly dependencies = new Map>() + private readonly owned = new Map>() + private owner: string | undefined + private version: unknown + private revision: number | undefined + private cold = true + private previousNow = -Infinity + + constructor( + private readonly db: OrchestrationDb, + private readonly transient = false + ) { + this.candidates = new PresentationDispatchIndex( + db, + (owner, key, dependencies, read) => + this.withDispatch(owner, () => this.memo(key, dependencies, read)), + (id) => this.release(id) + ) + if (!transient) { + installProjectionInvalidations(db) + } + // This facade is used only by projection readers; mutations and admission retain the real DB. + this.view = Object.create(db, { + getActiveDispatchForTerminal: { + value: (handle: string, pane?: string) => this.candidates.activeFor(handle, pane) + }, + getLatestDispatchForTerminal: { value: (handle: string) => this.candidates.latest(handle) }, + getTask: { + value: (id: string, run?: string) => + this.memo( + `task:${id}:${run ?? ''}`, + [`task:${id}`], + () => (run === undefined ? db.getTask(id) : db.getTask(id, run)), + (task) => + task?.created_by_terminal_handle ? [`handle:${task.created_by_terminal_handle}`] : [] + ) + }, + getRun: { value: (id: string) => this.memo(`run:${id}`, [`run:${id}`], () => db.getRun(id)) }, + runsBoundToPane: { + value: (pane: string) => + this.memo(`bound:${pane}`, [`bound:${paneKeyMatchSuffix(pane)}`], () => + db.runsBoundToPane(pane) + ) + }, + getActiveCoordinatorRun: { + value: () => this.memo('legacy', ['legacy'], () => db.getActiveCoordinatorRun()) + }, + getWorkerTerminalResourceByHandle: { + value: (handle: string) => + this.memo(`resource-handle:${handle}`, [`resource-handle:${handle}`], () => + db.getWorkerTerminalResourceByHandle(handle) + ) + }, + getWorkerTerminalResourceByProcessIncarnation: { + value: (process: string) => + this.memo(`resource-process:${process}`, [`resource-process:${process}`], () => + db.getWorkerTerminalResourceByProcessIncarnation(process) + ) + }, + hasRecordedStructuredWorkerSession: { + value: (session: string, process: string) => + this.memo(`recorded:${session}:${process}`, [`session:${session}`], () => + db.hasRecordedStructuredWorkerSession(session, process) + ) + }, + getWorkerAttentionFactsForDispatches: { + value: (ids: readonly string[], now: number) => this.attention(ids, now) + }, + getWorkerAttentionFacts: { + value: (id: string, now: number) => { + const result = this.attention([id], now).get(id) + if (!result) { + throw new Error(`Dispatch ${id} was not found.`) + } + return result + } + }, + listSessionDispatchesForPresentation: { + value: (now: number, sessions?: readonly string[]) => + this.candidates.sessions(now, sessions) + } + }) + views.set(this.view, this) + } + + refresh(now: number): void { + try { + withPresentationCompletionSource(this.db.db, now, ({ version, revision }) => { + const overflow = !this.transient && projectionNeedsRebuild(this.db) + const cold = + this.cold || + version !== this.version || + revision !== this.revision || + now < this.previousNow || + overflow + if (cold) { + this.reset() + } + const previousSize = this.candidates.size + const dirty = this.transient || cold ? [] : projectionDirtyKeys(this.db) + const affected = new Set() + for (const key of dirty) { + for (const factKey of this.dependencies.get(key) ?? []) { + for (const owner of this.facts.get(factKey)?.owners ?? []) { + affected.add(owner) + } + } + } + for (const owner of affected) { + this.release(owner) + } + this.candidates.refresh(now, dirty, cold) + if ( + !this.transient && + (cold || dirty.length > 0 || this.candidates.size !== previousSize) + ) { + acknowledgeProjectionDebt(this.db, this.candidates.size) + } + this.cold = false + this.version = version + this.revision = revision + this.previousNow = now + }) + } catch (error) { + // A retry discards partial indexes before consuming the still-unacknowledged obligation. + this.cold = true + throw error + } + } + + rows(): ReturnType { + return this.candidates.rows() + } + + withDispatch(id: string, read: () => T): T { + const previous = this.owner + this.owner = id + try { + return read() + } finally { + this.owner = previous + } + } + + private attention(ids: readonly string[], now: number) { + const missing = ids.filter((id) => !this.facts.has(`attention:${id}`)) + if (missing.length) { + for (const [id, input] of readWorkerAttentionInputs(this.db, missing)) { + this.withDispatch(id, () => + this.memo(`attention:${id}`, [`dispatch:${id}`, `task:${input.row.task_id}`], () => input) + ) + } + } + return new Map( + ids.flatMap((id) => { + const fact = this.facts.get(`attention:${id}`) + return fact + ? [ + [ + id, + projectWorkerAttentionInput( + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: attention entries are populated only from readWorkerAttentionInputs above. + fact.value as Parameters[0], + now + ) + ] as const + ] + : [] + }) + ) + } + + private memo( + key: string, + dependencies: readonly string[], + read: () => T, + valueDependencies?: (value: T) => readonly string[] + ): T { + let fact = this.facts.get(key) + if (!this.owner || !this.candidates.has(this.owner)) { + return read() + } + if (!fact) { + const value = read() + dependencies = [...dependencies, ...(valueDependencies?.(value) ?? [])] + fact = { value, dependencies, owners: new Set() } + this.facts.set(key, fact) + for (const dependency of dependencies) { + const keys = this.dependencies.get(dependency) ?? new Set() + if (keys.size === 0 && !this.transient) { + trackProjectionKey(this.db, dependency, true) + } + keys.add(key) + this.dependencies.set(dependency, keys) + } + } + fact.owners.add(this.owner) + const keys = this.owned.get(this.owner) ?? new Set() + keys.add(key) + this.owned.set(this.owner, keys) + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: each concrete domain key is written by one typed read function. + return fact.value as T + } + + private forget(key: string): void { + const fact = this.facts.get(key) + if (!fact) { + return + } + for (const owner of fact.owners) { + this.owned.get(owner)?.delete(key) + } + for (const dependency of fact.dependencies) { + const keys = this.dependencies.get(dependency) + keys?.delete(key) + if (keys?.size === 0) { + this.dependencies.delete(dependency) + if (!this.transient) { + trackProjectionKey(this.db, dependency, false) + } + } + } + this.facts.delete(key) + } + + private release(id: string): void { + for (const key of this.owned.get(id) ?? []) { + const fact = this.facts.get(key) + fact?.owners.delete(id) + if (fact?.owners.size === 0) { + this.forget(key) + } + } + this.owned.delete(id) + } + + private reset(): void { + if (!this.transient) { + // Rollback can restore SQL memberships after a failed refresh cleared the JS owners. + this.db.db.prepare('DELETE FROM temp.orchestration_projection_tracked').run() + } + this.facts.clear() + this.dependencies.clear() + this.candidates.clear() + this.owned.clear() + this.cold = true + } +} + +export function orchestrationProjectionFacts( + db: OrchestrationDb, + now = Date.now() +): OrchestrationProjectionFacts | undefined { + const view = views.get(db) + if (view) { + return view + } + let source = db.db.isTransaction ? undefined : sources.get(db) + if (!source) { + // An uncached probe also sees raw/local and external inserts after an empty read. + if (!db.db.prepare('SELECT 1 FROM dispatch_contexts LIMIT 1').get()) { + return undefined + } + source = new OrchestrationProjectionFacts(db, db.db.isTransaction) + if (!db.db.isTransaction) { + sources.set(db, source) + } + } + source.refresh(now) + return source +} diff --git a/src/main/runtime/orchestration/crew/orchestration-projection-invalidations.ts b/src/main/runtime/orchestration/crew/orchestration-projection-invalidations.ts new file mode 100644 index 00000000000..8a103db760e --- /dev/null +++ b/src/main/runtime/orchestration/crew/orchestration-projection-invalidations.ts @@ -0,0 +1,85 @@ +import type { OrchestrationDb } from '../db/orchestration-db' +import { projectionDebtSchema, markProjectionCandidate } from './orchestration-projection-debt' +import { projectionMutationTriggers } from '../db/projection-mutation-triggers' + +const table = 'orchestration_projection' +const pane = (value: string) => `substr(${value}, instr(${value}, ':') + 1)` +const tracked = (key: string) => `INSERT OR IGNORE INTO ${table}_dirty(key) + SELECT ${key} WHERE ${key} IS NOT NULL AND EXISTS (SELECT 1 FROM ${table}_tracked WHERE key = ${key});` + +export function installProjectionInvalidations(db: OrchestrationDb): void { + const specifications = [ + { + table: 'dispatch_contexts', + mark: (r: string) => + `${markProjectionCandidate(r)}${[ + `'dispatch:' || ${r}.id`, + `'task:' || ${r}.task_id`, + `'handle:' || ${r}.assignee_handle`, + `'session:' || ${r}.assignee_orca_session_id` + ] + .map(tracked) + .join(' ')}` + }, + { table: 'tasks', mark: (r: string) => tracked(`'task:' || ${r}.id`) }, + { + table: 'runs', + mark: (r: string) => + [ + tracked(`'run:' || ${r}.id`), + tracked(`'bound:' || ${pane(`${r}.coordinator_pane_key`)}`) + ].join(' ') + }, + { table: 'coordinator_runs', mark: () => tracked("'legacy'") }, + { + table: 'worker_dispatches', + mark: (r: string) => + tracked(`'dispatch:' || ${r}.dispatch_id`) + + tracked(`'task:' || (SELECT task_id FROM dispatch_contexts WHERE id = ${r}.dispatch_id)`) + }, + { + table: 'attempt_observation_facts', + mark: (r: string) => tracked(`'dispatch:' || ${r}.dispatch_id`) + }, + { table: 'question_threads', mark: (r: string) => tracked(`'dispatch:' || ${r}.dispatch_id`) }, + { table: 'decision_gates', mark: (r: string) => tracked(`'task:' || ${r}.task_id`) }, + { + table: 'worker_terminal_resources', + mark: (r: string) => + ['owner_dispatch_id', 'origin_dispatch_id'] + .map((key) => tracked(`'dispatch:' || ${r}.${key}`)) + .join(' ') + + tracked(`'resource-handle:' || ${r}.terminal_handle`) + + tracked(`'resource-process:' || ${r}.process_incarnation`) + }, + { + table: 'messages', + columns: 'run_id, to_handle, read, delivery_contract, type', + mark: (r: string) => `INSERT OR IGNORE INTO ${table}_dirty(key) + SELECT 'dispatch:' || substr(${r}.to_handle, 10) + WHERE ${r}.type <> 'heartbeat' AND substr(${r}.to_handle, 1, 9) = 'dispatch:' + AND EXISTS (SELECT 1 FROM ${table}_tracked WHERE key = 'dispatch:' || substr(${r}.to_handle, 10));` + } + ] + db.db.exec(`CREATE TEMP TABLE IF NOT EXISTS ${table}_tracked(key TEXT PRIMARY KEY) WITHOUT ROWID; + CREATE TEMP TABLE IF NOT EXISTS ${table}_dirty(key TEXT PRIMARY KEY) WITHOUT ROWID; + ${projectionDebtSchema} + ${projectionMutationTriggers(table, specifications)}`) +} + +export function projectionDirtyKeys(db: OrchestrationDb): string[] { + return db.db + .prepare(`SELECT key FROM temp.${table}_dirty`) + .all() + .flatMap((row) => (typeof row.key === 'string' ? [row.key] : [])) +} + +export function trackProjectionKey(db: OrchestrationDb, key: string, retained: boolean): void { + db.db + .prepare( + retained + ? `INSERT OR IGNORE INTO temp.${table}_tracked VALUES (?)` + : `DELETE FROM temp.${table}_tracked WHERE key = ?` + ) + .run(key) +} diff --git a/src/main/runtime/orchestration/crew/orchestration-terminal-candidates.ts b/src/main/runtime/orchestration/crew/orchestration-terminal-candidates.ts new file mode 100644 index 00000000000..ad90ea1da65 --- /dev/null +++ b/src/main/runtime/orchestration/crew/orchestration-terminal-candidates.ts @@ -0,0 +1,114 @@ +import { parsePaneKey } from '../../../../shared/workspace-layout/stable-pane-id' +import type { + RuntimeLeafRecord, + RuntimePtyWorktreeRecord +} from '../../terminal/records/runtime-terminal-state-records' +import type { PtyPaneOf } from '../../terminal/surface/pty-pane-query' + +/** One capture returns an unchanged, complete array per stable leaf or exact legacy pane. */ +export type OrchestrationTerminalCandidates = (pane: string) => readonly { + paneKey: string + handles: Iterable +}[] + +/** One read scope, retaining source order without choosing a terminal from dispatch insertion order. */ +export function captureOrchestrationTerminalCandidates(source: { + leaves: ReadonlyMap + ptys: ReadonlyMap + leafKey(tab: string, leaf: string): string + leavesForId(id: string): Iterable + ptysForPane?: (pane: string) => Iterable + capturePaneOf(): PtyPaneOf + paneOf?: PtyPaneOf + makePaneKey(leaf: RuntimeLeafRecord): string + issueLeaf(leaf: RuntimeLeafRecord): string + issuePty(pty: RuntimePtyWorktreeRecord): string +}): OrchestrationTerminalCandidates { + let captured: + | { panes: Map; leaves: Map; read: PtyPaneOf } + | undefined + const ptysFor = (pane: string): Iterable => { + if (source.ptysForPane) { + return source.ptysForPane(pane) + } + if (!captured) { + captured = { panes: new Map(), leaves: new Map(), read: source.capturePaneOf() } + for (const pty of source.ptys.values()) { + const key = captured.read(pty).paneKey + if (!key) { + continue + } + const leaf = parsePaneKey(key)?.leafId + for (const [map, address] of [ + [captured.panes, key], + [captured.leaves, leaf] + ] as const) { + if (!address) { + continue + } + const ids = map.get(address) ?? [] + ids.push(pty.ptyId) + map.set(address, ids) + } + } + } + const leaf = parsePaneKey(pane)?.leafId + return leaf ? (captured.leaves.get(leaf) ?? []) : (captured.panes.get(pane) ?? []) + } + const paneOf = (pty: RuntimePtyWorktreeRecord) => + (source.paneOf ?? captured?.read ?? source.capturePaneOf())(pty).paneKey + const requests = new Map>() + return (pane) => { + const parsed = parsePaneKey(pane) + const key = parsed ? `leaf:${parsed.leafId}` : `pane:${pane}` + const cached = requests.get(key) + if (cached) { + return cached + } + const panes = new Map() + if (parsed) { + for (const id of source.leavesForId(parsed.leafId)) { + const leaf = source.leaves.get(id) + if (leaf?.ptyId) { + panes.set(source.makePaneKey(leaf), []) + } + } + } + for (const id of ptysFor(pane)) { + const pty = source.ptys.get(id) + const address = pty && paneOf(pty) + if (pty && address) { + const records = panes.get(address) ?? [] + records.push(pty) + panes.set(address, records) + } + } + const groups = [...panes].map(([paneKey, ptys]) => ({ + paneKey, + handles: { + *[Symbol.iterator]() { + const seen = new Set() + const parsed = parsePaneKey(paneKey) + const leaf = parsed + ? source.leaves.get(source.leafKey(parsed.tabId, parsed.leafId)) + : undefined + if (leaf?.ptyId) { + const handle = source.issueLeaf(leaf) + seen.add(handle) + yield handle + } + // Mint fallback identities only if the preceding candidate had no context. + for (const pty of ptys) { + const handle = source.issuePty(pty) + if (!seen.has(handle)) { + seen.add(handle) + yield handle + } + } + } + } + })) + requests.set(key, groups) + return groups + } +} diff --git a/src/main/runtime/orchestration/crew/presentation-dispatch-index.ts b/src/main/runtime/orchestration/crew/presentation-dispatch-index.ts new file mode 100644 index 00000000000..d7b138008dd --- /dev/null +++ b/src/main/runtime/orchestration/crew/presentation-dispatch-index.ts @@ -0,0 +1,211 @@ +import { DispatchPresentationDeadlines } from './dispatch-presentation-deadlines' +import { DispatchPresentationPriority } from './dispatch-presentation-priority' +import { dispatchCompletionEpoch } from '../db/dispatch-context/dispatch-completion-epoch' +import { AGENT_STATUS_STALE_AFTER_MS } from '../../../../shared/agent-status/contracts/agent-status-freshness' +import type { OrchestrationDb } from '../db/orchestration-db' +import type { DispatchContextRow } from '../db/orchestration-records' +import { DISPATCH_CONTEXT_COLUMN_LIST } from '../db/row-column-lists' +import { + readPresentationDispatchCandidates, + isRecentPresentationDispatch +} from '../db/dispatch-context/dispatch-presentation' +import { paneKeyMatchSuffix } from '../db/pane-key-match' +import { parsePaneKey } from '../../../../shared/workspace-layout/stable-pane-id' + +type Candidate = DispatchContextRow & { presentation_order: number } +const active = (row: DispatchContextRow) => row.status === 'pending' || row.status === 'dispatched' +const paneAddress = (key: string) => `pane:${parsePaneKey(key) ? paneKeyMatchSuffix(key) : key}` +type Read = (owner: string, key: string, dependencies: readonly string[], read: () => T) => T + +export class PresentationDispatchIndex { + private readonly candidates = new Map() + private readonly addresses = new Map>() + private readonly allWinners = new Map() + private readonly activeWinners = new Map() + private readonly expiry = new DispatchPresentationDeadlines() + constructor( + private readonly db: OrchestrationDb, + private readonly read: Read, + private readonly release: (id: string) => void + ) {} + refresh(now: number, dirty: readonly string[], cold: boolean): void { + if (cold) { + for (const row of readPresentationDispatchCandidates(this.db, now)) { + if (active(row) || isRecentPresentationDispatch(row, now)) { + this.put(row) + } + } + } else { + for (const key of dirty) { + if (!key.startsWith('candidate:')) { + continue + } + const id = key.slice(10) + this.remove(id) + const raw = this.db.db + .prepare( + `SELECT rowid AS presentation_order, ${DISPATCH_CONTEXT_COLUMN_LIST} FROM dispatch_contexts WHERE id = ?` + ) + .get(id) + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: complete schema-owned dispatch projection plus SQLite rowid. + const row = raw as Candidate | undefined + if (row && (active(row) || isRecentPresentationDispatch(row, now))) { + this.put(row) + } + } + } + for (const id of this.expiry.expired(now)) { + this.remove(id) + } + } + get size(): number { + return this.candidates.size + } + rows(): IterableIterator { + return this.candidates.values() + } + has(id: string): boolean { + return this.candidates.has(id) + } + clear(): void { + this.expiry.clear() + this.candidates.clear() + this.addresses.clear() + this.allWinners.clear() + this.activeWinners.clear() + } + private keys(row: DispatchContextRow): string[] { + return [ + ...(row.assignee_handle ? [`handle:${row.assignee_handle}`] : []), + ...(row.assignee_pane_key + ? [paneAddress(row.assignee_pane_key), `exact:${row.assignee_pane_key}`] + : []), + ...(row.assignee_orca_session_id ? [`session:${row.assignee_orca_session_id}`] : []) + ] + } + + private put(row: Candidate): void { + this.candidates.set(row.id, row) + if (!active(row) && row.completed_at) { + const completed = dispatchCompletionEpoch(row.completed_at) + if (completed !== null) { + this.expiry.set(row.id, completed + AGENT_STATUS_STALE_AFTER_MS) + } + } + for (const key of this.keys(row)) { + const bucket = this.addresses.get(key) ?? new Set() + bucket.add(row.id) + this.addresses.set(key, bucket) + this.order(this.allWinners, key, row) + if (active(row)) { + this.order(this.activeWinners, key, row) + } + } + } + + private remove(id: string): void { + const row = this.candidates.get(id) + if (row) { + for (const key of this.keys(row)) { + const bucket = this.addresses.get(key) + this.unorder(this.allWinners, key, id) + this.unorder(this.activeWinners, key, id) + bucket?.delete(id) + if (bucket?.size === 0) { + this.addresses.delete(key) + } + } + } + this.expiry.delete(id) + this.candidates.delete(id) + this.release(id) + } + + private order( + buckets: Map, + key: string, + row: Candidate + ): void { + const bucket = buckets.get(key) ?? new DispatchPresentationPriority() + bucket.set(row.id, -row.presentation_order) + buckets.set(key, bucket) + } + + private unorder( + buckets: Map, + key: string, + id: string + ): void { + const bucket = buckets.get(key) + bucket?.delete(id) + if (bucket?.size === 0) { + buckets.delete(key) + } + } + + private newest(key: string, onlyActive = true): Candidate | undefined { + const id = (onlyActive ? this.activeWinners : this.allWinners).get(key)?.peek()?.id + return id === undefined ? undefined : this.candidates.get(id) + } + + activeFor(handle: string, pane?: string): Candidate | undefined { + return ( + this.newest(`handle:${handle}`) ?? + (pane + ? (this.newest(`exact:${pane}`) ?? + (parsePaneKey(pane) ? this.newest(paneAddress(pane)) : undefined)) + : undefined) + ) + } + + latest(handle: string): DispatchContextRow | undefined { + const candidate = this.newest(`handle:${handle}`, false) + return candidate + ? this.read(candidate.id, `latest:${handle}`, [`handle:${handle}`], () => + this.db.getLatestDispatchForTerminal(handle) + ) + : undefined + } + + sessions(now: number, sessions?: readonly string[]) { + const candidates = sessions + ? sessions.flatMap((id) => + [...(this.addresses.get(`session:${id}`) ?? [])].flatMap( + (key) => this.candidates.get(key) ?? [] + ) + ) + : [...this.candidates.values()].filter((row) => row.assignee_orca_session_id) + const selected = new Map() + for (const row of candidates) { + const address = row.assignee_handle + ? `handle:${row.assignee_handle}` + : `session:${row.assignee_orca_session_id}` + const previous = selected.get(address) + if ( + !previous || + (active(row) && !active(previous)) || + (active(row) === active(previous) && row.presentation_order > previous.presentation_order) + ) { + selected.set(address, row) + } + } + return [...selected].flatMap(([key, row]) => { + const latest = + active(row) && !row.assignee_handle + ? this.newest(`session:${row.assignee_orca_session_id}`) + : this.read(row.id, `session-latest:${active(row)}:${key}`, [key], () => + this.db.db + .prepare( + `SELECT rowid AS n FROM dispatch_contexts WHERE ${row.assignee_handle ? 'assignee_handle' : 'assignee_orca_session_id'} = ? ${active(row) ? "AND status IN ('pending', 'dispatched')" : ''} ORDER BY rowid DESC LIMIT 1` + ) + .get(row.assignee_handle || row.assignee_orca_session_id) + ) + const order = + latest && ('presentation_order' in latest ? latest.presentation_order : latest.n) + return order === row.presentation_order && + (active(row) || isRecentPresentationDispatch(row, now)) + ? [{ dispatch: row, order: row.presentation_order }] + : [] + }) + } +} diff --git a/src/main/runtime/orchestration/crew/runtime-agent-orchestration-dependencies.ts b/src/main/runtime/orchestration/crew/runtime-agent-orchestration-dependencies.ts index ff691472a91..9cd3b898457 100644 --- a/src/main/runtime/orchestration/crew/runtime-agent-orchestration-dependencies.ts +++ b/src/main/runtime/orchestration/crew/runtime-agent-orchestration-dependencies.ts @@ -1,10 +1,43 @@ +import { ORCA_LAYOUT_OWNER_IS_MAIN } from '../../../../shared/layout-owner-switch' +import { captureOrchestrationTerminalCandidates } from './orchestration-terminal-candidates' +import { + mintAgentStatusFleetEvidence, + type ObservedAgentStatusPaneIdentity +} from '../../../ipc/agent-status-ipc-boundary' import { readAgentOrchestrationProjectionRecords } from '../addressing/orchestration-fleet-agent-status-snapshot' import type { RuntimeAgentOrchestrationDependencies } from './runtime-agent-orchestration-projection' import { OrcaRuntimeWithRuntimeId } from '../../construction/runtime-identity-state' +import type { AgentStatusOrchestrationContext } from '../../../../shared/agent-status/contracts/agent-status-types' export abstract class OrcaRuntimeWithAgentOrchestrationDependencies extends OrcaRuntimeWithRuntimeId { + abstract getAgentStatusTerminalHandleForPaneKey(paneKey: string): string | undefined + abstract getAgentStatusOrchestrationContextForPaneKey( + paneKey: string + ): AgentStatusOrchestrationContext | undefined + abstract readonly readObservedAgentStatusPaneIdentityFn: ( + paneKey: string + ) => ObservedAgentStatusPaneIdentity + protected agentOrchestrationDependencies(bound?: Partial) { return { + captureTerminalCandidates: () => + captureOrchestrationTerminalCandidates({ + leaves: this.leaves, + ptys: this.ptysById, + leafKey: (tab, leaf) => this.getLeafKey(tab, leaf), + leavesForId: (id) => this.terminalIdentity.paneCandidates.leavesForId(id), + capturePaneOf: () => this.captureTerminalPaneReader(), + ...(!ORCA_LAYOUT_OWNER_IS_MAIN + ? { + ptysForPane: (pane: string) => + this.terminalIdentity.paneCandidates.ptysForPane(pane), + paneOf: (pty: Parameters[0]) => this.paneOfPty(pty) + } + : {}), + makePaneKey: (leaf) => this.makeRuntimePaneKey(leaf), + issueLeaf: (leaf) => this.issueHandle(leaf), + issuePty: (pty) => this.issuePtyHandle(pty) + }), getDb: () => this.getOrchestrationDbIfAvailable(), getLeaves: () => this.leaves.values(), getPtys: () => this.ptysById.values(), @@ -17,6 +50,21 @@ export abstract class OrcaRuntimeWithAgentOrchestrationDependencies extends Orca getPaneKey: (handle) => this.getPaneKeyForTerminalHandle(handle), getDispatchAuthority: (handle) => this.getOrchestrationDispatchAuthority(handle), getAgentStatusSnapshot: () => this.getOrchestrationFleetAgentStatusSnapshot(), + getAgentStatusForPaneKey: (paneKey, contextForPane) => + (this.publicPaneStatusFn?.(paneKey) ?? []).map((entry) => + mintAgentStatusFleetEvidence( + entry, + { + getAgentStatusTerminalHandleForPaneKey: (pane) => + this.getAgentStatusTerminalHandleForPaneKey(pane), + getTerminalProcessIncarnation: (handle) => this.getTerminalProcessIncarnation(handle), + getAgentStatusOrchestrationContextForPaneKey: + contextForPane ?? + ((pane) => this.getAgentStatusOrchestrationContextForPaneKey(pane)) + }, + this.readObservedAgentStatusPaneIdentityFn(paneKey) + ) + ), getSessionRecords: () => readAgentOrchestrationProjectionRecords(), ...bound } satisfies RuntimeAgentOrchestrationDependencies diff --git a/src/main/runtime/orchestration/crew/runtime-agent-orchestration-projection.test.ts b/src/main/runtime/orchestration/crew/runtime-agent-orchestration-projection.test.ts index ef37fe12772..3fc464a93f3 100644 --- a/src/main/runtime/orchestration/crew/runtime-agent-orchestration-projection.test.ts +++ b/src/main/runtime/orchestration/crew/runtime-agent-orchestration-projection.test.ts @@ -1,3 +1,4 @@ +import { runLifecycleWriteTransaction } from '../db/lifecycle-write-transaction-runner' import 'node:fs' import 'node:os' import 'node:path' @@ -8,7 +9,11 @@ import '../../../native-chat/agent-session-wire/host/testing/structured-agent-se import '../../orca-runtime' import { afterEach, describe, expect, it, vi } from 'vitest' -import '../../../../shared/agent-session/lifecycle/agent-session-conversation-view' +import { agentSessionConversationView } from '../../../../shared/agent-session/lifecycle/agent-session-conversation-view' +import { + agentSessionLeaseFixture, + agentSessionRecordFixture +} from '../../../../shared/agent-session/lifecycle/agent-session-record.test-fixture' import '../../rpc/orchestration-session-caller-test-fixture' import '../../../../shared/orca-session-address' @@ -95,9 +100,10 @@ describe('RuntimeAgentOrchestrationProjection chat lineage', () => { issueLeafHandle: () => TERMINAL_WORKER_HANDLE, issuePtyHandle: () => '', makePaneKey: () => TERMINAL_WORKER_PANE, - getWorktreeId: () => null, - getHandleForPaneKey: () => null, - getPaneKey: () => null, + getWorktreeId: (handle) => (handle === TERMINAL_WORKER_HANDLE ? leaf.worktreeId : null), + getHandleForPaneKey: (pane) => + pane === TERMINAL_WORKER_PANE ? TERMINAL_WORKER_HANDLE : null, + getPaneKey: (handle) => (handle === TERMINAL_WORKER_HANDLE ? TERMINAL_WORKER_PANE : null), getDispatchAuthority: () => null, getAgentStatusSnapshot: () => [], getSessionRecords: () => null @@ -107,8 +113,314 @@ describe('RuntimeAgentOrchestrationProjection chat lineage', () => { expect(contexts?.[chatRow(WORKER_CHAT)]?.parentPaneKey).toBe(chatRow(COORDINATOR_CHAT)) expect(contexts?.[TERMINAL_WORKER_PANE]?.parentPaneKey).toBe(chatRow(COORDINATOR_CHAT)) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)).toEqual(contexts?.[TERMINAL_WORKER_PANE]) + expect(projection.getForPaneKey(chatRow(WORKER_CHAT))).toEqual(contexts?.[chatRow(WORKER_CHAT)]) // The minted pane key authorizes the worker's mailbox; it must never reach a renderer. expect(JSON.stringify(contexts)).not.toContain(chatWorker.paneKey) expect(JSON.stringify(contexts)).not.toContain(chatWorker.handle) }) }) + +describe('keyed orchestration presentation', () => { + it('reads current task facts across commits, rollback and completion expiry', () => { + const db = new OrchestrationDb(':memory:') + const clock = vi.spyOn(Date, 'now').mockReturnValue(Date.parse('2026-11-09T12:00:00Z')) + try { + const run = db.createRun({ + objective: 'Keyed presentation', + coordinatorHandle: 'coordinator', + coordinatorPaneKey: null + }) + const task = db.createTask({ runId: run.id, spec: 'Original title' }) + const dispatch = db.createDispatchContext({ + taskId: task.id, + assigneeHandle: TERMINAL_WORKER_HANDLE, + assigneePaneKey: TERMINAL_WORKER_PANE, + creator: { kind: 'system' }, + maxDepth: 99 + }) + const projection = new RuntimeAgentOrchestrationProjection({ + getDb: () => db, + getLeaves: () => [], + getPtys: () => [], + paneOf: () => ({ tabId: null, paneKey: null, recordedAtGraphSequence: 0 }), + issueLeafHandle: () => '', + issuePtyHandle: () => '', + makePaneKey: () => '', + getWorktreeId: (handle) => (handle === TERMINAL_WORKER_HANDLE ? 'folder:/workspace' : null), + getHandleForPaneKey: (pane) => + pane === TERMINAL_WORKER_PANE ? TERMINAL_WORKER_HANDLE : null, + getPaneKey: (handle) => (handle === TERMINAL_WORKER_HANDLE ? TERMINAL_WORKER_PANE : null), + getDispatchAuthority: () => null, + getAgentStatusSnapshot: () => [], + getAgentStatusForPaneKey: () => [], + getSessionRecords: () => null + }) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.taskTitle).toBe('Original title') + db.db.prepare('UPDATE tasks SET task_title = ? WHERE id = ?').run('Committed title', task.id) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.taskTitle).toBe('Committed title') + expect(() => + runLifecycleWriteTransaction(db.db, 'projection_rollback', () => { + db.db + .prepare('UPDATE tasks SET task_title = ? WHERE id = ?') + .run('Rolled back title', task.id) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.taskTitle).toBe( + 'Rolled back title' + ) + throw new Error('rollback') + }) + ).toThrow('rollback') + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.taskTitle).toBe('Committed title') + db.db + .prepare("UPDATE dispatch_contexts SET status = 'completed', completed_at = ? WHERE id = ?") + .run('2026-11-09 12:00:00', dispatch.id) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.dispatchStatus).toBe('completed') + clock.mockReturnValue(Date.parse('2026-11-10T12:00:00Z')) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)).toBeUndefined() + clock.mockReturnValue(Date.parse('2026-11-09T12:00:00Z')) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.dispatchId).toBe(dispatch.id) + } finally { + db.close() + clock.mockRestore() + } + }) +}) + +function terminalProjection(db: OrchestrationDb) { + const panes = new Map([ + [TERMINAL_WORKER_HANDLE, TERMINAL_WORKER_PANE], + ['creator', 'tab-creator:cccccccc-cccc-4ccc-8ccc-cccccccccccc'], + ['coordinator', 'tab-coordinator:dddddddd-dddd-4ddd-8ddd-dddddddddddd'] + ]) + return new RuntimeAgentOrchestrationProjection({ + getDb: () => db, + getLeaves: () => [], + getPtys: () => [], + paneOf: () => ({ tabId: null, paneKey: null, recordedAtGraphSequence: 0 }), + issueLeafHandle: () => '', + issuePtyHandle: () => '', + makePaneKey: () => '', + getWorktreeId: (handle) => (panes.has(handle) ? 'folder:/workspace' : null), + getHandleForPaneKey: (pane) => [...panes].find(([, key]) => key === pane)?.[0] ?? null, + getPaneKey: (handle) => panes.get(handle) ?? null, + getDispatchAuthority: (handle) => ({ + paneKey: panes.get(handle)!, + processIncarnation: 'creator-process', + runtimeId: 'runtime', + terminalHandle: handle, + ptyId: `pty-${handle}`, + worktreeId: 'folder:/workspace', + launchTokenHash: null, + hostScope: { kind: 'local', hostId: 'local' } + }), + getAgentStatusSnapshot: () => [], + getAgentStatusForPaneKey: () => [], + getSessionRecords: () => null + }) +} + +it('updates child nesting when its creator dispatch settles without a child task write', () => { + const db = new OrchestrationDb(':memory:') + try { + const run = db.createRun({ + objective: 'Creator proof', + coordinatorHandle: 'coordinator', + coordinatorPaneKey: 'tab-coordinator:dddddddd-dddd-4ddd-8ddd-dddddddddddd' + }) + const creator = db.createDispatchContext({ + taskId: db.createTask({ runId: run.id, spec: 'Creator' }).id, + assigneeHandle: 'creator', + assigneePaneKey: 'tab-creator:cccccccc-cccc-4ccc-8ccc-cccccccccccc', + processIncarnation: 'creator-process', + creator: { kind: 'system' }, + maxDepth: 99 + }) + const task = db.createTask({ runId: run.id, spec: 'Child' }) + db.db + .prepare( + `UPDATE tasks SET created_by_terminal_handle = 'creator', created_by_pane_key = 'tab-creator:cccccccc-cccc-4ccc-8ccc-cccccccccccc', created_by_process_incarnation = 'creator-process', created_by_run_generation = ? WHERE id = ?` + ) + .run(run.consumer_generation, task.id) + db.createDispatchContext({ + taskId: task.id, + assigneeHandle: TERMINAL_WORKER_HANDLE, + assigneePaneKey: TERMINAL_WORKER_PANE, + creator: { kind: 'system' }, + maxDepth: 99 + }) + const projection = terminalProjection(db) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.parentTerminalHandle).toBe('creator') + db.db + .prepare( + "UPDATE dispatch_contexts SET status = 'completed', completed_at = datetime('now') WHERE id = ?" + ) + .run(creator.id) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.parentTerminalHandle).toBe('coordinator') + } finally { + db.close() + } +}) + +it('updates legacy nesting when a coordinator starts and finishes without a dispatch write', () => { + const db = new OrchestrationDb(':memory:') + try { + const legacy = db.createRun({ + objective: 'Legacy work', + coordinatorHandle: null, + coordinatorPaneKey: null + }) + db.db.prepare('UPDATE runs SET legacy = 1 WHERE id = ?').run(legacy.id) + db.createDispatchContext({ + taskId: db.createTask({ runId: legacy.id, spec: 'Legacy worker' }).id, + assigneeHandle: TERMINAL_WORKER_HANDLE, + assigneePaneKey: TERMINAL_WORKER_PANE, + creator: { kind: 'system' }, + maxDepth: 99 + }) + const projection = terminalProjection(db) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.parentTerminalHandle).toBeUndefined() + const run = db.createCoordinatorRun({ + spec: 'Legacy coordinator', + coordinatorHandle: 'coordinator' + }) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.parentTerminalHandle).toBe('coordinator') + db.updateCoordinatorRun(run.id, 'completed') + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.parentTerminalHandle).toBeUndefined() + } finally { + db.close() + } +}) + +it('keeps a cleared chat worker under its coordinator in the keyed attention read', () => { + const db = new OrchestrationDb(':memory:') + try { + const successor = testOrcaSessionId('bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb') + const run = db.createRun({ + objective: 'Cleared worker', + coordinatorHandle: null, + coordinatorPaneKey: null, + coordinatorOrcaSessionId: COORDINATOR_CHAT + }) + db.createDispatchContext({ + taskId: db.createTask({ runId: run.id, spec: 'Chat worker' }).id, + assigneeHandle: `orca_session_id:${WORKER_CHAT}`, + creator: { kind: 'system' }, + maxDepth: 99 + }) + const root = agentSessionRecordFixture(agentSessionLeaseFixture({ sessionId: WORKER_CHAT })) + root.conversationCommand = { + command: 'clear', + runtimeFence: 7, + operationId: 'clear-worker', + callerKey: 'renderer', + phase: 'committed', + state: 'completed', + replacementSessionId: successor + } + const records = new Map>([ + [WORKER_CHAT, agentSessionConversationView(root)], + [ + successor, + agentSessionConversationView( + agentSessionRecordFixture(agentSessionLeaseFixture({ sessionId: successor })) + ) + ], + [ + COORDINATOR_CHAT, + agentSessionConversationView( + agentSessionRecordFixture(agentSessionLeaseFixture({ sessionId: COORDINATOR_CHAT })) + ) + ] + ]) + const projection = new RuntimeAgentOrchestrationProjection({ + getDb: () => db, + getLeaves: () => [], + getPtys: () => [], + paneOf: () => ({ tabId: null, paneKey: null, recordedAtGraphSequence: 0 }), + issueLeafHandle: () => '', + issuePtyHandle: () => '', + makePaneKey: () => '', + getWorktreeId: () => null, + getHandleForPaneKey: () => null, + getPaneKey: () => null, + getDispatchAuthority: () => null, + getAgentStatusSnapshot: () => [], + getAgentStatusForPaneKey: () => [], + getSessionRecords: () => ({ + getRecord: (id) => records.get(id) ?? null, + listRecords: () => [...records.values()], + listClearedFrom: (id) => (id === successor ? [WORKER_CHAT] : []) + }) + }) + expect(projection.getForPaneKey(chatRow(successor))?.parentPaneKey).toBe( + chatRow(COORDINATOR_CHAT) + ) + expect(projection.getForPaneKey(chatRow(successor))).toEqual( + projection.buildByPaneKey()?.[chatRow(successor)] + ) + expect(projection.getForPaneKey(chatRow(WORKER_CHAT))).toBeUndefined() + } finally { + db.close() + } +}) + +it('reveals an accepted failure after only its sibling worker settles, and retires read guidance', () => { + const db = new OrchestrationDb(':memory:') + try { + const run = db.createRun({ + objective: 'Attention changes', + coordinatorHandle: 'coordinator', + coordinatorPaneKey: null + }) + const task = db.createTask({ runId: run.id, spec: 'Retrying work' }) + const first = db.createDispatchContext({ + taskId: task.id, + assigneeHandle: TERMINAL_WORKER_HANDLE, + assigneePaneKey: TERMINAL_WORKER_PANE, + creator: { kind: 'system' }, + maxDepth: 99 + }) + // A retry shares the task; lifecycle writers can change only its worker row. + db.db + .prepare( + "INSERT INTO dispatch_contexts(id,run_id,task_id,assignee_handle,status) VALUES('retry',?,?,?,'dispatched')" + ) + .run(run.id, task.id, 'retry-worker') + db.db.prepare("INSERT INTO worker_dispatches(dispatch_id,state) VALUES('retry','ready')").run() + db.recordAttemptObservation({ + id: 'accepted-failure', + dispatchId: first.id, + sequence: 1, + authorityId: 'home', + authorityClock: 'home', + facet: 'worker_report', + payload: { status: 'accepted', outcome: 'failed' }, + homeReceivedAt: Date.now() + }) + const projection = terminalProjection(db) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.attention?.categories).not.toContain( + 'failure' + ) + db.db.prepare("UPDATE worker_dispatches SET state='stopped' WHERE dispatch_id='retry'").run() + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.attention?.categories).toContain( + 'failure' + ) + db.db + .prepare( + "INSERT INTO messages(id,run_id,from_handle,to_handle,subject) VALUES('guidance',?,'coordinator',?,'Please check the output')" + ) + .run(run.id, `dispatch:${first.id}`) + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.attention?.categories).toContain( + 'guidance' + ) + db.db.prepare("UPDATE messages SET read=1 WHERE id='guidance'").run() + expect(projection.getForPaneKey(TERMINAL_WORKER_PANE)?.attention?.categories).not.toContain( + 'guidance' + ) + expect(projection.buildByPaneKey()?.[TERMINAL_WORKER_PANE]?.attention?.categories).toContain( + 'failure' + ) + } finally { + db.close() + } +}) diff --git a/src/main/runtime/orchestration/crew/runtime-agent-orchestration-projection.ts b/src/main/runtime/orchestration/crew/runtime-agent-orchestration-projection.ts index 5653a51832f..8ffc08116f3 100644 --- a/src/main/runtime/orchestration/crew/runtime-agent-orchestration-projection.ts +++ b/src/main/runtime/orchestration/crew/runtime-agent-orchestration-projection.ts @@ -1,6 +1,12 @@ +import type { OrchestrationTerminalCandidates } from './orchestration-terminal-candidates' +import { composeOrchestrationDispatch } from './orchestration-dispatch-context' +import { orchestrationProjectionFacts } from './orchestration-projection-facts' +import { + structuredAgentSessionPaneKey, + structuredAgentSessionTabId +} from '../../../../shared/agent-session/view/structured-agent-session-projection' import type { AgentStatusOrchestrationContext } from '../../../../shared/agent-status/contracts/agent-status-types' import type { FleetAgentStatusEvidence } from '../../../../shared/orchestration/fleet/orchestration-fleet-agent-status-evidence' -import { creatorFirstParent, crewTaskDisplay } from './crew-rules' import { parsePaneKey } from '../../../../shared/workspace-layout/stable-pane-id' import type { OrchestrationCompatibilityTerminalAuthority } from '../terminal-authority/orchestration-compatibility-authority' import type { @@ -8,15 +14,10 @@ import type { RuntimePtyWorktreeRecord } from '../../terminal/records/runtime-terminal-state-records' import type { OrchestrationDb } from '../db/orchestration-db' -import { - buildWorkerAttentionContext, - projectWorkerAttentionContext -} from '../workers/reports/worker-attention-context' -import { worktreeIdsEqual } from '../../../../shared/worktree/id' +import { projectWorkerAttentionContext } from '../workers/reports/worker-attention-context' import type { AgentSessionRecordReader } from '../addressing/session-lineage/structured-session-lineage' import { createOrchestrationProjectionScope } from './runtime-agent-orchestration-scope' -import { isRecentPresentationDispatch } from '../db/dispatch-context/dispatch-lookup' -import { currentRunCoordinatorOrcaSessionId } from '../db/runs/run-coordinator-orca-session' +import { isRecentPresentationDispatch } from '../db/dispatch-context/dispatch-presentation' import type { DispatchContextRow } from '../db/orchestration-records' import type { PtyPaneOf } from '../../terminal/surface/pty-pane-query' import { @@ -25,6 +26,7 @@ import { } from '../workers/lifecycle/session-worker-liveness' export type RuntimeAgentOrchestrationDependencies = { + captureTerminalCandidates?(): OrchestrationTerminalCandidates getDb(): OrchestrationDb | null getLeaves(): Iterable getPtys(): Iterable @@ -37,10 +39,14 @@ export type RuntimeAgentOrchestrationDependencies = { getPaneKey(handle: string): string | null getDispatchAuthority(handle: string): OrchestrationCompatibilityTerminalAuthority | null getAgentStatusSnapshot(): readonly FleetAgentStatusEvidence[] + getAgentStatusForPaneKey?( + paneKey: string, + contextForPane?: (paneKey: string) => AgentStatusOrchestrationContext | undefined + ): readonly FleetAgentStatusEvidence[] getSessionRecords(): AgentSessionRecordReader | null } -type DispatchProjectionOptions = { +export type DispatchProjectionOptions = { // Handles are process-local; pane identity still names the Dispatch after restart. paneKey?: string evidence?: FleetAgentStatusEvidence @@ -52,66 +58,82 @@ export class RuntimeAgentOrchestrationProjection { constructor(private readonly deps: RuntimeAgentOrchestrationDependencies) {} buildByPaneKey(): Record | undefined { - const db = this.deps.getDb() - if (!db || db.hasAnyDispatchContexts?.() === false) { + const raw = this.deps.getDb() + const source = raw?.db ? orchestrationProjectionFacts(raw) : undefined + if (raw?.db && !source) { + return undefined + } + const db = source?.view ?? raw + if (!db || (source ? source.rows().next().done : db.hasAnyDispatchContexts?.() === false)) { return undefined } const scope = createOrchestrationProjectionScope(db, this.deps) const contexts: Record = {} - const statuses = this.deps.getAgentStatusSnapshot() + const terminals = new Map>() + const terminalCandidates = this.deps.captureTerminalCandidates?.() + const expanded = new Set>() + for (const candidate of source?.rows() ?? []) { + const handle = + candidate.assignee_handle && this.deps.getWorktreeId(candidate.assignee_handle) !== null + ? candidate.assignee_handle + : candidate.assignee_pane_key + ? this.deps.getHandleForPaneKey(candidate.assignee_pane_key) + : null + const paneKey = handle ? this.deps.getPaneKey(handle) : null + for (const address of new Set([paneKey, candidate.assignee_pane_key])) { + if (!address) { + continue + } + const groups = + terminalCandidates?.(address) ?? + (handle && paneKey ? [{ paneKey, handles: [handle] }] : []) + if (expanded.has(groups)) { + continue + } + expanded.add(groups) + for (const group of groups) { + if (!terminals.has(group.paneKey)) { + terminals.set(group.paneKey, group.handles) + } + } + } + } + const statuses = + source && this.deps.getAgentStatusForPaneKey + ? [ + ...new Set([ + ...terminals.keys(), + ...[...source.rows()].flatMap((row) => + row.assignee_orca_session_id ? [scope.resolve(row.assignee_orca_session_id)] : [] + ) + ]) + ].flatMap((pane) => + this.deps.getAgentStatusForPaneKey!(pane, (key) => this.identityContext(key, db, scope)) + ) + : this.deps.getAgentStatusSnapshot() const evidenceByPaneKey = new Map( statuses.map((evidence) => [evidence.activity.paneKey, evidence]) ) const sessions = createDispatchSessionLivenessReader(db, statuses, scope.records) const observeSession = sessions.observe - // Batch attention queries below; per-pane reads would repeat every 16ms publication. const batchAttention = typeof db.getWorkerAttentionFactsForDispatches === 'function' - const queriedHandles = new Set() - for (const leaf of this.deps.getLeaves()) { - if (!leaf.ptyId) { - continue - } - const handle = this.deps.issueLeafHandle(leaf) - queriedHandles.add(handle) - const paneKey = this.deps.makePaneKey(leaf) - const context = this.getForHandle( - handle, - db, - { - paneKey, - evidence: evidenceByPaneKey.get(paneKey), - observeSession, - deferAttention: batchAttention - }, - scope - ) - if (context) { - contexts[paneKey] = context - } - } - for (const pty of this.deps.getPtys()) { - const { paneKey } = this.deps.paneOf(pty) - if (!paneKey || contexts[paneKey]) { - continue - } - const handle = this.deps.issuePtyHandle(pty) - if (queriedHandles.has(handle)) { - continue - } - queriedHandles.add(handle) - const context = this.getForHandle( - handle, - db, - { - paneKey, - evidence: evidenceByPaneKey.get(paneKey), - observeSession, - deferAttention: batchAttention - }, - scope - ) - if (context) { - contexts[paneKey] = context + for (const [paneKey, handles] of terminals) { + for (const handle of handles) { + const context = this.getForHandle( + handle, + db, + { + paneKey, + evidence: evidenceByPaneKey.get(paneKey), + observeSession, + deferAttention: batchAttention + }, + scope + ) + if (context) { + contexts[paneKey] = context + break + } } } for (const [paneKey, { dispatch }] of scope.sessionDispatches()) { @@ -159,19 +181,106 @@ export class RuntimeAgentOrchestrationProjection { return contexts } + getForPaneKey(paneKey: string): AgentStatusOrchestrationContext | undefined { + const raw = this.deps.getDb() + if (!raw) { + return undefined + } + const source = raw.db ? orchestrationProjectionFacts(raw) : undefined + if (raw.db && !source) { + return undefined + } + const db = source?.view ?? raw + const scope = createOrchestrationProjectionScope(db, this.deps) + const statuses = + this.deps.getAgentStatusForPaneKey?.(paneKey, (key) => + this.identityContext(key, db, scope) + ) ?? this.deps.getAgentStatusSnapshot().filter((entry) => entry.activity.paneKey === paneKey) + const options = { + paneKey, + evidence: statuses.at(-1), + observeSession: createDispatchSessionLivenessReader(db, statuses, scope.records).observe + } + const groups = this.deps.captureTerminalCandidates?.()(paneKey) + const fallback = this.deps.getHandleForPaneKey(paneKey) + const handles = + groups?.find((group) => group.paneKey === paneKey)?.handles ?? (fallback ? [fallback] : []) + for (const handle of handles) { + const terminal = this.getForHandle(handle, db, options, scope) + if (terminal) { + return terminal + } + } + const parsed = parsePaneKey(paneKey) + const prefix = 'structured-agent-session-' + if (!parsed?.tabId.startsWith(prefix)) { + return undefined + } + const session = parsed.tabId.slice(prefix.length) + if (structuredAgentSessionPaneKey(structuredAgentSessionTabId(session), session) !== paneKey) { + return undefined + } + const ids = new Set([session]) + const visit = (id: string) => { + for (const predecessor of scope.records?.listClearedFrom?.(id) ?? []) { + if (!ids.has(predecessor)) { + ids.add(predecessor) + visit(predecessor) + } + } + } + visit(session) + // Old record readers have no predecessor index; only their compatibility path enumerates. + if (scope.records && !scope.records.listClearedFrom) { + for (const record of scope.records.listRecords()) { + ids.add(record.sessionId) + } + } + const candidate = scope.sessionDispatches([...ids]).get(paneKey) + return candidate + ? this.projectDispatch( + candidate.dispatch, + candidate.dispatch.assignee_handle ?? '', + db, + options, + scope + ) + : undefined + } + + private identityContext( + paneKey: string, + db: OrchestrationDb, + scope: ReturnType + ) { + const handle = this.deps.getHandleForPaneKey(paneKey) + return handle + ? this.getForHandle(handle, db, { paneKey, deferAttention: true }, scope) + : undefined + } + getForHandle( handle: string, db = this.deps.getDb(), options: DispatchProjectionOptions = {}, scope = createOrchestrationProjectionScope(db, this.deps) ): AgentStatusOrchestrationContext | undefined { + const facts = db?.db ? orchestrationProjectionFacts(db, scope.now) : undefined + if (db?.db && !facts) { + return undefined + } + if (facts && facts.view !== db) { + db = facts.view + scope = createOrchestrationProjectionScope(db, this.deps, scope.now) + } const { paneKey } = options const dispatch = db?.getActiveDispatchForTerminal?.(handle, paneKey) ?? this.getRecent(handle, db, scope.now) if (!dispatch) { return undefined } - return this.projectDispatch(dispatch, handle, db, options, scope) + const read = () => this.projectDispatch(dispatch, handle, db, options, scope) + return facts ? facts.withDispatch(dispatch.id, read) : read() } private projectDispatch( @@ -181,127 +290,15 @@ export class RuntimeAgentOrchestrationProjection { options: DispatchProjectionOptions, scope: ReturnType ): AgentStatusOrchestrationContext { - const { paneKey, evidence, deferAttention = false } = options - const session = options.observeSession?.(dispatch) - const task = scope.task(dispatch.task_id, dispatch.run_id) - const display = crewTaskDisplay(task) - const owningRun = - task?.run_id && task.run_id === dispatch.run_id ? scope.run(dispatch.run_id) : undefined - const runCoordinatorHandle = owningRun?.coordinator_handle ?? undefined - const legacyActiveRun = - owningRun?.legacy === 1 && (dispatch.status === 'pending' || dispatch.status === 'dispatched') - ? db?.getActiveCoordinatorRun?.() - : undefined - const handleWorktreeId = legacyActiveRun ? this.deps.getWorktreeId(handle) : null - const coordinatorWorktreeId = legacyActiveRun - ? this.deps.getWorktreeId(legacyActiveRun.coordinator_handle) - : null - const scopedLegacyRun = - legacyActiveRun && - handleWorktreeId && - coordinatorWorktreeId && - worktreeIdsEqual(coordinatorWorktreeId, handleWorktreeId) - ? legacyActiveRun - : undefined - const coordinatorHandle = runCoordinatorHandle ?? scopedLegacyRun?.coordinator_handle - const orchestrationRunId = owningRun?.legacy === 0 ? owningRun.id : scopedLegacyRun?.id - const creatorPaneKey = task?.created_by_pane_key - const creatorPaneHandle = creatorPaneKey ? this.deps.getHandleForPaneKey(creatorPaneKey) : null - const creatorAuthority = creatorPaneHandle - ? this.deps.getDispatchAuthority(creatorPaneHandle) - : null - const storedCreatorPane = creatorPaneKey ? parsePaneKey(creatorPaneKey) : null - const currentCreatorPane = creatorAuthority?.paneKey - ? parsePaneKey(creatorAuthority.paneKey) - : null - const sameCreatorPane = Boolean( - creatorPaneKey && - creatorAuthority?.paneKey && - (creatorPaneKey === creatorAuthority.paneKey || - (storedCreatorPane && - currentCreatorPane && - storedCreatorPane.leafId === currentCreatorPane.leafId)) - ) - const paneRuns = creatorPaneKey ? scope.paneRuns(creatorPaneKey) : [] - const paneRun = paneRuns.find((run) => run.id === owningRun?.id) ?? paneRuns[0] - const sameRunCreatorDispatch = Boolean( - task?.creator_dispatch_id && - task.creator_dispatch_run_id === owningRun?.id && - task.creator_dispatch_pane_key && - task.creator_dispatch_process_incarnation === task.created_by_process_incarnation && - parsePaneKey(task.creator_dispatch_pane_key)?.leafId === storedCreatorPane?.leafId - ) - // Durable Run membership identifies the creator; live incarnation/handle checks only decide mutation authority. - const creatorLineageInRun = Boolean( - owningRun?.legacy === 0 && - task?.created_by_run_generation === owningRun.consumer_generation && - creatorPaneKey && - (paneRun - ? paneRun.id === owningRun.id && - paneRun.consumer_generation === task.created_by_run_generation - : sameRunCreatorDispatch) - ) - const currentCreatorHandle = - creatorLineageInRun && - task?.created_by_process_incarnation === creatorAuthority?.processIncarnation && - sameCreatorPane - ? (creatorPaneHandle ?? undefined) - : undefined - const selfSession = dispatch.assignee_orca_session_id - const selfPane = selfSession ? scope.resolve(selfSession) : paneKey - const coordinatorSession = - owningRun?.legacy === 0 ? currentRunCoordinatorOrcaSessionId(owningRun) : null - // Why: a chat party nests by its visible row; its handle and minted pane key match no row. - const coordinator: { handle?: string; paneKey?: string } = coordinatorSession - ? { paneKey: scope.resolve(coordinatorSession) } - : scope.resolveTerminal( - coordinatorHandle, - owningRun?.legacy === 0 ? owningRun.coordinator_pane_key : null - ) - const creatorSession = - dispatch.creator_orca_session_id && dispatch.creator_orca_session_id !== selfSession - ? dispatch.creator_orca_session_id - : null - const creator: { handle?: string; paneKey?: string } | undefined = creatorSession - ? { paneKey: scope.resolve(creatorSession) } - : currentCreatorHandle - ? scope.resolveTerminal(currentCreatorHandle, creatorAuthority?.paneKey ?? null) - : creatorLineageInRun - ? scope.resolveTerminal(creatorPaneHandle, creatorPaneKey ?? null) - : undefined - const coordinatorIsSelf = - coordinator.handle === handle || - (coordinatorSession !== null && coordinatorSession === selfSession) || - (paneKey !== undefined && - coordinator.paneKey !== undefined && - coordinator.paneKey === paneKey) - // Why: a creator whose pane is gone still has a coordinator to nest under. - const parent = - creatorFirstParent( - (creator?.handle || (creatorSession && creator?.paneKey)) && - (!selfPane || creator?.paneKey !== selfPane) && - creator?.handle !== handle - ? creator - : undefined, - coordinator, - coordinatorIsSelf || coordinator.paneKey === selfPane - ) ?? {} - const attention = - !deferAttention && db && typeof db.getWorkerAttentionFacts === 'function' - ? buildWorkerAttentionContext({ db, dispatch, task, evidence, session, now: scope.now }) - : undefined - return { - taskId: dispatch.task_id, - dispatchId: dispatch.id, - dispatchStatus: dispatch.status, - ...(display.taskTitle ? { taskTitle: display.taskTitle } : {}), - ...(display.displayName ? { displayName: display.displayName } : {}), - ...(parent.handle ? { parentTerminalHandle: parent.handle } : {}), - ...(parent.paneKey ? { parentPaneKey: parent.paneKey } : {}), - ...(coordinator.handle ? { coordinatorHandle: coordinator.handle } : {}), - ...(orchestrationRunId ? { orchestrationRunId } : {}), - ...(attention ? { attention } : {}) + const facts = db?.db ? orchestrationProjectionFacts(db, scope.now) : undefined + if (facts && db !== facts.view) { + db = facts.view } + return facts + ? facts.withDispatch(dispatch.id, () => + composeOrchestrationDispatch(this.deps, dispatch, handle, db, options, scope) + ) + : composeOrchestrationDispatch(this.deps, dispatch, handle, db, options, scope) } private getRecent(handle: string, db: OrchestrationDb | null, now: number) { diff --git a/src/main/runtime/orchestration/crew/runtime-agent-orchestration-scope.ts b/src/main/runtime/orchestration/crew/runtime-agent-orchestration-scope.ts index b00b5da501a..0d10868dac3 100644 --- a/src/main/runtime/orchestration/crew/runtime-agent-orchestration-scope.ts +++ b/src/main/runtime/orchestration/crew/runtime-agent-orchestration-scope.ts @@ -5,24 +5,24 @@ import { isStructuredWorkerHandle } from '../../../../shared/orchestration/worke export function createOrchestrationProjectionScope( db: OrchestrationDb | null, - deps: RuntimeAgentOrchestrationDependencies + deps: RuntimeAgentOrchestrationDependencies, + now = Date.now() ) { const tasks = new Map>() const runs = new Map>() const panes = new Map>() - const now = Date.now() const records = deps.getSessionRecords() const resolve = createCanonicalSessionPaneResolver(records) return { now, records, resolve, - sessionDispatches: () => { + sessionDispatches: (sessions?: readonly string[]) => { const destinations = new Map< string, ReturnType[number] >() - for (const candidate of db?.listSessionDispatchesForPresentation(now) ?? []) { + for (const candidate of db?.listSessionDispatchesForPresentation(now, sessions) ?? []) { if (!candidate.dispatch.assignee_orca_session_id) { continue } diff --git a/src/main/runtime/orchestration/db/attach-orchestration-db-methods.ts b/src/main/runtime/orchestration/db/attach-orchestration-db-methods.ts index 7d5bc369062..68624a6ade3 100644 --- a/src/main/runtime/orchestration/db/attach-orchestration-db-methods.ts +++ b/src/main/runtime/orchestration/db/attach-orchestration-db-methods.ts @@ -11,6 +11,7 @@ import { attachFederationRelayAck } from './federation/federation-relay-ack' import { attachLegacyRemoteDbMethods } from '../legacy-remote/legacy-remote-db-methods' import { attachLegacyRemoteHomeDbMethods } from '../legacy-remote-home/legacy-remote-home-db-methods' import { attachPeerMailStore } from './federation/peer-mail-store' +import { attachPeerRunStore } from './peer-runs/peer-run-store' import { attachLegacyAskOperation } from './legacy/legacy-ask-operation' import { attachLegacyCompatibilityCandidates } from './legacy/legacy-compatibility-candidates' import { attachLegacyCompatibilityPrincipals } from './legacy/legacy-compatibility-principals' @@ -107,6 +108,7 @@ export function attachOrchestrationDbMethods(ctor: { prototype: object }): void attachLegacyRemoteDbMethods(ctor) attachFederationRelayAck(ctor) attachPeerMailStore(ctor) + attachPeerRunStore(ctor) attachWorkerTerminalResourceStore(ctor) attachWorkerTerminalTransfer(ctor) attachWorkerTerminalRelease(ctor) diff --git a/src/main/runtime/orchestration/db/dispatch-context/dispatch-completion-epoch.ts b/src/main/runtime/orchestration/db/dispatch-context/dispatch-completion-epoch.ts new file mode 100644 index 00000000000..6d702735967 --- /dev/null +++ b/src/main/runtime/orchestration/db/dispatch-context/dispatch-completion-epoch.ts @@ -0,0 +1,8 @@ +/** Preserve the existing ISO/local and SQLite/UTC completion timestamp contract. */ +export function dispatchCompletionEpoch(value: unknown): number | null { + if (typeof value !== 'string') { + return null + } + const epoch = Date.parse(value.includes('T') ? value : `${value.replace(' ', 'T')}Z`) + return Number.isFinite(epoch) ? epoch : null +} diff --git a/src/main/runtime/orchestration/db/dispatch-context/dispatch-lookup.ts b/src/main/runtime/orchestration/db/dispatch-context/dispatch-lookup.ts index 60a50128f61..87b1370e9d0 100644 --- a/src/main/runtime/orchestration/db/dispatch-context/dispatch-lookup.ts +++ b/src/main/runtime/orchestration/db/dispatch-context/dispatch-lookup.ts @@ -1,4 +1,4 @@ -import { AGENT_STATUS_STALE_AFTER_MS } from '../../../../../shared/agent-status/contracts/agent-status-freshness' +import { listSessionDispatchesForPresentation } from './dispatch-presentation' import { parsePaneKey } from '../../../../../shared/workspace-layout/stable-pane-id' import type { DispatchContextRow } from '../orchestration-records' import { @@ -30,120 +30,17 @@ const ASSIGNEE_SQL = { latest: assigneeLookups('') } -function presentationAddressKey(column: string, address: string | null): string { - return `${column}:${address}` -} - -/** Preserve the terminal projection's exact ISO/SQLite recency contract, including future dates. */ -export function isRecentPresentationDispatch(dispatch: DispatchContextRow, now: number): boolean { - if (!dispatch.completed_at || dispatch.status === 'pending' || dispatch.status === 'dispatched') { - return false - } - const completedAt = Date.parse( - dispatch.completed_at.includes('T') - ? dispatch.completed_at - : `${dispatch.completed_at.replace(' ', 'T')}Z` - ) - return Number.isFinite(completedAt) && now - completedAt <= AGENT_STATUS_STALE_AFTER_MS -} - -/** Active first, otherwise latest per address; an older eligible completion never resurfaces. */ -export function listSessionDispatchesForPresentation( +export function hasRecordedStructuredWorkerSession( this: OrchestrationDb, - now: number -): { dispatch: DispatchContextRow; order: number }[] { - const lowerBound = new Date(now - AGENT_STATUS_STALE_AFTER_MS - 86_400_000).toISOString() - const rawCandidates = this.db - .prepare(` - SELECT rowid AS presentation_order, ${DISPATCH_CONTEXT_COLUMN_LIST} FROM dispatch_contexts - INDEXED BY idx_dispatch_session_presentation - WHERE assignee_orca_session_id IS NOT NULL AND status IN ('pending', 'dispatched') - UNION ALL - SELECT rowid AS presentation_order, ${DISPATCH_CONTEXT_COLUMN_LIST} FROM dispatch_contexts - INDEXED BY idx_dispatch_session_presentation - WHERE assignee_orca_session_id IS NOT NULL - AND status IN ('completed', 'failed', 'circuit_broken') AND completed_at >= ? - `) - .all(lowerBound) - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: The complete schema-pinned Dispatch projection restores the persisted-row contract; the default integer wrapper normalizes rowid to a safe number. - const candidates = rawCandidates as (DispatchContextRow & { presentation_order: number })[] - const newestActiveOrderBySession = new Map() - const selected = new Map() - for (const candidate of candidates) { - // Include handled rows even when a newer non-public row later suppresses their address. - if (candidate.status === 'pending' || candidate.status === 'dispatched') { - const session = candidate.assignee_orca_session_id - if (session) { - newestActiveOrderBySession.set( - session, - Math.max(newestActiveOrderBySession.get(session) ?? 0, candidate.presentation_order) - ) - } - } - const address = presentationAddressKey( - candidate.assignee_handle ? 'assignee_handle' : 'assignee_orca_session_id', - candidate.assignee_handle || candidate.assignee_orca_session_id - ) - const previous = selected.get(address) - const active = candidate.status === 'pending' || candidate.status === 'dispatched' - const previousActive = previous?.status === 'pending' || previous?.status === 'dispatched' - if ( - !previous || - (active && !previousActive) || - (active === previousActive && candidate.presentation_order > previous.presentation_order) - ) { - selected.set(address, candidate) - } - } - const eligible = [...selected].filter( - ([, candidate]) => - candidate.status === 'pending' || - candidate.status === 'dispatched' || - isRecentPresentationDispatch(candidate, now) + session: string, + process: string +): boolean { + return Boolean( + this.db + .prepare(`SELECT 1 FROM dispatch_contexts + WHERE assignee_orca_session_id = ? AND process_incarnation = ? LIMIT 1`) + .get(session, process) ) - const latestOrderByAddress = new Map() - for (const [column, active] of [ - ['assignee_handle', true], - ['assignee_handle', false], - ['assignee_orca_session_id', false] - ] as const) { - const addresses = eligible - .filter( - ([, candidate]) => - Boolean(candidate.assignee_handle) === (column === 'assignee_handle') && - (candidate.status === 'pending' || candidate.status === 'dispatched') === active - ) - .map(([, candidate]) => candidate[column]) - if (addresses.length === 0) { - continue - } - // Batch native calls, retaining one equality-index seek per selected address. - const latest = this.db - .prepare(`SELECT requested.value AS address, (SELECT rowid AS n FROM dispatch_contexts - WHERE ${column} = requested.value - ${active ? "AND status IN ('pending', 'dispatched')" : ''} - ORDER BY rowid DESC LIMIT 1) AS n FROM json_each(?) requested`) - .all(JSON.stringify(addresses)) - for (const row of latest) { - if (typeof row.address === 'string' && typeof row.n === 'number') { - latestOrderByAddress.set(presentationAddressKey(column, row.address), row.n) - } - } - } - const result: { dispatch: DispatchContextRow; order: number }[] = [] - for (const [address, candidate] of eligible) { - const { presentation_order, ...dispatch } = candidate - const active = dispatch.status === 'pending' || dispatch.status === 'dispatched' - const latest = - active && !candidate.assignee_handle - ? newestActiveOrderBySession.get(candidate.assignee_orca_session_id ?? '') - : latestOrderByAddress.get(address) - if (latest !== presentation_order) { - continue - } - result.push({ dispatch, order: presentation_order }) - } - return result } export function getActiveDispatchForTerminal( @@ -303,6 +200,7 @@ export function hasOpenHelperDispatch(this: OrchestrationDb, dispatchId: string) } export type DispatchLookupMethods = { + hasRecordedStructuredWorkerSession: typeof hasRecordedStructuredWorkerSession getActiveDispatchForTerminal: typeof getActiveDispatchForTerminal hasAnyDispatchContexts: typeof hasAnyDispatchContexts getActiveDispatchForIdentity: typeof getActiveDispatchForIdentity @@ -316,6 +214,7 @@ export type DispatchLookupMethods = { export function attachDispatchLookup(ctor: { prototype: object }): void { Object.assign(ctor.prototype, { + hasRecordedStructuredWorkerSession, getActiveDispatchForTerminal, hasAnyDispatchContexts, getActiveDispatchForIdentity, diff --git a/src/main/runtime/orchestration/db/dispatch-context/dispatch-presentation.ts b/src/main/runtime/orchestration/db/dispatch-context/dispatch-presentation.ts new file mode 100644 index 00000000000..1781b43ce64 --- /dev/null +++ b/src/main/runtime/orchestration/db/dispatch-context/dispatch-presentation.ts @@ -0,0 +1,134 @@ +import { AGENT_STATUS_STALE_AFTER_MS } from '../../../../../shared/agent-status/contracts/agent-status-freshness' +import type { DispatchContextRow } from '../orchestration-records' +import type { OrchestrationDb } from '../orchestration-db' +import { + DISPATCH_CONTEXT_COLUMN_LIST, + DISPATCH_CONTEXT_COLUMNS, + selectColumns +} from '../row-column-lists' +import { dispatchCompletionEpoch } from './dispatch-completion-epoch' +import { withPresentationCompletionSource } from './presentation-completion-source' +import { completionTable } from './presentation-completion-schema' +function presentationAddressKey(column: string, address: string | null): string { + return `${column}:${address}` +} + +/** Preserve the terminal projection's exact ISO/SQLite recency contract, including future dates. */ +export function isRecentPresentationDispatch(dispatch: DispatchContextRow, now: number): boolean { + if (!dispatch.completed_at || dispatch.status === 'pending' || dispatch.status === 'dispatched') { + return false + } + const completedAt = dispatchCompletionEpoch(dispatch.completed_at) + return completedAt !== null && now - completedAt <= AGENT_STATUS_STALE_AFTER_MS +} + +export type PresentationDispatchCandidate = DispatchContextRow & { presentation_order: number } + +/** Active/recent source facts shared by the keyed index and session presentation. */ +export function readPresentationDispatchCandidates( + db: OrchestrationDb, + now: number +): PresentationDispatchCandidate[] { + return withPresentationCompletionSource(db.db, now, () => { + const rows = db.db + .prepare(`SELECT rowid AS presentation_order, ${DISPATCH_CONTEXT_COLUMN_LIST} + FROM dispatch_contexts WHERE status IN ('pending', 'dispatched') + UNION ALL SELECT d.rowid AS presentation_order, ${selectColumns(DISPATCH_CONTEXT_COLUMNS, 'd')} + FROM temp.${completionTable} c INDEXED BY orchestration_presentation_completion_epoch + CROSS JOIN dispatch_contexts d ON d.id = c.id WHERE c.epoch >= ?`) + .all(now - AGENT_STATUS_STALE_AFTER_MS) + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: complete schema-owned dispatch projection plus SQLite rowid. + return (rows as PresentationDispatchCandidate[]).sort( + (a, b) => a.presentation_order - b.presentation_order + ) + }) +} + +/** Active first, otherwise latest per address; an older eligible completion never resurfaces. */ +export function listSessionDispatchesForPresentation( + this: OrchestrationDb, + now: number, + sessions?: readonly string[] +): { dispatch: DispatchContextRow; order: number }[] { + const candidates = readPresentationDispatchCandidates(this, now).filter( + (row) => + row.assignee_orca_session_id && (!sessions || sessions.includes(row.assignee_orca_session_id)) + ) + const newestActiveOrderBySession = new Map() + const selected = new Map() + for (const candidate of candidates) { + // Include handled rows even when a newer non-public row later suppresses their address. + if (candidate.status === 'pending' || candidate.status === 'dispatched') { + const session = candidate.assignee_orca_session_id + if (session) { + newestActiveOrderBySession.set( + session, + Math.max(newestActiveOrderBySession.get(session) ?? 0, candidate.presentation_order) + ) + } + } + const address = presentationAddressKey( + candidate.assignee_handle ? 'assignee_handle' : 'assignee_orca_session_id', + candidate.assignee_handle || candidate.assignee_orca_session_id + ) + const previous = selected.get(address) + const active = candidate.status === 'pending' || candidate.status === 'dispatched' + const previousActive = previous?.status === 'pending' || previous?.status === 'dispatched' + if ( + !previous || + (active && !previousActive) || + (active === previousActive && candidate.presentation_order > previous.presentation_order) + ) { + selected.set(address, candidate) + } + } + const eligible = [...selected].filter( + ([, candidate]) => + candidate.status === 'pending' || + candidate.status === 'dispatched' || + isRecentPresentationDispatch(candidate, now) + ) + const latestOrderByAddress = new Map() + for (const [column, active] of [ + ['assignee_handle', true], + ['assignee_handle', false], + ['assignee_orca_session_id', false] + ] as const) { + const addresses = eligible + .filter( + ([, candidate]) => + Boolean(candidate.assignee_handle) === (column === 'assignee_handle') && + (candidate.status === 'pending' || candidate.status === 'dispatched') === active + ) + .map(([, candidate]) => candidate[column]) + if (addresses.length === 0) { + continue + } + // Batch native calls, retaining one equality-index seek per selected address. + const latest = this.db + .prepare(`SELECT requested.value AS address, (SELECT rowid AS n FROM dispatch_contexts + WHERE ${column} = requested.value + ${active ? "AND status IN ('pending', 'dispatched')" : ''} + ORDER BY rowid DESC LIMIT 1) AS n FROM json_each(?) requested`) + .all(JSON.stringify(addresses)) + for (const row of latest) { + if (typeof row.address === 'string' && typeof row.n === 'number') { + latestOrderByAddress.set(presentationAddressKey(column, row.address), row.n) + } + } + } + const result: { dispatch: DispatchContextRow; order: number }[] = [] + for (const [address, candidate] of eligible) { + const { presentation_order, ...dispatch } = candidate + const active = dispatch.status === 'pending' || dispatch.status === 'dispatched' + const latest = + active && !candidate.assignee_handle + ? newestActiveOrderBySession.get(candidate.assignee_orca_session_id ?? '') + : latestOrderByAddress.get(address) + if (latest !== presentation_order) { + continue + } + result.push({ dispatch, order: presentation_order }) + } + return result +} diff --git a/src/main/runtime/orchestration/db/dispatch-context/presentation-completion-schema.ts b/src/main/runtime/orchestration/db/dispatch-context/presentation-completion-schema.ts new file mode 100644 index 00000000000..ca393021e15 --- /dev/null +++ b/src/main/runtime/orchestration/db/dispatch-context/presentation-completion-schema.ts @@ -0,0 +1,32 @@ +import { AGENT_STATUS_STALE_AFTER_MS } from '../../../../../shared/agent-status/contracts/agent-status-freshness' + +export const completionTable = 'orchestration_presentation_completions' +export const completionState = 'orchestration_presentation_completion_state' + +const operationNow = `(SELECT operation_now FROM ${completionState} WHERE id = 1)` +const expire = `DELETE FROM ${completionTable} WHERE epoch < ${operationNow} - ${AGENT_STATUS_STALE_AFTER_MS};` +const clock = `UPDATE ${completionState} SET operation_now = orchestration_presentation_now() WHERE id = 1; + UPDATE ${completionState} SET recovery = recovery OR operation_now < stamp, + stamp = operation_now WHERE id = 1; ${expire}` +const replace = `INSERT INTO ${completionTable}(id, epoch) + SELECT NEW.id, epoch FROM (SELECT orchestration_completion_epoch(NEW.completed_at) AS epoch) + WHERE NEW.status NOT IN ('pending', 'dispatched') + AND epoch >= ${operationNow} - ${AGENT_STATUS_STALE_AFTER_MS};` + +export const presentationCompletionSchema = ` + CREATE TEMP TABLE IF NOT EXISTS ${completionTable}(id TEXT PRIMARY KEY, epoch REAL NOT NULL); + CREATE INDEX IF NOT EXISTS temp.orchestration_presentation_completion_epoch ON ${completionTable}(epoch, id); + CREATE TEMP TABLE IF NOT EXISTS ${completionState}( + id INTEGER PRIMARY KEY CHECK(id = 1), ready INTEGER NOT NULL DEFAULT 0, + version INTEGER, zone TEXT, stamp REAL NOT NULL DEFAULT 0, + recovery INTEGER NOT NULL DEFAULT 0, revision INTEGER NOT NULL DEFAULT 0, + operation_now REAL NOT NULL DEFAULT 0); + INSERT OR IGNORE INTO ${completionState}(id) VALUES(1); + CREATE TEMP TRIGGER IF NOT EXISTS orchestration_presentation_completion_insert + AFTER INSERT ON main.dispatch_contexts BEGIN ${clock} ${replace} END; + CREATE TEMP TRIGGER IF NOT EXISTS orchestration_presentation_completion_update + AFTER UPDATE OF id, status, completed_at ON main.dispatch_contexts + BEGIN ${clock} DELETE FROM ${completionTable} WHERE id = OLD.id; ${replace} END; + CREATE TEMP TRIGGER IF NOT EXISTS orchestration_presentation_completion_delete + AFTER DELETE ON main.dispatch_contexts + BEGIN ${clock} DELETE FROM ${completionTable} WHERE id = OLD.id; END;` diff --git a/src/main/runtime/orchestration/db/dispatch-context/presentation-completion-source.test.ts b/src/main/runtime/orchestration/db/dispatch-context/presentation-completion-source.test.ts new file mode 100644 index 00000000000..1568e5a8615 --- /dev/null +++ b/src/main/runtime/orchestration/db/dispatch-context/presentation-completion-source.test.ts @@ -0,0 +1,92 @@ +import { mkdtempSync, rmSync } from 'node:fs' +import { join } from 'node:path' +import { tmpdir } from 'node:os' +import { afterEach, expect, it, vi } from 'vitest' +import { OrchestrationDb } from '../orchestration-db' +import { readPresentationDispatchCandidates } from './dispatch-presentation' +import { withPresentationCompletionSource } from './presentation-completion-source' +import { orchestrationProjectionFacts } from '../../crew/orchestration-projection-facts' + +const now = Date.parse('2026-11-09T12:00:00Z') +afterEach(() => vi.restoreAllMocks()) + +function add(db: OrchestrationDb, id: string, completedAt: string) { + db.db + .prepare( + "INSERT INTO dispatch_contexts(id,task_id,assignee_handle,status,completed_at) VALUES(?,'task',?,'completed',?)" + ) + .run(id, id, completedAt) +} + +it('reinstalls a completion source whose first initialization rolled back with its caller', () => { + const db = new OrchestrationDb(':memory:') + try { + db.db.exec('BEGIN; SAVEPOINT caller') + add(db, 'rolled-back', '2026-11-09T12:00:00Z') + expect(readPresentationDispatchCandidates(db, now).map((row) => row.id)).toEqual([ + 'rolled-back' + ]) + db.db.exec('ROLLBACK TO caller; RELEASE caller; ROLLBACK') + add(db, 'committed', '2026-11-09 12:00:00') + expect(readPresentationDispatchCandidates(db, now).map((row) => row.id)).toEqual(['committed']) + db.db + .prepare( + "UPDATE dispatch_contexts SET id='renamed',completed_at='2020-01-01T00:00:00Z' WHERE id='committed'" + ) + .run() + expect(readPresentationDispatchCandidates(db, now)).toEqual([]) + } finally { + db.close() + } +}) + +it('rebuilds warm projection membership when the runtime timezone changes local completion meaning', () => { + const prior = process.env.TZ + const db = new OrchestrationDb(':memory:') + vi.spyOn(Date, 'now').mockReturnValue(now) + try { + process.env.TZ = 'UTC' + add(db, 'local-completion', '2026-11-09T04:00:00') + expect([...orchestrationProjectionFacts(db, now)!.rows()]).toEqual([]) + process.env.TZ = 'America/Los_Angeles' + expect([...orchestrationProjectionFacts(db, now)!.rows()].map((row) => row.id)).toEqual([ + 'local-completion' + ]) + process.env.TZ = 'UTC' + expect([...orchestrationProjectionFacts(db, now)!.rows()]).toEqual([]) + } finally { + if (prior === undefined) { + delete process.env.TZ + } else { + process.env.TZ = prior + } + db.close() + } +}) + +it('keeps normalization and candidate retrieval on one snapshot across an ordinary external commit', () => { + const folder = mkdtempSync(join(tmpdir(), 'orca-completion-source-')) + const path = join(folder, 'orchestration.sqlite') + const db = new OrchestrationDb(path) + db.db.pragma('journal_mode = WAL') + const other = new OrchestrationDb(path) + try { + add(db, 'first', '2026-11-09T12:00:00Z') + withPresentationCompletionSource(db.db, now, () => { + add(other, 'external', '2026-11-09T12:00:00Z') + expect(readPresentationDispatchCandidates(db, now).map((row) => row.id)).toEqual(['first']) + }) + expect(readPresentationDispatchCandidates(db, now).map((row) => row.id)).toEqual([ + 'first', + 'external' + ]) + other.db + .prepare("UPDATE dispatch_contexts SET completed_at='2020-01-01T00:00:00Z' WHERE id='first'") + .run() + expect(readPresentationDispatchCandidates(db, now).map((row) => row.id)).toEqual(['external']) + } finally { + other.close() + db.close() + rmSync(folder, { recursive: true, force: true }) + } +}) diff --git a/src/main/runtime/orchestration/db/dispatch-context/presentation-completion-source.ts b/src/main/runtime/orchestration/db/dispatch-context/presentation-completion-source.ts new file mode 100644 index 00000000000..7153d6dcfbb --- /dev/null +++ b/src/main/runtime/orchestration/db/dispatch-context/presentation-completion-source.ts @@ -0,0 +1,121 @@ +import type Database from '../../../../sqlite/sync-database' +import { AGENT_STATUS_STALE_AFTER_MS } from '../../../../../shared/agent-status/contracts/agent-status-freshness' +import { dispatchCompletionEpoch } from './dispatch-completion-epoch' +import { + completionTable, + completionState, + presentationCompletionSchema +} from './presentation-completion-schema' + +type Snapshot = { revision: number; version: number } +const sources = new WeakMap() + +/** Normalization belongs to the connection, independently of disposable projection caches. */ +class PresentationCompletionSource { + private installed = false + private snapshot: Snapshot | undefined + + constructor(private readonly db: Database.Database) { + db.function('orchestration_completion_epoch', dispatchCompletionEpoch) + db.function('orchestration_presentation_now', () => Date.now()) + } + + read(now: number, read: (snapshot: Snapshot) => T): T { + if (this.snapshot) { + return read(this.snapshot) + } + const outer = this.db.isTransaction + this.db.exec('SAVEPOINT orchestration_presentation_source') + try { + this.install() + // Acquire the main snapshot before observing its data_version, including an empty source. + this.db.prepare('SELECT rowid FROM main.dispatch_contexts LIMIT 1').get() + const state = this.db + .prepare(`SELECT *, (SELECT data_version FROM pragma_data_version) AS current_version + FROM temp.${completionState} WHERE id = 1`) + .get() + if ( + !state || + typeof state.current_version !== 'number' || + typeof state.revision !== 'number' + ) { + throw new Error('Orchestration presentation source is unavailable') + } + const zone = `${process.env.TZ ?? ''}|${Intl.DateTimeFormat().resolvedOptions().timeZone}` + let revision = state.revision + if ( + state.ready !== 1 || + state.recovery === 1 || + state.version !== state.current_version || + state.zone !== zone || + typeof state.stamp !== 'number' || + now < state.stamp + ) { + this.rebuild(now) + revision++ + this.db + .prepare(`UPDATE temp.${completionState} SET ready = 1, version = ?, zone = ?, + recovery = 0, revision = ? WHERE id = 1`) + .run(state.current_version, zone, revision) + } + this.db + .prepare(`DELETE FROM temp.${completionTable} WHERE epoch < ?`) + .run(now - AGENT_STATUS_STALE_AFTER_MS) + this.db.prepare(`UPDATE temp.${completionState} SET stamp = ? WHERE id = 1`).run(now) + this.snapshot = { revision, version: state.current_version } + const result = read(this.snapshot) + this.db.exec('RELEASE orchestration_presentation_source') + if (!outer) { + this.installed = true + } + return result + } catch (error) { + this.db.exec('ROLLBACK TO orchestration_presentation_source') + this.db.exec('RELEASE orchestration_presentation_source') + throw error + } finally { + this.snapshot = undefined + } + } + + private install(): void { + if (this.installed) { + return + } + // First initialization inside a caller transaction may have rolled back its TEMP schema. + if ( + !this.db + .prepare('SELECT 1 FROM sqlite_temp_master WHERE type = ? AND name = ?') + .get('table', completionState) + ) { + this.db.exec(presentationCompletionSchema) + } + } + + private rebuild(now: number): void { + this.db.prepare(`DELETE FROM temp.${completionTable}`).run() + const insert = this.db.prepare(`INSERT INTO temp.${completionTable}(id, epoch) VALUES (?, ?)`) + for (const row of this.db + .prepare(`SELECT id, completed_at FROM dispatch_contexts + WHERE status NOT IN ('pending', 'dispatched')`) + .iterate()) { + const epoch = dispatchCompletionEpoch(row.completed_at) + if (epoch !== null && epoch >= now - AGENT_STATUS_STALE_AFTER_MS) { + insert.run(row.id, epoch) + } + } + } +} + +export function withPresentationCompletionSource( + db: Database.Database, + now: number, + read: (snapshot: Snapshot) => T +): T { + let source = sources.get(db) + if (!source) { + source = new PresentationCompletionSource(db) + sources.set(db, source) + } + return source.read(now, read) +} diff --git a/src/main/runtime/orchestration/db/dispatch-context/worker-report-settlement.ts b/src/main/runtime/orchestration/db/dispatch-context/worker-report-settlement.ts index 9152202ada9..4f812539964 100644 --- a/src/main/runtime/orchestration/db/dispatch-context/worker-report-settlement.ts +++ b/src/main/runtime/orchestration/db/dispatch-context/worker-report-settlement.ts @@ -168,6 +168,10 @@ export function settleWorkerReportInTransaction( let dispatchUpdate: { changes: number } let taskUpdate: { changes: number } if (settledByUnobservedPrompt) { + // A paired coordinator gets the correction once, after all its writes; see peer_run_corrections. + this.db + .prepare('INSERT INTO peer_run_corrections (dispatch_id) VALUES (?)') + .run(params.dispatchId) const now = new Date().toISOString() const dispatchTransition = transitionLifecycleWithDb(this.db, { entity: 'dispatch', @@ -239,6 +243,7 @@ export function settleWorkerReportInTransaction( projection: { stage: 'settled', updated_at: new Date().toISOString() }, correction: 'unobserved_prompt_report' }) + this.db.prepare('DELETE FROM peer_run_corrections WHERE dispatch_id = ?').run(params.dispatchId) } else if ((unprovenWorker || reportingStart) && params.outcome === 'succeeded') { transitionLifecycleWithDb(this.db, { entity: 'worker', diff --git a/src/main/runtime/orchestration/db/federated-worker-report-outcome.test.ts b/src/main/runtime/orchestration/db/federated-worker-report-outcome.test.ts deleted file mode 100644 index 229fa21a593..00000000000 --- a/src/main/runtime/orchestration/db/federated-worker-report-outcome.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { parseFederatedWorkerReportOutcome } from '../legacy-remote/federated-worker-report-outcome' - -describe('federated-worker-report-outcome', () => { - it('reads succeeded or failed from a nested report payload', () => { - const succeeded = JSON.stringify({ payload: JSON.stringify({ outcome: 'succeeded' }) }) - const failed = JSON.stringify({ payload: JSON.stringify({ outcome: 'failed' }) }) - expect(parseFederatedWorkerReportOutcome(succeeded)).toBe('succeeded') - expect(parseFederatedWorkerReportOutcome(failed)).toBe('failed') - }) - - it('returns undefined for malformed or non-terminal outcomes', () => { - expect(parseFederatedWorkerReportOutcome('not-json')).toBeUndefined() - expect(parseFederatedWorkerReportOutcome(JSON.stringify({ payload: {} }))).toBeUndefined() - const other = JSON.stringify({ payload: JSON.stringify({ outcome: 'running' }) }) - expect(parseFederatedWorkerReportOutcome(other)).toBeUndefined() - }) -}) diff --git a/src/main/runtime/orchestration/db/federation/peer-mail-store.ts b/src/main/runtime/orchestration/db/federation/peer-mail-store.ts index da829b40e5e..ffe1e3b2cb9 100644 --- a/src/main/runtime/orchestration/db/federation/peer-mail-store.ts +++ b/src/main/runtime/orchestration/db/federation/peer-mail-store.ts @@ -78,7 +78,7 @@ export function listHomePeerMailEnvironments(this: OrchestrationDb): string[] { export function listPeerConversationIds(this: OrchestrationDb, peerFingerprint: string): string[] { const statement = this.db.prepare( `SELECT conversation_id FROM peer_mail_conversations - WHERE role = 'peer' AND peer_fingerprint = ?` + WHERE role = 'peer' AND peer_fingerprint = ? ORDER BY conversation_id` ) // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: SELECT over this table returns exactly these columns. const rows = statement.all(peerFingerprint) as { conversation_id: string }[] @@ -118,6 +118,14 @@ export function insertPeerMailMessage( | { message: MessageRow | undefined; duplicate: true } { this.db.exec('SAVEPOINT peer_mail_insert') try { + // A peer Run's conversation keeps its own queue sequence, so it never carries peer mail. + if (this.getPeerRunForConversation(params.conversationId)) { + throw new OrchestrationError( + 'request_mismatch', + `Conversation ${params.conversationId} belongs to a coordinated Run. Nothing was delivered.`, + { effectsApplied: false } + ) + } if (params.peerFingerprint !== undefined) { const conversation = this.getPeerMailConversation(params.conversationId) if ( diff --git a/src/main/runtime/orchestration/db/lifecycle-transition.ts b/src/main/runtime/orchestration/db/lifecycle-transition.ts index 5eefd879ecb..f0b44ee85ae 100644 --- a/src/main/runtime/orchestration/db/lifecycle-transition.ts +++ b/src/main/runtime/orchestration/db/lifecycle-transition.ts @@ -1,6 +1,7 @@ import type Database from '../../../sqlite/sync-database' import { OrchestrationError } from '../orchestration-error' import type { OrchestrationDb } from './orchestration-db' +import { notifyPeerMailQueued } from '../federation/peer-mail/peer-mail-waiters' /** Callers own transactions so lifecycle projections and mailbox effects commit atomically together. */ export type LifecycleEntity = 'task' | 'dispatch' | 'worker' @@ -189,7 +190,8 @@ export function transitionLifecycleWithDb( `${params.entity} ${params.id} changed while transitioning.` ) } - + // A peer Run's change is queued home by trigger in this statement. + notifyPeerMailQueued(db) return { changed: true } } diff --git a/src/main/runtime/orchestration/db/messages/message-inbox.ts b/src/main/runtime/orchestration/db/messages/message-inbox.ts index e0ec891fd63..f201d19e808 100644 --- a/src/main/runtime/orchestration/db/messages/message-inbox.ts +++ b/src/main/runtime/orchestration/db/messages/message-inbox.ts @@ -226,11 +226,14 @@ export function markAsReadAndDelivered(this: OrchestrationDb, ids: string[]): vo ) } -export function getInbox(this: OrchestrationDb, limit = 20): MessageRow[] { +export function getInbox(this: OrchestrationDb, limit = 20, runId?: string): MessageRow[] { return exposeMessageListTimestamps( + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: SELECT * over messages returns the row shape its schema and MessageRow define, like every row cast in db/. this.db - .prepare('SELECT * FROM messages ORDER BY sequence DESC LIMIT ?') - .all(limit) as MessageRow[] + .prepare( + 'SELECT * FROM messages WHERE (?1 IS NULL OR run_id = ?1) ORDER BY sequence DESC LIMIT ?2' + ) + .all(runId ?? null, limit) as MessageRow[] ) } @@ -239,22 +242,19 @@ export function getAllMessagesForHandle( this: OrchestrationDb, toHandle: string, limit = 100, - types?: MessageType[] + types?: MessageType[], + runId?: string ): MessageRow[] { - if (types && types.length > 0) { - const placeholders = types.map(() => '?').join(',') - return exposeMessageListTimestamps( - this.db - .prepare( - `SELECT * FROM messages WHERE to_handle = ? AND type IN (${placeholders}) ORDER BY sequence DESC LIMIT ?` - ) - .all(toHandle, ...types, limit) as MessageRow[] - ) - } + const typed = types && types.length > 0 + const typeFilter = typed ? `AND type IN (${types.map(() => '?').join(',')})` : '' return exposeMessageListTimestamps( + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: SELECT * over messages returns the row shape its schema and MessageRow define, like every row cast in db/. this.db - .prepare('SELECT * FROM messages WHERE to_handle = ? ORDER BY sequence DESC LIMIT ?') - .all(toHandle, limit) as MessageRow[] + .prepare( + `SELECT * FROM messages WHERE to_handle = ? AND (? IS NULL OR run_id = ?) ${typeFilter} + ORDER BY sequence DESC LIMIT ?` + ) + .all(toHandle, runId ?? null, runId ?? null, ...(typed ? types : []), limit) as MessageRow[] ) } diff --git a/src/main/runtime/orchestration/db/messages/message-insert.ts b/src/main/runtime/orchestration/db/messages/message-insert.ts index cc590b76b1a..24c45a19e7d 100644 --- a/src/main/runtime/orchestration/db/messages/message-insert.ts +++ b/src/main/runtime/orchestration/db/messages/message-insert.ts @@ -8,6 +8,7 @@ import { generateId } from '../generated-id' import { exposeMessageTimestamps } from '../utc-timestamp' import type { OrchestrationDb } from '../orchestration-db' import { runLifecycleWriteTransaction } from '../lifecycle-write-transaction-runner' +import { notifyPeerMailQueued } from '../../federation/peer-mail/peer-mail-waiters' import { ORCHESTRATION_UNBOUND_RUN_ID as UNBOUND_RUN_ID } from '../../../../../shared/orchestration/orchestration-rpc-contract' const MESSAGE_INSERT_SAVEPOINT = 'message_insert_batch' @@ -27,6 +28,8 @@ export type MessageInsert = { runId?: string answerSenderSnapshot?: string deliveryContract?: MessageDeliveryContract + /** The Dispatch whose worker sent this, as the sender's own check found it; kept for a peer Run's queue. */ + senderDispatchId?: string } export function insertMessage(this: OrchestrationDb, msg: MessageInsert): MessageRow { @@ -44,6 +47,16 @@ export function insertMessage(this: OrchestrationDb, msg: MessageInsert): Messag this.requireRun(runId) const id = msg.id ?? generateId('msg') const type = msg.type ?? 'status' + if (msg.senderDispatchId) { + // Before the insert, whose trigger queues a peer Run's mail home with it; immutable after. + this.db + .prepare( + `INSERT OR IGNORE INTO message_dispatch_provenance (message_id, dispatch_id, task_id) + SELECT ?, d.id, d.task_id FROM dispatch_contexts d + WHERE d.id = ? AND d.run_id IN (SELECT run_id FROM peer_runs)` + ) + .run(id, msg.senderDispatchId) + } // Heartbeats only record liveness: store them handled so they never reach a mailbox or wake it. const handled = type === 'heartbeat' ? 1 : 0 const stmt = this.db.prepare(` @@ -70,6 +83,8 @@ export function insertMessage(this: OrchestrationDb, msg: MessageInsert): Messag handled, handled ) + // Mail filed in a peer Run is queued home by trigger in this statement. + notifyPeerMailQueued(this.db) return exposeMessageTimestamps( this.db.prepare('SELECT * FROM messages WHERE id = ?').get(id) as MessageRow ) diff --git a/src/main/runtime/orchestration/db/orchestration-db-methods.ts b/src/main/runtime/orchestration/db/orchestration-db-methods.ts index 0e06a05191d..9072fe5c5fe 100644 --- a/src/main/runtime/orchestration/db/orchestration-db-methods.ts +++ b/src/main/runtime/orchestration/db/orchestration-db-methods.ts @@ -10,6 +10,7 @@ import type { FederationRelayAckMethods } from './federation/federation-relay-ac import type { LegacyRemoteDbMethods } from '../legacy-remote/legacy-remote-db-methods' import type { LegacyRemoteHomeDbMethods } from '../legacy-remote-home/legacy-remote-home-db-methods' import type { PeerMailStoreMethods } from './federation/peer-mail-store' +import type { PeerRunStoreMethods } from './peer-runs/peer-run-store' import type { LegacyAskOperationMethods } from './legacy/legacy-ask-operation' import type { LegacyCompatibilityCandidatesMethods } from './legacy/legacy-compatibility-candidates' import type { LegacyCompatibilityPrincipalsMethods } from './legacy/legacy-compatibility-principals' @@ -104,6 +105,7 @@ export type OrchestrationDbMethods = AttemptObservationStoreMethods & LegacyRemoteDbMethods & FederationRelayAckMethods & PeerMailStoreMethods & + PeerRunStoreMethods & StructuredMailSendStoreMethods & WorkerTerminalResourceStoreMethods & WorkerTerminalTransferMethods & diff --git a/src/main/runtime/orchestration/db/orchestration-db.ts b/src/main/runtime/orchestration/db/orchestration-db.ts index 25bec3ae31c..3fcd88f18b1 100644 --- a/src/main/runtime/orchestration/db/orchestration-db.ts +++ b/src/main/runtime/orchestration/db/orchestration-db.ts @@ -15,6 +15,7 @@ import { rememberCurrentRunCoordinatorHandles } from './runs/run-coordinator-mail-routing' import { createTables } from './schema/create-tables' +import { createPeerRunQueueTriggers } from './peer-runs/peer-run-queue-sql' import { migrate } from './schema/migrate' import { backfillStructuredWorkerOrcaSessionIds } from './schema/structured-worker-orca-session-backfill' import { reconcileSettledWorkerDispatches } from './worker-dispatch/worker-dispatch-settlement' @@ -63,6 +64,7 @@ class OrchestrationDbCore { } } createRunCoordinatorAddressTriggers(this.db) + createPeerRunQueueTriggers(this.db) backfillFederatedStubHomeRuns(this.db) // After every open step that creates Runs, before any step that deletes work. installRemovedWorkCapture(this.db, removedWorkCaptureWasIntact) diff --git a/src/main/runtime/orchestration/db/peer-runs/peer-run-queue-sql.ts b/src/main/runtime/orchestration/db/peer-runs/peer-run-queue-sql.ts new file mode 100644 index 00000000000..c2862a64508 --- /dev/null +++ b/src/main/runtime/orchestration/db/peer-runs/peer-run-queue-sql.ts @@ -0,0 +1,175 @@ +import type Database from '../../../../sqlite/sync-database' +import { REMOTE_OWNED_WIRE_VERSION } from '../../../../../shared/orchestration/remote-owned-wire' + +/** + * A Run here whose coordinator is a paired Orca, keyed by the conversation its queue goes home + * under. It outlives this Orca's resets, so the conversation keeps its Run ID and its sequence. + * Each conversation's next `to_home` sequence is persistent too, so a reset never reuses one. + * A worker message's Dispatch is recorded when it is filed, before any reroute into the Run. + */ +export const PEER_RUN_SCHEMA_SQL = ` +CREATE TABLE IF NOT EXISTS peer_runs ( + run_id TEXT PRIMARY KEY, + conversation_id TEXT NOT NULL UNIQUE, + peer_fingerprint TEXT NOT NULL, + home_run_id TEXT NOT NULL, + home_label TEXT NOT NULL, + state TEXT NOT NULL DEFAULT 'open' CHECK(state IN ('open', 'closed')), + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE TABLE IF NOT EXISTS federation_relay_sequences ( + dispatch_id TEXT NOT NULL, + direction TEXT NOT NULL, + last_sequence INTEGER NOT NULL, + PRIMARY KEY (dispatch_id, direction) +); + +-- A Dispatch whose report owner's correction is being written: its edges queue nothing until the +-- row is removed, which queues the corrected state once, flagged. +CREATE TABLE IF NOT EXISTS peer_run_corrections ( + dispatch_id TEXT PRIMARY KEY +); + +CREATE TABLE IF NOT EXISTS message_dispatch_provenance ( + message_id TEXT PRIMARY KEY, + dispatch_id TEXT NOT NULL, + task_id TEXT NOT NULL +); +` + +/** A peer-Run Dispatch as a `worker_state` item carries it, with its Task and Run. */ +const PEER_RUN_DISPATCH_STATE_VIEW_SQL = ` +DROP VIEW IF EXISTS peer_run_dispatch_state; +CREATE VIEW peer_run_dispatch_state AS +SELECT d.id AS dispatch_id, pr.conversation_id, pr.home_run_id, pr.run_id AS peer_run_id, + json_object( + 'id', d.id, 'taskId', d.task_id, 'status', d.status, 'workerState', w.state, + 'lastFailure', d.last_failure, 'agent', json_extract(w.start_options, '$.agent') + ) AS dispatch_json, + json_object('status', t.status, 'result', t.result) AS task_json +FROM dispatch_contexts d +JOIN peer_runs pr ON pr.run_id = d.run_id +JOIN tasks t ON t.id = d.task_id +LEFT JOIN worker_dispatches w ON w.dispatch_id = d.id; +` + +const SEQUENCE = `(SELECT last_sequence FROM federation_relay_sequences + WHERE dispatch_id = conversation_id AND direction = 'to_home')` + +/** + * Takes the conversation's next sequence, then queues the item under it. `rows` selects at most one + * row with `conversation_id` and the item's `message_id` and `payload`; both statements read it. + */ +function queueItemStatements(rows: string, kind: string): [string, string] { + return [ + `INSERT INTO federation_relay_sequences (dispatch_id, direction, last_sequence) + SELECT conversation_id, 'to_home', 1 FROM (${rows}) WHERE true + ON CONFLICT(dispatch_id, direction) DO UPDATE SET last_sequence = last_sequence + 1`, + `INSERT INTO federation_relay_items + (dispatch_id, direction, sequence, message_id, kind, payload, byte_count) + SELECT conversation_id, 'to_home', ${SEQUENCE}, message_id, '${kind}', payload, length(payload) + FROM (${rows})` + ] +} + +/** One `worker_state` item for a peer-Run Dispatch; its ID is the sequence it is queued under. */ +export function peerRunDispatchStateStatements( + dispatchId: string, + corrected: boolean, + removed: string +): [string, string] { + return queueItemStatements( + `SELECT conversation_id, 'state_' || ${SEQUENCE} AS message_id, + json_object( + 'v', ${REMOTE_OWNED_WIRE_VERSION}, 'id', 'state_' || ${SEQUENCE}, + 'homeRunId', home_run_id, 'peerRunId', peer_run_id, + 'dispatch', json(dispatch_json), 'task', json(task_json), + 'correctedUnobservedPrompt', json('${corrected}'), + 'removed', ${removed} + ) AS payload + FROM peer_run_dispatch_state WHERE dispatch_id = ${dispatchId}`, + 'worker_state' + ) +} + +/** A message filed in a peer Run's mailbox, once, with the Dispatch its sender worked for. */ +function peerRunMailStatements(row: string): [string, string] { + return queueItemStatements( + `SELECT pr.conversation_id, ${row}.id AS message_id, + json_object( + 'v', ${REMOTE_OWNED_WIRE_VERSION}, 'id', ${row}.id, + 'homeRunId', pr.home_run_id, 'peerRunId', pr.run_id, + 'message', json_object( + 'from', ${row}.from_handle, 'type', ${row}.type, 'subject', ${row}.subject, + 'body', ${row}.body, 'payload', ${row}.payload, 'priority', ${row}.priority, + 'threadId', ${row}.thread_id + ), + 'dispatchId', p.dispatch_id, 'taskId', p.task_id + ) AS payload + FROM peer_runs pr + LEFT JOIN message_dispatch_provenance p ON p.message_id = ${row}.id + WHERE ${row}.to_handle = 'run:' || pr.run_id + AND NOT EXISTS ( + SELECT 1 FROM federation_relay_items + WHERE dispatch_id = pr.conversation_id AND direction = 'to_home' + AND message_id = ${row}.id + )`, + 'worker_mail' + ) +} + +const LATEST_TASK_DISPATCH = (taskId: string) => + `(SELECT id FROM dispatch_contexts WHERE task_id = ${taskId} ORDER BY rowid DESC LIMIT 1)` + +const NOT_CORRECTING = (dispatchId: string) => + `NOT EXISTS (SELECT 1 FROM peer_run_corrections WHERE dispatch_id = ${dispatchId})` + +const trigger = (statements: [string, string]) => `BEGIN ${statements.join(';\n')}; END;` + +/** + * Every final message of a peer Run's mailbox and every lifecycle change of its Dispatches, their + * workers and their Tasks queue home in the transaction that made them. Rebuilt on every open. + * The report owner's unobserved-prompt correction queues once, flagged, after all its writes. + */ +export function createPeerRunQueueTriggers(db: Database.Database): void { + db.exec('BEGIN IMMEDIATE') + try { + db.exec(` + ${PEER_RUN_DISPATCH_STATE_VIEW_SQL} + DROP TRIGGER IF EXISTS trg_peer_run_mail_insert; + DROP TRIGGER IF EXISTS trg_peer_run_mail_reroute; + DROP TRIGGER IF EXISTS trg_peer_run_dispatch_insert; + DROP TRIGGER IF EXISTS trg_peer_run_dispatch_status; + DROP TRIGGER IF EXISTS trg_peer_run_worker_state; + DROP TRIGGER IF EXISTS trg_peer_run_task_status; + DROP TRIGGER IF EXISTS trg_peer_run_correction; + CREATE TRIGGER trg_peer_run_mail_insert AFTER INSERT ON messages + WHEN NEW.to_handle LIKE 'run:%' AND NEW.type <> 'heartbeat' + ${trigger(peerRunMailStatements('NEW'))} + CREATE TRIGGER trg_peer_run_mail_reroute AFTER UPDATE OF to_handle ON messages + WHEN NEW.to_handle LIKE 'run:%' AND NEW.to_handle <> OLD.to_handle AND NEW.type <> 'heartbeat' + ${trigger(peerRunMailStatements('NEW'))} + CREATE TRIGGER trg_peer_run_dispatch_insert AFTER INSERT ON dispatch_contexts + ${trigger(peerRunDispatchStateStatements('NEW.id', false, 'NULL'))} + CREATE TRIGGER trg_peer_run_dispatch_status AFTER UPDATE OF status ON dispatch_contexts + WHEN NEW.status <> OLD.status AND ${NOT_CORRECTING('NEW.id')} + ${trigger(peerRunDispatchStateStatements('NEW.id', false, 'NULL'))} + CREATE TRIGGER trg_peer_run_worker_state AFTER UPDATE OF state ON worker_dispatches + WHEN NEW.state <> OLD.state AND ${NOT_CORRECTING('NEW.dispatch_id')} + ${trigger(peerRunDispatchStateStatements('NEW.dispatch_id', false, 'NULL'))} + CREATE TRIGGER trg_peer_run_task_status AFTER UPDATE OF status ON tasks + WHEN NEW.status <> OLD.status AND NOT EXISTS ( + SELECT 1 FROM peer_run_corrections c JOIN dispatch_contexts d ON d.id = c.dispatch_id + WHERE d.task_id = NEW.id + ) + ${trigger(peerRunDispatchStateStatements(LATEST_TASK_DISPATCH('NEW.id'), false, 'NULL'))} + CREATE TRIGGER trg_peer_run_correction AFTER DELETE ON peer_run_corrections + ${trigger(peerRunDispatchStateStatements('OLD.dispatch_id', true, 'NULL'))} + `) + db.exec('COMMIT') + } catch (error) { + db.exec('ROLLBACK') + throw error + } +} diff --git a/src/main/runtime/orchestration/db/peer-runs/peer-run-queue.test.ts b/src/main/runtime/orchestration/db/peer-runs/peer-run-queue.test.ts new file mode 100644 index 00000000000..a8b9bd4ce3b --- /dev/null +++ b/src/main/runtime/orchestration/db/peer-runs/peer-run-queue.test.ts @@ -0,0 +1,265 @@ +import { afterEach, beforeEach, describe, expect, it } from 'vitest' +import { OrchestrationDb } from '../orchestration-db' +import { generateId } from '../generated-id' +import { + RemoteOwnedWorkerMail, + RemoteOwnedWorkerState +} from '../../../../../shared/orchestration/remote-owned-wire' +import { AGENT_PROMPT_STALLED_ERROR } from '../../../terminal/input/agent-prompt-submission-verification' +import type { PeerRunRow } from './peer-run-store' + +describe("a paired Orca's Run: its queue home", () => { + let db: OrchestrationDb + let peerRun: PeerRunRow + + beforeEach(() => { + db = new OrchestrationDb(':memory:') + peerRun = db.admitPeerRun({ + peerFingerprint: 'fingerprint_a', + peerRun: { runId: 'run_home', conversationId: generateId('peerconv'), label: 'devA' } + }) + }) + + afterEach(() => db.close()) + + function start(params: { adoptTaskId?: string; retryOf?: string } = {}) { + return db.createStartingWorkerDispatch({ + taskSpec: 'Build it', + taskRunId: peerRun.run_id, + startOptions: { agent: 'claude' }, + creator: { kind: 'system' }, + maxDepth: 5, + ...params + }) + } + + function pending() { + return db.listPendingFederationRelay(peerRun.conversation_id, 'to_home', 500) + } + + function states() { + return pending() + .filter((item) => item.kind === 'worker_state') + .map((item) => RemoteOwnedWorkerState.parse(JSON.parse(item.payload))) + } + + function fail(dispatchId: string, taskId: string) { + db.transitionLifecycle({ entity: 'worker', id: dispatchId, from: 'starting', to: 'failed' }) + db.transitionLifecycle({ entity: 'dispatch', id: dispatchId, from: 'pending', to: 'failed' }) + db.transitionLifecycle({ entity: 'task', id: taskId, from: 'dispatched', to: 'failed' }) + } + + it('queues every lifecycle change of a Dispatch and its Task, in order, as the wire schema', () => { + const { dispatch, task } = start({ adoptTaskId: 'task_home1' }) + fail(dispatch.id, task.id) + + expect(task.id).toBe('task_home1') + const items = pending() + expect(items.map((item) => item.sequence)).toEqual(items.map((_, index) => index + 1)) + expect( + states().map((state) => [ + state.dispatch.status, + state.dispatch.workerState, + state.task.status + ]) + ).toEqual([ + ['pending', null, 'ready'], + ['pending', 'starting', 'dispatched'], + ['pending', 'failed', 'dispatched'], + ['failed', 'failed', 'dispatched'], + ['failed', 'failed', 'failed'] + ]) + expect(states().every((state) => state.homeRunId === 'run_home')).toBe(true) + for (const item of items) { + expect(JSON.parse(item.payload).id).toBe(item.message_id) + } + }) + + it("queues the report owner's unobserved-prompt correction once, flagged, with its result", () => { + const { dispatch, task } = start() + fail(dispatch.id, task.id) + db.transitionLifecycle({ + entity: 'dispatch', + id: dispatch.id, + from: 'failed', + to: 'failed', + projection: { last_failure: AGENT_PROMPT_STALLED_ERROR } + }) + const before = states().length + + db.settleWorkerReport({ + taskId: task.id, + dispatchId: dispatch.id, + outcome: 'succeeded', + result: 'actually done' + }) + + expect(states().slice(before)).toEqual([ + expect.objectContaining({ + correctedUnobservedPrompt: true, + dispatch: expect.objectContaining({ status: 'completed', workerState: 'succeeded' }), + task: { status: 'completed', result: 'actually done' } + }) + ]) + }) + + it('holds back the Task change of a correction even when a newer attempt is the latest', () => { + const first = start() + fail(first.dispatch.id, first.task.id) + db.transitionLifecycle({ + entity: 'dispatch', + id: first.dispatch.id, + from: 'failed', + to: 'failed', + projection: { last_failure: AGENT_PROMPT_STALLED_ERROR } + }) + const retry = start({ adoptTaskId: first.task.id }) + fail(retry.dispatch.id, first.task.id) + const before = states().length + + db.settleWorkerReport({ + taskId: first.task.id, + dispatchId: first.dispatch.id, + outcome: 'succeeded', + result: 'actually done' + }) + + expect(states().slice(before)).toEqual([ + expect.objectContaining({ + correctedUnobservedPrompt: true, + dispatch: expect.objectContaining({ id: first.dispatch.id }) + }) + ]) + }) + + it("queues a worker's question with its thread, so the coordinator can answer in it", () => { + const { dispatch } = start() + const { message } = db.createQuestion({ + runId: peerRun.run_id, + dispatchId: dispatch.id, + askerHandle: 'term_w', + question: 'Which branch?' + }) + const queued = pending().find((item) => item.message_id === message.id)! + expect(RemoteOwnedWorkerMail.parse(JSON.parse(queued.payload)).message.threadId).toBe( + message.id + ) + }) + + it('never reuses a sequence after a reset, and a reset tells the coordinator what it removed', () => { + const first = start() + const throughOld = Math.max(...pending().map((item) => item.sequence)) + + db.resetTasks() + const removed = states().filter((state) => state.removed) + expect(removed.map((state) => [state.dispatch.id, state.removed?.reason])).toEqual([ + [first.dispatch.id, 'reset on the server running it'] + ]) + start() + db.acknowledgeFederationRelay({ + dispatchId: peerRun.conversation_id, + direction: 'to_home', + throughSequence: throughOld + }) + + const after = pending() + expect(after.length).toBeGreaterThan(0) + expect(after.every((item) => item.sequence > throughOld)).toBe(true) + }) + + it('keeps the queue and the Run ID through a full reset, with a removed item per Dispatch', () => { + const { dispatch } = start() + db.resetAll() + + expect(states().find((state) => state.removed)?.dispatch.id).toBe(dispatch.id) + const again = db.admitPeerRun({ + peerFingerprint: 'fingerprint_a', + peerRun: { runId: 'run_home', conversationId: peerRun.conversation_id, label: 'devA' } + }) + expect(again.run_id).toBe(peerRun.run_id) + expect(db.getRun(peerRun.run_id)).toBeDefined() + }) + + it('attributes mail rerouted into the Run to the Dispatch its sender worked for when it sent it', () => { + const coordinator = `peer:${peerRun.conversation_id}` + const first = start() + const note = db.insertMessage({ + from: 'term_w', + to: 'term_unbound', + subject: 'late note', + runId: peerRun.run_id, + senderDispatchId: first.dispatch.id + }) + fail(first.dispatch.id, first.task.id) + start() + db.db.prepare('UPDATE messages SET to_handle = ? WHERE id = ?').run(coordinator, note.id) + db.db + .prepare('UPDATE messages SET to_handle = ? WHERE id = ?') + .run(`run:${peerRun.run_id}`, note.id) + + const mail = pending() + .filter((item) => item.kind === 'worker_mail') + .map((item) => RemoteOwnedWorkerMail.parse(JSON.parse(item.payload))) + expect(mail.map((item) => [item.id, item.dispatchId, item.taskId])).toEqual([ + [note.id, first.dispatch.id, first.task.id] + ]) + }) + + it('reopens an adopted Task whose last attempt settled, so the coordinator can run it again', () => { + const first = start({ adoptTaskId: 'task_home1' }) + fail(first.dispatch.id, first.task.id) + + const again = start({ adoptTaskId: 'task_home1' }) + expect(again.task.id).toBe('task_home1') + expect(again.dispatch.id).not.toBe(first.dispatch.id) + expect(() => start({ adoptTaskId: 'task_home1' })).toThrow(/only a ready Task can start/) + }) + + it('keeps a peer Run conversation and a peer-mail conversation apart, so their sequences never collide', () => { + const mailConversation = generateId('peerconv') + db.insertPeerMailMessage({ + conversationId: mailConversation, + peerFingerprint: 'fingerprint_a', + remoteParty: null, + message: { id: generateId('msg'), from: 'devA:term_x', to: 'term_w', subject: 'hi' } + }) + expect(() => + db.admitPeerRun({ + peerFingerprint: 'fingerprint_a', + peerRun: { runId: 'run_home2', conversationId: mailConversation, label: 'devA' } + }) + ).toThrow(expect.objectContaining({ code: 'request_mismatch' })) + expect(() => + db.insertPeerMailMessage({ + conversationId: peerRun.conversation_id, + peerFingerprint: 'fingerprint_a', + remoteParty: null, + message: { id: generateId('msg'), from: 'devA:term_x', to: 'term_w', subject: 'hi' } + }) + ).toThrow(expect.objectContaining({ code: 'request_mismatch' })) + }) + + it("follows a rename of the coordinating Orca's machine", () => { + const renamed = db.admitPeerRun({ + peerFingerprint: 'fingerprint_a', + peerRun: { runId: 'run_home', conversationId: peerRun.conversation_id, label: 'devA2' } + }) + expect(renamed.home_label).toBe('devA2') + }) + + it('leaves an adopted Task that still waits on its dependencies waiting', () => { + const dependency = db.createTask({ spec: 'first', runId: peerRun.run_id }) + const task = db.createTask({ + spec: 'second', + runId: peerRun.run_id, + deps: [dependency.id] + }) + expect(() => start({ adoptTaskId: task.id })).toThrow(/only a ready Task can start/) + expect(db.getTask(task.id)?.status).toBe('pending') + }) + + it('admits no start into a Run its coordinator cancelled', () => { + db.closePeerRun(peerRun.run_id) + expect(() => start()).toThrow(/cancelled by devA/) + }) +}) diff --git a/src/main/runtime/orchestration/db/peer-runs/peer-run-store.ts b/src/main/runtime/orchestration/db/peer-runs/peer-run-store.ts new file mode 100644 index 00000000000..20f70500176 --- /dev/null +++ b/src/main/runtime/orchestration/db/peer-runs/peer-run-store.ts @@ -0,0 +1,146 @@ +import type { RemoteOwnedPeerRun } from '../../../../../shared/orchestration/remote-owned-wire' +import { OrchestrationError } from '../../orchestration-error' +import { generateId } from '../generated-id' +import type { OrchestrationDb } from '../orchestration-db' +import { peerRunDispatchStateStatements } from './peer-run-queue-sql' +import { peerCoordinatorAddress } from '../../addressing/orchestration-caller-identity' + +export type PeerRunRow = { + run_id: string + conversation_id: string + peer_fingerprint: string + home_run_id: string + home_label: string + state: 'open' | 'closed' + created_at: string +} + +const NO_EFFECTS = { effectsApplied: false } as const + +/** + * The Run a paired Orca coordinates here for one conversation, written when its frame arrives and + * before any await, so a later frame of the same conversation (a cancel) always finds it. The Run + * keeps its ID across this Orca's resets: a reset that removed its row gets it back on the next call. + */ +export function admitPeerRun( + this: OrchestrationDb, + params: { peerFingerprint: string; peerRun: RemoteOwnedPeerRun } +): PeerRunRow { + const { peerFingerprint, peerRun } = params + this.db.exec('BEGIN IMMEDIATE') + try { + const conversation = this.getPeerMailConversation(peerRun.conversationId) + const existing = this.getPeerRunForConversation(peerRun.conversationId) + // A peer-mail conversation keeps its own queue sequence, so it never becomes a peer Run's. + if ( + existing + ? existing.peer_fingerprint !== peerFingerprint || existing.home_run_id !== peerRun.runId + : conversation + ) { + throw new OrchestrationError( + 'request_mismatch', + `Conversation ${peerRun.conversationId} belongs to another Run or pairing. No effects were applied.`, + NO_EFFECTS + ) + } + const runId = existing?.run_id ?? generateId('run') + if (existing && existing.home_label !== peerRun.label) { + this.db + .prepare('UPDATE peer_runs SET home_label = ? WHERE run_id = ?') + .run(peerRun.label, runId) + } + if (!existing) { + this.db + .prepare( + `INSERT OR IGNORE INTO peer_mail_conversations (conversation_id, role, peer_fingerprint) + VALUES (?, 'peer', ?)` + ) + .run(peerRun.conversationId, peerFingerprint) + this.db + .prepare( + `INSERT INTO peer_runs (run_id, conversation_id, peer_fingerprint, home_run_id, home_label) + VALUES (?, ?, ?, ?, ?)` + ) + .run(runId, peerRun.conversationId, peerFingerprint, peerRun.runId, peerRun.label) + } + if (!this.getRunRaw(runId)) { + const coordinator = peerCoordinatorAddress(peerRun.conversationId) + this.insertRunRow(runId, { + objective: `Coordinated from ${peerRun.label}`, + coordinatorHandle: coordinator, + coordinatorPaneKey: coordinator + }) + } + this.db.exec('COMMIT') + } catch (error) { + this.db.exec('ROLLBACK') + throw error + } + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the committed transaction above wrote or found this conversation's row. + return this.getPeerRunForConversation(peerRun.conversationId) as PeerRunRow +} + +export function getPeerRun(this: OrchestrationDb, runId: string): PeerRunRow | undefined { + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: SELECT * over this table returns exactly its row shape. + return this.db.prepare('SELECT * FROM peer_runs WHERE run_id = ?').get(runId) as + | PeerRunRow + | undefined +} + +export function hasPeerRuns(this: OrchestrationDb): boolean { + return this.db.prepare('SELECT 1 FROM peer_runs LIMIT 1').get() !== undefined +} + +export function getPeerRunForConversation( + this: OrchestrationDb, + conversationId: string +): PeerRunRow | undefined { + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: SELECT * over this table returns exactly its row shape. + return this.db + .prepare('SELECT * FROM peer_runs WHERE conversation_id = ?') + .get(conversationId) as PeerRunRow | undefined +} + +/** Closed for good: the claim refuses every start, follow-up and helper into it from now on. */ +export function closePeerRun(this: OrchestrationDb, runId: string): void { + this.db.prepare(`UPDATE peer_runs SET state = 'closed' WHERE run_id = ?`).run(runId) +} + +/** Inside a reset's transaction, before it deletes them: one final item per peer-Run Dispatch. */ +export function queueRemovedPeerRunDispatches(this: OrchestrationDb, reason: string): void { + const [allocate, queue] = peerRunDispatchStateStatements( + '?1', + false, + `json_object('reason', ?2)` + ).map((sql) => this.db.prepare(sql)) + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: SELECT of one column returns exactly that column. + const dispatches = this.db + .prepare( + `SELECT d.id FROM dispatch_contexts d JOIN peer_runs pr ON pr.run_id = d.run_id ORDER BY d.rowid` + ) + .all() as { id: string }[] + for (const { id } of dispatches) { + allocate.run(id, reason) + queue.run(id, reason) + } +} + +export type PeerRunStoreMethods = { + admitPeerRun: typeof admitPeerRun + getPeerRun: typeof getPeerRun + getPeerRunForConversation: typeof getPeerRunForConversation + hasPeerRuns: typeof hasPeerRuns + closePeerRun: typeof closePeerRun + queueRemovedPeerRunDispatches: typeof queueRemovedPeerRunDispatches +} + +export function attachPeerRunStore(ctor: { prototype: object }): void { + Object.assign(ctor.prototype, { + admitPeerRun, + getPeerRun, + getPeerRunForConversation, + hasPeerRuns, + closePeerRun, + queueRemovedPeerRunDispatches + }) +} diff --git a/src/main/runtime/orchestration/db/projection-mutation-triggers.ts b/src/main/runtime/orchestration/db/projection-mutation-triggers.ts new file mode 100644 index 00000000000..bd0a3a415d8 --- /dev/null +++ b/src/main/runtime/orchestration/db/projection-mutation-triggers.ts @@ -0,0 +1,30 @@ +export type ProjectionMutationTrigger = { + table: string + columns?: string + mark: (row: 'NEW' | 'OLD') => string +} + +/** Connection-local invalidations share the writer's transaction, including rollback. */ +export function projectionMutationTriggers( + name: string, + triggers: readonly ProjectionMutationTrigger[], + changed = '' +): string { + return triggers + .flatMap((trigger) => + [ + { name: 'insert', event: 'AFTER INSERT', rows: ['NEW'] as const }, + { name: 'delete', event: 'AFTER DELETE', rows: ['OLD'] as const }, + { + name: 'update', + event: trigger.columns ? `AFTER UPDATE OF ${trigger.columns}` : 'AFTER UPDATE', + rows: ['OLD', 'NEW'] as const + } + ].map( + (event) => `CREATE TEMP TRIGGER IF NOT EXISTS ${name}_${trigger.table}_${event.name} +${event.event} ON main.${trigger.table} +BEGIN ${changed} ${event.rows.map(trigger.mark).join(' ')} END;` + ) + ) + .join('\n') +} diff --git a/src/main/runtime/orchestration/db/questions/question-threads.ts b/src/main/runtime/orchestration/db/questions/question-threads.ts index 4f0be287206..5741dc5750a 100644 --- a/src/main/runtime/orchestration/db/questions/question-threads.ts +++ b/src/main/runtime/orchestration/db/questions/question-threads.ts @@ -2,6 +2,7 @@ import type { MessageRow, QuestionRow } from '../orchestration-records' import { OrchestrationError } from '../../orchestration-error' import { exposeQuestionTimestamps } from '../utc-timestamp' import type { OrchestrationDb } from '../orchestration-db' +import { generateId } from '../generated-id' import { handHelperMailToRun } from '../messages/helper-mailbox-hand-back' export function createQuestion( @@ -27,7 +28,11 @@ export function createQuestion( `Dispatch ${params.dispatchId} is not in Run ${params.runId}.` ) } + // A question is its own thread, set at insert so mail queued for a paired coordinator carries it. + const id = generateId('msg') const message = this.insertMessage({ + id, + threadId: id, from: `dispatch:${params.dispatchId}`, to: params.to ?? `run:${params.runId}`, subject: 'Question', @@ -39,9 +44,9 @@ export function createQuestion( question: params.question, options: params.options ?? [] }), + senderDispatchId: dispatch.id, runId: params.runId }) - this.db.prepare('UPDATE messages SET thread_id = ? WHERE id = ?').run(message.id, message.id) this.db .prepare( `INSERT INTO question_threads ( diff --git a/src/main/runtime/orchestration/db/reset/orchestration-reset.ts b/src/main/runtime/orchestration/db/reset/orchestration-reset.ts index ac68ba65767..b8af86962be 100644 --- a/src/main/runtime/orchestration/db/reset/orchestration-reset.ts +++ b/src/main/runtime/orchestration/db/reset/orchestration-reset.ts @@ -1,5 +1,6 @@ import { ORCHESTRATION_LEGACY_RUN_ID as LEGACY_RUN_ID } from '../../../../../shared/orchestration/orchestration-rpc-contract' import type { OrchestrationDb } from '../orchestration-db' +import { notifyPeerMailQueued } from '../../federation/peer-mail/peer-mail-waiters' import type { ResetRemovedWork } from '../../../../../shared/orchestration/orchestration-removed-work' import { readRemovedWorkWatermark, @@ -7,13 +8,22 @@ import { } from './removed-orchestration-work-read' /** Returns the removed-work watermark, read inside the transaction so the reply counts only this reset. */ -export function runResetTransaction(this: OrchestrationDb, statements: string): number { +export function runResetTransaction( + this: OrchestrationDb, + statements: string, + { removesDispatches = false }: { removesDispatches?: boolean } = {} +): number { this.db.exec('BEGIN IMMEDIATE') try { // Why unguarded: an error that ends the transaction must roll the whole reset back, not let the deletes autocommit. const watermark = readRemovedWorkWatermark(this.db) + if (removesDispatches) { + // Their paired coordinator learns of it from its queue, which the reset keeps. + this.queueRemovedPeerRunDispatches('reset on the server running it') + } this.db.exec(statements) this.db.exec('COMMIT') + notifyPeerMailQueued(this.db) return watermark } catch (error) { try { @@ -27,7 +37,8 @@ export function runResetTransaction(this: OrchestrationDb, statements: string): export function resetAll(this: OrchestrationDb): void { // Keep receipts so a lost reset reply cannot replay the mutation. - this.runResetTransaction(` + this.runResetTransaction( + ` DELETE FROM coordinator_runs; DELETE FROM decision_gates; DELETE FROM remote_questions; @@ -37,7 +48,7 @@ export function resetAll(this: OrchestrationDb): void { DELETE FROM legacy_operation_receipts; DELETE FROM legacy_compatibility_principals; DELETE FROM legacy_adoptions; - DELETE FROM federation_relay_items; + DELETE FROM federation_relay_items WHERE NOT (direction = 'to_home' AND dispatch_id IN (SELECT conversation_id FROM peer_runs)); DELETE FROM remote_dispatch_attachments; DELETE FROM federated_dispatches; DELETE FROM worker_terminal_archives; @@ -48,18 +59,22 @@ export function resetAll(this: OrchestrationDb): void { DELETE FROM dispatch_contexts; DELETE FROM tasks; DELETE FROM messages; + DELETE FROM message_dispatch_provenance; DELETE FROM run_coordinator_handles; DELETE FROM runs; DELETE FROM removed_orchestration_work; INSERT INTO runs (id, objective, home_database, consumer_generation, legacy) VALUES ('${LEGACY_RUN_ID}', 'Legacy orchestration state (inspect only)', 'this_database', 0, 1); - `) + `, + { removesDispatches: true } + ) this.hasAnyDispatchContextsCache = undefined } export function resetTasks(this: OrchestrationDb): ResetRemovedWork | undefined { // Messages survive, and so do replies waiting for a paired Orca to pull them; close threads so orphaned questions cannot masquerade as generic replies. - const watermark = this.runResetTransaction(` + const watermark = this.runResetTransaction( + ` DELETE FROM coordinator_runs; DELETE FROM decision_gates; DELETE FROM remote_questions; @@ -70,7 +85,7 @@ export function resetTasks(this: OrchestrationDb): ResetRemovedWork | undefined DELETE FROM legacy_operation_receipts; DELETE FROM legacy_compatibility_principals; DELETE FROM legacy_adoptions; - DELETE FROM federation_relay_items WHERE kind <> 'peer_mail'; + DELETE FROM federation_relay_items WHERE kind <> 'peer_mail' AND NOT (direction = 'to_home' AND dispatch_id IN (SELECT conversation_id FROM peer_runs)); DELETE FROM remote_dispatch_attachments; DELETE FROM federated_dispatches; DELETE FROM worker_terminal_archives; @@ -80,7 +95,9 @@ export function resetTasks(this: OrchestrationDb): ResetRemovedWork | undefined DELETE FROM worker_dispatches; DELETE FROM dispatch_contexts; DELETE FROM tasks; - `) + `, + { removesDispatches: true } + ) this.hasAnyDispatchContextsCache = undefined return summarizeRemovedWorkSince(this.db, watermark) } @@ -92,6 +109,7 @@ export function resetMessages(this: OrchestrationDb): void { DELETE FROM question_threads; DELETE FROM deliveries; DELETE FROM messages; + DELETE FROM message_dispatch_provenance; DELETE FROM structured_pointer_operations; `) } diff --git a/src/main/runtime/orchestration/db/runs/run-binding.ts b/src/main/runtime/orchestration/db/runs/run-binding.ts index 0d47fd2e34c..6950c8cba8b 100644 --- a/src/main/runtime/orchestration/db/runs/run-binding.ts +++ b/src/main/runtime/orchestration/db/runs/run-binding.ts @@ -42,6 +42,15 @@ export function bindRun( return undefined } const sameBinding = runBoundToCoordinator(run, coordinator) + const peerRun = this.getPeerRun(params.runId) + if (peerRun && !sameBinding) { + // A paired Orca's Run has that Orca as its only consumer; it never binds anything here. + throw new OrchestrationError( + 'consumer_fenced', + `Run ${params.runId} is coordinated from ${peerRun.home_label}, which stays its only coordinator. No effects were applied.`, + { effectsApplied: false } + ) + } const explicitTakeover = params.takeoverLegacy === true // Why: before the legacy gate, so a worker never sees its --takeover-legacy recovery command. const workerRefusal = sameBinding diff --git a/src/main/runtime/orchestration/db/runs/run-create.ts b/src/main/runtime/orchestration/db/runs/run-create.ts index 53b17414ea6..6ce7877082c 100644 --- a/src/main/runtime/orchestration/db/runs/run-create.ts +++ b/src/main/runtime/orchestration/db/runs/run-create.ts @@ -4,42 +4,19 @@ import type { OrchestrationDb } from '../orchestration-db' import type { OrcaSessionId } from '../../../../../shared/orca-session-address' import { mailboxAddressOf } from '../../addressing/orchestration-caller-identity' -export function createRun( - this: OrchestrationDb, - params: { - objective: string - coordinatorHandle: string | null - coordinatorPaneKey: string | null - /** The coordinator's bare Orca session id when it is a structured session; see orca-session-address. */ - coordinatorOrcaSessionId?: OrcaSessionId | null - } -): RunRow { - const coordinator = { - terminalHandle: params.coordinatorHandle, - paneKey: params.coordinatorPaneKey, - orcaSessionId: params.coordinatorOrcaSessionId ?? null - } +type RunCoordinatorParams = { + objective: string + coordinatorHandle: string | null + coordinatorPaneKey: string | null + /** The coordinator's bare Orca session id when it is a structured session; see orca-session-address. */ + coordinatorOrcaSessionId?: OrcaSessionId | null +} + +export function createRun(this: OrchestrationDb, params: RunCoordinatorParams): RunRow { const id = generateId('run') this.db.exec('BEGIN IMMEDIATE') try { - this.db - .prepare( - `INSERT INTO runs ( - id, objective, coordinator_handle, coordinator_pane_key, coordinator_orca_session_id, - coordinator_orca_session_id_generation, consumer_generation, legacy - ) VALUES (?, ?, ?, ?, ?, 1, 1, 0)` - ) - .run( - id, - params.objective, - coordinator.terminalHandle, - coordinator.paneKey, - coordinator.orcaSessionId - ) - const address = mailboxAddressOf(coordinator) - if (address !== null) { - this.rememberRunCoordinatorHandle(id, address) - } + this.insertRunRow(id, params) this.db.exec('COMMIT') } catch (error) { this.db.exec('ROLLBACK') @@ -48,12 +25,45 @@ export function createRun( return this.getRun(id) as RunRow } +/** Writes a Run bound to its coordinator inside the caller's transaction. */ +export function insertRunRow( + this: OrchestrationDb, + id: string, + params: RunCoordinatorParams +): void { + const coordinator = { + terminalHandle: params.coordinatorHandle, + paneKey: params.coordinatorPaneKey, + orcaSessionId: params.coordinatorOrcaSessionId ?? null + } + this.db + .prepare( + `INSERT INTO runs ( + id, objective, coordinator_handle, coordinator_pane_key, coordinator_orca_session_id, + coordinator_orca_session_id_generation, consumer_generation, legacy + ) VALUES (?, ?, ?, ?, ?, 1, 1, 0)` + ) + .run( + id, + params.objective, + coordinator.terminalHandle, + coordinator.paneKey, + coordinator.orcaSessionId + ) + const address = mailboxAddressOf(coordinator) + if (address !== null) { + this.rememberRunCoordinatorHandle(id, address) + } +} + export type RunCreateMethods = { createRun: typeof createRun + insertRunRow: typeof insertRunRow } export function attachRunCreate(ctor: { prototype: object }): void { Object.assign(ctor.prototype, { - createRun + createRun, + insertRunRow }) } diff --git a/src/main/runtime/orchestration/db/schema/create-tables.ts b/src/main/runtime/orchestration/db/schema/create-tables.ts index 1895230e847..5378ee71629 100644 --- a/src/main/runtime/orchestration/db/schema/create-tables.ts +++ b/src/main/runtime/orchestration/db/schema/create-tables.ts @@ -3,9 +3,12 @@ import { createCoreTablesSql } from './create-core-tables-sql' import { createGraphTablesSql } from './create-graph-tables-sql' import { DERIVED_DELIVERY_SCHEMA_SQL } from './migrate-v41' import { REMOVED_WORK_SCHEMA_SQL } from '../reset/removed-orchestration-work-store' +import { PEER_RUN_SCHEMA_SQL } from '../peer-runs/peer-run-queue-sql' export function createTables(this: OrchestrationDb): void { - this.db.exec(`${createCoreTablesSql()}\n${createGraphTablesSql()}\n${REMOVED_WORK_SCHEMA_SQL}`) + this.db.exec( + `${createCoreTablesSql()}\n${createGraphTablesSql()}\n${REMOVED_WORK_SCHEMA_SQL}\n${PEER_RUN_SCHEMA_SQL}` + ) // Unreleased builds saved each send's fence as NOT NULL; nothing reads it, and new rows carry none. if (this.hasColumn('structured_mail_sends', 'fence')) { this.db.exec('ALTER TABLE structured_mail_sends DROP COLUMN fence') diff --git a/src/main/runtime/orchestration/db/tasks/task-store.ts b/src/main/runtime/orchestration/db/tasks/task-store.ts index 401d3d68544..aebef0d890f 100644 --- a/src/main/runtime/orchestration/db/tasks/task-store.ts +++ b/src/main/runtime/orchestration/db/tasks/task-store.ts @@ -10,6 +10,8 @@ import { selectColumns, TASK_COLUMNS } from '../row-column-lists' export function createTask( this: OrchestrationDb, task: { + /** Set only for a Task placed on a paired server: one ID for it here and there, from the start's retry key. */ + id?: string spec: string taskTitle?: string displayName?: string @@ -39,7 +41,7 @@ export function createTask( throw new Error(`Dependency task ${depId} must belong to run ${runId}`) } } - const id = generateId('task') + const id = task.id ?? generateId('task') const depsJson = JSON.stringify(task.deps ?? []) const display = buildOrchestrationTaskDisplayMetadata({ spec: task.spec, diff --git a/src/main/runtime/orchestration/db/worker-dispatch/worker-dispatch-start.ts b/src/main/runtime/orchestration/db/worker-dispatch/worker-dispatch-start.ts index b65da6e2f61..f45cf6677e0 100644 --- a/src/main/runtime/orchestration/db/worker-dispatch/worker-dispatch-start.ts +++ b/src/main/runtime/orchestration/db/worker-dispatch/worker-dispatch-start.ts @@ -18,6 +18,8 @@ export function createStartingWorkerDispatch( params: { taskId?: string taskSpec?: string + /** The paired coordinator's ID for this Task: an existing one is reopened, else the new one takes it. */ + adoptTaskId?: string taskRunId?: string taskCreatedByTerminalHandle?: string taskCreatedByPaneKey?: string @@ -89,26 +91,42 @@ export function createStartingWorkerDispatch( { followUpDispatchId: claimedFollowUp.id } ) } + const adopted = params.adoptTaskId ? this.getTask(params.adoptTaskId) : undefined + if (adopted && !params.retryOf) { + reopenSettledAdoptedTask(this, adopted, params.taskRunId) + } const task = params.taskId ? this.getTask(params.taskId) - : params.taskSpec - ? this.createTask({ - spec: params.taskSpec, - taskTitle: params.taskTitle, - deps: params.taskDeps, - parentId: params.taskParentId, - createdByTerminalHandle: params.taskCreatedByTerminalHandle, - createdByPaneKey: params.taskCreatedByPaneKey, - createdByProcessIncarnation: params.taskCreatedByProcessIncarnation, - createdByRunGeneration: params.taskCreatedByRunGeneration, - runId: params.taskRunId - }) - : undefined + : adopted + ? this.getTask(adopted.id) + : params.taskSpec + ? this.createTask({ + id: params.adoptTaskId, + spec: params.taskSpec, + taskTitle: params.taskTitle, + deps: params.taskDeps, + parentId: params.taskParentId, + createdByTerminalHandle: params.taskCreatedByTerminalHandle, + createdByPaneKey: params.taskCreatedByPaneKey, + createdByProcessIncarnation: params.taskCreatedByProcessIncarnation, + createdByRunGeneration: params.taskCreatedByRunGeneration, + runId: params.taskRunId + }) + : undefined if (!task) { // An inline spec already creates its Task; missing rows here imply an explicit id. const taskId = params.taskId ?? '' throw taskNotFoundError(`Task ${taskId} was not found.`, { taskId }) } + const peerRun = this.getPeerRun(task.run_id) + if (peerRun?.state === 'closed') { + // Starts, follow-ups and helpers alike: its coordinator cancelled it. + throw new OrchestrationError( + 'run_not_found', + `Run ${task.run_id} was cancelled by ${peerRun.home_label}. No effects were applied.`, + { effectsApplied: false } + ) + } let priorFailures = 0 if (params.retryOf) { const prior = this.getDispatchContextById(params.retryOf) @@ -251,3 +269,30 @@ export function attachWorkerDispatchStart(ctor: { prototype: object }): void { createStartingWorkerDispatch }) } + +/** A Task its paired coordinator reopened gets a new attempt here once its latest attempt settled. */ +function reopenSettledAdoptedTask( + db: OrchestrationDb, + task: TaskRow, + runId: string | undefined +): void { + if (task.run_id !== runId) { + throw taskNotFoundError(`Task ${task.id} was not found in Run ${runId ?? ''}.`, { + taskId: task.id + }) + } + const latest = db.getDispatchContext(task.id) + const worker = latest ? db.getWorkerDispatch(latest.id) : undefined + const settled = worker + ? ['succeeded', 'failed', 'stopped', 'abandoned'].includes(worker.state) + : !latest || ['completed', 'failed', 'circuit_broken'].includes(latest.status) + // A pending Task still waits on its dependencies; the ordinary promotion readies it. + if (settled && task.status !== 'ready' && task.status !== 'pending') { + transitionLifecycleWithDb(db.db, { + entity: 'task', + id: task.id, + from: task.status, + to: 'ready' + }) + } +} diff --git a/src/main/runtime/orchestration/db/worker-terminal/worker-terminal-attention-query.ts b/src/main/runtime/orchestration/db/worker-terminal/worker-terminal-attention-query.ts index bb908a26d07..a4c81f024cb 100644 --- a/src/main/runtime/orchestration/db/worker-terminal/worker-terminal-attention-query.ts +++ b/src/main/runtime/orchestration/db/worker-terminal/worker-terminal-attention-query.ts @@ -27,18 +27,39 @@ export type WorkerAttentionFacts = { releaseState?: string | null } -export function getWorkerAttentionFactsForDispatches( - this: OrchestrationDb, - dispatchIds: readonly string[], - authorityNow: number -): Map { +type WorkerAttentionRow = { + dispatch_id: string + task_id: string + dispatch_status: DispatchStatus + termination_reason: TerminalExitCause['kind'] | null + worker_state: WorkerDispatchState | null + worker_stage: string | null + parent_task_id: string | null + resource_id: string | null + host_scope: string | null + release_state: string | null + pending_input: number + pending_approval: number + pending_guidance: number + active_sibling: number +} + +export type WorkerAttentionInput = { + row: WorkerAttentionRow + observations: ReturnType[] +} + +export function readWorkerAttentionInputs( + db: OrchestrationDb, + dispatchIds: readonly string[] +): Map { const ids = [...new Set(dispatchIds)] if (ids.length === 0) { return new Map() } const serializedIds = JSON.stringify(ids) - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: this row cast is unchanged and matches every other row cast in db/; the gate flags it only because this diff adds a column inside its span. - const rows = this.db + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the query selects each schema-owned WorkerAttentionRow column. + const rows = db.db .prepare( `SELECT d.id AS dispatch_id, d.task_id, d.status AS dispatch_status, d.termination_reason, w.state AS worker_state, w.stage AS worker_stage, @@ -64,26 +85,17 @@ export function getWorkerAttentionFactsForDispatches( LEFT JOIN worker_terminal_resources r ON r.owner_dispatch_id = d.id WHERE d.id IN (SELECT value FROM json_each(?))` ) - .all(serializedIds) as { - dispatch_id: string - task_id: string - dispatch_status: DispatchStatus - termination_reason: TerminalExitCause['kind'] | null - worker_state: WorkerDispatchState | null - worker_stage: string | null - parent_task_id: string | null - resource_id: string | null - host_scope: string | null - release_state: string | null - pending_input: number - pending_approval: number - pending_guidance: number - active_sibling: number - }[] - const observationRows = this.db + .all(serializedIds) as WorkerAttentionRow[] + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the query selects the schema-owned observation column list. + const observationRows = db.db .prepare( `SELECT ${ATTEMPT_OBSERVATION_FACT_COLUMN_LIST} FROM attempt_observation_facts - WHERE dispatch_id IN (SELECT value FROM json_each(?)) + WHERE rowid IN ( + SELECT (SELECT rowid FROM attempt_observation_facts + WHERE dispatch_id = requested.value AND facet = facets.value + ORDER BY sequence DESC LIMIT 1) + FROM json_each(?) requested, json_each('["process_turn","artifact_git","worker_report","coordinator_ack","liveness","outcome"]') facets + ) ORDER BY dispatch_id, sequence, rowid` ) .all(serializedIds) as AttemptObservationStorageRow[] @@ -95,34 +107,58 @@ export function getWorkerAttentionFactsForDispatches( } return new Map( rows.map((row) => { - const projected = projectAttemptOutcome({ - dispatchId: row.dispatch_id, - taskId: row.task_id, - facts: factsByDispatch.get(row.dispatch_id) ?? [], - activeSibling: row.active_sibling === 1, - authorityNow: { home: authorityNow } - }).taskOutcome - return [ - row.dispatch_id, - { - outcome: projected, - pendingInput: row.pending_input === 1, - pendingGuidance: row.pending_guidance === 1, - pendingApproval: row.pending_approval === 1, - terminationReason: row.termination_reason, - isRoot: row.parent_task_id === null, - workerState: row.worker_state, - workerStage: row.worker_stage, - dispatchStatus: row.dispatch_status, - ...(row.resource_id === null - ? {} - : { hostScope: row.host_scope, releaseState: row.release_state }) + const latest = new Map>() + for (const fact of factsByDispatch.get(row.dispatch_id) ?? []) { + const previous = latest.get(fact.facet) + if (!previous || previous.sequence < fact.sequence) { + latest.set(fact.facet, fact) } - ] + } + return [row.dispatch_id, { row, observations: [...latest.values()] }] }) ) } +export function projectWorkerAttentionInput( + input: WorkerAttentionInput, + authorityNow: number +): WorkerAttentionFacts { + const { row, observations } = input + return { + outcome: projectAttemptOutcome({ + dispatchId: row.dispatch_id, + taskId: row.task_id, + facts: observations, + activeSibling: row.active_sibling === 1, + authorityNow: { home: authorityNow } + }).taskOutcome, + pendingInput: row.pending_input === 1, + pendingGuidance: row.pending_guidance === 1, + pendingApproval: row.pending_approval === 1, + terminationReason: row.termination_reason, + isRoot: row.parent_task_id === null, + workerState: row.worker_state, + workerStage: row.worker_stage, + dispatchStatus: row.dispatch_status, + ...(row.resource_id === null + ? {} + : { hostScope: row.host_scope, releaseState: row.release_state }) + } +} + +export function getWorkerAttentionFactsForDispatches( + this: OrchestrationDb, + dispatchIds: readonly string[], + authorityNow: number +): Map { + return new Map( + [...readWorkerAttentionInputs(this, dispatchIds)].map(([id, input]) => [ + id, + projectWorkerAttentionInput(input, authorityNow) + ]) + ) +} + export function getWorkerAttentionFacts( this: OrchestrationDb, dispatchId: string, diff --git a/src/main/runtime/orchestration/db/worker-terminal/worker-terminal-listing.ts b/src/main/runtime/orchestration/db/worker-terminal/worker-terminal-listing.ts index 3e625c2126c..c2ce51ded5e 100644 --- a/src/main/runtime/orchestration/db/worker-terminal/worker-terminal-listing.ts +++ b/src/main/runtime/orchestration/db/worker-terminal/worker-terminal-listing.ts @@ -103,6 +103,8 @@ export function listWorkerTerminalResources( pendingApproval: boolean terminationReason: TerminalExitCause['kind'] | null resource: WorkerTerminalResourceRow | null + /** The paired Orca's name when its Run here coordinates this worker. */ + coordinatedFrom: string | null createdAt: string databaseId: number }[] { @@ -170,6 +172,7 @@ export function listWorkerTerminalResources( t.parent_id AS parent_task_id, d.task_id, d.run_id, d.status AS dispatch_status, d.termination_reason, + (SELECT home_label FROM peer_runs WHERE run_id = d.run_id) AS coordinated_from, EXISTS ( SELECT 1 FROM question_threads q WHERE q.dispatch_id = d.id AND q.status = 'pending' @@ -199,6 +202,7 @@ export function listWorkerTerminalResources( termination_reason: TerminalExitCause['kind'] | null pending_input: number pending_approval: number + coordinated_from: string | null created_at: string database_id: number }[] @@ -236,6 +240,7 @@ export function listWorkerTerminalResources( pendingApproval: row.pending_approval === 1, terminationReason: row.termination_reason, resource, + coordinatedFrom: row.coordinated_from, createdAt: row.created_at, databaseId: row.database_id } diff --git a/src/main/runtime/orchestration/federation/peer-mail/peer-mail-waiters.ts b/src/main/runtime/orchestration/federation/peer-mail/peer-mail-waiters.ts index 0e2b13c329d..5b88ac6206d 100644 --- a/src/main/runtime/orchestration/federation/peer-mail/peer-mail-waiters.ts +++ b/src/main/runtime/orchestration/federation/peer-mail/peer-mail-waiters.ts @@ -1,17 +1,18 @@ -import type { OrchestrationDb } from '../../db/orchestration-db' +import type Database from '../../../../sqlite/sync-database' -const waiters = new WeakMap void>>() +const waiters = new WeakMap void>>() -/** Wakes every pull waiting on this store; each re-reads its own conversations. */ -export function notifyPeerMailQueued(db: OrchestrationDb): void { +/** Wakes every pull waiting on this database; each re-reads its own conversations. Called by every + * write that can queue an item home: a reply, a message filed in a Run, a lifecycle change, a reset. */ +export function notifyPeerMailQueued(db: Database.Database): void { for (const wake of waiters.get(db) ?? []) { wake() } } -/** Resolves when a reply is queued, the wait ends, or the caller goes away. */ +/** Resolves when an item may have been queued, the wait ends, or the caller goes away. */ export function waitForPeerMail( - db: OrchestrationDb, + db: Database.Database, timeoutMs: number, signal?: AbortSignal ): Promise { diff --git a/src/main/runtime/orchestration/legacy-remote-home/federated-worker-child-parent.ts b/src/main/runtime/orchestration/legacy-remote-home/federated-worker-child-parent.ts index e0249544e10..be0580a0127 100644 --- a/src/main/runtime/orchestration/legacy-remote-home/federated-worker-child-parent.ts +++ b/src/main/runtime/orchestration/legacy-remote-home/federated-worker-child-parent.ts @@ -1,5 +1,5 @@ import type { OrcaRuntimeService } from '../../orca-runtime' -import type { OrchestrationSessionCaller } from '../addressing/orchestration-caller-identity' +import type { OrchestrationEntryCaller } from '../addressing/orchestration-caller-identity' import { OrchestrationError } from '../orchestration-error' import { readCallerStoreInstallationId } from '../../hosts/platform-probe/host-descriptor' import { getCanonicalUserDataPath } from '../../../persistence/loading-store/user-data-path' @@ -22,7 +22,7 @@ export async function resolveFederatedChildParent(args: { | 'getRuntimeId' > from: string - callerSession: OrchestrationSessionCaller | undefined + callerSession: OrchestrationEntryCaller | undefined serverCapabilities: readonly string[] | undefined serverName: string }): Promise< diff --git a/src/main/runtime/orchestration/legacy-remote-home/federated-worker-start-request.ts b/src/main/runtime/orchestration/legacy-remote-home/federated-worker-start-request.ts index 21dd2d80613..d4a6950dfc6 100644 --- a/src/main/runtime/orchestration/legacy-remote-home/federated-worker-start-request.ts +++ b/src/main/runtime/orchestration/legacy-remote-home/federated-worker-start-request.ts @@ -1,4 +1,4 @@ -import type { OrchestrationSessionCaller } from '../addressing/orchestration-caller-identity' +import type { OrchestrationEntryCaller } from '../addressing/orchestration-caller-identity' import type { OrcaRuntimeService } from '../../orca-runtime' import type { OrchestrationDb } from '../db/orchestration-db' import type { WorkerStartInput } from '../../rpc/methods/orchestration/worker/worker-start-schema' @@ -14,5 +14,5 @@ export type FederatedWorkerStartRequest = { taskDeps: string[] | undefined orchestrationMutation?: WorkerStartMutation /** The coordinator's resolved session, when it is one; recorded as the Dispatch creator. */ - callerSession?: OrchestrationSessionCaller + callerSession?: OrchestrationEntryCaller } diff --git a/src/main/runtime/orchestration/mailbox/routing/terminal-pane-mail-routing.ts b/src/main/runtime/orchestration/mailbox/routing/terminal-pane-mail-routing.ts index eac7375b1ad..6c76e0aec68 100644 --- a/src/main/runtime/orchestration/mailbox/routing/terminal-pane-mail-routing.ts +++ b/src/main/runtime/orchestration/mailbox/routing/terminal-pane-mail-routing.ts @@ -1,7 +1,6 @@ -import { - ptyRecordForPaneKey, - type TerminalIdentityReadContext -} from '../../../terminal/query/terminal-identity-read-context' +import { ORCA_LAYOUT_OWNER_IS_MAIN } from '../../../../../shared/layout-owner-switch' +import type { TerminalIdentityReadContext } from '../../../terminal/query/terminal-identity-read-context' +import { ptyRecordForPaneKey } from '../../../terminal/query/pty-pane-record' import type { RuntimeTerminalAgentPresenceOptions } from '../../../terminal/query/runtime-terminal-agent-presence' import { OrcaRuntimeWithPruneMobileSessionTabGroupLayout } from '../../../session-lifecycle/projection/prune-mobile-session-tab-group-layout' import type { RuntimePtyWorktreeRecord } from '../../../terminal/records/runtime-terminal-state-records' @@ -52,7 +51,14 @@ export abstract class OrcaRuntimeWithGetPtyRecordForPaneKey extends OrcaRuntimeW leaves: this.leaves, ptys: this.ptysById, leafKey: (tab, leaf) => this.getLeafKey(tab, leaf), - capturePaneOf: () => this.captureTerminalPaneReader() + capturePaneOf: () => this.captureTerminalPaneReader(), + ...(!ORCA_LAYOUT_OWNER_IS_MAIN + ? { + paneOf: (pty: Parameters[0]) => this.paneOfPty(pty), + leavesForId: (id: string) => this.terminalIdentity.paneCandidates.leavesForId(id), + ptysForPane: (pane: string) => this.terminalIdentity.paneCandidates.ptysForPane(pane) + } + : {}) }, context ) diff --git a/src/main/runtime/orchestration/mailbox/terminal-pointer/in-memory-orchestration-messages.spec.ts b/src/main/runtime/orchestration/mailbox/terminal-pointer/in-memory-orchestration-messages.spec.ts index 264b99b1f56..b7d5ab26485 100644 --- a/src/main/runtime/orchestration/mailbox/terminal-pointer/in-memory-orchestration-messages.spec.ts +++ b/src/main/runtime/orchestration/mailbox/terminal-pointer/in-memory-orchestration-messages.spec.ts @@ -5,6 +5,10 @@ import type { MessagePriority, MessageRow, MessageType } from '../../db/orchestr export class InMemoryOrchestrationMessages { readonly crewChanges = new CrewChanges() + hasAnyDispatchContexts(): boolean { + return false + } + private sequence = 0 private activeCoordinatorRun: { coordinator_handle: string } | null = null diff --git a/src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-cursor-native-title.spec.ts b/src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-cursor-native-title.spec.ts new file mode 100644 index 00000000000..32ff156a737 --- /dev/null +++ b/src/main/runtime/orchestration/mailbox/terminal-pointer/orchestration-cursor-native-title.spec.ts @@ -0,0 +1,47 @@ +import { rmSync } from 'node:fs' +import { afterEach, describe, expect, it, vi } from 'vitest' +import { settledWriteStub } from '../../../../providers/settled-pty-write-stub' +import { + createBoundRun, + createDatabase, + createRuntime, + insertDirectRunMessage, + PTY_ID, + temporaryDirectories +} from './orchestration-mailbox-notification-test-harness' + +describe('mail to a Cursor worker under its own status title', () => { + afterEach(() => { + vi.useRealTimers() + for (const directory of temporaryDirectories.splice(0)) { + rmSync(directory, { recursive: true, force: true }) + } + }) + + // cursor-agent titles its pane ` -