Part of #3264. ADR 0021 §5, §8, ADR 0006. Design D5 in the umbrella.
Blocked by: #3266
Real allocation also needs #3269. Until then the daemon path runs against the scripted fake allocator, iOS first.
Purpose
A worker asks Host for a device by type, such as "iPhone 16" or "Pixel 7", not by a local identity. Simlock resolves the type against installed components and creates a fresh device for the lease.
Required behavior
- When authenticated
/health says service: "agent-device-host" and advertises features: ["device-shape"], --device "<type>" is a device type. The client skips the inventory lookup and allocates with the type, --platform and --os-version in the device-selection fields lease.allocate already carries.
- Without
--platform (or a platform already on the connection) the client fails with details.reason: "host-shape-platform-required". A missing --device, a UDID or a serial fails with "host-shape-invalid", a missing token with "host-unauthenticated", and a different type on a session that already holds one with "host-shape-mismatch". All of these happen before any lease request.
- After allocation the command addresses the leased device by its UDID or serial, never a device that shares its type's name.
- A Host without the feature fails with
"host-shape-unsupported" before any mutation. No lease.allocate is sent.
- Plain
proxy (service: "agent-device-proxy") resolves --device against remote inventory as before.
- On the daemon,
lease.allocate with a trusted principal builds a strict { platform, deviceType, osVersion? } shape and calls a HostShapeAllocator seam with the principal, run and client attribution, the shape and the TTL. The daemon validates the lease scope before it provisions anything, publishes the Host lease only after the allocator returns, and gives the allocation back if publishing fails or the requester has left.
- The daemon advertises
device-shape on /health exactly when it has an allocator.
- A UDID or serial on a Host lease request gets
"host-shape-invalid". A daemon with no allocator configured gets "host-shape-allocation-unavailable".
- No
rpcProtocolVersion bump. The change is additive under ADR 0006, and the wire-compat ledger records an acknowledgement.
Completion conditions
- Through Host,
open --platform ios --device "iPhone 16" reaches the allocator seam with { platform: "ios", deviceType: "iPhone 16" } and the server principal, in a test with the scripted fake allocator.
- Against a Host without
device-shape, the client makes zero lease.allocate calls.
- The existing plain
proxy --device tests pass unchanged.
pnpm check:daemon-wire-compat passes.
Dependencies
#3266 for the principal handoff. #3269 implements HostShapeAllocator over Simlock.
Example
agent-device connect proxy --daemon-base-url https://build-mac.local:8443/agent-device --daemon-auth-token "$HOST_TOKEN"
agent-device open com.example.app --platform ios --device "iPhone 16"
agent-device open com.example.app --platform android --device "Pixel 7" --os-version 15
Part of #3264. ADR 0021 §5, §8, ADR 0006. Design D5 in the umbrella.
Blocked by: #3266
Real allocation also needs #3269. Until then the daemon path runs against the scripted fake allocator, iOS first.
Purpose
A worker asks Host for a device by type, such as "iPhone 16" or "Pixel 7", not by a local identity. Simlock resolves the type against installed components and creates a fresh device for the lease.
Required behavior
/healthsaysservice: "agent-device-host"and advertisesfeatures: ["device-shape"],--device "<type>"is a device type. The client skips the inventory lookup and allocates with the type,--platformand--os-versionin the device-selection fieldslease.allocatealready carries.--platform(or a platform already on the connection) the client fails withdetails.reason: "host-shape-platform-required". A missing--device, a UDID or a serial fails with"host-shape-invalid", a missing token with"host-unauthenticated", and a different type on a session that already holds one with"host-shape-mismatch". All of these happen before any lease request."host-shape-unsupported"before any mutation. Nolease.allocateis sent.proxy(service: "agent-device-proxy") resolves--deviceagainst remote inventory as before.lease.allocatewith a trusted principal builds a strict{ platform, deviceType, osVersion? }shape and calls aHostShapeAllocatorseam with the principal, run and client attribution, the shape and the TTL. The daemon validates the lease scope before it provisions anything, publishes the Host lease only after the allocator returns, and gives the allocation back if publishing fails or the requester has left.device-shapeon/healthexactly when it has an allocator."host-shape-invalid". A daemon with no allocator configured gets"host-shape-allocation-unavailable".rpcProtocolVersionbump. The change is additive under ADR 0006, and the wire-compat ledger records an acknowledgement.Completion conditions
open --platform ios --device "iPhone 16"reaches the allocator seam with{ platform: "ios", deviceType: "iPhone 16" }and the server principal, in a test with the scripted fake allocator.device-shape, the client makes zerolease.allocatecalls.proxy--devicetests pass unchanged.pnpm check:daemon-wire-compatpasses.Dependencies
#3266 for the principal handoff. #3269 implements
HostShapeAllocatorover Simlock.Example