Skip to content

Commit 6c8f37b

Browse files
docs(vrs): disambiguate the duplicate R27 and ratchet ledger ids
agent-identity: dev3.direct.omp.43sz6ujq agent-persona: generalist agent-supervisor: unavailable agent-tool: OMP agent-tool-version: 18.1.7 agent-runtime: OMP 18.1.7 tooling-profile: dotfiles@39a19af
1 parent 7f3d582 commit 6c8f37b

8 files changed

Lines changed: 148 additions & 19 deletions

docs/vrs/.decisions/0005-streams-are-agent-nested-and-stream-named.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ run natively without a second producer-identity mechanism.
7272
- Issue #49's "topic" remains a message-side axis; the event-side grouping
7373
axis is *key*. The two must not be merged by name.
7474
- Suspension semantics follow locality: the stream task is an owned task, so
75-
R27 tears it down with the agent — eyes closed, no accumulation, resume
75+
R41 tears it down with the agent — eyes closed, no accumulation, resume
7676
re-observes; the dedup ring makes re-emission of still-current state safe.
7777
- Ingress authority follows the same locality: `event emit` runs only when its
7878
resolved logical owner host and catalog lock match the unsynchronized

docs/vrs/.decisions/0016-systemd-scope-wrappers-disable-environment-expansion.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Status: accepted
44

5-
Accepted on 2026-09-05 for R40 launch argv transparency.
5+
Accepted on 2026-09-05 for R42 launch argv transparency.
66

77
## Context
88

docs/vrs/.experiments/2026-08-04-agent-desired-state-prototype.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ and runtime observation.
5555

5656
## VRS Impact
5757

58-
The result adds root R27 and R28, Agent Spec field rule F18, Doctor R07, the
58+
The result adds root R41 and R28, Agent Spec field rule F18, Doctor R07, the
5959
agent desired state/suspension/retirement/rationale ontology, and corresponding
6060
wire and acceptance text. It does not change the vision.
6161

docs/vrs/.experiments/2026-09-05-systemd-scope-argv-transparency.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ Systemd's default command-line expansion is not transparent to caller-owned
4242
argv. Passing `--expand-environment=no` before the command separator is the
4343
narrow correction: it preserves the complete dollar-bearing literal while all
4444
measured scope lifecycle, descriptor, PTY, exit-status, collection, and reuse
45-
semantics remain unchanged. This supports [R40 launch argv transparency](../requirements.md)
45+
semantics remain unchanged. This supports [R42 launch argv transparency](../requirements.md)
4646
and [decision 0016](../.decisions/0016-systemd-scope-wrappers-disable-environment-expansion.md).
4747

4848
## VRS Impact
4949

50-
- `requirements.md` adds R40 launch argv transparency.
50+
- `requirements.md` adds R42 launch argv transparency.
5151
- `ontology.md` defines **launch argv** as the canonical task-wide term.
5252
- `spec.md` fixes the exact systemd scope wrapper order and its deterministic
5353
scope/pass-through tests.

docs/vrs/ontology.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ the launch argv. This is not a shell command line. Use *provider argv* only
7676
when referring specifically to the canonical agent provider; *launch argv*
7777
applies to every PTY and exec task.
7878

79-
Authority: [R06 restartable launch definitions and R40 launch argv
79+
Authority: [R06 restartable launch definitions and R42 launch argv
8080
transparency](requirements.md);
8181
[host-local scheduling and supervision](spec.md#host-local-scheduling-and-supervision)
8282

@@ -463,7 +463,7 @@ Authority: [R31 reachable restart bounds](requirements.md);
463463
The declaration-owned whole-agent lifecycle intent: `running`, `suspended`, or
464464
`retired`. It is distinct from presence and session state.
465465

466-
Authority: [R27 typed agent desired state](requirements.md);
466+
Authority: [R41 typed agent desired state](requirements.md);
467467
[`AgentDesiredState`](../../crates/agent-spec/src/spec.rs)
468468

469469
### suspension
@@ -472,23 +472,23 @@ Reversible desired absence of an agent's live tasks while its declaration and
472472
catalog-backed durable state remain available. Suspension is not process pause
473473
or checkpointing.
474474

475-
Authority: [R27 typed agent desired state](requirements.md);
475+
Authority: [R41 typed agent desired state](requirements.md);
476476
[Agent Spec field rules](02-agent-spec/spec.md)
477477

478478
### retirement
479479

480480
Terminal desired absence whose completion additionally requires every declared
481481
task record to be collected. Legacy `retired #true` is a readable spelling.
482482

483-
Authority: [R27 typed agent desired state](requirements.md);
483+
Authority: [R41 typed agent desired state](requirements.md);
484484
[Doctor retired absence](02-doctor/requirements.md)
485485

486486
### desired-state rationale
487487

488488
The bounded human explanation required by a new suspended or retired desired
489489
state. It explains intent and grants no lifecycle authority of its own.
490490

491-
Authority: [R27 typed agent desired state](requirements.md)
491+
Authority: [R41 typed agent desired state](requirements.md)
492492

493493
### reconciliation
494494

docs/vrs/requirements.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ accepted.
126126
- **R06 Restartable launch definitions:** A restarted PTY or exec receives the
127127
complete effective launch definition, including environment and supported
128128
launch fields.
129-
- **R40 Launch argv transparency:** Every st2-added launch wrapper preserves the
129+
- **R42 Launch argv transparency:** Every st2-added launch wrapper preserves the
130130
effective task program and each argument as ordered, opaque OS strings. A
131131
Linux systemd scope launch disables systemd command-line environment
132132
expansion before the wrapper separator, so dollar-bearing literals including
@@ -411,7 +411,7 @@ accepted.
411411
the only source of address, name, and description; an explicit ID roster
412412
query returns the subject's current address and presentation without
413413
publishing a duplicate Agent Spec state file.
414-
- **R27 Typed agent desired state:** Every admitted Agent Spec has exactly one
414+
- **R41 Typed agent desired state:** Every admitted Agent Spec has exactly one
415415
whole-agent desired state: `running`, `suspended`, or `retired`. Omission and
416416
legacy `retired #false` mean running; legacy `retired #true` means retired
417417
without a rationale. New suspended and retired declarations require one

docs/vrs/spec.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ delivers messages. The agent grammar and harness-facing contract remain
1616
canonical in
1717
[`compoundingtech/evals/AGENT-SPEC.md`](https://github.com/compoundingtech/evals/blob/main/AGENT-SPEC.md).
1818

19+
## Decision citations
20+
21+
Decision records are cited by their full filename stem, `NNNN-<slug>`. Bare
22+
numbers are ambiguous for 0005, 0007, 0014, and 0015; their collisions are
23+
recorded history, and numbers are never reused under
24+
[`0006-observed-harness-state-is-a-driver-written-catalog-record`](.decisions/0006-observed-harness-state-is-a-driver-written-catalog-record.md).
25+
1926
## Canonical Agent Spec eval teams
2027

2128
An eval may opt into `canonical-agents` after its fixture copy and deterministic
@@ -67,7 +74,7 @@ implemented: the grammar, host-local address uniqueness, `st2 agent address`,
6774
and the fail-closed bare-or-qualified reference resolution. Its immutable-ID half
6875
is not: no writer emits `id`, so the positional `<host>.<identity>` bus identity
6976
remains the durable key every ownership, task-identity, and record surface uses.
70-
[0015 Amendment 1](.decisions/0015-immutable-agent-id-and-mutable-address.md)
77+
[`0015-immutable-agent-id-and-mutable-address` Amendment 1](.decisions/0015-immutable-agent-id-and-mutable-address.md)
7178
stages that half behind named triggers and
7279
[DELTA-003](.delta/DELTA-003-agent-address-not-implemented.md) records what it
7380
still requires.
@@ -285,7 +292,7 @@ its own durable waits. st2 provides no wait loop or timer and does not turn the
285292
request into agent lifecycle authority.
286293

287294
This transport is design-superseded but still normative for the shipped
288-
implementation: [decision 0004](.decisions/0004-stream-events-are-a-distinct-record-kind.md)
295+
implementation: [`0004-stream-events-are-a-distinct-record-kind`](.decisions/0004-stream-events-are-a-distinct-record-kind.md)
289296
absorbs typed requests into stream events plus ordinary replies, staged behind
290297
a deprecation window ([04-stream DQ-S4](04-stream/open-questions.md)). Until
291298
that staging completes, this section and its invariant row remain the truth;
@@ -777,7 +784,7 @@ validate ──► materialize ──► host-local st2 scheduler/reconciler
777784
manual PTY restart under a different ambient environment reconstructs the
778785
same effective color policy. Adoption of an already-live task remains
779786
non-mutating: this policy is applied only when st2 creates a generation.
780-
- **R40:** [Launch argv](ontology.md#launch-argv) is opaque at every
787+
- **R42:** [Launch argv](ontology.md#launch-argv) is opaque at every
781788
st2-added wrapper boundary. In Linux systemd scope mode the exact outer
782789
command order is:
783790

@@ -798,7 +805,7 @@ validate ──► materialize ──► host-local st2 scheduler/reconciler
798805
proves both pass-through modes. The live-system distinction and unaffected
799806
scope semantics are recorded in the
800807
[systemd scope argv experiment](.experiments/2026-09-05-systemd-scope-argv-transparency.md)
801-
and [decision 0016](.decisions/0016-systemd-scope-wrappers-disable-environment-expansion.md).
808+
and [`0016-systemd-scope-wrappers-disable-environment-expansion`](.decisions/0016-systemd-scope-wrappers-disable-environment-expansion.md).
802809
- **R07:** Hook bundles are explicit, content-addressed, installed separately,
803810
and verified before materialization references them. Their receipts use the
804811
same resolved build identity as the binary's version surfaces for both
@@ -911,7 +918,7 @@ validate ──► materialize ──► host-local st2 scheduler/reconciler
911918
only the marker channel owned by the exact canonical catalog folder and host
912919
it is observing.
913920

914-
- **R27/R28:** Agent lifecycle intent is one closed declaration state:
921+
- **R41/R28:** Agent lifecycle intent is one closed declaration state:
915922
`running`, `suspended`, or `retired`. The KDL form is a direct child such as
916923
`desired-state "suspended" reason="Waiting for capacity"`. Omission means
917924
running. New suspended and retired states require a bounded rationale;
@@ -987,7 +994,7 @@ parses structured output that must be whole, so it uses the explicitly named
987994
full-stdout variant; that read is intentionally uncapped and visible at its
988995
call site. Eval run steps and agent log dumps stream child output straight to
989996
their catalog log files without buffering it. Rationale and rejected
990-
alternatives: [decision 0007](.decisions/0007-child-output-capture-is-bounded-and-tail-preserving.md).
997+
alternatives: [`0007-child-output-capture-is-bounded-and-tail-preserving`](.decisions/0007-child-output-capture-is-bounded-and-tail-preserving.md).
991998

992999
## Catalog graph and native delivery admission (R35–R38)
9931000

@@ -1385,7 +1392,7 @@ The measured basis for this design, including the runs that fixed `steer` and
13851392
the modal case, is recorded in
13861393
[2026-08-18-pi-harness-integration](./.experiments/2026-08-18-pi-harness-integration.md);
13871394
the ruling is
1388-
[decision 0005](./.decisions/0005-pi-delivers-natively-through-an-injected-extension.md).
1395+
[`0005-pi-delivers-natively-through-an-injected-extension`](./.decisions/0005-pi-delivers-natively-through-an-injected-extension.md).
13891396

13901397
## Event contracts (R13–R15, R40)
13911398

tests/vrs_ledger.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
use std::collections::{BTreeMap, BTreeSet};
2+
use std::fs;
3+
use std::path::Path;
4+
5+
#[test]
6+
fn root_requirement_ids_are_unique() {
7+
let requirements = include_str!("../docs/vrs/requirements.md");
8+
let mut seen = BTreeSet::new();
9+
10+
for line in requirements.lines() {
11+
let Some(rest) = line.strip_prefix("- **R") else {
12+
continue;
13+
};
14+
let digits = rest.bytes().take_while(u8::is_ascii_digit).count();
15+
if digits == 0 || !rest[digits..].starts_with(' ') {
16+
continue;
17+
}
18+
let number = rest[..digits]
19+
.parse::<u32>()
20+
.expect("requirement ID digits must parse");
21+
assert!(
22+
seen.insert(number),
23+
"duplicate root requirement ID R{number}"
24+
);
25+
}
26+
}
27+
28+
#[test]
29+
fn root_decision_number_duplicates_match_recorded_history() {
30+
let decision_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("docs/vrs/.decisions");
31+
let mut by_number = BTreeMap::<String, BTreeSet<String>>::new();
32+
33+
for entry in fs::read_dir(decision_dir).expect("root decision directory must be readable") {
34+
let path = entry.expect("decision entry must be readable").path();
35+
let Some(stem) = path.file_stem().and_then(|stem| stem.to_str()) else {
36+
continue;
37+
};
38+
let Some((number, _)) = stem.split_once('-') else {
39+
continue;
40+
};
41+
if number.len() == 4 && number.bytes().all(|byte| byte.is_ascii_digit()) {
42+
by_number
43+
.entry(number.to_owned())
44+
.or_default()
45+
.insert(stem.to_owned());
46+
}
47+
}
48+
49+
let duplicates = by_number
50+
.into_iter()
51+
.filter(|(_, stems)| stems.len() > 1)
52+
.collect::<BTreeMap<_, _>>();
53+
let expected = [
54+
(
55+
"0005",
56+
[
57+
"0005-pi-delivers-natively-through-an-injected-extension",
58+
"0005-streams-are-agent-nested-and-stream-named",
59+
]
60+
.as_slice(),
61+
),
62+
(
63+
"0007",
64+
[
65+
"0007-child-output-capture-is-bounded-and-tail-preserving",
66+
"0007-omp-is-a-fifth-native-driver-with-its-own-channel-and-a-hard-version-gate",
67+
]
68+
.as_slice(),
69+
),
70+
(
71+
"0014",
72+
[
73+
"0014-harness-context-is-a-sibling-numeric-record",
74+
"0014-resource-profiles-are-state-first-read-and-observe-capabilities",
75+
]
76+
.as_slice(),
77+
),
78+
(
79+
"0015",
80+
[
81+
"0015-catalog-commits-and-direct-edits-use-independent-wake-channels",
82+
"0015-immutable-agent-id-and-mutable-address",
83+
]
84+
.as_slice(),
85+
),
86+
]
87+
.into_iter()
88+
.map(|(number, stems)| {
89+
(
90+
number.to_owned(),
91+
stems.iter().map(|stem| (*stem).to_owned()).collect(),
92+
)
93+
})
94+
.collect::<BTreeMap<_, _>>();
95+
96+
assert_eq!(duplicates, expected);
97+
}
98+
99+
#[test]
100+
fn root_delta_ids_are_unique() {
101+
let delta_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("docs/vrs/.delta");
102+
let mut seen = BTreeSet::new();
103+
104+
for entry in fs::read_dir(delta_dir).expect("root delta directory must be readable") {
105+
let path = entry.expect("delta entry must be readable").path();
106+
let Some(stem) = path.file_stem().and_then(|stem| stem.to_str()) else {
107+
continue;
108+
};
109+
let Some(rest) = stem.strip_prefix("DELTA-") else {
110+
continue;
111+
};
112+
let Some((number, _)) = rest.split_once('-') else {
113+
continue;
114+
};
115+
if number.len() == 3 && number.bytes().all(|byte| byte.is_ascii_digit()) {
116+
assert!(
117+
seen.insert(number.to_owned()),
118+
"duplicate root delta ID DELTA-{number}"
119+
);
120+
}
121+
}
122+
}

0 commit comments

Comments
 (0)