Skip to content

Commit bc8483a

Browse files
committed
docs(vrs): compact Agent Spec field conformance
1 parent 2128945 commit bc8483a

2 files changed

Lines changed: 364 additions & 508 deletions

File tree

Lines changed: 83 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -1,205 +1,97 @@
1-
# Agent Spec field-change requirements
1+
# st2 Agent Spec field-change conformance requirements
22

3-
## Technical terms
3+
## Context
44

5-
- A **VRS node** is one part of the st2 requirements and specification.
6-
- A **normalized Agent Spec** is the result after st2 parses a declaration and
7-
applies default values.
8-
- A **core field** is an Agent Spec field that core st2 uses.
9-
- **Lower** means change a field into one or more core fields.
10-
- A **semantic projection** is the set of effects from a normalized Agent Spec.
11-
- A **render plan** lists the final files and bytes that st2 must write.
12-
- A **catalog** is the set of Agent Spec declarations that st2 reads.
13-
- **Runtime state** contains the local processes, files, and ownership records.
14-
- A **local component** is a group of agents that share an owner, a rendered
15-
file, or another conflict.
16-
- An **incarnation** is one live generation of a task.
17-
- **Attribution** is proof that binds an object to its exact catalog, host,
18-
owner, task ID, and incarnation.
19-
- A **launch fingerprint** identifies all inputs that start one version of a
20-
task.
21-
- A **host projection** is the set of declarations that one host selects.
22-
- **Catalog skew** occurs when two hosts have different catalog versions.
23-
- A **host migration** is a coordinated move of a process between hosts.
24-
- **Last-known-good state (LKG)** is the latest local state for which st2 proved
25-
ownership.
26-
- A **survivor** is a healthy incarnation that st2 does not replace.
27-
- A **fence** prevents st2 from starting an ID while st2 changes that ID.
28-
- **Quiesce** means stop an incarnation and release its ports, locks, and
29-
ownership.
30-
- A **rollback** restores the state that existed before a failed change.
31-
- A **snapshot** is the complete catalog and runtime input for one st2 pass.
32-
- A **Resource** is a typed binding in an Agent Spec declaration.
33-
- A **provider** changes provider fields into concrete core fields.
34-
- A **materializer** is the st2 component that writes desired files.
35-
- A **sidecar** is a support task that st2 creates from compact syntax.
36-
- A **parser** reads a catalog declaration and creates a normalized Agent Spec.
37-
- A **watcher** detects a catalog file change.
38-
- A **reconcile pass** compares desired state with actual state and then applies
39-
allowed changes.
40-
- A **reconciler** runs a reconcile pass.
41-
- An **executor** applies planned actions.
42-
- **Replacement authority** is explicit permission to replace one exact
43-
incarnation.
44-
- A **destructive action** removes a file or stops, retires, or replaces work.
45-
- **DING** is a best-effort delivery attempt.
46-
It tells an agent to read its inbox.
47-
st2 does not guarantee delivery.
48-
A configured adapter can use terminal input or a post-turn hook.
49-
This contract does not require terminal input or harness-specific behavior.
50-
- A **PTY task** is an interactive terminal task.
51-
- An **exec task** is a non-interactive task.
52-
- The **CLI** is the st2 command-line interface.
53-
- **KDL** is one catalog declaration format.
54-
- An **anchor** is the declaration folder that owns state or Resources.
55-
- An **idempotency ID** identifies one event. A repeated event with this ID has
56-
no additional effect.
57-
- **Moved intent** is a possible future map from one old local address to one
58-
new local address.
59-
- An **address** identifies one Agent Spec object without ambiguity.
60-
- A **no-op** reports that st2 found no normalized change.
61-
- A **hold** waits and makes no requested lifecycle change.
62-
- A **refusal** makes no change because validation or proof failed.
63-
- **Drifted** reports that a launch fingerprint differs.
64-
- **Unknown** reports that st2 cannot prove actual state.
65-
- **Materialize** means write the final desired files.
66-
- **Compare-and-swap (CAS)** is a write rule. The write succeeds only when the
67-
current value equals an expected value.
5+
The canonical Agent Spec and its proof corpus live in
6+
[compoundingtech/evals at commit `b3cd5fbd98c11179a4555d0f9bbccfe98351a734`](https://github.com/compoundingtech/evals/blob/b3cd5fbd98c11179a4555d0f9bbccfe98351a734/AGENT-SPEC.md).
7+
st2 is one implementation. Another implementation, including a future st3, can
8+
target the same contract and proofs.
689

69-
## Context
10+
This sub-VRS defines desired st2 conformance when a normalized Agent Spec
11+
changes work on one host. It records st2-specific gaps; it does not own or copy
12+
the Agent Spec. General field-change behavior that the canonical specification
13+
does not yet define is proposed until a matching evals specification and proof
14+
change adopts it.
15+
16+
This work supports root [R01, R06, R11, and R13 through R19](../requirements.md).
17+
It applies to every st2 tool that runs an agent or test. A valid local catalog
18+
and host-local runtime state are sufficient. It requires no compare-and-swap
19+
(CAS), lock service, cross-host call, or external registry.
20+
21+
[spec.md](./spec.md) defines the proposed field-change rules and current st2
22+
implementation gaps. The root st2 VRS has authority for st2 behavior; the
23+
canonical evals Agent Spec remains the authoring authority.
7024

71-
This VRS node defines how normalized Agent Spec changes affect work on one
72-
host.
73-
It supports root
74-
[R01, R06, R11, and R13 through R19](../requirements.md).
75-
The same contract applies to all tools that run an agent or test.
76-
A valid local catalog and host-local runtime state provide all required input.
77-
The contract does not require CAS, a lock service, a cross-host call, or an
78-
external registry.
79-
[spec.md](./spec.md) lists all field rules and current gaps.
80-
If this node conflicts with the root VRS, the root VRS has authority.
25+
Field lookup: [F01](./spec.md#f01), [F02](./spec.md#f02),
26+
[F03](./spec.md#f03), [F04](./spec.md#f04), [F05](./spec.md#f05),
27+
[F06](./spec.md#f06), [F07](./spec.md#f07), [F08](./spec.md#f08),
28+
[F09](./spec.md#f09), [F10](./spec.md#f10), [F11](./spec.md#f11),
29+
[F12](./spec.md#f12), [F13](./spec.md#f13), [F14](./spec.md#f14),
30+
[F15](./spec.md#f15), and [F16](./spec.md#f16).
8131

82-
## Normative requirements
32+
## Shared invariants
8333

84-
- **SPEC-R01 Normalize and classify before an action.** st2 must compare
85-
normalized effects before it acts.
86-
- st2 must compare the normalized semantic projection.
87-
- st2 must compare the render plan and all resolved addresses and paths.
88-
- st2 must compare the task set and each launch fingerprint.
89-
- st2 must compare policy, retirement state, and host membership.
90-
- st2 must not use source bytes as the only comparison.
91-
- st2 can report `no-op` for format, order, comment, or source-path changes
92-
only when all normalized effects match.
93-
- A source `no-op` must not authorize a write.
94-
- A source `no-op` must not authorize a notification.
95-
- A source `no-op` must not prevent st2 from healing independently absent or
96-
dead work.
97-
- Provider fields do not create a core change until a provider lowers them
98-
into core fields.
34+
- **SPEC-R01 Normalize and classify before action.** Compare the normalized
35+
effects, not source bytes alone. The comparison includes the render plan,
36+
resolved addresses and paths, task set, launch fingerprints, policy,
37+
retirement state, and host membership. Formatting, order, comments, or a
38+
source path change are `no-op` only when every normalized effect is equal.
39+
A source-only `no-op` authorizes no write or notification. It does not block
40+
healing of independently absent or dead work. A provider field has no core
41+
effect until a provider lowers it into core fields.
9942

100-
- **SPEC-R02 Stop changes when local proof is incomplete.** st2 must divide
101-
local work into local components.
102-
- Before st2 changes a component, it must validate all input for that
103-
component.
104-
- st2 must prove the current owner of each affected process and file.
105-
- If st2 cannot complete this proof, it must not change that component.
106-
- st2 can change an independent component when proof for that component is
107-
complete.
108-
- If input is partial or unreadable, st2 must keep LKG ownership.
109-
- If input is ambiguous or conflicting, st2 must keep LKG ownership.
110-
- Incomplete input must not prove that st2 can remove an ID.
111-
- Removal proof must bind the catalog, host, owner, task ID, and current
112-
incarnation.
113-
- st2 must put work from an earlier version in `hold` when it has no
114-
attribution.
115-
- st2 must put other unattributed work in `hold`.
116-
- st2 must not require a previous synchronized snapshot.
117-
- st2 must not require a deletion record.
118-
- st2 must not require CAS.
43+
- **SPEC-R02 Fail closed at the smallest unproven local scope.** Before a
44+
change, validate the complete local owner, render dependency, and conflict
45+
component. Prove the current owner of each affected process and file. Partial,
46+
unreadable, ambiguous, or conflicting input retains the latest locally proved
47+
ownership. It never proves removal. Destructive action requires proof that
48+
binds the exact catalog, host, owner, task ID, and live incarnation (one task
49+
generation). Work without this proof stays in `hold`. Independent proved
50+
components can proceed. No prior synchronized snapshot, deletion record, or
51+
CAS is required.
11952

120-
- **SPEC-R03 Preserve live work unless an explicit action changes it.** A role
121-
change must not change a healthy task.
122-
- A future `keep`, restart, or `lifecycle` policy must not change a healthy
123-
task.
124-
- The agent `workspace` field supplies live context.
125-
- If a workspace change is visible to a survivor, st2 must notify that
126-
survivor.
127-
- If an incarnation is absent or dead, st2 must boot it with the latest
128-
workspace.
129-
- A boot for an absent or dead incarnation must not send this notification.
130-
- st2 must write changed render or Resource state only when the desired bytes
131-
differ.
132-
- If a changed render or Resource is visible to a survivor, st2 must notify
133-
that survivor.
134-
- F11 spawn inputs must form the launch fingerprint.
135-
- If a healthy launch fingerprint differs, st2 must report `drifted` or
136-
`unknown`.
137-
- A fingerprint difference must not authorize replacement.
138-
- Unrelated work must receive no action.
53+
- **SPEC-R03 Preserve live work unless the field rule changes it.** Metadata,
54+
live context, render data, Resource data, and future policy do not restart a
55+
healthy task. A changed workspace, render target, or Resource that is visible
56+
to a surviving task causes one post-commit notification. Absent or dead work
57+
boots with the latest desired data and gets no change notification. All spawn
58+
inputs form a versioned launch fingerprint. A healthy fingerprint mismatch is
59+
visible as `drifted` or `unknown`, but it does not authorize replacement.
60+
Unrelated work receives no action.
13961

140-
- **SPEC-R04 Change membership and lifecycle only for exact IDs.** st2 must add
141-
only missing IDs.
142-
- st2 must remove only old IDs with exact attribution.
143-
- Retirement must stop the declared set.
144-
- Retirement must prevent a new launch.
145-
- An identity change must remove the old ID.
146-
- An identity change must add the new ID.
147-
- A task name or task ID change must remove the old ID.
148-
- A task name or task ID change must add the new ID.
149-
- st2 must not infer a rename from these changes.
150-
- Moved intent is provisional.
151-
- st2 does not support moved intent.
152-
- Moved intent is limited to one host.
153-
- The agent `host` field defines host projection membership.
154-
- A `host` change is not a migration.
155-
- The old host must remove its local member after a complete
156-
present-to-absent change.
157-
- The new host must add its local member after a complete
158-
absent-to-present change.
159-
- The two hosts must not require a shared transition, order, receipt, or
160-
proof.
161-
- Catalog skew can cause a temporary overlap or absence.
162-
- During catalog skew, each host must use its local LKG state.
62+
- **SPEC-R04 Change membership and lifecycle only for exact IDs.** Add only a
63+
missing ID. Remove only an exactly attributed old ID. Retirement stops the
64+
declared set and prevents relaunch. An identity, task name, or task ID change
65+
is remove-old then add-new, not an inferred rename. Each host acts only on its
66+
local projection. A host change is independent removal on the old host and
67+
addition on the new host, never process migration. The hosts require no shared
68+
order, receipt, or proof. Catalog skew can cause temporary overlap or absence;
69+
each host retains its local last-known-good ownership.
16370

164-
- **SPEC-R05 Plan and run each local component in phases.** st2 must plan all
165-
actions and refusals before it changes a component.
166-
- The plan must include all proof, conflicts, and rollback conditions.
167-
- st2 must use this order: `FENCE`, `REMOVE/QUIESCE`, `MATERIALIZE`,
168-
`ADD/BOOT`, `NOTIFY`, and `VERIFY/REPORT`.
169-
- st2 must omit an empty phase.
170-
- If an add conflicts with an old incarnation, st2 must first prove that the
171-
old incarnation is quiescent.
172-
- A conflicting add must use the final desired bytes.
173-
- A deletion must have explicit desired state.
174-
- A deletion must have ownership proof.
175-
- A deletion must not remove a source declaration from the catalog.
176-
- If st2 proves a rollback, it can use that rollback after a failure.
177-
- If st2 cannot prove a rollback, it must `hold` or `refuse` before a
178-
dependent phase.
179-
- An independent component must not wait for another component.
180-
- A `drifted` incarnation needs explicit replacement authority.
71+
- **SPEC-R05 Plan and execute each local component in phases.** Plan every
72+
action, refusal, proof, conflict, and rollback condition before mutation. Use
73+
`FENCE`, `REMOVE/QUIESCE`, `MATERIALIZE`, `ADD/BOOT`, `NOTIFY`, then
74+
`VERIFY/REPORT`, and omit empty phases. Fence and remove an exact conflicting
75+
old incarnation before an add. Use final desired bytes for the add. A deletion
76+
requires explicit desired state and ownership proof, and never removes a
77+
catalog source declaration. Roll back only when rollback is proved; otherwise
78+
hold or refuse before a dependent phase. Explicit replacement authority is
79+
required for a drifted live incarnation.
18180

182-
- **SPEC-R06 Send one quiet event after a commit.** This rule applies when a
183-
committed workspace, render, or Resource change is visible to a survivor.
184-
- st2 must write one durable inbox event.
185-
- st2 must combine related changes into this one event.
186-
- After st2 writes the event, it must try DING.
187-
- The event must contain a stable idempotency ID.
188-
- The event must contain the agent, host, changed path, and change class.
189-
- A workspace event can contain the old path and the new path.
190-
- The event must not contain file contents or secrets.
191-
- A DING failure must not remove the event.
192-
- A DING failure must not roll back the commit.
193-
- st2 must not send an event for `no-op` or unchanged work.
194-
- st2 must not send an event for a failed or rolled-back change.
195-
- st2 must not send an event for a periodic pass.
196-
- st2 must not send an event for new, replaced, or retired work.
197-
- A notification must not cause a restart.
198-
- A notification must not cause another notification.
81+
- **SPEC-R06 Send one quiet event after commit.** When a committed workspace,
82+
render, or Resource change is visible to a survivor, write one coalesced
83+
durable inbox event and then try DING. DING is best-effort delivery through the
84+
configured adapter; this contract requires no terminal input or harness
85+
behavior. The event has a stable ID, and repeating that ID has no additional
86+
effect. It identifies the agent, host, changed path, and change class, but
87+
contains no file contents or secrets. Delivery failure does not remove the
88+
event or roll back the commit. Do not notify for unchanged, failed,
89+
rolled-back, periodic, new, replaced, or retired work. A notification cannot
90+
restart work or cause another notification.
19991

20092
## Evidence boundary
20193

202-
After approval, an external test matrix must test every
203-
[field rule and acceptance case](./spec.md).
204-
The matrix must use public CLI behavior and isolated PTY and exec state.
205-
Unit tests alone do not prove this contract.
94+
After approval, an external matrix must prove every
95+
[field rule](./spec.md#field-rules) and
96+
[acceptance case](./spec.md#acceptance-cases) through public CLI behavior and
97+
isolated PTY and exec state. Unit tests alone do not prove this contract.

0 commit comments

Comments
 (0)