Files
q792602257andClaude Opus 4.6 bead6e58ac
Tests / Test failed: 2, passed: 691
chore(openspec): archive host-agent-dependency-supervisor
Implementation verified on macOS (task 6.4 confirmed spawn + adoption
behavior). Archives the change under
openspec/changes/archive/2026-07-14-host-agent-dependency-supervisor/ and
syncs the delta spec into a new main capability at
openspec/specs/host-agent-dependency-supervisor/spec.md (5 baseline
requirements covering opt-in default, adopt-don't-fight, spawn, bounded
backoff restart, and lifecycle tied to Host Agent). openspec validate
--strict passes on the synced spec.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-14 10:07:07 +08:00

4.7 KiB

Why

On the macOS native real-device setup (docs/MACOS_IPHONE_SETUP.md), a device only reports idle/online to the Cloud Control Plane if DeviceManager.connect() (device/manager.py:68-108) can actually establish an Appium session — but the Host Agent process (apps/device-host-agent/host_agent/app.py) never starts Appium itself; the operator must run appium --address 127.0.0.1 --port 4723 in a separate terminal before starting device-host-agent, and separately run the local Runtime API (uvicorn api.rest:create_app --factory ...) if they want to inspect device/task state during local debugging. Forgetting (or losing) either process is invisible from the Host Agent's own output: heartbeats keep succeeding, so the Host looks "connected," while the device silently stays offline and every assigned task stays queued forever with no error. This was diagnosed live from exactly that symptom. Having the Host Agent supervise these known local dependencies for the single-machine dev/real-device workflow removes an easy-to-miss manual step and makes the failure visible instead of silent.

What Changes

  • HostAgentApplication gains an optional local dependency supervisor that, when enabled, starts and monitors two external processes alongside the existing heartbeat/claim loop:
    • Appium server (appium --address <host> --port <port>), whose reachability already gates real device connect() calls.
    • Local Runtime API (uvicorn api.rest:create_app --factory --host <host> --port <port>), used for local inspection/debugging of device and task state.
  • Before spawning either process, the supervisor probes the configured address: if something is already listening and answers the expected health check, it adopts the existing instance (log-only) instead of spawning a duplicate or rebinding the port. It only spawns a subprocess when the port is free.
  • Crash handling: if a supervised subprocess it spawned exits unexpectedly, the supervisor restarts it with capped exponential backoff and a maximum retry count per run; it does not touch a process it did not spawn (an adopted, externally-managed instance is never restarted or killed by the Host Agent).
  • New HostAgentConfig fields to control this, all opt-in and disabled by default (see design.md for the specific default-off rationale): enable/disable the supervisor as a whole, enable/disable each of the two dependencies independently, and host/port for each (defaulting to the existing documented conventions — Appium 127.0.0.1:4723, Runtime 127.0.0.1:8000).
  • Documentation update to docs/MACOS_IPHONE_SETUP.md describing the new opt-in supervised mode as an alternative to the existing manual multi-terminal flow (the manual flow remains fully supported and is still what's documented as the default path).
  • Explicitly out of scope: no change to WDA's own lifecycle (Appium continues to own WDA session management entirely unchanged), no Docker Compose changes (compose.yaml/compose.deploy.yaml are unaffected — this is a native-process-only capability), no change to the outbound cloud protocol.

Capabilities

New Capabilities

  • host-agent-dependency-supervisor: optional, opt-in local process supervision inside the Host Agent for the Appium server and the local Runtime API — port/adoption probing, spawn, health-checked readiness, and rate-limited crash-restart, scoped to the macOS native single-machine real-device workflow.

Modified Capabilities

(none — host-agent-protocol outbound behavior is unchanged; driver-registry/device-pool behavior for how a Driver.connect() reaches Appium is unchanged, this change only affects whether Appium happens to already be running when that connect attempt occurs)

Impact

  • Affected code: apps/device-host-agent/host_agent/ (new supervisor module, app.py wiring to start/stop it alongside the heartbeat/claim loop, config.py new fields), apps/device-host-agent/pyproject.toml (no new runtime dependency expected — spawning uses stdlib subprocess; Runtime API is already invoked via its existing uvicorn/api.rest entry point).
  • Not affected: cloud.*, apps/cloud-api, compose.yaml, compose.deploy.yaml, driver/wda_driver.py / driver/android_driver.py connection logic, WDA's own session lifecycle (still fully owned by Appium).
  • Operational impact: opt-in only — a Host Agent with the supervisor disabled (the default) behaves exactly as it does today. When enabled, the Host Agent's own process lifecycle now indirectly affects two more local processes, which changes what "the Host Agent crashed" or "the Host Agent's log" means for local troubleshooting (see design.md for how adoption-vs-spawn is surfaced in logs to keep this legible).