Skip to content

refactor(daemon): own Apple runner session observation behind a semantic port #2332

Description

@thymikee

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.tssrc/platform-runtime-apple-resources.ts (inspectAppleRunnerSession)
  • src/daemon/session-device-resolution.tssrc/platform-runtime-apple-resources.ts (inspectAppleRunnerSession)
  • src/daemon/ios-app-session-hint.tssrc/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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions