Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/dependency-graph-findings.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,8 @@ writing must be removed so the table cannot drift into fiction.
to stop core/daemon from BRANCHING on platform." Four facets are live (`appLog`, `recording`,
`perf`, provider gating); the branch count says the mechanism is right and unfinished. Worst
offenders: `handlers/session-perf.ts` (12), `handlers/session-doctor-device.ts` (6),
`handlers/session-replay-maestro-runtime.ts` (6), `handlers/session-state.ts` (5). Each is a
`handlers/session-replay-maestro-runtime.ts` (6), `handlers/session-state.ts` (5; since deleted —
its commands route straight to their handlers from the `session.ts` table). Each is a
candidate facet, and each facet retired is a branch deleted in every command that shares it.

### 5c. Redundant edges: hub concentration, not debt
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/app-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { SessionSurface } from './session-surface.ts';

/**
* Closed result of the `appstate` command, grounded in the daemon handler's
* success returns (src/daemon/handlers/session-state.ts `handleAppStateCommand`).
* success returns (src/daemon/handlers/session-appstate.ts `handleAppStateCommand`).
* A discriminated union on `platform`:
* - Apple (`ios` / `macos`) session state, with iOS-only device locators that
* the previous hand-written mirror omitted; and
Expand Down
4 changes: 2 additions & 2 deletions packages/contracts/src/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { TargetShutdownResult } from './target-shutdown-contract.ts';

/**
* Closed result of the `boot` command. Mirrors the daemon handler's only
* success return EXACTLY (src/daemon/handlers/session-state.ts) — the fixed
* success return EXACTLY (src/daemon/handlers/session-appstate.ts) — the fixed
* object literal `{ platform, target, device, id, kind, booted }` plus the
* additive `appleOs` discriminant, emitted only for Apple devices.
*/
Expand All @@ -32,7 +32,7 @@ export type BootCommandResult = {

/**
* Closed result of the `shutdown` command. Mirrors the daemon handler's success
* return EXACTLY (src/daemon/handlers/session-state.ts) — the fixed object
* return EXACTLY (src/daemon/handlers/session-appstate.ts) — the fixed object
* literal `{ platform, target, device, id, kind, shutdown }` plus the additive
* `appleOs` discriminant (Apple devices only). The `shutdown` field is the raw
* {@link TargetShutdownResult} returned by the bound `shutdownTarget` operation.
Expand Down
1 change: 0 additions & 1 deletion scripts/layering/daemon-layer-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,6 @@
"src/daemon/handlers/session-runtime-port-reverse.ts",
"src/daemon/handlers/session-script-publication.ts",
"src/daemon/handlers/session-shutdown.ts",
"src/daemon/handlers/session-state.ts",
"src/daemon/handlers/session.ts",
"src/daemon/handlers/snapshot.ts",
"src/daemon/handlers/trace-runtime.ts",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { daemonPlatformServicesFixture } from '../../__tests__/platform-services-fixture.ts';
import { test, expect, vi } from 'vitest';

import { handleSessionStateCommands } from '../session-state.ts';
import { handleAppStateCommand } from '../session-appstate.ts';
import { makeSessionStore } from '../../../__tests__/test-utils/store-factory.ts';
import { withTestDeviceInventory } from '../../../__tests__/test-utils/device-inventory-gateways.ts';
import { unavailableDeploymentSnapshotAndShutdownOperationFacts } from '../../../__tests__/test-utils/runtime-operation-facts.ts';
Expand Down Expand Up @@ -39,7 +39,7 @@ test('appstate rejects web before Android app-state backend dispatch', async ()
local: async () => [device],
},
async () =>
await handleSessionStateCommands({
await handleAppStateCommand({
platformServices: daemonPlatformServicesFixture(),
req: {
token: 't',
Expand Down Expand Up @@ -160,7 +160,7 @@ test('appstate rejects a missing readiness fact even when appState is available'
const response = await withTestDeviceInventory(
{ local: async () => [device] },
async () =>
await handleSessionStateCommands({
await handleAppStateCommand({
platformServices: daemonPlatformServicesFixture(),
req: {
token: 't',
Expand Down Expand Up @@ -258,7 +258,7 @@ test('sessionless Android appstate inspects once, binds once, and preserves oper
const response = await withTestDeviceInventory(
{ local: async () => [device] },
async () =>
await handleSessionStateCommands({
await handleAppStateCommand({
platformServices: daemonPlatformServicesFixture(),
req: {
token: 't',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import { LeaseRegistry } from '../../lease-registry.ts';
import { acquireDeviceClaim } from '../../device/device-claims.ts';
import { inspectDeviceClaims } from '../../device/device-claim-inspection.ts';
import { createRequestExecutionScope } from '../../request-execution-scope.ts';
import { handleSessionStateCommands } from '../session-state.ts';
import { handleBootCommand } from '../session-boot.ts';
import { handleShutdownCommand } from '../session-shutdown.ts';
import type { DaemonRequest, DaemonResponse } from '../../daemon-request.ts';

// #1799: `boot`/`shutdown` route through a daemon that need not own the target
Expand Down Expand Up @@ -57,7 +58,7 @@ async function claimForeignDaemon(root: string): Promise<string> {
async function runStateCommand(
command: 'boot' | 'shutdown',
store: SessionStore,
): Promise<DaemonResponse | null> {
): Promise<DaemonResponse> {
const req: DaemonRequest = {
token: 't',
session: 'default',
Expand All @@ -80,14 +81,17 @@ async function runStateCommand(
},
});
try {
return await handleSessionStateCommands({
const handlerParams = {
platformServices: daemonPlatformServicesFixture(),
req,
sessionName: 'default',
sessionStore: store,
inspectFacts: scope.inspectFacts,
bindDevice: scope.bindDevice,
});
};
return command === 'boot'
? await handleBootCommand(handlerParams)
: await handleShutdownCommand(handlerParams);
} catch (error) {
return { ok: false, error: normalizeError(error) };
} finally {
Expand Down
4 changes: 2 additions & 2 deletions src/daemon/handlers/__tests__/session-boot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import { createUnavailablePlatformRuntimeFacts } from '@agent-device/contracts/platform-runtime-unavailable';
import { applicationLifecycleOperationFacts } from '@agent-device/contracts/application-lifecycle-runtime';
import { localRuntimeOwner } from '@agent-device/contracts/platform-runtime';
import { handleSessionStateCommands } from '../session-state.ts';
import { handleBootCommand } from '../session-boot.ts';
import type { SessionState } from '../../session-state.ts';
import {
handleSessionCommands,
Expand Down Expand Up @@ -456,7 +456,7 @@ test('boot rejects --headless outside Android directly', async () => {
booted: false,
};
mockResolveTargetDevice.mockResolvedValue(device);
const response = await handleSessionStateCommands({
const response = await handleBootCommand({
platformServices: daemonPlatformServicesFixture(),
req: {
token: 't',
Expand Down
36 changes: 0 additions & 36 deletions src/daemon/handlers/__tests__/session-state.test.ts

This file was deleted.

42 changes: 42 additions & 0 deletions src/daemon/handlers/__tests__/session.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { daemonPlatformServicesFixture } from '../../__tests__/platform-services-fixture.ts';
import { expect, test } from 'vitest';
import * as path from 'node:path';
import { handleSessionCommands } from './session-command-harness.ts';
import { makeSessionStore } from '../../../__tests__/test-utils/store-factory.ts';
import { mkdtempForTestSync } from '../../../__tests__/test-utils/tmp-dir.ts';
import { testCreateCommandSurface } from '../../__tests__/command-surface-fixture.ts';
import type { DaemonRequest } from '../../daemon-request.ts';

function request(command: string): DaemonRequest {
return { token: 't', session: 'default', command, positionals: [], flags: {} };
}

async function dispatch(command: string) {
return await handleSessionCommands({
createCommandSurface: testCreateCommandSurface,
platformServices: daemonPlatformServicesFixture(),
req: request(command),
sessionName: 'default',
logPath: path.join(mkdtempForTestSync('daemon'), 'daemon.log'),
sessionStore: makeSessionStore('agent-device-session-router-'),
invoke: async () => ({ ok: true, data: {} }),
});
}

test('the session router stays silent for commands its table does not carry', async () => {
expect(await dispatch('not_a_command')).toBeNull();
});

test('the session router maps boot, shutdown and appstate straight to their handlers', async () => {
// No session and no selector: each command reaches its own handler's guard rather than
// the router's null, which is what distinguishes routing from silence.
for (const command of ['boot', 'shutdown', 'appstate']) {
const response = await dispatch(command);
if (!response || response.ok) {
throw new Error(
`${command} should reach its handler's guard as an INVALID_ARGS refusal, got ${JSON.stringify(response)}`,
);
}
expect(response.error.code, command).toBe('INVALID_ARGS');
}
});
19 changes: 0 additions & 19 deletions src/daemon/handlers/session-state.ts

This file was deleted.

48 changes: 42 additions & 6 deletions src/daemon/handlers/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import {
handleSessionInventoryCommands,
handleSessionOpenCommands,
} from '../session-lifecycle/index.ts';
import { handleSessionStateCommands } from './session-state.ts';
import { handleBootCommand } from './session-boot.ts';
Comment thread
thymikee marked this conversation as resolved.
import { handleShutdownCommand } from './session-shutdown.ts';
import { handleAppStateCommand } from './session-appstate.ts';
import { handleSessionObservabilityCommands } from '../session-observability/index.ts';
import { handleReplayCommand, handleReplayTestCommand } from './session-replay-command.ts';
import { handleSessionScriptPublication } from './session-script-publication.ts';
Expand Down Expand Up @@ -61,15 +63,49 @@ const handleSessionCloseCommandGroup: SessionCommandHandler = (params) =>
platformResourceCleanup: params.platformResourceCleanup,
} satisfies SessionCloseCommandInput);

const handleSessionStateCommandGroup: SessionCommandHandler = async ({
const handleBootCommandEntry: SessionCommandHandler = async ({
req,
sessionName,
sessionStore,
inspectFacts,
bindDevice,
platformServices,
}) =>
await handleSessionStateCommands({
await handleBootCommand({
req,
sessionName,
sessionStore,
inspectFacts,
bindDevice,
platformServices,
});

const handleShutdownCommandEntry: SessionCommandHandler = async ({
req,
sessionName,
sessionStore,
inspectFacts,
bindDevice,
platformServices,
}) =>
await handleShutdownCommand({
req,
sessionName,
sessionStore,
inspectFacts,
bindDevice,
platformServices,
});

const handleAppStateCommandEntry: SessionCommandHandler = async ({
req,
sessionName,
sessionStore,
inspectFacts,
bindDevice,
platformServices,
}) =>
await handleAppStateCommand({
req,
sessionName,
sessionStore,
Expand Down Expand Up @@ -136,9 +172,9 @@ const SESSION_COMMAND_HANDLER_IMPLS = {
inspectFacts,
bindDevice,
}),
boot: handleSessionStateCommandGroup,
shutdown: handleSessionStateCommandGroup,
appstate: handleSessionStateCommandGroup,
boot: handleBootCommandEntry,
shutdown: handleShutdownCommandEntry,
appstate: handleAppStateCommandEntry,
session_save_script: async ({ req, sessionName, sessionStore }) =>
handleSessionScriptPublication({ req, sessionName, sessionStore }),
runtime: async ({
Expand Down
4 changes: 2 additions & 2 deletions src/platform-runtime-gateway.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { viewportRuntimeOperationFacts } from '@agent-device/contracts/viewport-
import type { DeviceInfo } from '@agent-device/kernel/device';
import { createLimrunRuntime } from '@agent-device/provider-limrun';
import { describe, expect, test, vi } from 'vitest';
import { handleSessionStateCommands } from './daemon/handlers/session-state.ts';
import { handleAppStateCommand } from './daemon/handlers/session-appstate.ts';
import { createRequestRuntimeBindings } from './daemon/request-runtime-binding.ts';
import { createRequestDispatchLedger } from './daemon/request-dispatch-ledger.ts';
import { makeSessionStore } from './__tests__/test-utils/store-factory.ts';
Expand Down Expand Up @@ -344,7 +344,7 @@ describe('composed platform runtime gateway', () => {
const response = await withTestDeviceInventory(
{ local: async () => [staleDevice] },
async () =>
await handleSessionStateCommands({
await handleAppStateCommand({
platformServices: daemonPlatformServicesFixture(),
req: {
token: 't',
Expand Down
Loading