Skip to content

refactor(daemon): establish session lifecycle facade and neutral admission seams #2173

Description

@thymikee

Parent: #2132

Blocked by: #2166 (merged). First child in the #2132 chain.

Outcome

Remove the neutral session selection/admission helpers and inventory implementation from the handler grab-bag, then establish the lifecycle concern's single public facade. This is the foundation for the open/close children; it must not move open or close behavior yet.

Exact production scope

  • Move src/daemon/handlers/session-device-utils.ts to src/daemon/session-device-resolution.ts. Keep it neutral: it is already used by inventory, state, deployment, reverse-port, selector dispatch, prepare, clipboard, open, and close.
  • Move src/daemon/handlers/session-runtime-admission.ts to src/daemon/session-runtime-admission.ts. It remains a shared admission helper over InspectDeviceRuntimeFacts and BindDeviceRuntime, not lifecycle-owned internals.
  • Move src/daemon/handlers/session-inventory.ts to src/daemon/session-lifecycle/internal/inventory.ts.
  • Add src/daemon/session-lifecycle/index.ts as the only external lifecycle facade. Initially export only the inventory route operation and its narrow input type.
  • Keep src/daemon/handlers/session.ts as the route adapter. It may import the facade, but no caller may import session-lifecycle/internal/**.
  • Update all exact production importers of the two neutral moves. Do not add a barrel or compatibility re-export at the old paths.
  • Update scripts/layering/architecture-ownership.ts and its tests with the lifecycle facade and both forbidden deep-import directions.

Commands covered by the facade in this child: session_list, devices, capabilities, and apps.

Authority contract

Inventory may read only the current fields it uses: name, createdAt, device, surface, appBundleId, and appName. It keeps SessionStore as read authority for now; it must not acquire a write operation or copy SessionState.

Injected capabilities are exactly InspectDeviceRuntimeFacts, BindDeviceRuntime, and optional ProviderAppCatalog. Device claims continue through inspectDeviceClaims; lease scoping continues through resolveLeaseScope. No new capability aggregate unless the diff deletes more plumbing than it adds.

The neutral selection module preserves explicit-selector checks, session-device conflict behavior, readiness refresh, and typed errors. The neutral admission module preserves fact-first admission and the opaque admitted-plan token.

Behavior proof

Move the inventory/device-selection/admission tests with their owners, including:

  • session-inventory-*, session-capabilities*, and session-devices-batch-runtime.test.ts
  • session-device-utils.test.ts
  • session-runtime-admission.test.ts
  • session-inventory-apps-runtime.test.ts

Before moving implementation, add a route-level characterization proving the four commands still pass through the lifecycle facade with identical response data and typed failures.

Plant and observe red for: (1) a handler deep-importing session-lifecycle/internal/inventory.ts; (2) lifecycle internal code importing src/daemon/handlers/**; and (3) restoring either old helper path. The structural gate must name the invariant and path.

Shrink and validation

Delete the old modules and any superseded test harness/fixtures. Report gross production additions/deletions and move-adjusted LOC; move-adjusted production LOC must not grow. Run focused tests, pnpm check:layering, the fallow audit for moved keys, and pnpm check:affected --run after staging structural files.

Non-goals

No open/close move, no replay/test move, no state-field write relocation, no wire/help behavior change, and no generic SessionContext/Pick<SessionStore> wrapper.

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