|
| 1 | +# Host-local supervision — Spec |
| 2 | + |
| 3 | +This is a concise map from the |
| 4 | +[Host-local supervision requirements](requirements.md) to current mechanisms |
| 5 | +and evidence. It does not define transport, remote attachment, deployment |
| 6 | +policy, or a second Doctor health model. |
| 7 | + |
| 8 | +## Subject selection and ownership |
| 9 | + |
| 10 | +The CLI selects a catalog and an explicit or locally detected host. A |
| 11 | +[`HostLock`](../../../src/host_lock.rs#L1-L67) tracks resident ownership of |
| 12 | +that `(catalog, host)` subject independently from another host's slice of the |
| 13 | +same synced catalog. |
| 14 | + |
| 15 | +## Current mechanism and evidence |
| 16 | + |
| 17 | +| Requirement | Current mechanism | Evidence | |
| 18 | +| --- | --- | --- | |
| 19 | +| HOST-R01 | Reconciliation filters every declaration through its resolved host; remote declarations are reported but not acted on. | [`reconcile`](../../../src/reconcile.rs#L106-L191); [host-placement tests](../../../tests/reconcile.rs#L135-L153) | |
| 20 | +| HOST-R02 | One pass discovers declarations, obtains an authoritative local session view, computes desired versus actual, and then adopts or executes the plan. A failed session listing skips the whole pass. | [reconcile pass](../../../src/run.rs#L737-L813); [reconcile-plan model](../../../src/reconcile.rs#L66-L81) | |
| 21 | +| HOST-R03 | The long-running CLI checks for a live owner of the same catalog and host, records its own PID, and reclaims stale ownership. | [catalog supervisor entry](../../../src/main.rs#L1738-L1838); [`HostLock` tests](../../../src/host_lock.rs#L83-L143) | |
| 22 | +| HOST-R04 | PTY and exec tasks survive normal or forced control-plane termination and binary replacement; the successor preserves PID and creation identity while adopting them. | [replacement acceptance](../../../tests/nomad_survival.rs#L592-L701) | |
| 23 | +| HOST-R05 | Normal supervisor exit leaves tasks running. Teardown and retirement are separate paths that target only the selected host's declared task IDs. | [`down` and teardown](../../../src/run.rs#L987-L1056); [explicit-lifecycle acceptance](../../../tests/nomad_survival.rs#L703-L780) | |
| 24 | +| HOST-R06 | The deterministic loop surfaces bounded crash-loop failure to the declared supervisor; the root-agent responsibility itself is owned by root R04. | [crash-loop surfacing](../../../src/run.rs#L1090-L1189); [R04](../requirements.md#L43-L46) | |
| 25 | +| HOST-R07 | Agent/task liveness and the resident supervisor lock are separate observations. A replacement adopts matching work visible in its selected current state. Sidecar-only work does not make an otherwise unrunnable agent live. No global catalog-liveness classifier is implemented. | [replacement adoption](https://github.com/compoundingtech/st2/blob/661c88b6e50cddbdf85e8ffaca9245c46491a1e0/tests/nomad_survival.rs#L608-L717); [separate supervisor report](https://github.com/compoundingtech/st2/blob/661c88b6e50cddbdf85e8ffaca9245c46491a1e0/src/main.rs#L985-L1008); [DING-only boundary](https://github.com/compoundingtech/st2/blob/661c88b6e50cddbdf85e8ffaca9245c46491a1e0/tests/reconcile.rs#L533-L561) | |
| 26 | +| HOST-R08 | Stable catalog-root and PTY-root path lifetime is an accepted constraint. The guided coordinated relocation operation is not implemented. | [migration contract](https://github.com/compoundingtech/st2/issues/85) | |
| 27 | + |
| 28 | +## Catalog liveness and path lifetime |
| 29 | + |
| 30 | +A live canonical catalog agent keeps the catalog live across supervisor |
| 31 | +downtime. The missing supervisor is separate factual state: it can delay |
| 32 | +convergence, but it cannot turn the continuing agent into dead work, erase the |
| 33 | +last-applied catalog, or authorize teardown. On restart, st2 adopts matching |
| 34 | +work that is visible in the selected current state and launches only genuinely |
| 35 | +missing work. A surviving generated DING sidecar without a canonical agent does |
| 36 | +not satisfy the catalog-agent liveness predicate. |
| 37 | + |
| 38 | +This is a host-local contract, not cross-root or global discovery. Under a |
| 39 | +partition or otherwise incomplete observation, st2 cannot infer that a catalog |
| 40 | +is globally not live merely because it cannot currently see a canonical agent. |
| 41 | +Supervisor state remains independently reportable. |
| 42 | + |
| 43 | +While the catalog is live, or while its resident supervisor is running, its |
| 44 | +resolved catalog root and PTY root are stable mounted state paths. Ordinary |
| 45 | +edits and file sync within the catalog remain allowed under the separate |
| 46 | +complete-version and last-known-good rules; this is a path-lifetime constraint, |
| 47 | +not an opaque-database contract. Relocating either resolved root requires the |
| 48 | +explicit coordinated operation in |
| 49 | +[issue #85](https://github.com/compoundingtech/st2/issues/85). Ordinary |
| 50 | +`up`, `doctor`, and reconciliation remain scoped to the currently selected |
| 51 | +paths and never scan arbitrary old roots. |
| 52 | + |
| 53 | +## Partition boundary |
| 54 | + |
| 55 | +The root [R18/R22](../requirements.md) contract requires a complete, |
| 56 | +validated, locally applied catalog to remain authoritative through transport |
| 57 | +loss. The current reconciler instead discovers the live catalog filesystem on |
| 58 | +each pass ([source](../../../src/run.rs#L737-L758)), while validation is a |
| 59 | +separate read-only command |
| 60 | +([source](../../../src/validate.rs#L1-L24)). st2 does not yet stage a candidate |
| 61 | +catalog, assign or compare catalog versions, atomically activate a validated |
| 62 | +snapshot, or retain an activation receipt. That durable last-known-good |
| 63 | +activation path is unimplemented. |
| 64 | + |
| 65 | +Peer reachability is not currently a reconciler input. This is consistent with |
| 66 | +peer absence being neutral, but the declaration shape for an explicit local |
| 67 | +operation that depends on a peer or source is not yet specified. |
| 68 | + |
| 69 | +## Open questions |
| 70 | + |
| 71 | +- What identifies a complete candidate catalog and orders it after the locally |
| 72 | + applied version? |
| 73 | +- What atomic activation and durable receipt let a replacement control plane |
| 74 | + recover the last-known-good version after interruption? |
| 75 | +- How does a declaration express a local operation's dependency on a peer or |
| 76 | + source without turning peer presence into general health? |
| 77 | +- [`HostLock` acquisition](../../../src/host_lock.rs#L26-L48) is currently |
| 78 | + check-then-write rather than an atomic create. What ownership primitive |
| 79 | + closes simultaneous first-start races while retaining host-scoped |
| 80 | + stale-owner recovery? |
0 commit comments