Skip to main content

supercode_harness/
parity.rs

1//! Behavior-parity ledger: the product's own gap count, for the `cc-parity`
2//! and `cx-parity` presets and for the orchestration harnesses.
3//!
4//! Two embedded ledgers, one report shape:
5//!
6//! * `parity/ledger.json` — one row per capability in
7//!   `docs/composable-harness/CAPABILITY-CATALOG.md` (263 rows, ids derived
8//!   from the capability name), columns `cc` / `cx`.
9//! * `parity/orchestration.json` — one row per (orchestration concept × verb
10//!   group) from `docs/composable-harness/inventory/orchestration.md`,
11//!   columns `hermes` / `openclaw`.
12//!
13//! Each row records which harness has the capability and supercode's audited
14//! status, with EVIDENCE that the test suite resolves mechanically against
15//! the real preset resolver, module registry, tool registry, runtime
16//! backends, the committed harness `--help` fixtures and the source tree —
17//! an "implemented" claim that cites nothing checkable does not parse as
18//! implemented. The ledger is the denominator for the parity program:
19//! `supercode harness parity --preset cc-parity|cx-parity|hermes|openclaw`
20//! prints the headline count, and only zero is done.
21//!
22//! The embedded JSON is the single source; the catalog's "supercode today"
23//! column is a snapshot of the survey and is NOT consulted at runtime.
24
25use std::collections::BTreeMap;
26use std::path::Path;
27
28use serde::{Deserialize, Serialize};
29
30use crate::configfile::{resolve, ResolveOptions, Resolved};
31use crate::presets;
32use crate::runtime::{RuntimeBackend, RuntimeCapabilities};
33use crate::tools::ToolRegistry;
34
35/// Raw ledger rows, embedded at build time.
36pub const LEDGER_JSON: &str = include_str!("parity/ledger.json");
37
38/// Raw orchestration ledger rows, embedded at build time.
39pub const ORCHESTRATION_JSON: &str = include_str!("parity/orchestration.json");
40
41/// Presets the ledger reports on, keyed by the catalog column they mirror.
42pub const PARITY_PRESETS: &[(&str, &str)] = &[("cc", "cc-parity"), ("cx", "cx-parity")];
43
44/// Orchestration harnesses the orchestration ledger reports on. The preset
45/// name IS the column name (there is no `*-parity` config preset behind
46/// these: supercode does not emulate a gateway, it reports on one).
47pub const ORCHESTRATION_PRESETS: &[&str] = &["hermes", "openclaw"];
48
49/// ORC-7: supercode's OWN orchestrator, graded on the same 17 rows through
50/// its own column.
51///
52/// It is not one of [`ORCHESTRATION_PRESETS`]: those are external harnesses
53/// whose columns cite a verb their PINNED CLI advertises, checked against a
54/// committed `--help` fixture. The orchestrator has no such CLI — it is a
55/// package in this workspace — so its column is graded like a supercode
56/// status, from `store` and `code` citations that resolve here.
57///
58/// Its denominator is the WHOLE ledger: every concept is one the
59/// orchestrator's own model either has or deliberately does not
60/// (`docs/ORCHESTRATOR-IR.md` §2), so a row it lacks is reported as
61/// `not_applicable` rather than dropped from the count.
62pub const ORCHESTRATOR_PRESET: &str = "orchestrator";
63
64/// `hermes --help` capture for the pinned version (see the fixture header).
65const HERMES_HELP_FIXTURE: &str = include_str!("parity/fixtures/hermes-help.txt");
66
67/// `openclaw --help` capture for the pinned version (see the fixture header).
68const OPENCLAW_HELP_FIXTURE: &str = include_str!("parity/fixtures/openclaw-help.txt");
69
70/// Workspace directories searched for a loader that opens a harness store.
71const STORE_SEARCH_ROOTS: &[&str] = &["crates/interchange/src", "crates/harness/src"];
72
73/// Call forms that count as "a loader opens this": a SQL read, a file open,
74/// or a path join. A bare mention (comment, doc-comment, error string) does
75/// not resolve a [`Evidence::Store`] citation.
76const STORE_OPEN_CALLS: &[&str] = &["SELECT", "open(", "open_with_flags(", ".join("];
77
78/// Every preset name `report` accepts, in product order.
79pub fn preset_names() -> Vec<&'static str> {
80    PARITY_PRESETS
81        .iter()
82        .map(|(_, preset)| *preset)
83        .chain(ORCHESTRATION_PRESETS.iter().copied())
84        .chain(std::iter::once(ORCHESTRATOR_PRESET))
85        .collect()
86}
87
88/// The committed `--help` fixture for a pinned orchestration harness CLI.
89pub fn help_fixture(harness: &str) -> Option<&'static str> {
90    match harness {
91        "hermes" => Some(HERMES_HELP_FIXTURE),
92        "openclaw" => Some(OPENCLAW_HELP_FIXTURE),
93        _ => None,
94    }
95}
96
97/// Whether a harness has a capability (the catalog's per-harness column).
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
99#[serde(rename_all = "snake_case")]
100pub enum Has {
101    /// `✓` — has it as described.
102    Yes,
103    /// `✓*` — has it with a footnoted variant.
104    Variant,
105    /// `ext` — only through an extension, plugin, or example.
106    Extension,
107    /// `—` — lacks it.
108    No,
109}
110
111impl Has {
112    /// True for every column value except `—`.
113    pub fn present(self) -> bool {
114        !matches!(self, Has::No)
115    }
116}
117
118/// supercode's audited status for a row.
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
120#[serde(rename_all = "snake_case")]
121pub enum Status {
122    /// Behaves as the catalog row describes, under the applicable preset(s).
123    Implemented,
124    /// Some of the row's semantics exist; the note names what is missing.
125    Partial,
126    /// Nothing exists yet.
127    Absent,
128    /// Cannot be reproduced by design (the note cites the design-doc ledger).
129    Irreducible,
130    /// Neither Claude Code nor Codex has it; outside the parity program.
131    NotApplicable,
132    /// Seeded from the catalog and not yet audited against current code.
133    Unaudited,
134}
135
136impl Status {
137    /// Whether the row counts against the preset's gap headline.
138    pub fn is_gap(self) -> bool {
139        matches!(
140            self,
141            Status::Partial | Status::Absent | Status::Irreducible | Status::Unaudited
142        )
143    }
144
145    /// Whether the row must cite at least one checkable evidence item.
146    pub fn requires_evidence(self) -> bool {
147        matches!(self, Status::Implemented | Status::Partial)
148    }
149
150    fn label(self) -> &'static str {
151        match self {
152            Status::Implemented => "implemented",
153            Status::Partial => "partial",
154            Status::Absent => "absent",
155            Status::Irreducible => "irreducible",
156            Status::NotApplicable => "not_applicable",
157            Status::Unaudited => "unaudited",
158        }
159    }
160}
161
162/// Adoption cost class for an absent row (the catalog's §4 split).
163#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
164#[serde(rename_all = "snake_case")]
165pub enum Cost {
166    /// Config knob, small tool, or prompt-assembly change; no new subsystem.
167    Trivial,
168    /// New subsystem or cross-cutting contract.
169    Architectural,
170}
171
172/// A mechanically checkable citation. Every variant is resolved by
173/// [`check_evidence`] against the applicable preset(s) or the source tree.
174#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
175#[serde(tag = "kind", rename_all = "snake_case")]
176pub enum Evidence {
177    /// A tool registered under the applicable preset's resolved config.
178    Tool {
179        /// Registered tool name (e.g. `read_file`).
180        name: String,
181    },
182    /// A capability module enabled in the applicable preset(s).
183    Module {
184        /// Capability module name (a `MODULE_NAMES` entry).
185        name: String,
186    },
187    /// A dotted key that the applicable preset TOML sets explicitly.
188    Config {
189        /// Dotted TOML key path (e.g. `core.tools.edit_file.require_read_before_edit`).
190        key: String,
191    },
192    /// A live-runtime capability flag on the harness's own backend.
193    Runtime {
194        /// `RuntimeCapabilities` flag name (e.g. `steer`).
195        capability: String,
196    },
197    /// A source file (workspace-relative) that must exist and, when
198    /// `symbol` is given, contain that text. The weakest kind; for loop
199    /// mechanics that no config key or tool name expresses.
200    Code {
201        /// Workspace-relative source path.
202        path: String,
203        /// Text the file must contain.
204        #[serde(default, skip_serializing_if = "Option::is_none")]
205        symbol: Option<String>,
206    },
207    /// A subcommand the PINNED harness CLI advertises. Resolved against the
208    /// committed capture `parity/fixtures/<harness>-help.txt`: the verb's
209    /// leaf must appear as a subcommand entry inside the
210    /// `$ <harness> <parents> --help` section. Backs a harness column, never
211    /// a supercode status — that a harness has a verb says nothing about
212    /// whether supercode calls it.
213    CliVerb {
214        /// One of [`ORCHESTRATION_PRESETS`].
215        harness: String,
216        /// Space-separated verb path (`cron list`, `agents bindings`, `acp`).
217        verb: String,
218    },
219    /// A harness store (file path, table, or column) that a loader in THIS
220    /// workspace actually opens. Resolved by a symbol search over
221    /// [`STORE_SEARCH_ROOTS`]: every non-placeholder segment of `path` must
222    /// appear in a [`STORE_OPEN_CALLS`] form on a non-comment line.
223    /// `<...>` segments are placeholders and are skipped.
224    Store {
225        /// The store's owner, one of [`ORCHESTRATION_PRESETS`].
226        harness: String,
227        /// `/`-separated store path, e.g. `state.db/sessions/session_key`.
228        path: String,
229    },
230}
231
232/// One catalog row with its audited status.
233#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
234pub struct Row {
235    /// Stable slug derived from the capability name.
236    pub id: String,
237    /// Catalog domain number (1..=11).
238    pub domain: u8,
239    /// Catalog domain title.
240    pub domain_name: String,
241    /// Capability name as the catalog states it.
242    pub capability: String,
243    /// The catalog's one-line semantics.
244    pub semantics: String,
245    /// Claude Code column.
246    pub cc: Has,
247    /// Codex column.
248    pub cx: Has,
249    /// Claude Code cell text (variant footnotes live here).
250    pub cc_detail: String,
251    /// Codex cell text.
252    pub cx_detail: String,
253    /// The catalog's own "supercode today" cell at survey time (prior claim,
254    /// never consulted for status).
255    pub catalog_supercode_today: String,
256    /// Catalog provenance citations.
257    pub provenance: String,
258    /// Audited status.
259    pub status: Status,
260    /// Checkable citations backing `status`.
261    #[serde(default)]
262    pub evidence: Vec<Evidence>,
263    /// What is missing (partial), why (irreducible), or where (absent).
264    #[serde(default)]
265    pub note: String,
266    /// Adoption cost class; required when `status` is absent.
267    #[serde(default, skip_serializing_if = "Option::is_none")]
268    pub cost: Option<Cost>,
269}
270
271impl Row {
272    /// Whether the harness behind `column` (`"cc"` / `"cx"`) has this row.
273    pub fn has(&self, column: &str) -> bool {
274        match column {
275            "cc" => self.cc.present(),
276            "cx" => self.cx.present(),
277            _ => false,
278        }
279    }
280
281    /// Preset names this row must hold under.
282    pub fn applicable_presets(&self) -> Vec<&'static str> {
283        PARITY_PRESETS
284            .iter()
285            .filter(|(column, _)| self.has(column))
286            .map(|(_, preset)| *preset)
287            .collect()
288    }
289}
290
291/// Parse the embedded ledger.
292pub fn ledger() -> Vec<Row> {
293    serde_json::from_str(LEDGER_JSON).expect("embedded parity ledger is valid JSON")
294}
295
296/// Catalog domain the orchestration rows belong to (Domain 11,
297/// "Orchestration & automation"). The orchestration ledger is the same
298/// domain seen through the two orchestration-level harnesses' own doors.
299pub const ORCHESTRATION_DOMAIN: u8 = 11;
300
301/// One (orchestration concept × verb group) row with its audited status.
302///
303/// Same shape as [`Row`] with the harness columns swapped: `hermes` /
304/// `openclaw` instead of `cc` / `cx`, and a per-column evidence list, since
305/// what a harness advertises is checkable independently of what supercode
306/// does with it.
307#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
308pub struct OrchestrationRow {
309    /// Stable slug (`orch-` + concept + verb group).
310    pub id: String,
311    /// One of `crate::support::ORCHESTRATION_CONCEPTS`.
312    pub concept: String,
313    /// The verb group this row covers (`list/get`, `create/update/...`).
314    pub verbs: String,
315    /// Row name as the inventory states it (`Scheduled job: list/get`).
316    pub capability: String,
317    /// The inventory's one-line semantics.
318    pub semantics: String,
319    /// Hermes column.
320    pub hermes: Has,
321    /// OpenClaw column.
322    pub openclaw: Has,
323    /// The orchestrator's column: whether ITS model has this concept
324    /// (ORC-7). `no` means the concept is deliberately outside
325    /// `docs/ORCHESTRATOR-IR.md` §2.
326    pub orchestrator: Has,
327    /// Hermes cell text (variant footnotes live here).
328    pub hermes_detail: String,
329    /// OpenClaw cell text.
330    pub openclaw_detail: String,
331    /// The orchestrator cell text.
332    pub orchestrator_detail: String,
333    /// Citations backing the Hermes column (`cli_verb` against the pin).
334    #[serde(default)]
335    pub hermes_evidence: Vec<Evidence>,
336    /// Citations backing the OpenClaw column.
337    #[serde(default)]
338    pub openclaw_evidence: Vec<Evidence>,
339    /// Audited status of supercode's support for the ORCHESTRATOR on this
340    /// row, which is a different question from [`OrchestrationRow::status`]
341    /// (that one grades the Hermes and OpenClaw readers).
342    pub orchestrator_status: Status,
343    /// Citations backing `orchestrator_status` (`store` / `code`, resolved in
344    /// this workspace exactly like a supercode status).
345    #[serde(default)]
346    pub orchestrator_evidence: Vec<Evidence>,
347    /// What is missing (partial), why (not_applicable), or where (absent) for
348    /// the orchestrator.
349    pub orchestrator_note: String,
350    /// Adoption cost class for an absent orchestrator row.
351    #[serde(default, skip_serializing_if = "Option::is_none")]
352    pub orchestrator_cost: Option<Cost>,
353    /// Inventory provenance.
354    pub provenance: String,
355    /// Audited status of SUPERCODE, not of the harnesses.
356    pub status: Status,
357    /// Checkable citations backing `status` (`store` / `code`).
358    #[serde(default)]
359    pub evidence: Vec<Evidence>,
360    /// What is missing (partial), why (irreducible), or where (absent).
361    #[serde(default)]
362    pub note: String,
363    /// Adoption cost class; required when `status` is absent.
364    #[serde(default, skip_serializing_if = "Option::is_none")]
365    pub cost: Option<Cost>,
366}
367
368impl OrchestrationRow {
369    /// Whether `harness` (`"hermes"` / `"openclaw"`) has this row.
370    pub fn has(&self, harness: &str) -> bool {
371        self.column(harness)
372            .is_some_and(|(has, _, _)| has.present())
373    }
374
375    /// The `(has, detail, evidence)` triple for one harness column.
376    pub fn column(&self, harness: &str) -> Option<(Has, &str, &[Evidence])> {
377        match harness {
378            "hermes" => Some((
379                self.hermes,
380                self.hermes_detail.as_str(),
381                self.hermes_evidence.as_slice(),
382            )),
383            "openclaw" => Some((
384                self.openclaw,
385                self.openclaw_detail.as_str(),
386                self.openclaw_evidence.as_slice(),
387            )),
388            _ => None,
389        }
390    }
391}
392
393/// Parse the embedded orchestration ledger.
394pub fn orchestration_ledger() -> Vec<OrchestrationRow> {
395    serde_json::from_str(ORCHESTRATION_JSON).expect("embedded orchestration ledger is valid JSON")
396}
397
398/// Per-status counts plus the headline gap number for one preset.
399#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
400pub struct PresetSummary {
401    /// Preset name.
402    pub preset: String,
403    /// Catalog column the preset mirrors (`cc` / `cx`).
404    pub harness_column: String,
405    /// Rows the harness has (the denominator).
406    pub rows: usize,
407    /// Row count per status label.
408    pub counts: BTreeMap<String, usize>,
409    /// The headline: rows that are not implemented.
410    pub gaps: usize,
411}
412
413/// A gap row as printed: enough to act on without opening the ledger.
414#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
415pub struct GapRow {
416    /// Row id.
417    pub id: String,
418    /// Catalog domain.
419    pub domain: u8,
420    /// Capability name.
421    pub capability: String,
422    /// Audited status (never implemented here).
423    pub status: Status,
424    /// Adoption cost class when known.
425    #[serde(default, skip_serializing_if = "Option::is_none")]
426    pub cost: Option<Cost>,
427    /// Row note.
428    pub note: String,
429}
430
431/// The parity report for one preset.
432#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
433pub struct PresetReport {
434    /// Headline counts.
435    pub summary: PresetSummary,
436    /// Every gap row, in catalog order.
437    pub gaps: Vec<GapRow>,
438}
439
440/// Build the report for `preset`: a capability preset (`cc-parity` /
441/// `cx-parity`) or an orchestration harness (`hermes` / `openclaw`).
442pub fn report(preset: &str) -> Option<PresetReport> {
443    if let Some((column, _)) = PARITY_PRESETS.iter().find(|(_, p)| *p == preset) {
444        return Some(catalog_report(preset, column));
445    }
446    if preset == ORCHESTRATOR_PRESET {
447        return Some(orchestrator_report());
448    }
449    if ORCHESTRATION_PRESETS.contains(&preset) {
450        return Some(orchestration_report(preset));
451    }
452    None
453}
454
455fn catalog_report(preset: &str, column: &str) -> PresetReport {
456    let rows: Vec<Row> = ledger().into_iter().filter(|r| r.has(column)).collect();
457    let mut counts: BTreeMap<String, usize> = BTreeMap::new();
458    let mut gaps = Vec::new();
459    for row in &rows {
460        *counts.entry(row.status.label().to_string()).or_default() += 1;
461        if row.status.is_gap() {
462            gaps.push(GapRow {
463                id: row.id.clone(),
464                domain: row.domain,
465                capability: row.capability.clone(),
466                status: row.status,
467                cost: row.cost,
468                note: row.note.clone(),
469            });
470        }
471    }
472    PresetReport {
473        summary: PresetSummary {
474            preset: preset.to_string(),
475            harness_column: column.to_string(),
476            rows: rows.len(),
477            counts,
478            gaps: gaps.len(),
479        },
480        gaps,
481    }
482}
483
484fn orchestration_report(harness: &str) -> PresetReport {
485    let rows: Vec<OrchestrationRow> = orchestration_ledger()
486        .into_iter()
487        .filter(|r| r.has(harness))
488        .collect();
489    let mut counts: BTreeMap<String, usize> = BTreeMap::new();
490    let mut gaps = Vec::new();
491    for row in &rows {
492        *counts.entry(row.status.label().to_string()).or_default() += 1;
493        if row.status.is_gap() {
494            gaps.push(GapRow {
495                id: row.id.clone(),
496                domain: ORCHESTRATION_DOMAIN,
497                capability: row.capability.clone(),
498                status: row.status,
499                cost: row.cost,
500                note: row.note.clone(),
501            });
502        }
503    }
504    PresetReport {
505        summary: PresetSummary {
506            preset: harness.to_string(),
507            harness_column: harness.to_string(),
508            rows: rows.len(),
509            counts,
510            gaps: gaps.len(),
511        },
512        gaps,
513    }
514}
515
516/// ORC-7: the same 17 rows, graded through the orchestrator's own column.
517///
518/// Every row counts: a concept the orchestrator's model does not have is
519/// `not_applicable` (not a gap, but still in the denominator), so the
520/// headline can never be improved by dropping a row.
521fn orchestrator_report() -> PresetReport {
522    let rows = orchestration_ledger();
523    let mut counts: BTreeMap<String, usize> = BTreeMap::new();
524    let mut gaps = Vec::new();
525    for row in &rows {
526        *counts
527            .entry(row.orchestrator_status.label().to_string())
528            .or_default() += 1;
529        if row.orchestrator_status.is_gap() {
530            gaps.push(GapRow {
531                id: row.id.clone(),
532                domain: ORCHESTRATION_DOMAIN,
533                capability: row.capability.clone(),
534                status: row.orchestrator_status,
535                cost: row.orchestrator_cost,
536                note: row.orchestrator_note.clone(),
537            });
538        }
539    }
540    PresetReport {
541        summary: PresetSummary {
542            preset: ORCHESTRATOR_PRESET.to_string(),
543            harness_column: ORCHESTRATOR_PRESET.to_string(),
544            rows: rows.len(),
545            counts,
546            gaps: gaps.len(),
547        },
548        gaps,
549    }
550}
551
552/// Render the headline plus the gap list, grouped by domain.
553pub fn render(report: &PresetReport) -> String {
554    let s = &report.summary;
555    let mut out = format!("{}: {} rows · {} gaps", s.preset, s.rows, s.gaps);
556    for status in [
557        Status::Implemented,
558        Status::Partial,
559        Status::Absent,
560        Status::Irreducible,
561        // ORC-7: a preset whose denominator is the WHOLE ledger reports rows
562        // its subject deliberately lacks; leaving them out of the headline
563        // would make the counts fail to add up to the row count.
564        Status::NotApplicable,
565        Status::Unaudited,
566    ] {
567        if let Some(n) = s.counts.get(status.label()) {
568            out.push_str(&format!(" · {n} {}", status.label()));
569        }
570    }
571    out.push('\n');
572    let mut domain = 0u8;
573    for gap in &report.gaps {
574        if gap.domain != domain {
575            domain = gap.domain;
576            out.push_str(&format!("\nDomain {domain}\n"));
577        }
578        let cost = match gap.cost {
579            Some(Cost::Trivial) => " [trivial]",
580            Some(Cost::Architectural) => " [architectural]",
581            None => "",
582        };
583        out.push_str(&format!(
584            "  {:<12}{cost} {} ({})",
585            gap.status.label(),
586            gap.capability,
587            gap.id
588        ));
589        if !gap.note.is_empty() {
590            out.push_str(&format!(" — {}", gap.note));
591        }
592        out.push('\n');
593    }
594    out
595}
596
597/// Resolve a built-in preset through the real resolver (strict mode).
598pub fn resolve_preset(preset: &str) -> Result<Resolved, String> {
599    let toml = presets::lookup(preset).ok_or_else(|| format!("unknown preset `{preset}`"))?;
600    resolve(toml, None, &ResolveOptions { strict: true }).map_err(|e| e.to_string())
601}
602
603fn runtime_flag(capabilities: &RuntimeCapabilities, flag: &str) -> Option<bool> {
604    Some(match flag {
605        "start_session" => capabilities.start_session,
606        "resume_session" => capabilities.resume_session,
607        "attach_existing_process" => capabilities.attach_existing_process,
608        "send_input" => capabilities.send_input,
609        "stream_events" => capabilities.stream_events,
610        "interrupt" => capabilities.interrupt,
611        "steer" => capabilities.steer,
612        "respond_to_requests" => capabilities.respond_to_requests,
613        _ => return None,
614    })
615}
616
617fn backend_capabilities(column: &str) -> RuntimeCapabilities {
618    match column {
619        "cc" => crate::runtime::ClaudeCodeRuntimeBackend::default().capabilities(),
620        "cx" => crate::runtime::CodexRuntimeBackend::default().capabilities(),
621        other => panic!("no runtime backend for column `{other}`"),
622    }
623}
624
625/// Resolve a [`Evidence::CliVerb`] against the committed help fixture.
626///
627/// A verb is advertised when its LEAF appears as a subcommand entry inside
628/// the section headed `$ <harness> <parents> --help`. Subcommand entries are
629/// shallow-indented lines whose first token names the command; both help
630/// renderers' alias forms are accepted (`create (add)` from argparse,
631/// `add|create` from Commander).
632fn check_cli_verb(harness: &str, verb: &str) -> Result<(), String> {
633    let fixture = help_fixture(harness)
634        .ok_or_else(|| format!("no committed help fixture for harness `{harness}`"))?;
635    let mut parts: Vec<&str> = verb.split_whitespace().collect();
636    let leaf = parts.pop().ok_or_else(|| "empty cli verb".to_string())?;
637    let header = if parts.is_empty() {
638        format!("$ {harness} --help")
639    } else {
640        format!("$ {harness} {} --help", parts.join(" "))
641    };
642    let mut in_section = false;
643    let mut saw_section = false;
644    for line in fixture.lines() {
645        if line.starts_with("$ ") {
646            in_section = line.trim() == header;
647            saw_section |= in_section;
648            continue;
649        }
650        if !in_section || line.starts_with('#') {
651            continue;
652        }
653        // Subcommand entries sit 2–6 columns in; description continuations
654        // and usage wrapping sit far deeper, so they cannot false-positive.
655        let indent = line.len() - line.trim_start().len();
656        if !(2..=6).contains(&indent) {
657            continue;
658        }
659        let Some(token) = line.split_whitespace().next() else {
660            continue;
661        };
662        if token.starts_with('-') {
663            continue;
664        }
665        if token.split('|').any(|alias| alias == leaf) {
666            return Ok(());
667        }
668    }
669    if !saw_section {
670        return Err(format!(
671            "`{header}` is not a section of the {harness} help fixture"
672        ));
673    }
674    Err(format!(
675        "`{harness} {verb}` is not advertised under `{header}`"
676    ))
677}
678
679fn push_rust_sources(dir: &Path, out: &mut Vec<std::path::PathBuf>) {
680    let Ok(entries) = std::fs::read_dir(dir) else {
681        return;
682    };
683    for entry in entries.flatten() {
684        let path = entry.path();
685        if path.is_dir() {
686            push_rust_sources(&path, out);
687        } else if path.extension().is_some_and(|ext| ext == "rs") {
688            out.push(path);
689        }
690    }
691}
692
693/// True when `segment` appears inside an opening call (SQL read, file open,
694/// path join) on a non-comment line under [`STORE_SEARCH_ROOTS`]. The call
695/// may be split across lines (multi-line SQL), so the three preceding lines
696/// count as the same call context.
697fn store_segment_is_opened(segment: &str, workspace_root: &Path) -> bool {
698    let mut files = Vec::new();
699    for root in STORE_SEARCH_ROOTS {
700        push_rust_sources(&workspace_root.join(root), &mut files);
701    }
702    for file in files {
703        let Ok(text) = std::fs::read_to_string(&file) else {
704            continue;
705        };
706        let lines: Vec<&str> = text.lines().collect();
707        for (index, line) in lines.iter().enumerate() {
708            if !line.contains(segment) || line.trim_start().starts_with("//") {
709                continue;
710            }
711            let start = index.saturating_sub(3);
712            let context = lines[start..=index].join("\n");
713            if STORE_OPEN_CALLS.iter().any(|call| context.contains(call)) {
714                return true;
715            }
716        }
717    }
718    false
719}
720
721/// Resolve a [`Evidence::Store`]: every non-placeholder path segment must be
722/// opened by a loader in this workspace.
723fn check_store(harness: &str, path: &str, workspace_root: &Path) -> Result<(), String> {
724    if !ORCHESTRATION_PRESETS.contains(&harness) && harness != ORCHESTRATOR_PRESET {
725        return Err(format!(
726            "`{harness}` is not an orchestration harness or the orchestrator"
727        ));
728    }
729    let mut checked = 0usize;
730    for segment in path.split('/') {
731        if segment.is_empty() || (segment.starts_with('<') && segment.ends_with('>')) {
732            continue;
733        }
734        if segment.len() < 3 {
735            return Err(format!(
736                "store segment `{segment}` is too short to identify a store"
737            ));
738        }
739        if !store_segment_is_opened(segment, workspace_root) {
740            return Err(format!(
741                "no loader under {} opens `{segment}` (from {harness} store `{path}`)",
742                STORE_SEARCH_ROOTS.join(", ")
743            ));
744        }
745        checked += 1;
746    }
747    if checked == 0 {
748        return Err(format!("store path `{path}` names no concrete segment"));
749    }
750    Ok(())
751}
752
753fn toml_has_key(doc: &toml::Value, key: &str) -> bool {
754    let mut cur = doc;
755    for part in key.split('.') {
756        match cur.get(part) {
757            Some(next) => cur = next,
758            None => return false,
759        }
760    }
761    true
762}
763
764/// Check one evidence item for one row. Returns `Err(reason)` when the
765/// citation does not resolve under every applicable preset / harness.
766pub fn check_evidence(
767    row: &Row,
768    evidence: &Evidence,
769    workspace_root: &std::path::Path,
770) -> Result<(), String> {
771    let applicable: Vec<(&str, &str)> = PARITY_PRESETS
772        .iter()
773        .filter(|(column, _)| row.has(column))
774        .map(|(c, p)| (*c, *p))
775        .collect();
776    if applicable.is_empty() {
777        return Err("row has no applicable preset (neither cc nor cx has it)".into());
778    }
779    match evidence {
780        Evidence::Tool { name } => {
781            for (_, preset) in &applicable {
782                let resolved = resolve_preset(preset)?;
783                let registry = ToolRegistry::from_config(&resolved.config);
784                if registry.get(name).is_none() {
785                    return Err(format!("tool `{name}` is not registered under `{preset}`"));
786                }
787            }
788            Ok(())
789        }
790        Evidence::Module { name } => {
791            for (_, preset) in &applicable {
792                let resolved = resolve_preset(preset)?;
793                match resolved.modules.get(name) {
794                    Some(true) => {}
795                    Some(false) => {
796                        return Err(format!("module `{name}` is disabled under `{preset}`"))
797                    }
798                    None => return Err(format!("module `{name}` is not a known module")),
799                }
800            }
801            Ok(())
802        }
803        Evidence::Config { key } => {
804            for (_, preset) in &applicable {
805                let text =
806                    presets::lookup(preset).ok_or_else(|| format!("unknown preset `{preset}`"))?;
807                let doc: toml::Value = toml::from_str(text).map_err(|e| e.to_string())?;
808                if !toml_has_key(&doc, key) {
809                    return Err(format!("`{preset}` does not set `{key}`"));
810                }
811            }
812            Ok(())
813        }
814        Evidence::Runtime { capability } => {
815            for (column, _) in &applicable {
816                let caps = backend_capabilities(column);
817                match runtime_flag(&caps, capability) {
818                    Some(true) => {}
819                    Some(false) => {
820                        return Err(format!(
821                            "runtime capability `{capability}` is false for `{column}`"
822                        ))
823                    }
824                    None => return Err(format!("`{capability}` is not a runtime capability flag")),
825                }
826            }
827            Ok(())
828        }
829        Evidence::Code { .. } | Evidence::CliVerb { .. } | Evidence::Store { .. } => {
830            check_source_evidence(evidence, workspace_root)
831        }
832    }
833}
834
835/// Check one evidence item whose resolution does not depend on a preset:
836/// `code` against the source tree, `cli_verb` against the pinned help
837/// fixture, `store` against the workspace's loaders.
838pub fn check_source_evidence(
839    evidence: &Evidence,
840    workspace_root: &std::path::Path,
841) -> Result<(), String> {
842    match evidence {
843        Evidence::Code { path, symbol } => {
844            let full = workspace_root.join(path);
845            let text =
846                std::fs::read_to_string(&full).map_err(|e| format!("cannot read `{path}`: {e}"))?;
847            if let Some(symbol) = symbol {
848                if !text.contains(symbol.as_str()) {
849                    return Err(format!("`{path}` does not contain `{symbol}`"));
850                }
851            }
852            Ok(())
853        }
854        Evidence::CliVerb { harness, verb } => check_cli_verb(harness, verb),
855        Evidence::Store { harness, path } => check_store(harness, path, workspace_root),
856        other => Err(format!(
857            "{other:?} needs a preset context; use `check_evidence`"
858        )),
859    }
860}
861
862/// Check one evidence item on an orchestration row.
863///
864/// The two evidence lanes are kept apart on purpose: a harness COLUMN may
865/// only cite a `cli_verb` of that same harness (what the pinned CLI
866/// advertises), and supercode's STATUS may only cite `store` / `code` (what
867/// this workspace actually does). A `cli_verb` can never make supercode look
868/// implemented, and a `code` citation can never make a harness look capable.
869pub fn check_orchestration_evidence(
870    lane: OrchestrationLane<'_>,
871    evidence: &Evidence,
872    workspace_root: &std::path::Path,
873) -> Result<(), String> {
874    match (lane, evidence) {
875        (OrchestrationLane::Column(harness), Evidence::CliVerb { harness: cited, .. }) => {
876            if cited != harness {
877                return Err(format!(
878                    "the {harness} column cites a `{cited}` verb ({evidence:?})"
879                ));
880            }
881            check_source_evidence(evidence, workspace_root)
882        }
883        (OrchestrationLane::Column(harness), other) => Err(format!(
884            "the {harness} column may only cite `cli_verb`, not {other:?}"
885        )),
886        (OrchestrationLane::Supercode, Evidence::Store { .. } | Evidence::Code { .. }) => {
887            check_source_evidence(evidence, workspace_root)
888        }
889        (OrchestrationLane::Supercode, other) => Err(format!(
890            "a supercode status may only cite `store` or `code`, not {other:?}"
891        )),
892    }
893}
894
895/// Which side of an orchestration row an evidence item backs.
896#[derive(Debug, Clone, Copy, PartialEq, Eq)]
897pub enum OrchestrationLane<'a> {
898    /// One harness column: what the pinned harness CLI advertises.
899    Column(&'a str),
900    /// supercode's audited status: what this workspace does.
901    Supercode,
902}
903
904#[cfg(test)]
905mod tests {
906    use super::*;
907    use std::collections::HashSet;
908    use std::path::PathBuf;
909
910    fn workspace_root() -> PathBuf {
911        PathBuf::from(env!("CARGO_MANIFEST_DIR"))
912            .join("../..")
913            .canonicalize()
914            .unwrap()
915    }
916
917    #[test]
918    fn ledger_parses_with_unique_ids_and_full_catalog() {
919        let rows = ledger();
920        assert_eq!(rows.len(), 263, "one row per catalog capability");
921        let ids: HashSet<&str> = rows.iter().map(|r| r.id.as_str()).collect();
922        assert_eq!(ids.len(), rows.len(), "row ids must be unique");
923        for row in &rows {
924            assert!(
925                (1..=11).contains(&row.domain),
926                "{}: domain out of range",
927                row.id
928            );
929        }
930    }
931
932    #[test]
933    fn not_applicable_rows_are_exactly_those_neither_harness_has() {
934        for row in ledger() {
935            let neither = !row.cc.present() && !row.cx.present();
936            assert_eq!(
937                row.status == Status::NotApplicable,
938                neither,
939                "{}: not_applicable must mean neither cc nor cx has it",
940                row.id
941            );
942        }
943    }
944
945    /// The audit is complete: a row may never regress to `unaudited`, in
946    /// EITHER ledger.
947    #[test]
948    fn no_row_remains_unaudited() {
949        let mut stale: Vec<String> = ledger()
950            .into_iter()
951            .filter(|r| r.status == Status::Unaudited)
952            .map(|r| r.id)
953            .collect();
954        stale.extend(
955            orchestration_ledger()
956                .into_iter()
957                .filter(|r| r.status == Status::Unaudited)
958                .map(|r| r.id),
959        );
960        assert!(stale.is_empty(), "unaudited rows: {stale:?}");
961    }
962
963    #[test]
964    fn both_parity_presets_resolve_strictly() {
965        for (_, preset) in PARITY_PRESETS {
966            resolve_preset(preset).unwrap_or_else(|e| panic!("{preset}: {e}"));
967        }
968    }
969
970    /// The honesty gate: every implemented/partial row must cite at least one
971    /// evidence item, and EVERY cited item must resolve mechanically.
972    #[test]
973    fn every_audited_claim_is_backed_by_resolvable_evidence() {
974        let root = workspace_root();
975        let mut failures = Vec::new();
976        for row in ledger() {
977            if row.status.requires_evidence() && row.evidence.is_empty() {
978                failures.push(format!(
979                    "{}: `{}` cites no evidence",
980                    row.id,
981                    row.status.label()
982                ));
983            }
984            if row.status == Status::Irreducible && row.note.is_empty() {
985                failures.push(format!("{}: irreducible without a note", row.id));
986            }
987            if row.status == Status::Absent && row.cost.is_none() {
988                failures.push(format!("{}: absent without a cost class", row.id));
989            }
990            for ev in &row.evidence {
991                if let Err(reason) = check_evidence(&row, ev, &root) {
992                    failures.push(format!("{}: {reason}", row.id));
993                }
994            }
995        }
996        assert!(
997            failures.is_empty(),
998            "ledger evidence failures:\n{}",
999            failures.join("\n")
1000        );
1001    }
1002
1003    /// The gate must bite: fabricated citations of every kind are rejected.
1004    #[test]
1005    fn evidence_gate_rejects_unresolvable_citations() {
1006        let root = workspace_root();
1007        let mut row = ledger().into_iter().find(|r| r.cc.present()).unwrap();
1008        row.cx = Has::No;
1009        let bad = [
1010            Evidence::Tool {
1011                name: "no_such_tool".into(),
1012            },
1013            Evidence::Module {
1014                name: "no_such_module".into(),
1015            },
1016            Evidence::Module {
1017                name: "model_oauth".into(),
1018            }, // present but disabled in cc-parity
1019            Evidence::Config {
1020                key: "capabilities.no_such.key".into(),
1021            },
1022            Evidence::Runtime {
1023                capability: "attach_existing_process".into(),
1024            }, // false on the claude door
1025            Evidence::Runtime {
1026                capability: "not_a_flag".into(),
1027            },
1028            Evidence::Code {
1029                path: "crates/harness/src/no_such_file.rs".into(),
1030                symbol: None,
1031            },
1032            Evidence::Code {
1033                path: "crates/harness/src/parity.rs".into(),
1034                // Built at runtime so the literal is not in this file.
1035                symbol: Some(["ZZZ_NOT", "_PRESENT_ZZZ"].concat()),
1036            },
1037        ];
1038        for ev in bad {
1039            assert!(
1040                check_evidence(&row, &ev, &root).is_err(),
1041                "{ev:?} must be rejected"
1042            );
1043        }
1044        let good = [
1045            Evidence::Tool {
1046                name: "read_file".into(),
1047            },
1048            Evidence::Module {
1049                name: "subagents".into(),
1050            },
1051            Evidence::Config {
1052                key: "capabilities.subagents".into(),
1053            },
1054            Evidence::Runtime {
1055                capability: "steer".into(),
1056            },
1057            Evidence::Code {
1058                path: "crates/harness/src/parity.rs".into(),
1059                symbol: Some("pub fn check_evidence".into()),
1060            },
1061        ];
1062        for ev in good {
1063            check_evidence(&row, &ev, &root).unwrap_or_else(|e| panic!("{ev:?}: {e}"));
1064        }
1065        // A row no harness has cannot cite anything.
1066        row.cc = Has::No;
1067        assert!(check_evidence(
1068            &row,
1069            &Evidence::Tool {
1070                name: "read_file".into()
1071            },
1072            &root
1073        )
1074        .is_err());
1075    }
1076
1077    #[test]
1078    fn report_counts_add_up() {
1079        for preset in preset_names() {
1080            let r = report(preset).unwrap();
1081            let total: usize = r.summary.counts.values().sum();
1082            assert_eq!(total, r.summary.rows);
1083            assert_eq!(r.gaps.len(), r.summary.gaps);
1084            assert!(!render(&r).is_empty());
1085        }
1086        assert!(report("pi-core").is_none());
1087    }
1088
1089    /// dev/01: the orchestration presets are reportable and named alongside
1090    /// the capability presets, so the CLI's `--preset` error lists all four.
1091    #[test]
1092    fn preset_names_cover_both_ledgers() {
1093        assert_eq!(
1094            preset_names(),
1095            vec![
1096                "cc-parity",
1097                "cx-parity",
1098                "hermes",
1099                "openclaw",
1100                "orchestrator"
1101            ]
1102        );
1103        for harness in ORCHESTRATION_PRESETS {
1104            let r = report(harness).unwrap();
1105            assert_eq!(&r.summary.preset, harness);
1106            assert_eq!(&r.summary.harness_column, harness);
1107            assert!(r.summary.rows > 0, "{harness}: empty denominator");
1108            let rendered = render(&r);
1109            assert!(
1110                rendered.starts_with(&format!("{harness}: {} rows · ", r.summary.rows)),
1111                "{harness}: unexpected headline: {rendered}"
1112            );
1113            assert!(rendered.contains("\nDomain 11\n"), "{harness}: {rendered}");
1114        }
1115    }
1116
1117    /// ORC-7 dev/01: the orchestrator preset reports on the WHOLE ledger,
1118    /// every row is graded, and its column obeys the same honesty rules as
1119    /// the harness columns: a present column has detail, an
1120    /// implemented/partial status cites evidence that resolves here, an
1121    /// absent row names its cost, and a row the orchestrator's model does not
1122    /// have is `not_applicable` with no citation.
1123    #[test]
1124    fn the_orchestrator_column_is_graded_on_every_row_with_resolvable_evidence() {
1125        let root = workspace_root();
1126        let rows = orchestration_ledger();
1127        let report = report(ORCHESTRATOR_PRESET).unwrap();
1128        assert_eq!(
1129            report.summary.rows,
1130            rows.len(),
1131            "the orchestrator is graded on every row, never a filtered subset"
1132        );
1133        let mut failures = Vec::new();
1134        for row in &rows {
1135            if row.orchestrator.present() && row.orchestrator_detail.is_empty() {
1136                failures.push(format!("{}: orchestrator column has no detail", row.id));
1137            }
1138            if !row.orchestrator.present() && row.orchestrator_status != Status::NotApplicable {
1139                failures.push(format!(
1140                    "{}: the orchestrator lacks this row but is graded `{}`",
1141                    row.id,
1142                    row.orchestrator_status.label()
1143                ));
1144            }
1145            if !row.orchestrator.present() && !row.orchestrator_evidence.is_empty() {
1146                failures.push(format!("{}: a `no` column cites evidence", row.id));
1147            }
1148            if row.orchestrator_status.requires_evidence() && row.orchestrator_evidence.is_empty() {
1149                failures.push(format!(
1150                    "{}: orchestrator `{}` cites no evidence",
1151                    row.id,
1152                    row.orchestrator_status.label()
1153                ));
1154            }
1155            if row.orchestrator_status == Status::Absent && row.orchestrator_cost.is_none() {
1156                failures.push(format!(
1157                    "{}: orchestrator absent without a cost class",
1158                    row.id
1159                ));
1160            }
1161            if row.orchestrator_note.is_empty() {
1162                failures.push(format!("{}: no orchestrator note", row.id));
1163            }
1164            for ev in &row.orchestrator_evidence {
1165                if let Err(reason) =
1166                    check_orchestration_evidence(OrchestrationLane::Supercode, ev, &root)
1167                {
1168                    failures.push(format!("{}: {reason}", row.id));
1169                }
1170            }
1171        }
1172        assert!(
1173            failures.is_empty(),
1174            "orchestrator column failures:\n{}",
1175            failures.join("\n")
1176        );
1177        // The headline is honest about the gap count, and only zero is done.
1178        let rendered = render(&report);
1179        assert!(
1180            rendered.starts_with(&format!(
1181                "orchestrator: {} rows · {} gaps",
1182                report.summary.rows, report.summary.gaps
1183            )),
1184            "{rendered}"
1185        );
1186    }
1187
1188    /// A `store` citation for the orchestrator resolves against this
1189    /// workspace's own loaders, and a fabricated one still does not.
1190    #[test]
1191    fn orchestrator_store_citations_resolve_like_every_other_supercode_status() {
1192        let root = workspace_root();
1193        check_orchestration_evidence(
1194            OrchestrationLane::Supercode,
1195            &Evidence::Store {
1196                harness: ORCHESTRATOR_PRESET.into(),
1197                path: "cron/jobs.json".into(),
1198            },
1199            &root,
1200        )
1201        .unwrap();
1202        assert!(check_orchestration_evidence(
1203            OrchestrationLane::Supercode,
1204            &Evidence::Store {
1205                harness: ORCHESTRATOR_PRESET.into(),
1206                path: "cron/no_such_store.json".into(),
1207            },
1208            &root,
1209        )
1210        .is_err());
1211    }
1212
1213    #[test]
1214    fn orchestration_ledger_parses_with_unique_ids_and_every_concept() {
1215        let rows = orchestration_ledger();
1216        let ids: HashSet<&str> = rows.iter().map(|r| r.id.as_str()).collect();
1217        assert_eq!(ids.len(), rows.len(), "row ids must be unique");
1218        let concepts: HashSet<&str> = rows.iter().map(|r| r.concept.as_str()).collect();
1219        let expected: HashSet<&str> = crate::support::ORCHESTRATION_CONCEPTS
1220            .iter()
1221            .copied()
1222            .collect();
1223        assert_eq!(
1224            concepts, expected,
1225            "every ORCHESTRATION_CONCEPTS entry needs at least one row, and no others"
1226        );
1227        for row in &rows {
1228            assert!(!row.verbs.is_empty(), "{}: no verb group", row.id);
1229            assert!(!row.semantics.is_empty(), "{}: no semantics", row.id);
1230            assert!(!row.provenance.is_empty(), "{}: no provenance", row.id);
1231        }
1232    }
1233
1234    #[test]
1235    fn orchestration_not_applicable_rows_are_exactly_those_neither_harness_has() {
1236        for row in orchestration_ledger() {
1237            let neither = !row.hermes.present() && !row.openclaw.present();
1238            assert_eq!(
1239                row.status == Status::NotApplicable,
1240                neither,
1241                "{}: not_applicable must mean neither hermes nor openclaw has it",
1242                row.id
1243            );
1244        }
1245    }
1246
1247    /// The honesty gate for the orchestration ledger: a present harness
1248    /// column must cite a verb the PINNED CLI advertises, and an
1249    /// implemented/partial status must cite a store or symbol that resolves
1250    /// in this workspace.
1251    #[test]
1252    fn every_orchestration_claim_is_backed_by_resolvable_evidence() {
1253        let root = workspace_root();
1254        let mut failures = Vec::new();
1255        for row in orchestration_ledger() {
1256            for harness in ORCHESTRATION_PRESETS {
1257                let (has, detail, evidence) = row.column(harness).unwrap();
1258                if has.present() {
1259                    if detail.is_empty() {
1260                        failures.push(format!("{}: {harness} column has no detail", row.id));
1261                    }
1262                    if evidence.is_empty() {
1263                        failures.push(format!("{}: {harness} column cites no verb", row.id));
1264                    }
1265                } else if !evidence.is_empty() {
1266                    failures.push(format!(
1267                        "{}: {harness} lacks the row but cites {evidence:?}",
1268                        row.id
1269                    ));
1270                }
1271                for ev in evidence {
1272                    if let Err(reason) =
1273                        check_orchestration_evidence(OrchestrationLane::Column(harness), ev, &root)
1274                    {
1275                        failures.push(format!("{}: {reason}", row.id));
1276                    }
1277                }
1278            }
1279            if row.status.requires_evidence() && row.evidence.is_empty() {
1280                failures.push(format!(
1281                    "{}: `{}` cites no evidence",
1282                    row.id,
1283                    row.status.label()
1284                ));
1285            }
1286            if row.status == Status::Absent && row.cost.is_none() {
1287                failures.push(format!("{}: absent without a cost class", row.id));
1288            }
1289            if row.note.is_empty() {
1290                failures.push(format!("{}: no note", row.id));
1291            }
1292            for ev in &row.evidence {
1293                if let Err(reason) =
1294                    check_orchestration_evidence(OrchestrationLane::Supercode, ev, &root)
1295                {
1296                    failures.push(format!("{}: {reason}", row.id));
1297                }
1298            }
1299        }
1300        assert!(
1301            failures.is_empty(),
1302            "orchestration ledger evidence failures:\n{}",
1303            failures.join("\n")
1304        );
1305    }
1306
1307    /// dev/02: the new evidence kinds must bite. Fabricated `cli_verb` and
1308    /// `store` citations are rejected, and neither lane accepts the other's
1309    /// kind.
1310    #[test]
1311    fn orchestration_evidence_gate_rejects_unresolvable_citations() {
1312        let root = workspace_root();
1313        let bad = [
1314            // Verbs the pinned CLIs do not advertise (the inventory claims
1315            // three of these; the pin does not have them).
1316            Evidence::CliVerb {
1317                harness: "hermes".into(),
1318                verb: "cron teleport".into(),
1319            },
1320            Evidence::CliVerb {
1321                harness: "hermes".into(),
1322                verb: "approvals list".into(),
1323            },
1324            Evidence::CliVerb {
1325                harness: "openclaw".into(),
1326                verb: "sessions archive".into(),
1327            },
1328            Evidence::CliVerb {
1329                harness: "openclaw".into(),
1330                verb: "approvals resolve".into(),
1331            },
1332            // A section the fixture never captured.
1333            Evidence::CliVerb {
1334                harness: "hermes".into(),
1335                verb: "kanban list".into(),
1336            },
1337            // A harness with no committed fixture at all.
1338            Evidence::CliVerb {
1339                harness: "claude-code".into(),
1340                verb: "cron list".into(),
1341            },
1342            // Stores no loader in this workspace opens. `state/openclaw.sqlite`
1343            // IS opened, so this case proves the check is per-SEGMENT: the
1344            // outbound delivery QUEUE inside it still resolves to nothing —
1345            // ORCH-13 reads the run log's delivery columns, never the queue.
1346            Evidence::Store {
1347                harness: "openclaw".into(),
1348                path: "state/openclaw.sqlite/delivery_queue_entries".into(),
1349            },
1350            // The table name upstream `main` uses. The PINNED 2026.7.1-2 run
1351            // store is `cron_run_logs`, so this spelling must not resolve.
1352            Evidence::Store {
1353                harness: "openclaw".into(),
1354                path: "cron_run_receipts".into(),
1355            },
1356            Evidence::Store {
1357                harness: "grok".into(),
1358                path: "state.db".into(),
1359            },
1360            Evidence::Store {
1361                harness: "hermes".into(),
1362                path: "<agentId>".into(),
1363            },
1364        ];
1365        for ev in &bad {
1366            let lane = match ev {
1367                Evidence::CliVerb { harness, .. } => OrchestrationLane::Column(harness),
1368                _ => OrchestrationLane::Supercode,
1369            };
1370            assert!(
1371                check_orchestration_evidence(lane, ev, &root).is_err(),
1372                "{ev:?} must be rejected"
1373            );
1374        }
1375        let good = [
1376            Evidence::CliVerb {
1377                harness: "hermes".into(),
1378                verb: "cron list".into(),
1379            },
1380            Evidence::CliVerb {
1381                harness: "openclaw".into(),
1382                verb: "agents bindings".into(),
1383            },
1384            Evidence::Store {
1385                harness: "hermes".into(),
1386                path: "state.db/sessions/session_key".into(),
1387            },
1388            // ORCH-7: the job stores both harnesses keep, now opened by
1389            // `crates/harness/src/jobs.rs`.
1390            Evidence::Store {
1391                harness: "hermes".into(),
1392                path: "profiles/<name>/cron/jobs.json".into(),
1393            },
1394            Evidence::Store {
1395                harness: "openclaw".into(),
1396                path: "cron/jobs.json".into(),
1397            },
1398            // ORCH-8: the fire stores, now opened by
1399            // `crates/harness/src/runs.rs`.
1400            Evidence::Store {
1401                harness: "hermes".into(),
1402                path: "cron/executions.db".into(),
1403            },
1404            Evidence::Store {
1405                harness: "openclaw".into(),
1406                path: "state/openclaw.sqlite/cron_run_logs".into(),
1407            },
1408            // ORCH-13: the delivery ledger, now opened by
1409            // `crates/harness/src/runs.rs`.
1410            Evidence::Store {
1411                harness: "hermes".into(),
1412                path: "state.db/delivery_obligations".into(),
1413            },
1414        ];
1415        for ev in &good {
1416            let lane = match ev {
1417                Evidence::CliVerb { harness, .. } => OrchestrationLane::Column(harness),
1418                _ => OrchestrationLane::Supercode,
1419            };
1420            check_orchestration_evidence(lane, ev, &root).unwrap_or_else(|e| panic!("{ev:?}: {e}"));
1421        }
1422        // The lanes do not accept each other's kinds, and a column may not
1423        // cite the OTHER harness's CLI.
1424        assert!(
1425            check_orchestration_evidence(OrchestrationLane::Supercode, &good[0], &root).is_err()
1426        );
1427        assert!(
1428            check_orchestration_evidence(OrchestrationLane::Column("hermes"), &good[2], &root)
1429                .is_err()
1430        );
1431        assert!(check_orchestration_evidence(
1432            OrchestrationLane::Column("openclaw"),
1433            &good[0],
1434            &root
1435        )
1436        .is_err());
1437    }
1438
1439    /// dev/03: a fixture without its recapture header is unfalsifiable — a
1440    /// reader could not reproduce it against the pin.
1441    #[test]
1442    fn help_fixtures_record_the_pin_and_how_to_recapture() {
1443        for harness in ORCHESTRATION_PRESETS {
1444            let fixture = help_fixture(harness).expect("committed fixture");
1445            let mut lines = fixture.lines();
1446            let first = lines.next().unwrap_or_default();
1447            assert!(
1448                first.starts_with(&format!("# fixture: {harness} CLI help @ ")),
1449                "{harness}: first line must name the harness and the pinned version: {first}"
1450            );
1451            assert!(
1452                first.trim_end().len() > format!("# fixture: {harness} CLI help @ ").len(),
1453                "{harness}: no pinned version in `{first}`"
1454            );
1455            let recapture = fixture
1456                .lines()
1457                .find(|line| line.starts_with("# recapture:"))
1458                .unwrap_or_else(|| panic!("{harness}: no `# recapture:` header line"));
1459            assert!(
1460                recapture.contains("--help"),
1461                "{harness}: recapture line names no command: {recapture}"
1462            );
1463            assert!(
1464                fixture
1465                    .lines()
1466                    .any(|line| line.starts_with("# provenance:")),
1467                "{harness}: no `# provenance:` header line"
1468            );
1469            assert!(
1470                fixture
1471                    .lines()
1472                    .any(|line| line.starts_with(&format!("$ {harness} "))),
1473                "{harness}: fixture captures no `$ {harness} ... --help` section"
1474            );
1475        }
1476        assert!(help_fixture("claude-code").is_none());
1477    }
1478}