Purpose
Child of #2278 (audit area: Apple selector and session observations). The daemon consumes Apple runner session health and the sole-foreground-app probe directly from root composition modules — four classified edges in scripts/layering/daemon-platform-runtime-inventory.ts (R74):
src/daemon/request-recording-health.ts → src/platform-runtime-apple-resources.ts (inspectAppleRunnerSession)
src/daemon/session-device-resolution.ts → src/platform-runtime-apple-resources.ts (inspectAppleRunnerSession)
src/daemon/ios-app-session-hint.ts → src/platform-runtime-open-target.ts (resolveSoleForegroundIosApp, import and re-export)
Define the smallest semantic observation/query interface that supports the daemon contract without exposing Apple runner mechanics.
Required behavior
- The two runner-health consumers need one observation: for a UDID, whether a live runner session exists and its current session id (recording-health invalidation; simulator-boot evidence for device refresh). The daemon today compares
snapshot.sessionId against the recorded runnerSessionId and treats alive: false as invalidation — the port must preserve those decisions.
- The open-hint consumer needs the sole-foreground-app probe with its never-guess contract: exactly one booted simulator in the device set with exactly one running app, else
undefined; probe failures are inconclusive, control-flow/composition failures propagate. The hint policy (when to emit, MAX_HINT_LENGTH, command composition) stays daemon-owned.
- The owning seam is a neutral observation interface: declared in
@agent-device/contracts or a root-composed capability named in scripts/layering/architecture-ownership.ts, with the Apple implementation in packages/platform-apple. Data shape sketch:
// contracts (sketch)
type RunnerSessionObservation = Readonly<{ alive: boolean; sessionId?: string }>;
type SoleForegroundApp = Readonly<{ device: DeviceInfo; app: Readonly<{ bundleId: string }> }>;
type AppleSessionObservation = Readonly<{
observeRunnerSession(deviceId: string): Promise<RunnerSessionObservation | undefined>;
resolveSoleForegroundApp(params: { simulatorSetPath?: string }): Promise<SoleForegroundApp | undefined>;
}>;
Observable completion conditions
- The four R74 inventory edges above are reclassified or removed (R74 fails on stale entries, forcing the update).
- No production importer of
inspectAppleRunnerSession or resolveSoleForegroundIosApp remains under src/daemon/**.
- Recording-health invalidation and the "run open first" hint behave identically (existing behavior tests stay green).
- Planted violation: a new daemon import of either symbol is red against R74 (or R65 for a direct platform-package import).
pnpm check:layering and pnpm check:affected --run pass.
Dependencies
Coordinate with #2273 and #2274; this issue must not duplicate the selector-producer seam or snapshot-producer policy.
Purpose
Child of #2278 (audit area: Apple selector and session observations). The daemon consumes Apple runner session health and the sole-foreground-app probe directly from root composition modules — four classified edges in
scripts/layering/daemon-platform-runtime-inventory.ts(R74):src/daemon/request-recording-health.ts→src/platform-runtime-apple-resources.ts(inspectAppleRunnerSession)src/daemon/session-device-resolution.ts→src/platform-runtime-apple-resources.ts(inspectAppleRunnerSession)src/daemon/ios-app-session-hint.ts→src/platform-runtime-open-target.ts(resolveSoleForegroundIosApp, import and re-export)Define the smallest semantic observation/query interface that supports the daemon contract without exposing Apple runner mechanics.
Required behavior
snapshot.sessionIdagainst the recordedrunnerSessionIdand treatsalive: falseas invalidation — the port must preserve those decisions.undefined; probe failures are inconclusive, control-flow/composition failures propagate. The hint policy (when to emit,MAX_HINT_LENGTH, command composition) stays daemon-owned.@agent-device/contractsor a root-composed capability named inscripts/layering/architecture-ownership.ts, with the Apple implementation inpackages/platform-apple. Data shape sketch:src/daemon/direct-ios-selector.ts→queryAppleRuntimeSelector): that edge is owned by the A failed selector query cannot be told apart from a true negative, and it ends the session without saying so #2273/Selector queries have no fallback producer on the iOS Simulator, and any fallback needs producer equivalence #2274 selector-seam work.Observable completion conditions
inspectAppleRunnerSessionorresolveSoleForegroundIosAppremains undersrc/daemon/**.pnpm check:layeringandpnpm check:affected --runpass.Dependencies
Coordinate with #2273 and #2274; this issue must not duplicate the selector-producer seam or snapshot-producer policy.