* feat: add integrated device leasing * fix: keep metro bearer token out of generated proxy profile The proxy connect profile is written to disk as a non-secret remote config, but it unconditionally copied `metroBearerToken` into that file, leaking the secret at rest. Mirror the cloud path, which keeps `daemonAuthToken` in-memory only: the token still flows through this connect via the returned flags, and later commands re-supply it via AGENT_DEVICE_METRO_BEARER_TOKEN. Extend the non-secret-profile test to assert the bearer token is absent from disk. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VPa5Z9GBkeqoxVctC85N7e * fix: always release device lease on session close releaseSessionLease + sessionStore.delete ran only on the happy path, after several awaits (app-log/perf/snapshot teardown, platform close dispatch, runner stop) that can throw. A failed close therefore stranded the device lease until the inactivity expiry. Wrap teardown in try/finally so ownership is always freed; the original error still propagates after finally. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VPa5Z9GBkeqoxVctC85N7e * fix: reconcile integrated device leasing * docs: simplify remote lease guidance * refactor: satisfy leasing fallow checks * fix: harden integrated device leasing * refactor: deepen device lease lifecycle * refactor: centralize lease scope projection * fix: harden proxy lease e2e flow * fix: address lease review feedback * refactor: tighten lease release cleanup * fix: simplify proxy startup output * fix: harden cloud lease identity * fix: color proxy startup output * fix: simplify proxy tunnel placeholder --------- Co-authored-by: Claude <noreply@anthropic.com>
2.1 KiB
ADR 0007: Remote Device Leases
Status
Accepted
Context
Remote daemon users need a clear ownership boundary before commands reach a platform runner or helper. Shared proxy and hosted providers need ownership to include the selected device and connection provider, not only tenant/run.
Runner and helper processes already have backend-specific mutual exclusion. That guard protects platform tooling, not remote client ownership, so surfacing those errors directly makes device contention harder to recover from.
Decision
A remote device lease is logical ownership of one selected device by one
remote client for a connection provider such as proxy, cloud, or limrun.
connect establishes connection profile and client identity. Lease allocation
is lazy and happens when a device, backend, and provider are known.
A runner/process lease is a backend helper guard and is not a user/client ownership boundary. It stays below daemon device leases and should not be weakened or replaced by them.
open is the natural point to acquire a device lease because target resolution
and session creation meet there. Commands after open must refresh the lease;
no activity for five minutes should make the device available again.
Lease admission, heartbeat, stored session lease refresh, and request execution must run under the same daemon request lock. Scope resolution may happen before the lock, but lease ownership mutation must not.
Generated connection profiles are non-secret. They may persist routing and lease metadata, but must strip daemon and Metro bearer tokens. Tokens are supplied in-memory for the current command or through environment/CLI token paths.
The proxy process is expected to be long-lived and self-serve. Recovery from a stale or expired device lease should not require restarting the proxy.
Consequences
Device contention can fail before platform execution with an explicit device-lease error that includes the backend, provider, selected device key, and owning lease expiry.
Backend-only leases remain valid for older remote clients, while provider-aware clients get device-level contention and clearer recovery.