From f19c9b207ce01b651b94ad24b421ca7eb2ca06aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Fri, 25 Sep 2026 18:13:34 +0200 Subject: [PATCH 1/3] test: delete tests that only assert their own scaffolding Audit lanes found assertions that cannot fail for a production reason. Each deletion here was measured by planting the bug it claims to catch and proving a surviving test goes red; candidates that no surviving test caught were kept. Removed shapes: - self-comparison: the daemon closure-trait table compared against the derive helper that produced it, the MCP exposure list rebuilt from the same filter, the runtime-fact catalog intersected with the CLI names derived from the same catalog, and the Apple trait helpers looped against the table they read. - fixture restated as expectation: the runner-protocol fixture compared its own keys to the trait table it types against, while runner-requests.json already owns per-command wire coverage. - assertion-free composition probes and `typeof x === 'function'` rows beside the test that calls x, kept only where nothing else reached the seam. - duplicated strictness: the Apple keyboard reader re-pinned the kernel's `readSnapshotKeyboardBandFact` table; the seam now asserts forwarding only. - test-only exports deleted with their callers: `shouldResetDaemonAfterRequestTimeout` keeps one caller in the module that declares it. Kept after measuring, because the mutant survived every other test: the boot keep-hot witness, owner-cleanup composition, `--update` retirement residue, the package gate's probe assertions, the shutdown teardown-mechanic parity, the restricted-by-default runtime policy, and the screenshot flag key arrays where a duplicate key is invisible to a membership scan. --- .../__tests__/apps-runtime-execution.test.ts | 1 - .../appstate-runtime-execution.test.ts | 1 - .../__tests__/boot-runtime-execution.test.ts | 1 - .../__tests__/click-runtime-execution.test.ts | 4 - .../__tests__/find-runtime-execution.test.ts | 1 - .../__tests__/focus-runtime-execution.test.ts | 2 - .../screenshot-runtime-execution.test.ts | 2 - .../snapshot-runtime-execution.test.ts | 4 - .../__tests__/type-runtime-execution.test.ts | 2 - .../viewport-runtime-execution.test.ts | 2 - .../__tests__/wait-runtime-execution.test.ts | 2 - .../runner/__tests__/runner-client.test.ts | 85 +-------- .../__tests__/runner-command-traits.test.ts | 21 --- .../__tests__/snapshot-presentation.test.ts | 42 ++--- .../command-descriptor-parity.test.ts | 75 +------- ...criptor-shutdown-runtime-execution.test.ts | 1 - src/__tests__/runtime-public.test.ts | 12 +- .../interaction/runtime/settle.test.ts | 169 ------------------ .../schema/command-schema-guards.test.ts | 19 +- .../__tests__/daemon-client.test.ts | 47 ----- src/daemon-client/daemon-client-timeout.ts | 2 +- .../__tests__/snapshot-handler-wait.test.ts | 16 -- ...form-runtime-screen-recording-host.test.ts | 15 -- 23 files changed, 20 insertions(+), 506 deletions(-) delete mode 100644 src/platform-runtime-screen-recording-host.test.ts diff --git a/packages/command-registry/src/__tests__/apps-runtime-execution.test.ts b/packages/command-registry/src/__tests__/apps-runtime-execution.test.ts index eccd932b25..87a4eb9fcc 100644 --- a/packages/command-registry/src/__tests__/apps-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/apps-runtime-execution.test.ts @@ -11,5 +11,4 @@ test('apps declares the complete request-scoped runtime use', () => { }); expect(appsRuntimeUse.required).toEqual(['ensureReady', 'listApps']); expect(appsRuntimeUse.preferred).toEqual([]); - expect(descriptor).not.toHaveProperty('capability'); }); diff --git a/packages/command-registry/src/__tests__/appstate-runtime-execution.test.ts b/packages/command-registry/src/__tests__/appstate-runtime-execution.test.ts index 18933aafc3..692218601e 100644 --- a/packages/command-registry/src/__tests__/appstate-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/appstate-runtime-execution.test.ts @@ -8,7 +8,6 @@ import { commandDescriptors } from '../registry.ts'; test('appstate descriptor declares the complete readiness and foreground-state use', () => { const appstate = commandDescriptors.find(({ name }) => name === 'appstate'); - expect(appstate).not.toHaveProperty('capability'); expect(appstate?.platformExecution).toEqual({ kind: 'device-runtime', uses: appStateRuntimeUses, diff --git a/packages/command-registry/src/__tests__/boot-runtime-execution.test.ts b/packages/command-registry/src/__tests__/boot-runtime-execution.test.ts index 04391b610d..8dbbe5de57 100644 --- a/packages/command-registry/src/__tests__/boot-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/boot-runtime-execution.test.ts @@ -9,7 +9,6 @@ import { commandDescriptors } from '../registry.ts'; test('boot descriptor declares both readiness uses instead of a capability bucket', () => { const boot = commandDescriptors.find(({ name }) => name === 'boot'); - expect(boot).not.toHaveProperty('capability'); expect(boot?.platformExecution).toEqual({ kind: 'device-runtime', uses: deviceBootRuntimeUses, diff --git a/packages/command-registry/src/__tests__/click-runtime-execution.test.ts b/packages/command-registry/src/__tests__/click-runtime-execution.test.ts index c6a7d74824..49c85bd199 100644 --- a/packages/command-registry/src/__tests__/click-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/click-runtime-execution.test.ts @@ -13,10 +13,6 @@ test('press descriptor reuses the complete click plan uses with no legacy projec const click = commandDescriptors.find(({ name }) => name === 'click'); const press = commandDescriptors.find(({ name }) => name === 'press'); - expect(click).not.toHaveProperty('capability'); - expect(click).not.toHaveProperty('dispatch'); - expect(press).not.toHaveProperty('capability'); - expect(press).not.toHaveProperty('dispatch'); expect(click?.platformExecution).toEqual({ kind: 'device-runtime', uses: clickRuntimeUses }); expect(press?.platformExecution).toEqual({ kind: 'device-runtime', uses: clickRuntimeUses }); expect(pressRuntimeUses).toBe(clickRuntimeUses); diff --git a/packages/command-registry/src/__tests__/find-runtime-execution.test.ts b/packages/command-registry/src/__tests__/find-runtime-execution.test.ts index 5adb98c40c..1a12ff5e04 100644 --- a/packages/command-registry/src/__tests__/find-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/find-runtime-execution.test.ts @@ -5,7 +5,6 @@ import { findRuntimePlanUses } from '@agent-device/contracts/platform-runtime-op test('find descriptor declares its complete runtime uses with no legacy projection', () => { const find = commandDescriptors.find(({ name }) => name === 'find'); - expect(find).not.toHaveProperty('capability'); // Plan-time consumers select the alternative from the step input the way the handler does. expect(find?.platformExecution).toEqual({ kind: 'device-runtime', diff --git a/packages/command-registry/src/__tests__/focus-runtime-execution.test.ts b/packages/command-registry/src/__tests__/focus-runtime-execution.test.ts index 6bd1a48d5f..d2071105af 100644 --- a/packages/command-registry/src/__tests__/focus-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/focus-runtime-execution.test.ts @@ -5,8 +5,6 @@ import { commandDescriptors, listRuntimeFactCommands } from '../registry.ts'; test('focus descriptor declares its complete runtime use', () => { const focus = commandDescriptors.find(({ name }) => name === 'focus'); - expect(focus).not.toHaveProperty('capability'); - expect(focus).not.toHaveProperty('dispatch'); expect(focus?.platformExecution).toEqual({ kind: 'device-runtime', uses: [focusRuntimeUse], diff --git a/packages/command-registry/src/__tests__/screenshot-runtime-execution.test.ts b/packages/command-registry/src/__tests__/screenshot-runtime-execution.test.ts index 504609015b..c0a999c379 100644 --- a/packages/command-registry/src/__tests__/screenshot-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/screenshot-runtime-execution.test.ts @@ -5,8 +5,6 @@ import { commandDescriptors } from '../registry.ts'; test('screenshot descriptor declares its complete runtime uses with no legacy projection', () => { const screenshot = commandDescriptors.find(({ name }) => name === 'screenshot'); - expect(screenshot).not.toHaveProperty('capability'); - expect(screenshot).not.toHaveProperty('dispatch'); expect(screenshot?.platformExecution).toEqual({ kind: 'device-runtime', uses: screenshotRuntimePlanUses, diff --git a/packages/command-registry/src/__tests__/snapshot-runtime-execution.test.ts b/packages/command-registry/src/__tests__/snapshot-runtime-execution.test.ts index 96646bd1a4..46b7c87766 100644 --- a/packages/command-registry/src/__tests__/snapshot-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/snapshot-runtime-execution.test.ts @@ -5,8 +5,6 @@ import { expect, test } from 'vitest'; test('snapshot descriptor declares its complete planned capture uses with no legacy projection', () => { const snapshot = commandDescriptors.find(({ name }) => name === 'snapshot'); - expect(snapshot).not.toHaveProperty('capability'); - expect(snapshot).not.toHaveProperty('dispatch'); // Plan-time consumers select the alternative from the step input the way the handler does. expect(snapshot?.platformExecution).toEqual({ kind: 'device-runtime', @@ -24,8 +22,6 @@ test('snapshot descriptor declares its complete planned capture uses with no leg test('diff descriptor reuses the complete snapshot plan uses with no legacy projection', () => { const diff = commandDescriptors.find(({ name }) => name === 'diff'); - expect(diff).not.toHaveProperty('capability'); - expect(diff).not.toHaveProperty('dispatch'); expect(diff?.platformExecution).toEqual({ kind: 'device-runtime', uses: snapshotRuntimePlanUses, diff --git a/packages/command-registry/src/__tests__/type-runtime-execution.test.ts b/packages/command-registry/src/__tests__/type-runtime-execution.test.ts index 0df6a6ac7e..16978ad9d6 100644 --- a/packages/command-registry/src/__tests__/type-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/type-runtime-execution.test.ts @@ -5,8 +5,6 @@ import { commandDescriptors } from '../registry.ts'; test('type descriptor declares its complete runtime use with no legacy projection', () => { const type = commandDescriptors.find(({ name }) => name === 'type'); - expect(type).not.toHaveProperty('capability'); - expect(type).not.toHaveProperty('dispatch'); expect(type?.platformExecution).toEqual({ kind: 'device-runtime', uses: [typeTextRuntimeUse], diff --git a/packages/command-registry/src/__tests__/viewport-runtime-execution.test.ts b/packages/command-registry/src/__tests__/viewport-runtime-execution.test.ts index c7ad6e47f6..46203e1aad 100644 --- a/packages/command-registry/src/__tests__/viewport-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/viewport-runtime-execution.test.ts @@ -5,8 +5,6 @@ import { commandDescriptors } from '../registry.ts'; test('viewport descriptor declares its complete runtime use with no legacy projection', () => { const viewport = commandDescriptors.find(({ name }) => name === 'viewport'); - expect(viewport).not.toHaveProperty('capability'); - expect(viewport).not.toHaveProperty('dispatch'); expect(viewport?.platformExecution).toEqual({ kind: 'device-runtime', uses: [viewportRuntimeUse], diff --git a/packages/command-registry/src/__tests__/wait-runtime-execution.test.ts b/packages/command-registry/src/__tests__/wait-runtime-execution.test.ts index 3b13f2cf0f..24d31ba342 100644 --- a/packages/command-registry/src/__tests__/wait-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/wait-runtime-execution.test.ts @@ -6,8 +6,6 @@ import { commandDescriptors } from '../registry.ts'; test('wait descriptor declares its complete runtime use with no capability bucket', () => { const wait = commandDescriptors.find(({ name }) => name === 'wait'); - expect(wait).not.toHaveProperty('capability'); - expect(wait).not.toHaveProperty('dispatch'); expect(wait?.platformExecution).toEqual({ kind: 'device-runtime', uses: waitSelectorCaptureRuntimePlanUses, diff --git a/packages/platform-apple/src/runner/__tests__/runner-client.test.ts b/packages/platform-apple/src/runner/__tests__/runner-client.test.ts index 1e76d12d53..9b99d107eb 100644 --- a/packages/platform-apple/src/runner/__tests__/runner-client.test.ts +++ b/packages/platform-apple/src/runner/__tests__/runner-client.test.ts @@ -29,8 +29,8 @@ vi.mock('../runner-macos-products.ts', async () => { }); import type { DeviceInfo } from '@agent-device/kernel/device'; -import { RUNNER_COMMAND_TRAITS, isReadOnlyRunnerCommand } from '../runner-command-traits.ts'; -import { withRunnerCommandId, type RunnerCommand } from '../runner-contract.ts'; +import { isReadOnlyRunnerCommand } from '../runner-command-traits.ts'; +import { withRunnerCommandId } from '../runner-contract.ts'; import { resolveRunnerBuildDestination, resolveRunnerDestination, @@ -94,66 +94,6 @@ const macOsDevice: DeviceInfo = { booted: true, }; -const runnerProtocolCommandFixtures: Record = { - tap: { command: 'tap', x: 120, y: 240 }, - mouseClick: { command: 'mouseClick', x: 120, y: 240, button: 'secondary' }, - longPress: { command: 'longPress', x: 120, y: 240, durationMs: 750 }, - drag: { command: 'drag', x: 120, y: 240, x2: 300, y2: 420, durationMs: 400 }, - remotePress: { command: 'remotePress', remoteButton: 'down', durationMs: 250 }, - type: { command: 'type', text: 'hello', delayMs: 20, textEntryMode: 'replace' }, - swipe: { command: 'swipe', direction: 'down', durationMs: 250 }, - scroll: { command: 'scroll', direction: 'down', amount: 0.6, pixels: 240 }, - desktopScroll: { - command: 'desktopScroll', - direction: 'down', - amount: 0.6, - pixels: 240, - durationMs: 50, - }, - findText: { command: 'findText', text: 'Settings' }, - querySelector: { command: 'querySelector', selectorKey: 'id', selectorValue: 'submit' }, - readText: { command: 'readText' }, - appState: { command: 'appState', appBundleId: 'com.demo.app' }, - snapshot: { - command: 'snapshot', - interactiveOnly: true, - depth: 2, - scope: 'app', - raw: false, - }, - screenshot: { command: 'screenshot', outPath: '/tmp/runner-screenshot.png', fullscreen: true }, - backInApp: { command: 'backInApp' }, - backSystem: { command: 'backSystem' }, - home: { command: 'home' }, - rotate: { command: 'rotate', orientation: 'landscape-left' }, - appSwitcher: { command: 'appSwitcher' }, - actionButton: { command: 'actionButton' }, - keyboardDismiss: { command: 'keyboardDismiss' }, - keyboardReturn: { command: 'keyboardReturn' }, - alert: { command: 'alert', action: 'accept' }, - sequence: { - command: 'sequence', - steps: [ - { kind: 'tap', x: 120, y: 240 }, - { kind: 'longPress', x: 120, y: 240, durationMs: 300 }, - { kind: 'doubleTap', x: 10, y: 600, pauseMs: 50 }, - ], - }, - gesture: { command: 'gesture' }, - gestureViewport: { command: 'gestureViewport' }, - recordStart: { - command: 'recordStart', - outPath: '/tmp/runner-recording.mp4', - fps: 30, - }, - recordStop: { command: 'recordStop' }, - status: { command: 'status', statusCommandId: 'runner-command-1' }, - uptime: { command: 'uptime' }, - activate: { command: 'activate', appBundleId: 'com.example.app' }, - terminate: { command: 'terminate', appBundleId: 'com.example.app' }, - targetReset: { command: 'targetReset' }, - shutdown: { command: 'shutdown' }, -}; const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../..'); async function makeTmpDir(): Promise { @@ -301,27 +241,6 @@ test('resolveRunnerDestination uses simulator destination for simulators', () => assert.equal(resolveRunnerDestination(iosSimulator), 'platform=iOS Simulator,id=sim-1'); }); -test('runner protocol fixtures cover every runner command with JSON-safe samples', () => { - // The trait table is the exhaustive runner-command enumeration — it is `satisfies - // Record` — so the fixture set is checked against that declaration - // instead of against a second hand-maintained list that a new command has to remember to update. - assert.deepEqual( - Object.keys(runnerProtocolCommandFixtures).sort(), - Object.keys(RUNNER_COMMAND_TRAITS).sort(), - ); - - const roundTrip = JSON.parse(JSON.stringify(runnerProtocolCommandFixtures)) as Record< - string, - Record - >; - assert.equal(roundTrip.tap!.command, 'tap'); - assert.equal(roundTrip.mouseClick!.button, 'secondary'); - assert.equal(roundTrip.snapshot!.scope, 'app'); - assert.equal(roundTrip.screenshot!.fullscreen, true); - assert.equal(roundTrip.rotate!.orientation, 'landscape-left'); - assert.equal(roundTrip.recordStart!.fps, 30); -}); - test('withRunnerCommandId replaces blank command ids', () => { const command = withRunnerCommandId({ command: 'uptime', commandId: ' ' }); diff --git a/packages/platform-apple/src/runner/__tests__/runner-command-traits.test.ts b/packages/platform-apple/src/runner/__tests__/runner-command-traits.test.ts index e698119eb3..ead94b43cd 100644 --- a/packages/platform-apple/src/runner/__tests__/runner-command-traits.test.ts +++ b/packages/platform-apple/src/runner/__tests__/runner-command-traits.test.ts @@ -4,10 +4,7 @@ import { isDeepStrictEqual } from 'node:util'; import { test } from 'vitest'; import type { RunnerCommand } from '../runner-contract.ts'; import { - canSkipRunnerReadinessPreflightAfterHealthyMutation, isReadOnlyRunnerCommand, - isRunnerReadinessPreflightExempt, - isRunnerReadinessProbeCommand, readRunnerCommandTraits, RUNNER_COMMAND_TRAITS, type RunnerCommandTraits, @@ -67,24 +64,6 @@ test('runner command trait table pins lifecycle-sensitive command groups', () => assert.deepEqual(Object.values(groups).flat().sort(), [...RUNNER_COMMANDS].sort()); }); -test('runner command trait helpers read from the shared trait table', () => { - for (const command of RUNNER_COMMANDS) { - const traits = readRunnerCommandTraits({ command }); - assert.equal(isReadOnlyRunnerCommand({ command }), traits.readOnly, command); - assert.equal(isRunnerReadinessProbeCommand({ command }), traits.readinessProbe, command); - assert.equal( - isRunnerReadinessPreflightExempt({ command }), - traits.readinessPreflightExempt, - command, - ); - assert.equal( - canSkipRunnerReadinessPreflightAfterHealthyMutation({ command }), - traits.readinessPreflightSkipEligibleAfterHealthyMutation, - command, - ); - } -}); - test('alert actions match the native read-only golden table', () => { // The fixture's `query` column records whether the alert request changes anything — `get` is the // one action that is side-effect-free — and each side consumes it under its own name: `readOnly` diff --git a/packages/platform-apple/src/runner/__tests__/snapshot-presentation.test.ts b/packages/platform-apple/src/runner/__tests__/snapshot-presentation.test.ts index 917efddbd9..bdca5aceec 100644 --- a/packages/platform-apple/src/runner/__tests__/snapshot-presentation.test.ts +++ b/packages/platform-apple/src/runner/__tests__/snapshot-presentation.test.ts @@ -234,24 +234,20 @@ test('a runner payload with the hittable bit absent presents without declaring i } }); -// The keyboard band the runner measured for a capture (#2660). The reader is the only place a wire -// fact becomes a daemon fact, so it owns the whole strictness budget: what cannot be placed is -// restated as `unmeasurable` with a reason, never as a band and never as silence. +// The keyboard band the runner measured for a capture (#2660). The strictness budget that decides +// what cannot be placed belongs to `readSnapshotKeyboardBandFact` in @agent-device/kernel, which owns +// that table; this seam owns only the forwarding, so a published band must arrive unchanged and a +// producer that never looked must stay silent. -test('a measured keyboard band is read as the band the guard will measure against', () => { +test('the reader forwards each published keyboard band shape unchanged', () => { // The landscape band #2653 confirmed on iPhone 17 Pro: the runner answers `app.keyboards` in the // app's own orientation space, so the daemon reads these numbers beside node rects unchanged. - const result = readAppleSnapshotResult({ - keyboard: { kind: 'visible', frame: { x: 0, y: 198, width: 874, height: 204 } }, - }); - - assert.deepEqual(result.keyboard, { - kind: 'visible', - frame: { x: 0, y: 198, width: 874, height: 204 }, - }); -}); - -test('a proven absence and a stated failure both survive the wire as themselves', () => { + assert.deepEqual( + readAppleSnapshotResult({ + keyboard: { kind: 'visible', frame: { x: 0, y: 198, width: 874, height: 204 } }, + }).keyboard, + { kind: 'visible', frame: { x: 0, y: 198, width: 874, height: 204 } }, + ); assert.deepEqual(readAppleSnapshotResult({ keyboard: { kind: 'absent' } }).keyboard, { kind: 'absent', }); @@ -268,19 +264,3 @@ test('a capture from a tier that never reads the keyboard publishes no fact at a // learns to keep deriving the band from that tree instead of being told the screen is clear. assert.equal(readAppleSnapshotResult({ nodes: [] }).keyboard, undefined); }); - -test('a band that cannot be placed is restated as unmeasurable rather than dropped or trusted', () => { - const cases: ReadonlyArray = [ - [{ kind: 'visible' }, 'invalid-visible-frame'], - [{ kind: 'visible', frame: { x: 0, y: 198, width: 0, height: 204 } }, 'invalid-visible-frame'], - [{ kind: 'visible', frame: { x: 0, y: 198 } }, 'invalid-visible-frame'], - [{ kind: 'unmeasurable' }, 'unreported-reason'], - [{ kind: 'measured' }, 'unrecognized-kind'], - ['visible', 'malformed-fact'], - ]; - - for (const [payload, reason] of cases) { - const read = readAppleSnapshotResult({ keyboard: payload }).keyboard; - assert.deepEqual(read, { kind: 'unmeasurable', reason }, `payload ${JSON.stringify(payload)}`); - } -}); diff --git a/src/__tests__/command-descriptor-parity.test.ts b/src/__tests__/command-descriptor-parity.test.ts index 4eff08be53..954ea5eb77 100644 --- a/src/__tests__/command-descriptor-parity.test.ts +++ b/src/__tests__/command-descriptor-parity.test.ts @@ -6,12 +6,7 @@ import { listCliCommandNames, PUBLIC_COMMANDS, } from '@agent-device/command-registry/catalog'; -import { - DAEMON_COMMAND_DESCRIPTORS, - canRunReplayScopedAction, - type DaemonCommandDescriptor, -} from '../daemon/daemon-command-registry.ts'; -import type { DaemonRequest } from '../daemon/daemon-request.ts'; +import { canRunReplayScopedAction } from '../daemon/daemon-command-registry.ts'; import { deriveDaemonCommandDescriptors, deriveStructuredBatchCommandNames, @@ -19,7 +14,6 @@ import { import { commandDescriptors, listDescriptorCatalogCommandNames, - listMcpExposedCommandNames, resolveCommandFrameworkTier, resolveCommandRecordsSessionAction, resolveCommandRecordingEffect, @@ -27,15 +21,6 @@ import { RAW_COMMAND_DESCRIPTORS, } from '@agent-device/command-registry/registry'; -// Function-valued traits cannot be deep-equaled across re-authored closures, so -// (mirroring daemon-command-registry.test.ts) they are compared by presence and -// by behavior on a representative sample, while every other field is deepEqual'd. -const DAEMON_FUNCTION_TRAITS = [ - 'allowSessionlessDefaultDevice', - 'skipSessionlessProviderDevice', - 'sessionlessLeaseAdmissionExemption', -] as const; - // Public commands that intentionally have no daemon route — they live only in the // capability/batch tables, so the daemon registry has never covered them. // `install-from-source` projects to the daemon via the `install_source` internal @@ -46,24 +31,6 @@ const UNROUTED_PUBLIC_COMMANDS = new Set([PUBLIC_COMMANDS.installFromSou type TestCommandDescriptor = (typeof commandDescriptors)[number]; -function makeRequest(command: string, positionals: string[] = []): DaemonRequest { - return { command, token: 'parity-token', session: 'parity-session', positionals, flags: {} }; -} - -// Sample requests that exercise both closure traits' branches for any command. -function sampleRequests(command: string): DaemonRequest[] { - return [ - makeRequest(command), - makeRequest(command, ['start']), - makeRequest(command, ['stop']), - makeRequest(command, ['START']), - { ...makeRequest(command), flags: { shardAll: 2 } }, - { ...makeRequest(command), flags: { shardSplit: 3 } }, - { ...makeRequest(PUBLIC_COMMANDS.test), flags: { shardAll: 2 } }, - { ...makeRequest(PUBLIC_COMMANDS.test), flags: { shardSplit: 1 } }, - ]; -} - function hasDaemonFacet(descriptor: TestCommandDescriptor): boolean { return 'daemon' in descriptor && descriptor.daemon !== undefined; } @@ -100,30 +67,6 @@ test('derived daemon registry holds its routing invariants', () => { } }); -test('derived daemon descriptors preserve closure traits by presence and behavior', () => { - const liveByCommand = new Map( - DAEMON_COMMAND_DESCRIPTORS.map((d) => [d.command, d as DaemonCommandDescriptor]), - ); - for (const derived of deriveDaemonCommandDescriptors(commandDescriptors)) { - const live = liveByCommand.get(derived.command); - assert.ok(live, `${derived.command} present in hand table`); - for (const trait of DAEMON_FUNCTION_TRAITS) { - const derivedFn = derived[trait] as ((req: DaemonRequest) => unknown) | undefined; - const liveFn = live[trait] as ((req: DaemonRequest) => unknown) | undefined; - assert.equal(typeof derivedFn, typeof liveFn, `${derived.command} ${trait} presence`); - if (typeof liveFn === 'function' && typeof derivedFn === 'function') { - for (const request of sampleRequests(derived.command)) { - assert.deepEqual( - derivedFn(request), - liveFn(request), - `${derived.command} ${trait} behavior`, - ); - } - } - } - } -}); - test('command catalog projections are built from descriptor catalog facets', () => { const publicCommands = listDescriptorCatalogCommandNames('public'); const internalCommands = listDescriptorCatalogCommandNames('internal'); @@ -188,22 +131,6 @@ test('structured-batch allowlist is built from descriptors', () => { } }); -test('MCP exposure list is built from descriptors', () => { - const cliCommands = new Set(listCliCommandNames()); - const expected = commandDescriptors - .filter((descriptor) => descriptor.mcpExposed && cliCommands.has(descriptor.name)) - .map((descriptor) => descriptor.name) - .sort(); - const expectedNames = new Set(expected); - - assert.deepEqual(listMcpExposedCommandNames(), expected); - assert.ok(expectedNames.has('debug'), 'local debug command stays MCP-exposed'); - assert.ok(expectedNames.has('metro'), 'local metro command stays MCP-exposed'); - assert.ok(expectedNames.has('session'), 'local session command stays MCP-exposed'); - assert.equal(expectedNames.has(PUBLIC_COMMANDS.prepare), false, 'prepare stays out of MCP'); - assert.equal(expectedNames.has('auth'), false, 'schema-only auth command stays out of MCP'); -}); - // #1310: every raw descriptor explicitly decides recording; the daemon // replayScopedAction trait and MCP schema projection are both derived from it. test('recordsSessionAction is explicit on every raw descriptor and drives daemon replay policy', () => { diff --git a/src/__tests__/command-descriptor-shutdown-runtime-execution.test.ts b/src/__tests__/command-descriptor-shutdown-runtime-execution.test.ts index 33f086dfcb..fada2caabf 100644 --- a/src/__tests__/command-descriptor-shutdown-runtime-execution.test.ts +++ b/src/__tests__/command-descriptor-shutdown-runtime-execution.test.ts @@ -35,7 +35,6 @@ const androidShutdownSource = readFileSync( test('shutdown descriptor declares one canonical runtime operation', () => { const shutdown = commandDescriptors.find(({ name }) => name === 'shutdown'); - expect(shutdown).not.toHaveProperty('capability'); expect(shutdown?.platformExecution).toEqual({ kind: 'device-runtime', use: shutdownTargetUse, diff --git a/src/__tests__/runtime-public.test.ts b/src/__tests__/runtime-public.test.ts index 1c668c9d07..234a9aa890 100644 --- a/src/__tests__/runtime-public.test.ts +++ b/src/__tests__/runtime-public.test.ts @@ -56,7 +56,10 @@ const sessions = { set: () => {}, } satisfies CommandSessionStore; -test('internal command runtime skeleton is available', async () => { +// A constructed runtime defaults to the restricted policy: nothing may read a local file path +// unless the caller explicitly opts into `localCommandPolicy()`. No other seam asserts this +// default, so flipping the factory's fallback must fail here. +test('a runtime built with no policy restricts local input paths', async () => { const device: AgentDevice = createAgentDevice({ backend, artifacts, @@ -64,13 +67,6 @@ test('internal command runtime skeleton is available', async () => { assert.equal(device.backend.platform, 'ios'); assert.equal(device.policy.allowLocalInputPaths, false); - assert.equal(typeof device.capture.screenshot, 'function'); - assert.equal(typeof device.interactions.click, 'function'); - assert.equal(typeof device.system.back, 'function'); - assert.equal(typeof device.apps.open, 'function'); - assert.equal(typeof device.admin.install, 'function'); - assert.equal(typeof device.recording.record, 'function'); - assert.equal(typeof device.observability.logs, 'function'); const result = await device.capture.screenshot({}); assert.equal(result.path, '/tmp/path.png'); }); diff --git a/src/commands/interaction/runtime/settle.test.ts b/src/commands/interaction/runtime/settle.test.ts index 1e9a2cddc2..78c9959f35 100644 --- a/src/commands/interaction/runtime/settle.test.ts +++ b/src/commands/interaction/runtime/settle.test.ts @@ -2073,175 +2073,6 @@ test('the unchanged interactive tail is capped with a truncation marker', async assert.equal(settle.tailTruncated, true); }); -test('buildSettleTailEntries dedups candidates already carrying an excluded ref', () => { - const settledNodes = makeSnapshotState([ - { - index: 0, - depth: 0, - type: 'Button', - label: 'Add to cart', - rect: { x: 10, y: 20, width: 100, height: 40 }, - hittable: true, - }, - { - index: 1, - depth: 0, - type: 'Button', - label: 'Share', - rect: { x: 10, y: 80, width: 100, height: 40 }, - hittable: true, - }, - ]).nodes; - - const result = buildSettleTailEntries(settledNodes, new Set(['e1'])); - - assert.deepEqual(result.tail, [{ ref: 'e2', role: 'button', label: 'Share' }]); -}); - -test('buildSettleTailEntries drops application/window chrome and does not require hittable', () => { - const settledNodes = makeSnapshotState([ - { index: 0, depth: 0, type: 'Application', label: 'Example' }, - { index: 1, depth: 0, type: 'Window' }, - { - index: 2, - depth: 0, - type: 'Button', - label: 'Discard and go back', - rect: { x: 10, y: 20, width: 100, height: 40 }, - // Deliberately no `hittable` field, mirroring a real post-dismiss - // capture: the tail bar no longer requires `hittable === true`. - }, - ]).nodes; - - const result = buildSettleTailEntries(settledNodes, new Set()); - - assert.deepEqual(result.tail, [{ ref: 'e3', role: 'button', label: 'Discard and go back' }]); -}); - -test('buildSettleTailEntries drops the keyboard container and its chrome descendants', () => { - const settledNodes = makeSnapshotState([ - { - index: 0, - depth: 0, - type: 'Button', - label: 'Send', - rect: { x: 10, y: 20, width: 100, height: 40 }, - hittable: true, - }, - { index: 1, depth: 0, type: 'Keyboard', label: 'keyboard' }, - { index: 2, depth: 1, parentIndex: 1, type: 'Key', label: 'q' }, - { index: 3, depth: 1, parentIndex: 1, type: 'Button', label: 'shift' }, - ]).nodes; - - const result = buildSettleTailEntries(settledNodes, new Set()); - - assert.deepEqual(result.tail, [{ ref: 'e1', role: 'button', label: 'Send' }]); -}); - -test('buildSettleTailEntries drops Android IME chrome and status-bar chrome (#1198)', () => { - const settledNodes = makeSnapshotState([ - { - index: 0, - depth: 0, - type: 'android.widget.Button', - label: 'Send', - bundleId: 'org.reactnavigation.playground', - rect: { x: 10, y: 20, width: 100, height: 40 }, - hittable: true, - }, - { - // Status-bar marker: this systemui run drops whole. - index: 1, - depth: 0, - type: 'android.widget.FrameLayout', - identifier: 'com.android.systemui:id/status_bar', - bundleId: 'com.android.systemui', - }, - { - index: 2, - depth: 1, - parentIndex: 1, - type: 'android.widget.TextView', - identifier: 'com.android.systemui:id/clock', - label: '12:23', - bundleId: 'com.android.systemui', - }, - { - index: 3, - depth: 0, - type: 'android.widget.FrameLayout', - bundleId: 'com.google.android.inputmethod.latin', - hittable: true, - }, - { - index: 4, - depth: 1, - parentIndex: 3, - type: 'android.widget.FrameLayout', - label: 'Delete', - bundleId: 'com.google.android.inputmethod.latin', - hittable: true, - }, - ]).nodes; - - const result = buildSettleTailEntries(settledNodes, new Set(), 'org.reactnavigation.playground'); - - assert.deepEqual(result.tail, [{ ref: 'e1', role: 'button', label: 'Send' }]); -}); - -test('buildSettleTailEntries keeps unknown-foreign packages and drops only marked systemui chrome, with or without appBundleId (#1198)', () => { - // Keep-unknown-foreign default: a system dialog's buttons (package - // `android`) stay tail candidates; only the marked status/nav-bar - // window-run drops, and that does not depend on knowing the session's app. - const settledNodes = makeSnapshotState([ - { - index: 0, - depth: 0, - type: 'android.widget.Button', - label: 'Send', - bundleId: 'org.reactnavigation.playground', - rect: { x: 10, y: 20, width: 100, height: 40 }, - hittable: true, - }, - { - index: 1, - depth: 0, - type: 'android.widget.FrameLayout', - identifier: 'com.android.systemui:id/status_bar_container', - bundleId: 'com.android.systemui', - rect: { x: 0, y: 0, width: 1344, height: 159 }, - }, - { - index: 2, - depth: 1, - parentIndex: 1, - type: 'android.widget.TextView', - identifier: 'com.android.systemui:id/clock', - label: '12:23', - bundleId: 'com.android.systemui', - rect: { x: 40, y: 40, width: 80, height: 40 }, - }, - { - index: 3, - depth: 0, - type: 'android.widget.Button', - label: 'Just once', - identifier: 'android:id/button_once', - bundleId: 'android', - rect: { x: 829, y: 2734, width: 255, height: 162 }, - hittable: true, - }, - ]).nodes; - - for (const appBundleId of [undefined, 'org.reactnavigation.playground']) { - const result = buildSettleTailEntries(settledNodes, new Set(), appBundleId); - assert.deepEqual( - result.tail?.map((entry) => entry.label), - ['Send', 'Just once'], - ); - } -}); - test('a systemui volume dialog survives the settled diff and tail while the status bar drops (#1198)', async () => { // PR #1200 second review round: systemui is not all chrome — it hosts // actionable overlays (volume panel, media pickers). Only window-runs diff --git a/src/commands/schema/command-schema-guards.test.ts b/src/commands/schema/command-schema-guards.test.ts index beaa1d70ee..e3b432de06 100644 --- a/src/commands/schema/command-schema-guards.test.ts +++ b/src/commands/schema/command-schema-guards.test.ts @@ -10,10 +10,7 @@ import { listCliCommandNames, SPECIAL_CLI_COMMANDS, } from '@agent-device/command-registry/catalog'; -import { - commandDescriptors, - listRuntimeFactCommands, -} from '@agent-device/command-registry/registry'; +import { listRuntimeFactCommands } from '@agent-device/command-registry/registry'; import { getCliCommandSchema } from './command-schema.ts'; test('every public runtime-fact command has a parser schema entry', () => { @@ -58,20 +55,6 @@ test('cli.ts command dispatch checks are recognized by parser-level unknown-comm } }); -test('schema runtime-fact mappings match descriptor source-of-truth', () => { - const cliCommands = new Set(listCliCommandNames()); - const runtimeFactCatalogCommands = commandDescriptors - .filter( - (descriptor) => - descriptor.catalog.group === 'public' && - descriptor.platformExecution.kind === 'device-runtime' && - cliCommands.has(descriptor.name), - ) - .map((descriptor) => descriptor.name) - .sort(); - assert.deepEqual(runtimeFactCatalogCommands, listRuntimeFactCommands()); -}); - function collectCliDispatchCommandLiterals(): Set { const cliPath = fileURLToPath(new URL('../../cli.ts', import.meta.url)); const sourceText = fs.readFileSync(cliPath, 'utf8'); diff --git a/src/daemon-client/__tests__/daemon-client.test.ts b/src/daemon-client/__tests__/daemon-client.test.ts index 1f42d0d51c..89f77a6c6e 100644 --- a/src/daemon-client/__tests__/daemon-client.test.ts +++ b/src/daemon-client/__tests__/daemon-client.test.ts @@ -27,9 +27,7 @@ import { } from '../daemon-client-metadata.ts'; import { canConnectSocket } from '../daemon-client-transport.ts'; import { DAEMON_RPC_PROTOCOL_VERSION } from '@agent-device/contracts/daemon-http'; -import { shouldResetDaemonAfterRequestTimeout } from '../daemon-client-timeout.ts'; import { resolveDaemonPaths } from '../../daemon-resolution.ts'; -import { stopProcessForTakeover } from '../../daemon-process.ts'; import { findProjectRoot, readVersion } from '@agent-device/host-kit/version'; import { mkdtempForTestSync } from '../../__tests__/test-utils/tmp-dir.ts'; @@ -231,23 +229,6 @@ test('resolveDaemonStartupHint shell-quotes cleanup paths', () => { ); }); -test('snapshot request timeout preserves daemon metadata for follow-up evidence commands', () => { - assert.equal(shouldResetDaemonAfterRequestTimeout('snapshot'), false); - assert.equal(shouldResetDaemonAfterRequestTimeout('screenshot'), true); - assert.equal(shouldResetDaemonAfterRequestTimeout(undefined), true); -}); - -test('read-only polling command timeouts preserve the daemon like snapshot', () => { - // wait/find are repeated snapshot captures: a stalled accessibility bridge - // must not turn one timed-out poll into a daemon reset that loses every session. - assert.equal(shouldResetDaemonAfterRequestTimeout('wait'), false); - assert.equal(shouldResetDaemonAfterRequestTimeout('find'), false); - // Interaction commands resolve targets through the same capture, so their - // timeouts preserve the daemon too (#1105); non-capture commands still reset. - assert.equal(shouldResetDaemonAfterRequestTimeout('press'), false); - assert.equal(shouldResetDaemonAfterRequestTimeout('open'), true); -}); - test('cleanupFailedDaemonStartupMetadata removes partial startup metadata', async () => { const stateDir = mkdtempForTestSync('agent-device-daemon-cleanup-'); const paths = resolveDaemonPaths(stateDir); @@ -1598,31 +1579,3 @@ test('computeDaemonCodeSignature ignores a relative-path-shaped string that is n fs.rmSync(root, { recursive: true, force: true }); } }); - -test('stopDaemonProcessForTakeover does not terminate non-daemon process', async () => { - const daemonProcess = runCmdBackground(process.execPath, ['-e', 'setInterval(() => {}, 1000)'], { - stdio: 'ignore', - allowFailure: true, - captureOutput: false, - }); - void daemonProcess.wait.catch(() => {}); - const child = daemonProcess.child; - const pid = child.pid; - assert.ok(pid, 'spawned child should have a pid'); - - try { - await new Promise((resolve) => setTimeout(resolve, 50)); - assert.equal(isProcessAlive(pid), true); - await stopProcessForTakeover(pid, { - termTimeoutMs: 100, - killTimeoutMs: 100, - expectedStartTime: undefined, - }); - assert.equal(isProcessAlive(pid), true); - } finally { - if (isProcessAlive(pid)) { - process.kill(pid, 'SIGKILL'); - await waitForProcessExit(pid, 1_500); - } - } -}); diff --git a/src/daemon-client/daemon-client-timeout.ts b/src/daemon-client/daemon-client-timeout.ts index 4fd9ca802a..ea19056595 100644 --- a/src/daemon-client/daemon-client-timeout.ts +++ b/src/daemon-client/daemon-client-timeout.ts @@ -110,7 +110,7 @@ export function handleRequestTimeout( // capture/polling commands preserve the daemon so sessions survive and evidence // commands still work; everything else resets it. Unknown/undefined commands // fall back to the default reset-daemon policy. -export function shouldResetDaemonAfterRequestTimeout(command: string | undefined): boolean { +function shouldResetDaemonAfterRequestTimeout(command: string | undefined): boolean { return resolveCommandTimeoutPolicy(command).onTimeout === 'reset-daemon'; } diff --git a/src/daemon/handlers/__tests__/snapshot-handler-wait.test.ts b/src/daemon/handlers/__tests__/snapshot-handler-wait.test.ts index 90a38568cf..809b64c98a 100644 --- a/src/daemon/handlers/__tests__/snapshot-handler-wait.test.ts +++ b/src/daemon/handlers/__tests__/snapshot-handler-wait.test.ts @@ -387,19 +387,3 @@ test('wait selector bypasses a fresh matching session snapshot', async () => { expect.anything(), ); }); - -test('wait sleep bypasses sessionless runner cleanup wrapper', async () => { - const sessionStore = makeSessionStore(); - const sessionName = 'ios-sim'; - sessionStore.set(sessionName, makeSession(sessionName, iosSimulatorDevice)); - - const response = await handleSnapshotCommands({ - req: snapshotRequest(sessionName, 'wait', { positionals: ['0'] }), - sessionName, - logPath: '/tmp/daemon.log', - sessionStore, - }); - - expect(response).toBeTruthy(); - expect(response?.ok).toBe(true); -}); diff --git a/src/platform-runtime-screen-recording-host.test.ts b/src/platform-runtime-screen-recording-host.test.ts deleted file mode 100644 index abe1262faf..0000000000 --- a/src/platform-runtime-screen-recording-host.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { expect, test } from 'vitest'; -import { createScreenRecordingRuntimeHost } from './platform-runtime-screen-recording-host.ts'; - -test('composes the focused recording host capabilities', () => { - const host = createScreenRecordingRuntimeHost(); - expect(Object.keys(host).sort()).toEqual([ - 'android', - 'apple', - 'finalize', - 'harmony', - 'outputs', - 'ownedProcesses', - 'web', - ]); -}); From 6456356f054637d7a3cd7572b19e1589ff4f8379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Fri, 25 Sep 2026 18:13:40 +0200 Subject: [PATCH 2/3] chore(gates): sweep retired descriptor projections registry-wide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The per-command runtime-execution tests each re-pinned `not.toHaveProperty('capability')` and `('dispatch')` on their own descriptor. Those pins did not close the hole they claimed: a retired key written in a descriptor literal fails `tsc` (excess-property check), while one smuggled through a conditional spread — the shape `ownerFiles` already uses — typechecks, and no `toEqual` on `platformExecution` can see a sibling key. Measured with the retired key planted both ways: the literal form failed the build, the spread form stayed green across every surviving test. One sweep over raw and normalized descriptors now owns the invariant at the registry, so a new descriptor is covered without repeating the pair per command. --- .../retired-descriptor-projection.test.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 packages/command-registry/src/__tests__/retired-descriptor-projection.test.ts diff --git a/packages/command-registry/src/__tests__/retired-descriptor-projection.test.ts b/packages/command-registry/src/__tests__/retired-descriptor-projection.test.ts new file mode 100644 index 0000000000..71955391ef --- /dev/null +++ b/packages/command-registry/src/__tests__/retired-descriptor-projection.test.ts @@ -0,0 +1,20 @@ +import { expect, test } from 'vitest'; +import { commandDescriptors, RAW_COMMAND_DESCRIPTORS } from '../registry.ts'; + +// A retired projection written in a descriptor literal fails `tsc`, but one smuggled through a +// conditional spread — the shape `ownerFiles` uses — slips past the excess-property check, and no +// `toEqual` on `platformExecution` sees a sibling key. This sweep is what actually closes it. +const RETIRED_DESCRIPTOR_KEYS = ['capability', 'dispatch'] as const; + +test('no registered descriptor carries a retired capability or dispatch projection', () => { + for (const descriptor of RAW_COMMAND_DESCRIPTORS) { + for (const key of RETIRED_DESCRIPTOR_KEYS) { + expect(descriptor, `${descriptor.name} raw ${key}`).not.toHaveProperty(key); + } + } + for (const descriptor of commandDescriptors) { + for (const key of RETIRED_DESCRIPTOR_KEYS) { + expect(descriptor, `${descriptor.name} runtime ${key}`).not.toHaveProperty(key); + } + } +}); From 1d546a302570a928214f216cdbadf3a693091c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Fri, 25 Sep 2026 19:02:25 +0200 Subject: [PATCH 3/3] test: restore keyboard-seam routing proof and retitle moved claims Review finding: `readAppleSnapshotResult` is the only place the Apple runner's wire keyboard fact becomes a daemon fact, and on the same-process capture path it feeds the tap/click occlusion guard before any serialization. After the table dedup, every remaining case used well-formed payloads, so a seam forwarding `result.keyboard` raw survived all 618 runner tests and typechecks. Restored one malformed-payload case per kernel reason code as the routing proof: those restated shapes exist only if the kernel reader ran. Measured: the raw-forwarding mutant now fails here. Titles now match the input after the retired-projection sweep moved that claim to retired-descriptor-projection.test.ts: eight per-command runtime-execution tests dropped "with no legacy projection"/"capability bucket", and the runtime-policy default test names the flag it asserts, pointing at contact-sheet.test.ts for the refusal seam it does not exercise. --- .../__tests__/boot-runtime-execution.test.ts | 2 +- .../__tests__/click-runtime-execution.test.ts | 2 +- .../__tests__/find-runtime-execution.test.ts | 2 +- .../screenshot-runtime-execution.test.ts | 2 +- .../snapshot-runtime-execution.test.ts | 4 ++-- .../__tests__/type-runtime-execution.test.ts | 2 +- .../viewport-runtime-execution.test.ts | 2 +- .../__tests__/wait-runtime-execution.test.ts | 2 +- .../__tests__/snapshot-presentation.test.ts | 24 +++++++++++++++++-- src/__tests__/runtime-public.test.ts | 8 +++---- 10 files changed, 35 insertions(+), 15 deletions(-) diff --git a/packages/command-registry/src/__tests__/boot-runtime-execution.test.ts b/packages/command-registry/src/__tests__/boot-runtime-execution.test.ts index 8dbbe5de57..3106a2bdde 100644 --- a/packages/command-registry/src/__tests__/boot-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/boot-runtime-execution.test.ts @@ -6,7 +6,7 @@ import { import { expect, test } from 'vitest'; import { commandDescriptors } from '../registry.ts'; -test('boot descriptor declares both readiness uses instead of a capability bucket', () => { +test('boot descriptor declares both readiness uses', () => { const boot = commandDescriptors.find(({ name }) => name === 'boot'); expect(boot?.platformExecution).toEqual({ diff --git a/packages/command-registry/src/__tests__/click-runtime-execution.test.ts b/packages/command-registry/src/__tests__/click-runtime-execution.test.ts index 49c85bd199..a37fe01488 100644 --- a/packages/command-registry/src/__tests__/click-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/click-runtime-execution.test.ts @@ -9,7 +9,7 @@ import { commandDescriptors } from '../registry.ts'; // operation ("press shares the admitted tapPoint fact that live click and press both require"). // That claim rests on `pressRuntimeUses` and the `press` descriptor literally being click's, not // merely looking similar — pin both here so a future divergence fails this test, not silently. -test('press descriptor reuses the complete click plan uses with no legacy projection', () => { +test('press descriptor reuses the complete click plan uses', () => { const click = commandDescriptors.find(({ name }) => name === 'click'); const press = commandDescriptors.find(({ name }) => name === 'press'); diff --git a/packages/command-registry/src/__tests__/find-runtime-execution.test.ts b/packages/command-registry/src/__tests__/find-runtime-execution.test.ts index 1a12ff5e04..46085f7d76 100644 --- a/packages/command-registry/src/__tests__/find-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/find-runtime-execution.test.ts @@ -2,7 +2,7 @@ import { commandDescriptors, selectFindStepUses } from '../registry.ts'; import { expect, test } from 'vitest'; import { findRuntimePlanUses } from '@agent-device/contracts/platform-runtime-operations'; -test('find descriptor declares its complete runtime uses with no legacy projection', () => { +test('find descriptor declares its complete runtime uses', () => { const find = commandDescriptors.find(({ name }) => name === 'find'); // Plan-time consumers select the alternative from the step input the way the handler does. diff --git a/packages/command-registry/src/__tests__/screenshot-runtime-execution.test.ts b/packages/command-registry/src/__tests__/screenshot-runtime-execution.test.ts index c0a999c379..75b519f992 100644 --- a/packages/command-registry/src/__tests__/screenshot-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/screenshot-runtime-execution.test.ts @@ -2,7 +2,7 @@ import { expect, test } from 'vitest'; import { screenshotRuntimePlanUses } from '@agent-device/contracts/platform-runtime-operations'; import { commandDescriptors } from '../registry.ts'; -test('screenshot descriptor declares its complete runtime uses with no legacy projection', () => { +test('screenshot descriptor declares its complete runtime uses', () => { const screenshot = commandDescriptors.find(({ name }) => name === 'screenshot'); expect(screenshot?.platformExecution).toEqual({ diff --git a/packages/command-registry/src/__tests__/snapshot-runtime-execution.test.ts b/packages/command-registry/src/__tests__/snapshot-runtime-execution.test.ts index 46b7c87766..8df50ba104 100644 --- a/packages/command-registry/src/__tests__/snapshot-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/snapshot-runtime-execution.test.ts @@ -2,7 +2,7 @@ import { commandDescriptors, selectSnapshotStepUses } from '../registry.ts'; import { snapshotRuntimePlanUses } from '@agent-device/contracts/platform-runtime-operations'; import { expect, test } from 'vitest'; -test('snapshot descriptor declares its complete planned capture uses with no legacy projection', () => { +test('snapshot descriptor declares its complete planned capture uses', () => { const snapshot = commandDescriptors.find(({ name }) => name === 'snapshot'); // Plan-time consumers select the alternative from the step input the way the handler does. @@ -19,7 +19,7 @@ test('snapshot descriptor declares its complete planned capture uses with no leg ]); }); -test('diff descriptor reuses the complete snapshot plan uses with no legacy projection', () => { +test('diff descriptor reuses the complete snapshot plan uses', () => { const diff = commandDescriptors.find(({ name }) => name === 'diff'); expect(diff?.platformExecution).toEqual({ diff --git a/packages/command-registry/src/__tests__/type-runtime-execution.test.ts b/packages/command-registry/src/__tests__/type-runtime-execution.test.ts index 16978ad9d6..aeb30dfc7a 100644 --- a/packages/command-registry/src/__tests__/type-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/type-runtime-execution.test.ts @@ -2,7 +2,7 @@ import { expect, test } from 'vitest'; import { typeTextRuntimeUse } from '@agent-device/contracts/platform-runtime-operations'; import { commandDescriptors } from '../registry.ts'; -test('type descriptor declares its complete runtime use with no legacy projection', () => { +test('type descriptor declares its complete runtime use', () => { const type = commandDescriptors.find(({ name }) => name === 'type'); expect(type?.platformExecution).toEqual({ diff --git a/packages/command-registry/src/__tests__/viewport-runtime-execution.test.ts b/packages/command-registry/src/__tests__/viewport-runtime-execution.test.ts index 46203e1aad..7ad5ebfbcc 100644 --- a/packages/command-registry/src/__tests__/viewport-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/viewport-runtime-execution.test.ts @@ -2,7 +2,7 @@ import { expect, test } from 'vitest'; import { viewportRuntimeUse } from '@agent-device/contracts/platform-runtime-operations'; import { commandDescriptors } from '../registry.ts'; -test('viewport descriptor declares its complete runtime use with no legacy projection', () => { +test('viewport descriptor declares its complete runtime use', () => { const viewport = commandDescriptors.find(({ name }) => name === 'viewport'); expect(viewport?.platformExecution).toEqual({ diff --git a/packages/command-registry/src/__tests__/wait-runtime-execution.test.ts b/packages/command-registry/src/__tests__/wait-runtime-execution.test.ts index 24d31ba342..b95df25ac2 100644 --- a/packages/command-registry/src/__tests__/wait-runtime-execution.test.ts +++ b/packages/command-registry/src/__tests__/wait-runtime-execution.test.ts @@ -3,7 +3,7 @@ import { waitSelectorCaptureRuntimePlanUses } from '@agent-device/contracts/plat import { waitObservesDevice } from '@agent-device/contracts/wait-runtime-plan'; import { commandDescriptors } from '../registry.ts'; -test('wait descriptor declares its complete runtime use with no capability bucket', () => { +test('wait descriptor declares its complete runtime use', () => { const wait = commandDescriptors.find(({ name }) => name === 'wait'); expect(wait?.platformExecution).toEqual({ diff --git a/packages/platform-apple/src/runner/__tests__/snapshot-presentation.test.ts b/packages/platform-apple/src/runner/__tests__/snapshot-presentation.test.ts index bdca5aceec..96cebd1001 100644 --- a/packages/platform-apple/src/runner/__tests__/snapshot-presentation.test.ts +++ b/packages/platform-apple/src/runner/__tests__/snapshot-presentation.test.ts @@ -236,8 +236,11 @@ test('a runner payload with the hittable bit absent presents without declaring i // The keyboard band the runner measured for a capture (#2660). The strictness budget that decides // what cannot be placed belongs to `readSnapshotKeyboardBandFact` in @agent-device/kernel, which owns -// that table; this seam owns only the forwarding, so a published band must arrive unchanged and a -// producer that never looked must stay silent. +// that table; this seam owns forwarding AND the proof that it forwards through that reader. The +// same-process capture path feeds `result.keyboard` straight into the tap/click occlusion guard in +// src/commands/interaction/runtime/keyboard-occlusion.ts before any serialization, so a seam that +// passed the raw wire value through would hand the guard an unvalidated shape with nothing red. +// The malformed cases below are what prove the routing; kernel/src/record.test.ts owns the table. test('the reader forwards each published keyboard band shape unchanged', () => { // The landscape band #2653 confirmed on iPhone 17 Pro: the runner answers `app.keyboards` in the @@ -264,3 +267,20 @@ test('a capture from a tier that never reads the keyboard publishes no fact at a // learns to keep deriving the band from that tree instead of being told the screen is clear. assert.equal(readAppleSnapshotResult({ nodes: [] }).keyboard, undefined); }); + +// Routing proof: every reason below is emitted only by the kernel reader, never by a wire producer. +// One case per reason code — enough that a seam forwarding the raw payload fails on each branch, +// without re-owning the shape table kernel/src/record.test.ts already pins exhaustively. +test('a malformed keyboard payload is restated by the kernel reader, never forwarded raw', () => { + const cases: ReadonlyArray = [ + ['visible', 'malformed-fact'], + [{ kind: 'measured' }, 'unrecognized-kind'], + [{ kind: 'unmeasurable' }, 'unreported-reason'], + [{ kind: 'visible', frame: { x: 0, y: 198, width: 0, height: 204 } }, 'invalid-visible-frame'], + ]; + + for (const [payload, reason] of cases) { + const read = readAppleSnapshotResult({ keyboard: payload }).keyboard; + assert.deepEqual(read, { kind: 'unmeasurable', reason }, `payload ${JSON.stringify(payload)}`); + } +}); diff --git a/src/__tests__/runtime-public.test.ts b/src/__tests__/runtime-public.test.ts index 234a9aa890..8f296154d9 100644 --- a/src/__tests__/runtime-public.test.ts +++ b/src/__tests__/runtime-public.test.ts @@ -56,10 +56,10 @@ const sessions = { set: () => {}, } satisfies CommandSessionStore; -// A constructed runtime defaults to the restricted policy: nothing may read a local file path -// unless the caller explicitly opts into `localCommandPolicy()`. No other seam asserts this -// default, so flipping the factory's fallback must fail here. -test('a runtime built with no policy restricts local input paths', async () => { +// A runtime built without a policy lands on `restrictedCommandPolicy()`, not the local one. No +// other seam asserts that fallback, so flipping it in the factory must fail here. The refusal a +// restricted policy raises for a local path is owned by contact-sheet.test.ts on the io-policy seam. +test('a runtime built with no policy defaults to the restricted policy', async () => { const device: AgentDevice = createAgentDevice({ backend, artifacts,