From bead6e58acdfba7897d0896dd4d82703e33d4b52 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Tue, 14 Jul 2026 10:07:07 +0800 Subject: [PATCH] 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 --- .../.openspec.yaml | 0 .../design.md | 0 .../proposal.md | 0 .../host-agent-dependency-supervisor/spec.md | 0 .../tasks.md | 4 +- .../host-agent-dependency-supervisor/spec.md | 64 +++++++++++++++++++ 6 files changed, 66 insertions(+), 2 deletions(-) rename openspec/changes/{host-agent-dependency-supervisor => archive/2026-07-14-host-agent-dependency-supervisor}/.openspec.yaml (100%) rename openspec/changes/{host-agent-dependency-supervisor => archive/2026-07-14-host-agent-dependency-supervisor}/design.md (100%) rename openspec/changes/{host-agent-dependency-supervisor => archive/2026-07-14-host-agent-dependency-supervisor}/proposal.md (100%) rename openspec/changes/{host-agent-dependency-supervisor => archive/2026-07-14-host-agent-dependency-supervisor}/specs/host-agent-dependency-supervisor/spec.md (100%) rename openspec/changes/{host-agent-dependency-supervisor => archive/2026-07-14-host-agent-dependency-supervisor}/tasks.md (95%) create mode 100644 openspec/specs/host-agent-dependency-supervisor/spec.md diff --git a/openspec/changes/host-agent-dependency-supervisor/.openspec.yaml b/openspec/changes/archive/2026-07-14-host-agent-dependency-supervisor/.openspec.yaml similarity index 100% rename from openspec/changes/host-agent-dependency-supervisor/.openspec.yaml rename to openspec/changes/archive/2026-07-14-host-agent-dependency-supervisor/.openspec.yaml diff --git a/openspec/changes/host-agent-dependency-supervisor/design.md b/openspec/changes/archive/2026-07-14-host-agent-dependency-supervisor/design.md similarity index 100% rename from openspec/changes/host-agent-dependency-supervisor/design.md rename to openspec/changes/archive/2026-07-14-host-agent-dependency-supervisor/design.md diff --git a/openspec/changes/host-agent-dependency-supervisor/proposal.md b/openspec/changes/archive/2026-07-14-host-agent-dependency-supervisor/proposal.md similarity index 100% rename from openspec/changes/host-agent-dependency-supervisor/proposal.md rename to openspec/changes/archive/2026-07-14-host-agent-dependency-supervisor/proposal.md diff --git a/openspec/changes/host-agent-dependency-supervisor/specs/host-agent-dependency-supervisor/spec.md b/openspec/changes/archive/2026-07-14-host-agent-dependency-supervisor/specs/host-agent-dependency-supervisor/spec.md similarity index 100% rename from openspec/changes/host-agent-dependency-supervisor/specs/host-agent-dependency-supervisor/spec.md rename to openspec/changes/archive/2026-07-14-host-agent-dependency-supervisor/specs/host-agent-dependency-supervisor/spec.md diff --git a/openspec/changes/host-agent-dependency-supervisor/tasks.md b/openspec/changes/archive/2026-07-14-host-agent-dependency-supervisor/tasks.md similarity index 95% rename from openspec/changes/host-agent-dependency-supervisor/tasks.md rename to openspec/changes/archive/2026-07-14-host-agent-dependency-supervisor/tasks.md index 536fd5e..180c9d0 100644 --- a/openspec/changes/host-agent-dependency-supervisor/tasks.md +++ b/openspec/changes/archive/2026-07-14-host-agent-dependency-supervisor/tasks.md @@ -42,6 +42,6 @@ - [x] 6.3 `openspec validate --strict` for this change. Result: `Change 'host-agent-dependency-supervisor' is valid`. -- [ ] 6.4 Manual verification on macOS: start Host Agent with supervisor enabled and no Appium/Runtime running, confirm both are spawned and device reaches `idle`; then start Host Agent again with an already-running Appium, confirm it's adopted (not duplicated) and logged as such. +- [x] 6.4 Manual verification on macOS: start Host Agent with supervisor enabled and no Appium/Runtime running, confirm both are spawned and device reaches `idle`; then start Host Agent again with an already-running Appium, confirm it's adopted (not duplicated) and logged as such. - **Deferred.** This session ran on Windows where the Appium/WebDriverAgent real-device workflow doesn't apply. To be executed on a macOS host per `docs/MACOS_IPHONE_SETUP.md` §9 once available. + Verified by the user on a macOS host following `docs/MACOS_IPHONE_SETUP.md` §9. diff --git a/openspec/specs/host-agent-dependency-supervisor/spec.md b/openspec/specs/host-agent-dependency-supervisor/spec.md new file mode 100644 index 0000000..730ac32 --- /dev/null +++ b/openspec/specs/host-agent-dependency-supervisor/spec.md @@ -0,0 +1,64 @@ +## Purpose + +Define how the Host Agent optionally supervises its own dependencies (Appium and the local Runtime API), including opt-in activation, adoption of already-running healthy instances, bounded-restart lifecycle for spawned processes, and cleanup tied to the Host Agent's own process lifecycle. + +## Requirements + +### Requirement: Supervisor is opt-in and disabled by default +The Host Agent SHALL NOT start, adopt-check, or supervise Appium or the local Runtime API unless `HOST_AGENT_DEPENDENCY_SUPERVISOR_ENABLED` is explicitly set to true. Each of the two dependencies SHALL additionally have its own independent enable flag (`HOST_AGENT_APPIUM_SUPERVISED`, `HOST_AGENT_RUNTIME_SUPERVISED`), both defaulting to false. + +#### Scenario: Default configuration behaves exactly as before +- **WHEN** a Host Agent starts with no `HOST_AGENT_DEPENDENCY_SUPERVISOR_ENABLED` (or any related) environment variable set +- **THEN** the Host Agent does not attempt to connect to, probe, or spawn Appium or the Runtime API, and its heartbeat/claim behavior is unchanged from before this capability existed + +#### Scenario: Top-level flag on, individual dependency flag off +- **WHEN** `HOST_AGENT_DEPENDENCY_SUPERVISOR_ENABLED=true` and `HOST_AGENT_APPIUM_SUPERVISED=false` (Runtime supervised is true) +- **THEN** the Host Agent supervises only the Runtime API and does not probe, adopt, or spawn Appium + +### Requirement: Adopt an already-running, healthy dependency instead of spawning a duplicate +Before spawning a supervised dependency, the Host Agent SHALL attempt a TCP connection to its configured host/port, and if something is listening, SHALL perform the dependency-specific health check (Appium: HTTP GET to its status endpoint expecting a successful response; Runtime: HTTP GET to its health endpoint expecting a successful response). If the health check succeeds, the Host Agent SHALL treat the existing process as adopted, SHALL NOT spawn a subprocess for that dependency, and SHALL NOT restart or terminate the adopted process at any point in its lifecycle. + +#### Scenario: Appium already running and healthy +- **WHEN** Appium supervision is enabled and a healthy Appium server is already listening on the configured host/port +- **THEN** the Host Agent logs that it adopted the existing instance and does not spawn a new Appium process + +#### Scenario: Port occupied by something unhealthy or unrelated +- **WHEN** a supervised dependency's port has a listener that does not pass the dependency-specific health check +- **THEN** the Host Agent logs an error identifying the port conflict for that dependency and does not spawn a subprocess for it, and does not treat the dependency as available + +### Requirement: Spawn supervised dependencies that are not already running +When a dependency is enabled for supervision and no healthy instance is adopted, the Host Agent SHALL spawn it as a child process (Appium via `appium --address --port `; Runtime API via its existing `uvicorn api.rest:create_app --factory` entry point with the configured host/port), and SHALL forward the child process's stdout/stderr into the Host Agent's own logging, tagged by dependency name. + +#### Scenario: Neither dependency is running at Host Agent startup +- **WHEN** both Appium and Runtime supervision are enabled and neither has a healthy instance already listening +- **THEN** the Host Agent spawns both as child processes before proceeding to its first device-connect attempt, and both processes' output is visible in the Host Agent's logs + +#### Scenario: Spawn fails because the executable is missing +- **WHEN** the Host Agent attempts to spawn Appium but `appium` is not found on `PATH` +- **THEN** the Host Agent logs a dependency-supervisor-specific startup error naming the missing dependency, distinct from a runtime crash of an already-started process + +### Requirement: Restart only processes the supervisor itself spawned, with bounded backoff +The Host Agent SHALL restart a supervised dependency automatically only if the Host Agent's own child process handle for it exits unexpectedly. Restart attempts SHALL use capped exponential backoff and SHALL stop permanently for that dependency, for the remaining lifetime of the current Host Agent process, once a configured maximum attempt count (`HOST_AGENT_DEPENDENCY_RESTART_MAX_ATTEMPTS`) is reached. The Host Agent SHALL NOT restart or terminate a dependency instance it adopted rather than spawned. + +#### Scenario: Spawned Appium process crashes +- **WHEN** a Host Agent-spawned Appium child process exits unexpectedly and the per-dependency restart attempt count is below the configured maximum +- **THEN** the Host Agent waits the current backoff interval and attempts to spawn Appium again + +#### Scenario: Restart attempts exhausted +- **WHEN** a supervised dependency has crashed and been restarted until reaching `HOST_AGENT_DEPENDENCY_RESTART_MAX_ATTEMPTS` +- **THEN** the Host Agent logs that it has given up restarting that dependency and does not attempt to spawn it again for the rest of the current process lifetime + +#### Scenario: Adopted process exits +- **WHEN** a dependency instance the Host Agent adopted (did not spawn) stops running +- **THEN** the Host Agent does not attempt to restart it, since it never held a child process handle for it + +### Requirement: Supervisor lifecycle is tied to Host Agent process lifecycle +The Host Agent SHALL start enabled, not-yet-healthy supervised dependencies before beginning its normal device-connect/heartbeat/claim sequence, and SHALL stop any dependency processes it spawned (not ones it adopted) during its own graceful shutdown. + +#### Scenario: Host Agent shuts down gracefully +- **WHEN** the Host Agent receives a shutdown signal while it holds a child process handle for a spawned Appium instance +- **THEN** the Host Agent terminates the spawned Appium child process as part of its own shutdown sequence + +#### Scenario: Host Agent shuts down while an adopted dependency is running +- **WHEN** the Host Agent shuts down and Appium was adopted (not spawned) rather than spawned by this Host Agent +- **THEN** the adopted Appium process is left running, untouched, after the Host Agent exits