Files
orca/src/shared/agent-launch-operation.test.ts
T
OrcaWinandOrcaWin 70c4c55db9 test: remove duplicate coverage and strengthen boundary assertions (#33047)
* test: strengthen launch, subject identity, and release witnesses

* test: strengthen approval paths and prompt answer boundaries

* test: strengthen conversation names and mobile log persistence

* refactor: group background task stop contract with stop operations

* test: strengthen question, title, and release validation

* test: distinguish row text and generated dispatch titles

* test: verify mobile revival events and retry exclusivity

* test: reject incomplete child row output assertions

* test: verify copied modules and option selection contracts

* test: verify mobile host state and status retry boundaries

* test: observe connector refusals and real diagnostic delivery

* test: consolidate platform memory coverage and verify bounded work

* test: allow cached legacy failure reads within work bounds

* test: verify packaging boundaries with independent fixtures

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-24 00:13:25 -07:00

133 lines
5.8 KiB
TypeScript

/**
* Which launch inputs the replay digest covers, and — just as deliberately — which it does not.
*
* The digest decides whether a retry replays the first answer or is refused as a different call
* wearing the same id, so every field added to the launch wire is a decision in one of two
* directions. Both directions are pinned here: a behavioural field that fell OUT would let a retry
* carrying different arguments silently inherit the original's outcome, and a telemetry field that
* crept IN would refuse an honest retry that merely got re-attributed.
*/
import { describe, expect, it } from 'vitest'
import {
computeAgentLaunchFingerprint,
type AgentLaunchFingerprintInput
} from './agent-launch-operation'
import { canonicalAgentSessionDigest } from './agent-session-mutation-envelope'
const BASE = {
agent: 'claude',
target: { kind: 'existing' as const, worktree: 'wt-1' }
}
const PANE_KEY = '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d:3f2504e0-4f89-41d3-9a0c-0305e82c3301'
const OTHER_PANE_KEY = '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d:6fa459ea-ee8a-4ca4-894e-db77e160355e'
/**
* The handler digests the whole params object, `launchSource` included — excess properties are only
* rejected on an object literal, never on the params value it actually passes. Going through this
* signature keeps the exclusion tests honest: they prove the digest IGNORES the field at runtime,
* not merely that the input type has no name for it.
*/
function fingerprintOfWirePayload(
params: AgentLaunchFingerprintInput & { launchSource?: string }
): string {
return computeAgentLaunchFingerprint(params)
}
describe('fields the launch fingerprint covers', () => {
it('separates two launches that differ only in agentArgs', () => {
expect(computeAgentLaunchFingerprint({ ...BASE, agentArgs: '--model opus' })).not.toBe(
computeAgentLaunchFingerprint({ ...BASE, agentArgs: '--model sonnet' })
)
})
it('treats an explicit "no arguments" as different from falling back to the settings default', () => {
// `null` and absent are the tri-state the wire keeps; collapsing them here would let a retry
// that cleared its arguments replay an answer produced with the user's configured ones.
expect(computeAgentLaunchFingerprint({ ...BASE, agentArgs: null })).not.toBe(
computeAgentLaunchFingerprint(BASE)
)
})
it('separates two launches that differ only in cwd', () => {
expect(computeAgentLaunchFingerprint({ ...BASE, cwd: '/repo/packages/a' })).not.toBe(
computeAgentLaunchFingerprint({ ...BASE, cwd: '/repo/packages/b' })
)
})
it('separates two launches that reserved different panes or sessions', () => {
// The key is baked into the pane's env; replaying another pane's key strands the new reservation.
expect(computeAgentLaunchFingerprint({ ...BASE, paneKey: PANE_KEY })).not.toBe(
computeAgentLaunchFingerprint({ ...BASE, paneKey: OTHER_PANE_KEY })
)
expect(computeAgentLaunchFingerprint({ ...BASE, paneKey: PANE_KEY })).not.toBe(
computeAgentLaunchFingerprint(BASE)
)
const sessionId = '11111111-1111-4111-8111-111111111111'
expect(computeAgentLaunchFingerprint({ ...BASE, sessionId })).not.toBe(
computeAgentLaunchFingerprint({ ...BASE, sessionId: '22222222-2222-4222-8222-222222222222' })
)
expect(computeAgentLaunchFingerprint({ ...BASE, sessionId })).not.toBe(
computeAgentLaunchFingerprint(BASE)
)
})
it('separates a retry that picked another surface, or none, from the first launch', () => {
const terminal = computeAgentLaunchFingerprint({ ...BASE, surface: 'terminal' })
expect(terminal).not.toBe(computeAgentLaunchFingerprint({ ...BASE, surface: 'chat' }))
expect(terminal).not.toBe(computeAgentLaunchFingerprint(BASE))
})
})
describe('fields the launch fingerprint deliberately ignores', () => {
it('does not separate two launches that differ only in launchSource', () => {
// Telemetry. Two buttons producing the same launch are one operation, and a retry that got
// re-attributed must replay rather than be refused as a conflict.
expect(fingerprintOfWirePayload({ ...BASE, launchSource: 'shortcut' })).toBe(
fingerprintOfWirePayload({ ...BASE, launchSource: 'tab_bar_quick_launch' })
)
})
it('ignores launchSource entirely, so sending one matches sending none', () => {
expect(fingerprintOfWirePayload({ ...BASE, launchSource: 'sidebar' })).toBe(
computeAgentLaunchFingerprint(BASE)
)
})
})
describe('compatibility with rows written before these fields existed', () => {
/**
* A client that sends none of the new fields must still digest to what the previous build
* produced, or an upgraded host would refuse the in-flight retries of every launch admitted
* before it restarted. This is the old expression verbatim rather than a captured constant, so it
* keeps checking the property rather than a value someone can re-record.
*/
it('matches the pre-existing digest when no new field is sent', () => {
const previousBuild = canonicalAgentSessionDigest({
method: 'agent.launch',
agent: BASE.agent,
target: BASE.target,
prompt: undefined,
sessionOptions: undefined,
reuseTerminal: undefined
})
expect(computeAgentLaunchFingerprint(BASE)).toBe(previousBuild)
})
it('matches the digest from before the pane key existed when no pane is reserved', () => {
const beforePaneKey = canonicalAgentSessionDigest({
method: 'agent.launch',
agent: BASE.agent,
target: BASE.target,
prompt: undefined,
sessionOptions: undefined,
reuseTerminal: undefined,
agentArgs: '--model opus',
cwd: '/repo/packages/a'
})
expect(
computeAgentLaunchFingerprint({ ...BASE, agentArgs: '--model opus', cwd: '/repo/packages/a' })
).toBe(beforePaneKey)
})
})