Skip to content

Commit d7e83eb

Browse files
committed
docs(vrs): define host-local partition contract
1 parent a5c6eb9 commit d7e83eb

4 files changed

Lines changed: 179 additions & 0 deletions

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Host-local supervision — Requirements
2+
3+
Host-local supervision is one machine's application of the root
4+
[st2 vision](../vision.md). It refines host placement, root supervision, and
5+
control-plane replacement in
6+
[R03](../requirements.md#L38-L39),
7+
[R04](../requirements.md#L43-L46), and
8+
[R11](../requirements.md#L65-L70). Partition safety remains a fleet-level
9+
contract in [R18/R22](../requirements.md); this sub-VRS does not redefine it.
10+
11+
## Requirements
12+
13+
- **HOST-R01 One local subject:** A supervisor reconciles one selected catalog
14+
for one selected host. Another host's declarations and runtime records are
15+
outside that subject.
16+
- **HOST-R02 Local desired-versus-actual convergence:** The deterministic
17+
control plane compares declarations pinned to the selected host with that
18+
host's observed task state, adopts matching live work, and starts only
19+
genuinely missing work.
20+
- **HOST-R03 One control-plane writer:** At most one resident control plane may
21+
reconcile a given catalog and host at a time. A different host supervising
22+
the same synced catalog is a different subject.
23+
- **HOST-R04 Independent task lifetime:** Stopping, killing, or replacing the
24+
control plane does not stop or replace running agent tasks. A successor
25+
adopts surviving tasks without duplicating them.
26+
- **HOST-R05 Explicit destructive lifecycle:** Control-plane absence, restart,
27+
or loss of a transport peer is not teardown authority. Local tasks are
28+
stopped only by an explicit local lifecycle decision, including a locally
29+
applied retirement declaration or teardown command.
30+
- **HOST-R06 Intelligent local escalation:** The selected host's root agent
31+
observes local health, performs bounded recovery, and escalates unresolved
32+
failures without turning unavailable peer state into a fleet-health verdict.
33+
- **HOST-R07 Catalog liveness is not supervisor liveness:** A catalog remains
34+
live while any canonical agent belonging to it is running, including while
35+
its resident control plane is stopped, restarting, or unavailable.
36+
Supervisor state is reported separately. Its absence may delay convergence
37+
but does not make continuing agents dead, authorize teardown, or erase the
38+
last-applied catalog. DING/sidecar survival alone does not satisfy this
39+
agent-liveness predicate. Under incomplete or partitioned observation,
40+
absence of evidence cannot prove the catalog globally not live.
41+
- **HOST-R08 Stable resolved state roots:** While a catalog is live, or while
42+
its resident supervisor is running, the resolved catalog root and PTY root
43+
remain stable mounted state paths and must not be relocated. Their contents
44+
have different semantics; ordinary catalog edit/sync remains allowed.
45+
Relocation requires the explicit coordinated migration contract in
46+
[issue #85](https://github.com/compoundingtech/st2/issues/85).
47+
48+
Current mechanisms, executable evidence, and unimplemented partition
49+
activation work are mapped in [spec.md](spec.md).

docs/vrs/03-host-local/spec.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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?

docs/vrs/requirements.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ accepted.
105105
- **R17 Durable error propagation:** Lifecycle, harness/eval, provider-turn,
106106
task/exec/PTY, hook, and delivery errors are durably reported to the
107107
responsible supervisor with agent/task identity and actionable context.
108+
108109
- **R19 Targeted reconciliation:** An exact agent/task selector resolves its
109110
identity and pinned host before mutation; unknown, ambiguous, and wrong-host
110111
targets refuse before writes, listing, or actions. Materialization, hook
@@ -122,3 +123,15 @@ accepted.
122123
inspection exposes every Resource binding without interpreting its type or URI.
123124
Resource-only declaration changes do not alter a task's effective launch
124125
definition and do not stop, replace, or relaunch healthy work.
126+
127+
### Must remain safe through host partitions
128+
129+
- **R18 Last-known-good local desired state:** During transport loss, each host
130+
continues converging locally applied work from its last complete, validated
131+
catalog. A missing, partial, or invalid incoming catalog cannot replace that
132+
desired state or authorize teardown.
133+
- **R22 Independent fleet convergence:** Temporary catalog-version skew between
134+
hosts is acceptable. On reconnect, a host may apply only a complete,
135+
validated, newer catalog and then converges its own work independently. Peer
136+
or source reachability is factual state, not a health classification; its
137+
absence affects local work only through an explicit local dependency.

docs/vrs/spec.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,17 @@ validate ──► materialize ──► host-local st2 scheduler/reconciler
167167
lifecycle is the explicit authority to resume ordinary replacement.
168168
`retired #true` remains the separate explicit teardown path.
169169

170+
- **Catalog liveness:** The
171+
[Host-local supervision contract](03-host-local/requirements.md) separates
172+
continuing canonical-agent liveness from resident-supervisor state. A
173+
running canonical agent keeps its catalog live across supervisor downtime;
174+
DING/sidecar-only survival does not. Incomplete observation cannot prove a
175+
catalog globally not live. While the catalog is live, or its supervisor is
176+
running, the resolved catalog root and PTY root remain stable paths; ordinary
177+
catalog edit/sync remains allowed, while relocation requires the coordinated
178+
operation in
179+
[issue #85](https://github.com/compoundingtech/st2/issues/85).
180+
170181
- **Session registry:** A catalog owns the `pty` registry holding its tasks.
171182
`<catalog>/pty` is the default; a catalog may declare another so that one host
172183
can share a single registry across catalogs. Resolution is an exported
@@ -179,6 +190,32 @@ validate ──► materialize ──► host-local st2 scheduler/reconciler
179190
closed instead of hanging reconciliation. The deadline is containment, not
180191
the mechanism for admitting a larger fleet.
181192

193+
## Partition and catalog activation
194+
195+
- **R18:** Transport loss does not invalidate a host's locally applied desired
196+
state. Missing, partial, or invalid incoming catalog state cannot replace the
197+
last complete validated version or cause teardown.
198+
- **R22:** Hosts may temporarily apply different catalog versions and converge
199+
independently. Peer or source absence is neutral unless a declared local
200+
operation explicitly depends on it; reconnect is not itself evidence that a
201+
candidate catalog is complete, valid, or newer.
202+
203+
Current host isolation is source-backed: reconciliation filters declarations
204+
to one selected host
205+
([source](../../src/reconcile.rs#L106-L191)), a host-scoped lock detects an
206+
existing resident writer for the same local subject
207+
([source](../../src/host_lock.rs#L1-L67)), and running tasks survive control
208+
plane loss and adoption
209+
([evidence](../../tests/nomad_survival.rs#L592-L701)).
210+
211+
The durable catalog-activation half of R18/R22 is not implemented. Each pass
212+
currently discovers the live catalog directory directly
213+
([source](../../src/run.rs#L737-L758)); `st2 validate` is separate and
214+
read-only. There is no staged candidate boundary, catalog version ordering,
215+
atomic validated activation, or durable last-known-good receipt. The exact
216+
candidate-completeness, version, and activation-recovery contracts remain open
217+
design work.
218+
182219
## Message lifecycle
183220

184221
```text

0 commit comments

Comments
 (0)