docs(vrs): define the canonical vocabulary and its collisions - #36
docs(vrs): define the canonical vocabulary and its collisions#36schickling-assistant wants to merge 4 commits into
Conversation
st2 had no ontology, so terms were established by whichever document used them first. That is workable while a system is small and stops being workable once several nodes describe the same runtime. This records what each term means, which terms st2 owns rather than inherits from the agent-spec it implements, and — the part with teeth — where one word carries several meanings. The collisions are not hypothetical. `root` has at least six senses, four of them inside these VRS documents: vision.md uses bare "root" for the root agent in a list of actors, while requirements.md uses bare "roots" for host-local scopes in one requirement and watcher scopes in another. `supervisor` names both the control plane and the agent a declaration points at for crash notifications, and both are user-facing. `status` has six senses, `receipt` four, `session` and `spec` three each. The document prescribes usage, not renames. Where a code identifier diverges from the canonical term, the divergence is recorded rather than demanded away. One instance sits in a ratified requirement and is left for the owner. Also records the terms that exist only in prose — including two where the specification and the implementation simply use different words, and one that names intent with nothing built behind it. agent-session-id: e5217740-eef6-48eb-a794-3e5e11939e4d agent-tool: Claude Code agent-tool-version: 2.1.220 agent-model: claude-opus-5 agent-runtime-profile: /nix/store/i8y8b542cyqi385ywcjw5fvsq24f75v4-coding-agent-runtime-profile/share/coding-agents/profile.json agent-skills-manifest: /nix/store/i81qxhzlrzcxrrdwpp6i8hagka2gby8y-agent-skills-corpus/share/agent-skills/manifest.json tooling-profile: dotfiles@unknown-dirty
A full survey against the tree corrected several entries and added four that reading the docs alone would not have found. `keep` has a third sense, and it is the one that misleads: the runtime forces the tag on for tasks named `agent` or `ding`, so an operator who authors the pin as false on a ding still gets it. The authored word does not describe the resulting behaviour. `agent` names both the declared entity and a task literally called `agent`, which the runtime special-cases by string comparison — so a declaration named `mix` has an agent task whose id is `<host>.mix`. `status` gained the session-lifecycle sense the terminal tool reports, and the bus-root entry now records that it is normally equal to the catalog root: two names for one path that can still diverge, which is worse than two names for two paths. DING is mid-rename to ping. The command answers to both, while the authored keyword, the derived task name matched as a literal, and the wire prefix still say ding. Recorded as a term in transition rather than settled either way — the direction is the maintainer's to confirm. Adds a section for keywords the parser accepts and the runtime ignores. Dropping unknown keys is deliberate, but the effect is that `harness`, `model`, `persona` and others read as configuration and bind nothing — and `harness` and `persona` do bind as generator flags, so the same word is effective in one surface and inert in another. `live` is downgraded to editorial: the implementation already separates `alive` for processes from `live` for the lock. agent-session-id: e5217740-eef6-48eb-a794-3e5e11939e4d agent-tool: Claude Code agent-tool-version: 2.1.220 agent-model: claude-opus-5 agent-runtime-profile: /nix/store/i8y8b542cyqi385ywcjw5fvsq24f75v4-coding-agent-runtime-profile/share/coding-agents/profile.json agent-skills-manifest: /nix/store/i81qxhzlrzcxrrdwpp6i8hagka2gby8y-agent-skills-corpus/share/agent-skills/manifest.json tooling-profile: dotfiles@unknown-dirty
The earlier prescription for the ambiguous requirement was the weak reading. Taking "host-local roots" as a catalog directory says a directory owns reconciliation, which is not a thing a directory does; taking it as root agents contradicts the neighbouring requirement, which gives reconciliation to the deterministic reconciler and observation to the root agent. The only coherent reading is a third, informal sense — the host-local st2 instance — defined nowhere. The spec does not settle it: its gloss of that requirement drops the word entirely. Two terms are undefined rather than unimplemented, which is worse, because both are load-bearing where they appear. "Lifecycle owner" is named once as the subject of a rule about removing exit evidence, and nothing says who it is — while "lifecycle" qualifies two other nouns that are pinned, so the third use reads as established. `face607` is a bare codename in three places standing for a delivery delay and a reaping rule, resolvable nowhere in this repository, and cited as the justification for both. Adds `generation` as a homograph: a reused session id's incarnation and a rotated log file, both bounded-retention concepts in lifecycle code a few files apart. Records `job` as a synonym for `agent` rather than a second concept, and names the scheduler analogy as the origin of both that synonym and the `task` homograph. Also states what the federation seam does not establish: the direction of deference to the agent-spec is documented in both directions, but which words that document defines cannot be settled from this repository, since it is not vendored here. agent-session-id: e5217740-eef6-48eb-a794-3e5e11939e4d agent-tool: Claude Code agent-tool-version: 2.1.220 agent-model: claude-opus-5 agent-runtime-profile: /nix/store/i8y8b542cyqi385ywcjw5fvsq24f75v4-coding-agent-runtime-profile/share/coding-agents/profile.json agent-skills-manifest: /nix/store/i81qxhzlrzcxrrdwpp6i8hagka2gby8y-agent-skills-corpus/share/agent-skills/manifest.json tooling-profile: dotfiles@unknown-dirty
The ontology being added in #36 records `root` as the worst homograph in the system — six senses, four of them inside these VRS documents — and prescribes never writing it bare. This file, which the same series added, used it bare twice in one sentence. The referent here is the root VRS documents, which is the one sense the ontology does not enumerate as a directory, so the bare word invited exactly the wrong reading. agent-session-id: e5217740-eef6-48eb-a794-3e5e11939e4d agent-tool: Claude Code agent-tool-version: 2.1.220 agent-model: claude-opus-5 agent-runtime-profile: /nix/store/i8y8b542cyqi385ywcjw5fvsq24f75v4-coding-agent-runtime-profile/share/coding-agents/profile.json agent-skills-manifest: /nix/store/i81qxhzlrzcxrrdwpp6i8hagka2gby8y-agent-skills-corpus/share/agent-skills/manifest.json tooling-profile: dotfiles@unknown-dirty
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8722aa71c4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| run. | ||
| - **Eval** — an executable run of an agent spec, used as evidence that a | ||
| declaration behaves as claimed. | ||
| - **Judge** — one assertion over an eval's outcome. All judges must pass. |
There was a problem hiding this comment.
Exclude signal judges from the all-must-pass definition
When an eval declares a signal judge, that judge is intentionally shown in the report but excluded from the score and verdict; a failing signal judge can coexist with a passing eval, and an eval containing only signal judges does not pass. Defining all judges as gating therefore gives readers the wrong interpretation of experiment results; distinguish gating judges from signal judges here.
Useful? React with 👍 / 👎.
| analogy the declaration is built on: the agent *is* the job, and its tasks are | ||
| what run. Both words are in use. Prefer **agent**, and read *job* as pointing | ||
| at the analogy rather than at a second concept. | ||
| - **Identity** — an agent's bare name, unique within the fleet. |
There was a problem hiding this comment.
Do not promise fleet-wide identity uniqueness
In a multi-host catalog, two declarations may currently share a bare identity because validation detects duplicate <host>.<identity> bus IDs rather than duplicate bare names. Bare recipient resolution then selects the first matching identity, so this definition incorrectly makes such addressing appear unambiguous and can conceal delivery to the wrong declaration. Scope uniqueness to the host/bus ID, or enforce fleet-wide uniqueness before documenting it.
Useful? React with 👍 / 👎.
| **DING is a pipeline, and its stage names are the vocabulary.** Each stage is a | ||
| distinct term because each is a distinct state a payload can be stuck in: | ||
|
|
||
| ```text | ||
| message → notice → staged → observed → submitted |
There was a problem hiding this comment.
Preserve the safety observations in the DING pipeline
For maintained harnesses, a fresh DING attempt first observes an empty safe composer before pasting, then requires two exact post-paste observations before sending Return. Observation is therefore a repeated guard/action, not a single payload state after staged; this canonical pipeline omits the pre-paste guard and the second confirmation, obscuring the sequencing that prevents DING from altering or submitting a human draft.
Useful? React with 👍 / 👎.
Three subsystems state a fail-closed rule independently and none references the others, so for a safety property the drift risk is the failure mode that matters. Definition and obligation are split along the existing doc-class line: the ontology says what fail-closed means, and each subsystem's requirements say which of its surfaces must be. The obligation stays where it can be argued with; the definition stops being restated. Records the asymmetry that makes the term operationally useful — widening what counts as proven needs evidence, widening what counts as unproven is always safe — and that fail-closed is a property of a mechanism's unknown path, not a wish about it. Names fail-open too, since it is usually reached by removing a check that was accidentally load-bearing rather than by writing a permissive one. agent-session-id: e5217740-eef6-48eb-a794-3e5e11939e4d agent-tool: Claude Code agent-tool-version: 2.1.220 agent-model: claude-opus-5 agent-runtime-profile: /nix/store/i8y8b542cyqi385ywcjw5fvsq24f75v4-coding-agent-runtime-profile/share/coding-agents/profile.json agent-skills-manifest: /nix/store/i81qxhzlrzcxrrdwpp6i8hagka2gby8y-agent-skills-corpus/share/agent-skills/manifest.json tooling-profile: dotfiles@unknown-dirty
|
Closing per stable-main hygiene disposition: documentation scope is preserved on main history; no merge required. |
Adds
docs/vrs/ontology.md. There was none, so terms were established by whichever document used them first.Derived from the code at
51c8254rather than from the docs, so the vocabulary reflects what ships. Every term is pinned to a definition in the tree, and anything that could not be pinned is recorded as prose-only rather than asserted.What it contains
AGENT-SPEC.md, so terms describing what an agent is are inherited, not coined here. st2 owns the terms for running a declared fleet on a host. Domain words from POSIX, the scheduler tradition, and the terminal are borrowed with their established meanings.The collisions
These are not hypothetical, and four of
root's six senses are inside the VRS documents themselves:rootvision.mduses bare root for the root agent in a list of actors;requirements.mduses bare roots for host-local scopes in one requirement and watcher scopes in anotherstatusreceiptsupervisorsession,specidentity,check,keep,service,run,liveidentityis the sharpest: the roster'sidentityfield carries the bus id, not the identityWhat it deliberately does not do
It prescribes usage, not renames. Where a code identifier diverges from the canonical term, the divergence is recorded rather than demanded away. No code changes here.
One instance is left for the owner.
requirements.mduses bare roots in a ratified requirement, where the sentence alone cannot resolve which sense is meant. Changing that file needs explicit approval, so the ontology flags it and states how to read it in the meantime rather than proposing a rewording.Two divergences are recorded, not resolved. The specification says hook bundle where the implementation says hook set; and it requires activity status to be distinct from presence, but no field carries that name — the nearest shipped signal is a last-activity timestamp in the enriched roster. Both are stated so a reader does not conclude that two words name two things, or go looking for something that was never built.
root agentis in the same category: defined in the vision and requirements, with no implementation. It names intent, which is legitimate for a vision — worth knowing when reading the requirement.Gates
axe vrs check --profile strict docs/vrspasses.Sibling nodes are in flight in #27 (
01-ding/) and #32 (02-doctor/); all three touch disjoint paths. One term here — live composer — is introduced by the DING node, and the ontology flags it against the established process-liveness sense of live rather than letting it pass unremarked.Posted on behalf of @schickling
agent_nameagent_session_idagent_toolagent_tool_versionagent_runtimeagent_modelruntime_profileskills_manifestworktreemachinetooling_profile