Skip to main content

supercode_harness/
support.rs

1//! Canonical implementation inventory for external coding harnesses.
2//!
3//! This registry describes wiring that exists in the compiled core. It does
4//! not claim that a harness has passed a real executable smoke test; the
5//! support audit joins this inventory with behavioral probe receipts and
6//! tracker state before it calls anything verified.
7
8use std::collections::BTreeMap;
9
10use serde::{Deserialize, Serialize};
11
12use crate::{
13    AcpRuntimeBackend, ClaudeCodeRuntimeBackend, CodexRuntimeBackend, HarnessId,
14    OpenCodeRuntimeBackend, PiRuntimeBackend, RuntimeBackend, RuntimeCapabilities,
15    RuntimeConnectLaunch, RuntimeLaunch,
16};
17
18/// Schema emitted by [`harness_support_registry`].
19pub const SUPPORT_REGISTRY_SCHEMA: &str = "supercode.support-registry.v1";
20
21/// How a primitive is wired into the compiled core.
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
23#[serde(rename_all = "snake_case")]
24pub enum ImplementationKind {
25    /// A harness-specific implementation is registered.
26    BuiltIn,
27    /// A protocol-generic implementation is usable with a known launch.
28    GenericProtocol,
29    /// No implementation is present.
30    Absent,
31}
32
33/// Persisted-session and translation implementation facts.
34#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35pub struct NativeSupport {
36    /// Whether the catalog can discover this harness's sessions.
37    pub discover: ImplementationKind,
38    /// Whether the core can load this harness's native persisted format.
39    pub load: ImplementationKind,
40    /// Whether the generic follower can open this harness's native storage.
41    pub follow: ImplementationKind,
42    /// Whether the canonical session can import this native format.
43    pub import: ImplementationKind,
44    /// Whether the canonical session can export this native format.
45    pub export: ImplementationKind,
46}
47
48/// Live runtime wiring known without launching the real executable.
49#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
50pub struct RuntimeSupport {
51    /// Harness-specific or protocol-generic adapter registration.
52    pub implementation: ImplementationKind,
53    /// Protocol spoken by the adapter.
54    pub protocol: String,
55    /// Command used when callers do not provide an override.
56    pub default_launch: Option<RuntimeLaunch>,
57    /// Connect-mode launch for gateway harnesses: where a running endpoint's
58    /// address and credential live in the harness's own config file. `None`
59    /// for spawn-only harnesses; declaring one is an explicit registry
60    /// decision, never inferred.
61    #[serde(default, skip_serializing_if = "Option::is_none")]
62    pub connect_launch: Option<RuntimeConnectLaunch>,
63    /// Static adapter capabilities. Optional protocol features are only true
64    /// for known agents that advertise them; the adapter validates them again
65    /// during the live handshake.
66    pub capabilities: RuntimeCapabilities,
67}
68
69/// One compiled harness implementation descriptor.
70
71/// The twelve Domain 11 concepts, in plan order
72/// (`docs/plans/orchestration-domain-11-2026-09-02.md`).
73pub const ORCHESTRATION_CONCEPTS: &[&str] = &[
74    "scheduled_job",
75    "run",
76    "conversation",
77    "pending_request",
78    "profile",
79    "skills",
80    "memory",
81    "delivery_target",
82    "channel",
83    "routing",
84    "inbound_trigger",
85    "gateway_health",
86];
87
88/// One orchestration concept's tiers for one harness (ORCH-4).
89#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
90pub struct ConceptSupport {
91    /// One of [`ORCHESTRATION_CONCEPTS`].
92    pub concept: String,
93    /// Read tier: supercode lists/inspects the concept from the harness's own files or CLI.
94    pub observed: ImplementationKind,
95    /// Write tier: supercode mutates the concept through the harness's own verb.
96    pub controlled: ImplementationKind,
97    /// `harness.v1.<noun>.<verb>` methods backing the non-`Absent` tiers.
98    #[serde(default, skip_serializing_if = "Vec::is_empty")]
99    pub methods: Vec<String>,
100}
101
102/// Per-concept observed / controlled tiers for one harness (additive to the
103/// v1 registry schema, like `connect_launch`).
104#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
105pub struct OrchestrationSupport {
106    /// Exactly [`ORCHESTRATION_CONCEPTS`], in order.
107    pub concepts: Vec<ConceptSupport>,
108}
109
110#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
111pub struct HarnessSupportDescriptor {
112    /// Stable harness identifier.
113    pub id: HarnessId,
114    /// Human-readable name.
115    pub display_name: String,
116    /// Native persistence/translation implementation.
117    pub native: NativeSupport,
118    /// Live runtime implementation.
119    pub runtime: RuntimeSupport,
120    /// ORCH-4: orchestration concept tiers (defaults to all-`Absent`).
121    #[serde(default)]
122    pub orchestration: OrchestrationSupport,
123}
124
125/// Machine-readable compiled support inventory.
126#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
127pub struct SupportRegistryReport {
128    /// Report schema.
129    pub schema: String,
130    /// Harness descriptors, in stable product order.
131    pub harnesses: Vec<HarnessSupportDescriptor>,
132}
133
134/// Whether a harness can enter its own sandbox by replacing its process image.
135///
136/// WebAssembly has no process replacement, so a harness asked to sandbox itself
137/// there aborts before its handshake. Everything the loader starts on that
138/// target is already confined to the browser it runs in.
139pub(crate) fn self_sandbox_supported() -> bool {
140    !cfg!(target_family = "wasm")
141}
142
143/// Grok refuses its `workspace` sandbox when its home is a symlink ("symlinked GROK_HOME is
144/// not allowed under sandbox write-deny"), so a symlinked `~/.grok` is named by the path it
145/// resolves to: the same directory, which the sandbox can then protect. An explicit
146/// `GROK_HOME` is left to the caller.
147pub(crate) fn grok_home_env() -> BTreeMap<String, String> {
148    let mut env = BTreeMap::new();
149    if std::env::var_os("GROK_HOME").is_none() {
150        if let Some(home) = supercode_interchange::user_home()
151            .map(std::path::PathBuf::into_os_string)
152            .map(std::path::PathBuf::from)
153        {
154            let grok = home.join(".grok");
155            let linked = std::fs::symlink_metadata(&grok)
156                .map(|metadata| metadata.file_type().is_symlink())
157                .unwrap_or(false);
158            if let (true, Ok(resolved)) = (linked, grok.canonicalize()) {
159                env.insert("GROK_HOME".into(), resolved.to_string_lossy().into_owned());
160            }
161        }
162    }
163    env
164}
165
166/// A headless Grok runtime's environment: no agent dashboard, and [`grok_home_env`].
167pub(crate) fn grok_env() -> BTreeMap<String, String> {
168    let mut env = grok_home_env();
169    env.insert("GROK_AGENT_DASHBOARD".into(), "0".into());
170    env
171}
172
173/// Builds Grok's stdio launch, asking it to sandbox itself where it can.
174fn grok_arguments() -> Vec<String> {
175    let mut arguments: Vec<String> = Vec::new();
176    if self_sandbox_supported() {
177        arguments.push("--sandbox".into());
178        arguments.push("workspace".into());
179    }
180    arguments.push("agent".into());
181    arguments.push("--no-leader".into());
182    arguments.push("stdio".into());
183    arguments
184}
185
186fn built_in_native() -> NativeSupport {
187    NativeSupport {
188        discover: ImplementationKind::BuiltIn,
189        load: ImplementationKind::BuiltIn,
190        follow: ImplementationKind::BuiltIn,
191        import: ImplementationKind::BuiltIn,
192        export: ImplementationKind::BuiltIn,
193    }
194}
195
196fn built_in_runtime(
197    backend: &dyn RuntimeBackend,
198    protocol: &str,
199    launch: RuntimeLaunch,
200) -> RuntimeSupport {
201    RuntimeSupport {
202        implementation: ImplementationKind::BuiltIn,
203        protocol: protocol.into(),
204        default_launch: Some(launch),
205        connect_launch: None,
206        capabilities: backend.capabilities(),
207    }
208}
209
210/// Return the single compiled inventory used by product surfaces and audits.
211
212/// Derive a harness's orchestration tiers from what the registry already
213/// proves: a harness whose sessions load natively is `observed` for the
214/// conversation concept (`sessions.discover`/`load`), and a runtime door that
215/// answers protocol requests is `controlled` for pending requests
216/// (`runtimes.respond`). Every other cell is `Absent` until its ORCH item
217/// lands and adds its method here.
218pub fn orchestration_support(descriptor: &HarnessSupportDescriptor) -> OrchestrationSupport {
219    let concepts = ORCHESTRATION_CONCEPTS
220        .iter()
221        .map(|concept| {
222            let (observed, controlled, methods): (
223                ImplementationKind,
224                ImplementationKind,
225                Vec<&str>,
226            ) = match *concept {
227                // ORCH-18: the two harnesses that publish a client-callable
228                // cron verb are also CONTROLLED — supercode runs `hermes cron
229                // …` / `openclaw cron …` on the caller's behalf and re-reads
230                // the row (`crate::jobs_control`). supercode still schedules
231                // nothing itself; the tier means "the harness's own verb is
232                // reachable through one uniform door".
233                "scheduled_job"
234                    if crate::jobs_control::supports_job_control(descriptor.id.as_str()) =>
235                {
236                    (
237                        ImplementationKind::BuiltIn,
238                        ImplementationKind::BuiltIn,
239                        vec![
240                            "harness.v1.jobs.list",
241                            "harness.v1.jobs.get",
242                            "harness.v1.jobs.create",
243                            "harness.v1.jobs.update",
244                            "harness.v1.jobs.pause",
245                            "harness.v1.jobs.resume",
246                            "harness.v1.jobs.run",
247                            "harness.v1.jobs.delete",
248                        ],
249                    )
250                }
251                // ORCH-7: the three harnesses that HAVE scheduled jobs are read
252                // uniformly from their own stores. Claude Code stays read-only
253                // on purpose: its jobs are session-scoped runtime state created
254                // by the model inside a session (`CronCreate`), so there is no
255                // harness verb for a client to call.
256                "scheduled_job" if crate::jobs::supports_jobs(descriptor.id.as_str()) => (
257                    ImplementationKind::BuiltIn,
258                    ImplementationKind::Absent,
259                    vec!["harness.v1.jobs.list", "harness.v1.jobs.get"],
260                ),
261                // ORCH-8: a harness is `observed` for runs when it KEEPS a
262                // fire store the loader in `crate::runs` opens. Claude Code
263                // has scheduled jobs but no run store — its fires are turns —
264                // so it is deliberately absent here while `scheduled_job`
265                // above is built-in for it.
266                "run" if crate::runs::supports_runs(descriptor.id.as_str()) => (
267                    ImplementationKind::BuiltIn,
268                    ImplementationKind::Absent,
269                    vec!["harness.v1.runs.list", "harness.v1.runs.get"],
270                ),
271                // ORCH-19: a harness is CONTROLLED for conversations when it
272                // publishes at least one lifecycle DOOR supercode can drive —
273                // Codex's `archive`/`delete` CLI verbs, OpenCode's HTTP session
274                // API, Hermes's and OpenClaw's `/new`/`/reset` slash commands
275                // typed into a live driven session, Hermes's `sessions delete`,
276                // and supercode's own store. The advertised methods come from
277                // `sessions_control`'s own door table, so a method can never be
278                // listed here without a door behind it. Claude Code stays
279                // read-only on purpose: it publishes no lifecycle verb at all
280                // (its sessions expire on a retention window it owns).
281                "conversation"
282                    if descriptor.native.load == ImplementationKind::BuiltIn
283                        && !crate::sessions_control::controlled_methods(descriptor.id.as_str())
284                            .is_empty() =>
285                {
286                    let mut methods =
287                        vec!["harness.v1.sessions.discover", "harness.v1.sessions.load"];
288                    methods.extend(crate::sessions_control::controlled_methods(
289                        descriptor.id.as_str(),
290                    ));
291                    (
292                        ImplementationKind::BuiltIn,
293                        ImplementationKind::BuiltIn,
294                        methods,
295                    )
296                }
297                // ORC-7: the orchestrator's conversations are its BINDINGS,
298                // discovered from every profile folder's `bindings` table
299                // (`supercode_interchange::catalog::discover_orchestrator`). They are
300                // observed, not loadable: the transcript belongs to the
301                // worker harness the binding addresses and is read through
302                // that harness's own `sessions.load`.
303                // ORC-13 makes them CONTROLLED: `/new` and `/reset` are the
304                // two chat commands the daemon's reducer applies to a binding
305                // (`docs/ORCHESTRATOR-IR.md` §4.5), and the operator door now
306                // reaches that reducer from outside a chat — the daemon's own
307                // socket, or its package's CLI when the daemon is down. The
308                // methods come from `sessions_control`'s door table, so a
309                // method can never be advertised without a door behind it.
310                "conversation" if descriptor.id.as_str() == HarnessId::ORCHESTRATOR => {
311                    let mut methods = vec!["harness.v1.sessions.discover"];
312                    methods.extend(crate::sessions_control::controlled_methods(
313                        descriptor.id.as_str(),
314                    ));
315                    (
316                        ImplementationKind::BuiltIn,
317                        ImplementationKind::BuiltIn,
318                        methods,
319                    )
320                }
321                "conversation" if descriptor.native.load == ImplementationKind::BuiltIn => (
322                    ImplementationKind::BuiltIn,
323                    ImplementationKind::Absent,
324                    vec!["harness.v1.sessions.discover", "harness.v1.sessions.load"],
325                ),
326                // ORCH-9: a harness is `observed` for pending requests when
327                // its runtime door can carry one — the same flag that makes
328                // it `controlled`, because at the pinned versions the LIVE
329                // request IS the only uniform source (no harness stores
330                // approvals; see `crate::approvals`).
331                // ORCH-20 adds `harness.v1.approvals.resolve` to the
332                // controlled tier: one uniform decision, translated onto the
333                // request's own options and sent through `runtimes.respond`.
334                "pending_request" if descriptor.runtime.capabilities.respond_to_requests => (
335                    ImplementationKind::BuiltIn,
336                    ImplementationKind::BuiltIn,
337                    vec![
338                        "harness.v1.approvals.list",
339                        "harness.v1.approvals.resolve",
340                        "harness.v1.runtimes.respond",
341                    ],
342                ),
343                // ORCH-21: the two harnesses that publish a client-callable
344                // profile lifecycle verb are also CONTROLLED — supercode runs
345                // `hermes profile create|delete` / `openclaw agents
346                // add|delete` on the caller's behalf and re-reads the row
347                // (`crate::profiles_control`). supercode still owns no config
348                // plane; the tier means "the harness's own verb is reachable
349                // through one uniform door".
350                "profile"
351                    if crate::profiles_control::supports_profile_control(
352                        descriptor.id.as_str(),
353                    ) =>
354                {
355                    (
356                        ImplementationKind::BuiltIn,
357                        ImplementationKind::BuiltIn,
358                        vec![
359                            "harness.v1.profiles.list",
360                            "harness.v1.profiles.get",
361                            "harness.v1.profiles.create",
362                            "harness.v1.profiles.delete",
363                        ],
364                    )
365                }
366                // ORCH-10: the profile noun is read for the four harnesses
367                // that have one — supercode's presets, Codex's
368                // `[profiles.<name>]` tables, Hermes's profile homes, and
369                // OpenClaw's agent homes. Every other harness refuses. Codex
370                // and supercode stay read-only on purpose: a Codex profile is
371                // a table a human authors in `config.toml` and a supercode
372                // preset is compiled-in code, so neither publishes a verb a
373                // client could call.
374                "profile"
375                    if crate::profiles::PROFILE_HARNESSES.contains(&descriptor.id.as_str()) =>
376                {
377                    (
378                        ImplementationKind::BuiltIn,
379                        ImplementationKind::Absent,
380                        vec!["harness.v1.profiles.list", "harness.v1.profiles.get"],
381                    )
382                }
383                // ORCH-11: a harness is `observed` for skills when the loader
384                // in `crate::skills` opens its documented skill roots.
385                // ORCH-22 makes those same harnesses `controlled`: each one
386                // publishes a skills door supercode drives — `hermes skills
387                // install|uninstall`, `openclaw skills install`, and for the
388                // core four the loader's own directory, which IS their only
389                // skills door. supercode resolves no registry and unpacks no
390                // archive; a verb a harness lacks (OpenClaw has no `skills
391                // remove` at the pin) refuses with UnsupportedAction.
392                "skills"
393                    if crate::skills_control::supports_skill_control(descriptor.id.as_str()) =>
394                {
395                    (
396                        ImplementationKind::BuiltIn,
397                        ImplementationKind::BuiltIn,
398                        vec![
399                            "harness.v1.skills.list",
400                            "harness.v1.skills.install",
401                            "harness.v1.skills.remove",
402                        ],
403                    )
404                }
405                // ORCH-13: a delivery target is a FIELD on a job or a run,
406                // not a noun with verbs of its own, so it is observed exactly
407                // where those rows are — `deliver` on every job harness, and
408                // the delivery record on the two that keep a fire store.
409                // Nothing is controlled: supercode never sends.
410                "delivery_target" if crate::jobs::supports_jobs(descriptor.id.as_str()) => {
411                    let mut methods = vec!["harness.v1.jobs.list", "harness.v1.jobs.get"];
412                    if crate::runs::supports_runs(descriptor.id.as_str()) {
413                        methods.push("harness.v1.runs.list");
414                        methods.push("harness.v1.runs.get");
415                    }
416                    (
417                        ImplementationKind::BuiltIn,
418                        ImplementationKind::Absent,
419                        methods,
420                    )
421                }
422                // ORCH-14: the channel noun is read for the two gateway
423                // harnesses that HAVE install-scoped channels — Hermes's
424                // `platforms:` blocks and OpenClaw's `channels.<name>`
425                // entries. Claude Code's channels are MCP servers that
426                // declare the capability over the protocol, not in a config
427                // file, so it is refused rather than guessed at.
428                // ORCH-17: gateway state/endpoint on the inventory row, derived from the
429                // UNI-7 running-instance probe and the harness's own config.
430                "gateway_health"
431                    if matches!(
432                        descriptor.id.as_str(),
433                        // ORC-7: the orchestrator's gateway state is its
434                        // daemon lease (`<home>/orchestrator.lock` plus a
435                        // liveness check on the pid it names), reported on
436                        // the same `harnesses.list` row as the other two.
437                        HarnessId::HERMES | HarnessId::OPENCLAW | HarnessId::ORCHESTRATOR
438                    ) =>
439                {
440                    (
441                        ImplementationKind::BuiltIn,
442                        ImplementationKind::Absent,
443                        vec!["harness.v1.harnesses.list"],
444                    )
445                }
446                // ORCH-16: inbound webhook routes / hook mappings from the same configs.
447                "inbound_trigger"
448                    if crate::triggers::TRIGGER_HARNESSES.contains(&descriptor.id.as_str()) =>
449                {
450                    (
451                        ImplementationKind::BuiltIn,
452                        ImplementationKind::Absent,
453                        vec!["harness.v1.triggers.list"],
454                    )
455                }
456                // ORCH-15: routing entries read from the same gateway configs.
457                "routing" if crate::routes::ROUTE_HARNESSES.contains(&descriptor.id.as_str()) => (
458                    ImplementationKind::BuiltIn,
459                    ImplementationKind::Absent,
460                    vec!["harness.v1.routes.list"],
461                ),
462                "channel"
463                    if crate::channels::CHANNEL_HARNESSES.contains(&descriptor.id.as_str()) =>
464                {
465                    (
466                        ImplementationKind::BuiltIn,
467                        ImplementationKind::Absent,
468                        vec!["harness.v1.channels.list", "harness.v1.channels.status"],
469                    )
470                }
471                // ORCH-12: a harness is `observed` for memory when
472                // `crate::memory` opens its own persistent memory documents —
473                // Claude Code's per-project auto-memory directory, Hermes's
474                // `memories/MEMORY.md`/`USER.md` per profile home, and
475                // OpenClaw memory-core's workspace files. Nothing is
476                // controlled: forget/reset stay the harness's own verb.
477                "memory" if crate::memory::supports_memory(descriptor.id.as_str()) => (
478                    ImplementationKind::BuiltIn,
479                    ImplementationKind::Absent,
480                    vec!["harness.v1.memory.show", "harness.v1.memory.search"],
481                ),
482                _ => (
483                    ImplementationKind::Absent,
484                    ImplementationKind::Absent,
485                    vec![],
486                ),
487            };
488            ConceptSupport {
489                concept: (*concept).to_string(),
490                observed,
491                controlled,
492                methods: methods.into_iter().map(str::to_string).collect(),
493            }
494        })
495        .collect();
496    OrchestrationSupport { concepts }
497}
498
499pub fn harness_support_registry() -> SupportRegistryReport {
500    let claude = ClaudeCodeRuntimeBackend::new();
501    let codex = CodexRuntimeBackend::new();
502    let opencode = OpenCodeRuntimeBackend::new();
503    let pi = PiRuntimeBackend::new();
504    let grok_launch = RuntimeLaunch {
505        program: "grok".into(),
506        arguments: grok_arguments(),
507        env: grok_env(),
508    };
509    let grok = AcpRuntimeBackend::new(HarnessId::from(HarnessId::GROK), grok_launch.clone())
510        .with_resume_support(true);
511    let gemini_launch = RuntimeLaunch {
512        program: "gemini".into(),
513        // PARITY-24 drift 2026-08-31: gemini-cli 0.29.x renamed the ACP
514        // flag; `--acp` is rejected with "Unknown argument". Verified live:
515        // `--experimental-acp` completes the v1 initialize handshake.
516        arguments: vec!["--experimental-acp".into()],
517        env: BTreeMap::new(),
518    };
519    let gemini = AcpRuntimeBackend::new(HarnessId::from(HarnessId::GEMINI), gemini_launch.clone())
520        .with_resume_support(true);
521    let goose_launch = RuntimeLaunch {
522        program: "goose".into(),
523        arguments: vec!["acp".into()],
524        env: BTreeMap::new(),
525    };
526    let goose = AcpRuntimeBackend::new(HarnessId::from(HarnessId::GOOSE), goose_launch.clone())
527        .with_resume_support(true);
528    let hermes_launch = RuntimeLaunch {
529        program: "hermes-acp".into(),
530        arguments: Vec::new(),
531        env: BTreeMap::new(),
532    };
533    let hermes = AcpRuntimeBackend::new(HarnessId::from(HarnessId::HERMES), hermes_launch.clone())
534        .with_resume_support(true);
535    let openclaw_launch = RuntimeLaunch {
536        // `openclaw acp` is a stdio ACP bridge that CONNECTS to a running
537        // Gateway (never spawns one); with no flags it resolves the gateway
538        // target from OpenClaw's own config. The explicit-endpoint variant is
539        // the connect_launch below.
540        program: "openclaw".into(),
541        arguments: vec!["acp".into()],
542        env: BTreeMap::new(),
543    };
544    let openclaw = AcpRuntimeBackend::new(
545        HarnessId::from(HarnessId::OPENCLAW),
546        openclaw_launch.clone(),
547    )
548    .with_resume_support(true);
549    let supercode_launch = RuntimeLaunch {
550        program: "supercode".into(),
551        arguments: vec!["acp".into()],
552        env: BTreeMap::new(),
553    };
554    let supercode = AcpRuntimeBackend::new(
555        HarnessId::from(HarnessId::SUPERCODE),
556        supercode_launch.clone(),
557    )
558    .with_resume_support(true);
559
560    let mut report = SupportRegistryReport {
561        schema: SUPPORT_REGISTRY_SCHEMA.into(),
562        harnesses: vec![
563            HarnessSupportDescriptor {
564                id: HarnessId::from(HarnessId::CLAUDE_CODE),
565                display_name: "Claude Code".into(),
566                orchestration: OrchestrationSupport::default(),
567                native: built_in_native(),
568                // the backend's own prefix: a published launch that omitted the
569                // stream-json flags started the interactive TUI on a pipe when
570                // handed back through `RuntimeStart.launch`
571                runtime: built_in_runtime(&claude, "claude-stream-json", claude.launch().clone()),
572            },
573            HarnessSupportDescriptor {
574                id: HarnessId::from(HarnessId::CODEX),
575                display_name: "Codex".into(),
576                orchestration: OrchestrationSupport::default(),
577                native: built_in_native(),
578                runtime: built_in_runtime(
579                    &codex,
580                    "codex-app-server-jsonl",
581                    RuntimeLaunch {
582                        program: "codex".into(),
583                        arguments: vec!["app-server".into()],
584                        env: BTreeMap::new(),
585                    },
586                ),
587            },
588            HarnessSupportDescriptor {
589                id: HarnessId::from(HarnessId::OPENCODE),
590                display_name: "OpenCode".into(),
591                orchestration: OrchestrationSupport::default(),
592                native: built_in_native(),
593                runtime: built_in_runtime(
594                    &opencode,
595                    "opencode-http-sse",
596                    RuntimeLaunch {
597                        program: "opencode".into(),
598                        arguments: vec!["serve".into()],
599                        env: BTreeMap::new(),
600                    },
601                ),
602            },
603            HarnessSupportDescriptor {
604                id: HarnessId::from(HarnessId::PI),
605                display_name: "Pi".into(),
606                orchestration: OrchestrationSupport::default(),
607                native: built_in_native(),
608                runtime: built_in_runtime(
609                    &pi,
610                    "pi-rpc-jsonl",
611                    RuntimeLaunch {
612                        program: "pi".into(),
613                        arguments: vec!["--mode".into(), "rpc".into()],
614                        env: BTreeMap::new(),
615                    },
616                ),
617            },
618            HarnessSupportDescriptor {
619                id: HarnessId::from(HarnessId::GROK),
620                display_name: "Grok".into(),
621                orchestration: OrchestrationSupport::default(),
622                native: built_in_native(),
623                runtime: RuntimeSupport {
624                    implementation: ImplementationKind::GenericProtocol,
625                    protocol: "acp-v1-jsonrpc".into(),
626                    default_launch: Some(grok_launch),
627                    connect_launch: None,
628                    capabilities: grok.capabilities(),
629                },
630            },
631            HarnessSupportDescriptor {
632                id: HarnessId::from(HarnessId::GEMINI),
633                display_name: "Gemini CLI".into(),
634                orchestration: OrchestrationSupport::default(),
635                native: built_in_native(),
636                runtime: RuntimeSupport {
637                    implementation: ImplementationKind::GenericProtocol,
638                    protocol: "acp-v1-jsonrpc".into(),
639                    default_launch: Some(gemini_launch),
640                    connect_launch: None,
641                    capabilities: gemini.capabilities(),
642                },
643            },
644            HarnessSupportDescriptor {
645                id: HarnessId::from(HarnessId::GOOSE),
646                display_name: "Goose".into(),
647                orchestration: OrchestrationSupport::default(),
648                native: built_in_native(),
649                runtime: RuntimeSupport {
650                    implementation: ImplementationKind::GenericProtocol,
651                    protocol: "acp-v1-jsonrpc".into(),
652                    default_launch: Some(goose_launch),
653                    connect_launch: None,
654                    capabilities: goose.capabilities(),
655                },
656            },
657            HarnessSupportDescriptor {
658                id: HarnessId::from(HarnessId::HERMES),
659                display_name: "Hermes Agent".into(),
660                orchestration: OrchestrationSupport::default(),
661                native: NativeSupport {
662                    // UNI-15 read-only tier: discovery + load over the
663                    // state.db SQLite store. Follow/import stay Absent.
664                    // EXPORT (UNI-18) goes through Hermes's own door:
665                    // `hermes sessions import --from codex` (0.21.0), which
666                    // writes the store with Hermes's own writer — supercode
667                    // never writes a live Hermes store itself. The tier
668                    // stays driven (matrix membership is UNI-17's flip).
669                    discover: ImplementationKind::BuiltIn,
670                    load: ImplementationKind::BuiltIn,
671                    follow: ImplementationKind::Absent,
672                    import: ImplementationKind::Absent,
673                    export: ImplementationKind::GenericProtocol,
674                },
675                runtime: RuntimeSupport {
676                    implementation: ImplementationKind::GenericProtocol,
677                    protocol: "acp-v1-jsonrpc".into(),
678                    default_launch: Some(hermes_launch),
679                    connect_launch: None,
680                    capabilities: hermes.capabilities(),
681                },
682            },
683            HarnessSupportDescriptor {
684                id: HarnessId::from(HarnessId::OPENCLAW),
685                display_name: "OpenClaw".into(),
686                orchestration: OrchestrationSupport::default(),
687                native: NativeSupport {
688                    // UNI-16 read-only tier: discovery over
689                    // `agents/<id>/sessions/*.jsonl` and the pi-v3-dialect
690                    // loader (`from_openclaw_str`). Import (translate IN),
691                    // export (write OUT), and follow stay Absent — the write
692                    // path is a permanent skip, and the TIER stays `driven`:
693                    // matrix membership remains UNI-17's priced flip.
694                    discover: ImplementationKind::BuiltIn,
695                    load: ImplementationKind::BuiltIn,
696                    follow: ImplementationKind::Absent,
697                    import: ImplementationKind::Absent,
698                    export: ImplementationKind::Absent,
699                },
700                runtime: RuntimeSupport {
701                    implementation: ImplementationKind::GenericProtocol,
702                    protocol: "acp-v1-jsonrpc".into(),
703                    default_launch: Some(openclaw_launch),
704                    // Blind-walk finding 2026-08-31: `gateway.url` is NOT a
705                    // key openclaw's config schema accepts (the gateway
706                    // rejects the whole file as invalid config). The real
707                    // shape: an optional full URL at `gateway.remote.url`, a
708                    // bare `gateway.port` number, or nothing at all — the
709                    // documented out-of-the-box endpoint is ws://127.0.0.1:18789.
710                    connect_launch: Some(RuntimeConnectLaunch {
711                        config_path: "~/.openclaw/openclaw.json".into(),
712                        address_pointer: "/gateway/remote/url".into(),
713                        port_pointer: Some("/gateway/port".into()),
714                        default_address: Some("ws://127.0.0.1:18789".into()),
715                        auth_pointer: Some("/gateway/auth/token".into()),
716                        protocol: "acp-v1-jsonrpc".into(),
717                    }),
718                    capabilities: openclaw.capabilities(),
719                },
720            },
721            // ORC-7: the orchestrator is a harness id so the EXISTING
722            // orchestration readers list its state — its folder is a
723            // Hermes-shaped home (`docs/ORCHESTRATOR-IR.md` §6) and each
724            // reader is pointed at it with no new reader code. It has no
725            // native session tier of its own: it keeps no transcripts, only
726            // BINDINGS that address a WORKER harness's session, which is read
727            // through that harness's own door. It has no runtime either — the
728            // daemon is a Node process the operator verbs start and stop, not
729            // an adapter supercode connects a turn to.
730            HarnessSupportDescriptor {
731                id: HarnessId::from(HarnessId::ORCHESTRATOR),
732                display_name: "Orchestrator".into(),
733                orchestration: OrchestrationSupport::default(),
734                native: NativeSupport {
735                    discover: ImplementationKind::Absent,
736                    load: ImplementationKind::Absent,
737                    follow: ImplementationKind::Absent,
738                    import: ImplementationKind::Absent,
739                    export: ImplementationKind::Absent,
740                },
741                runtime: RuntimeSupport {
742                    implementation: ImplementationKind::Absent,
743                    protocol: "none".into(),
744                    default_launch: None,
745                    connect_launch: None,
746                    capabilities: RuntimeCapabilities {
747                        start_session: false,
748                        resume_session: false,
749                        attach_existing_process: false,
750                        send_input: false,
751                        stream_events: false,
752                        interrupt: false,
753                        steer: false,
754                        respond_to_requests: false,
755                    },
756                },
757            },
758            HarnessSupportDescriptor {
759                id: HarnessId::from(HarnessId::SUPERCODE),
760                display_name: "Volter Harness".into(),
761                orchestration: OrchestrationSupport::default(),
762                native: built_in_native(),
763                runtime: RuntimeSupport {
764                    implementation: ImplementationKind::GenericProtocol,
765                    protocol: "acp-v1-jsonrpc".into(),
766                    default_launch: Some(supercode_launch),
767                    connect_launch: None,
768                    capabilities: supercode.capabilities(),
769                },
770            },
771        ],
772    };
773    for descriptor in &mut report.harnesses {
774        descriptor.orchestration = orchestration_support(descriptor);
775    }
776    report
777}
778
779/// Look up one harness in the compiled registry.
780pub fn harness_support(id: &str) -> Option<HarnessSupportDescriptor> {
781    harness_support_registry()
782        .harnesses
783        .into_iter()
784        .find(|harness| harness.id.as_str() == id)
785}
786
787#[cfg(test)]
788mod tests {
789    use super::*;
790
791    #[test]
792    fn claude_code_default_launch_is_the_stream_json_prefix() {
793        let claude = harness_support_registry()
794            .harnesses
795            .into_iter()
796            .find(|h| h.id.as_str() == HarnessId::CLAUDE_CODE)
797            .unwrap();
798        let launch = claude.runtime.default_launch.unwrap();
799        assert_eq!(launch.program, "claude");
800        let joined = launch.arguments.join(" ");
801        assert!(joined.contains("--input-format stream-json"), "{joined}");
802        assert!(joined.contains("--output-format stream-json"), "{joined}");
803        assert!(
804            joined.contains("--permission-prompt-tool stdio"),
805            "{joined}"
806        );
807    }
808
809    #[test]
810    fn grok_asks_for_a_self_sandbox_only_where_one_is_possible() {
811        let arguments = grok_arguments();
812        assert_eq!(
813            arguments.iter().any(|argument| argument == "--sandbox"),
814            self_sandbox_supported(),
815        );
816        assert!(
817            arguments.ends_with(&["agent".into(), "--no-leader".into(), "stdio".into()]),
818            "{arguments:?}",
819        );
820    }
821
822    #[test]
823    fn registry_is_unique_and_reports_all_native_support() {
824        let report = harness_support_registry();
825        assert_eq!(report.schema, SUPPORT_REGISTRY_SCHEMA);
826        // Ten harnesses plus the orchestrator (ORC-7), which is a registry id
827        // with orchestration tiers and no native or runtime tier of its own.
828        assert_eq!(report.harnesses.len(), 11);
829        let ids = report
830            .harnesses
831            .iter()
832            .map(|harness| harness.id.as_str())
833            .collect::<std::collections::BTreeSet<_>>();
834        assert_eq!(ids.len(), report.harnesses.len());
835
836        let grok = report
837            .harnesses
838            .iter()
839            .find(|harness| harness.id.as_str() == HarnessId::GROK)
840            .unwrap();
841        assert_eq!(grok.native.discover, ImplementationKind::BuiltIn);
842        assert_eq!(grok.native.load, ImplementationKind::BuiltIn);
843        assert_eq!(grok.native.follow, ImplementationKind::BuiltIn);
844        assert_eq!(grok.native.import, ImplementationKind::BuiltIn);
845        for id in [HarnessId::GEMINI, HarnessId::SUPERCODE] {
846            let harness = report
847                .harnesses
848                .iter()
849                .find(|harness| harness.id.as_str() == id)
850                .unwrap();
851            assert_eq!(harness.native.discover, ImplementationKind::BuiltIn);
852            assert_eq!(harness.native.load, ImplementationKind::BuiltIn);
853            assert_eq!(harness.native.follow, ImplementationKind::BuiltIn);
854        }
855        assert_eq!(grok.native.export, ImplementationKind::BuiltIn);
856        assert_eq!(
857            grok.runtime.implementation,
858            ImplementationKind::GenericProtocol
859        );
860        let expected: Vec<&str> = if self_sandbox_supported() {
861            vec!["--sandbox", "workspace", "agent", "--no-leader", "stdio"]
862        } else {
863            vec!["agent", "--no-leader", "stdio"]
864        };
865        assert_eq!(
866            grok.runtime.default_launch.as_ref().unwrap().arguments,
867            expected
868        );
869        assert!(!grok
870            .runtime
871            .default_launch
872            .as_ref()
873            .unwrap()
874            .arguments
875            .iter()
876            .any(|argument| argument == "--always-approve"));
877        assert!(grok.runtime.capabilities.resume_session);
878    }
879
880    /// UNI-5 dev/03: every OpenClaw path is gateway-mediated — the registry
881    /// declares NO native primitive, so no supercode code path can open the
882    /// openclaw-agent SQLite store (direct-DB-write-as-product is a permanent
883    /// skip; the read tier is UNI-16's gated wave). The connect launch stores
884    /// pointers into openclaw's config, never endpoint or credential values.
885    #[test]
886    fn openclaw_registers_gateway_mediated_with_no_store_access() {
887        let report = harness_support_registry();
888        let openclaw = report
889            .harnesses
890            .iter()
891            .find(|harness| harness.id.as_str() == HarnessId::OPENCLAW)
892            .expect("openclaw must be registered");
893        assert_eq!(openclaw.display_name, "OpenClaw");
894        // UNI-16 read tier: discover + load are BuiltIn (pi-v3-dialect
895        // files); follow/import/EXPORT stay Absent — no code path can WRITE
896        // the openclaw store, and the tier stays driven (matrix membership
897        // remains UNI-17's priced flip).
898        assert_eq!(openclaw.native.discover, ImplementationKind::BuiltIn);
899        assert_eq!(openclaw.native.load, ImplementationKind::BuiltIn);
900        for kind in [
901            openclaw.native.follow,
902            openclaw.native.import,
903            openclaw.native.export,
904        ] {
905            assert_eq!(kind, ImplementationKind::Absent);
906        }
907        assert_eq!(
908            openclaw.runtime.implementation,
909            ImplementationKind::GenericProtocol
910        );
911        assert_eq!(openclaw.runtime.protocol, "acp-v1-jsonrpc");
912        let launch = openclaw.runtime.default_launch.as_ref().unwrap();
913        assert_eq!(launch.program, "openclaw");
914        assert_eq!(launch.arguments, ["acp"]);
915        let connect = openclaw.runtime.connect_launch.as_ref().unwrap();
916        assert_eq!(connect.config_path, "~/.openclaw/openclaw.json");
917        // Blind-walk correction 2026-08-31: openclaw's schema has no
918        // `gateway.url`; the real chain is remote.url -> port -> the
919        // documented default endpoint.
920        assert_eq!(connect.address_pointer, "/gateway/remote/url");
921        assert_eq!(connect.port_pointer.as_deref(), Some("/gateway/port"));
922        assert_eq!(
923            connect.default_address.as_deref(),
924            Some("ws://127.0.0.1:18789")
925        );
926        assert_eq!(connect.auth_pointer.as_deref(), Some("/gateway/auth/token"));
927        // Executed dialect probe
928        // (docs/interop/research/openclaw-acp-dialect-2026-08-30.json):
929        // resume + list advertised on >= 2026.7.
930        assert!(openclaw.runtime.capabilities.resume_session);
931    }
932
933    #[test]
934    fn hermes_registers_as_a_driven_tier_acp_entry_without_native_claims() {
935        let report = harness_support_registry();
936        let hermes = report
937            .harnesses
938            .iter()
939            .find(|harness| harness.id.as_str() == HarnessId::HERMES)
940            .expect("hermes must be registered");
941        assert_eq!(hermes.display_name, "Hermes Agent");
942        // UNI-15 read tier: discover + load BuiltIn over state.db;
943        // follow/import stay Absent; export is Hermes's own door (UNI-18).
944        assert_eq!(hermes.native.discover, ImplementationKind::BuiltIn);
945        assert_eq!(hermes.native.load, ImplementationKind::BuiltIn);
946        for kind in [hermes.native.follow, hermes.native.import] {
947            assert_eq!(kind, ImplementationKind::Absent);
948        }
949        assert_eq!(hermes.native.export, ImplementationKind::GenericProtocol);
950        assert_eq!(
951            hermes.runtime.implementation,
952            ImplementationKind::GenericProtocol
953        );
954        assert_eq!(hermes.runtime.protocol, "acp-v1-jsonrpc");
955        let launch = hermes.runtime.default_launch.as_ref().unwrap();
956        assert_eq!(launch.program, "hermes-acp");
957        assert!(launch.arguments.is_empty());
958        assert!(hermes.runtime.connect_launch.is_none());
959        // Verified against the executed dialect probe
960        // (docs/interop/research/hermes-acp-dialect-2026-08-30.json):
961        // loadSession + sessionCapabilities.resume are advertised.
962        assert!(hermes.runtime.capabilities.resume_session);
963        assert!(!hermes.runtime.capabilities.attach_existing_process);
964    }
965
966    #[test]
967    fn connect_mode_descriptor_round_trips_the_registry_schema() {
968        let descriptor = HarnessSupportDescriptor {
969            id: HarnessId::from("openclaw"),
970            display_name: "OpenClaw".into(),
971            orchestration: OrchestrationSupport::default(),
972            native: NativeSupport {
973                discover: ImplementationKind::Absent,
974                load: ImplementationKind::Absent,
975                follow: ImplementationKind::Absent,
976                import: ImplementationKind::Absent,
977                export: ImplementationKind::Absent,
978            },
979            runtime: RuntimeSupport {
980                implementation: ImplementationKind::GenericProtocol,
981                protocol: "acp-v1-jsonrpc".into(),
982                default_launch: None,
983                connect_launch: Some(RuntimeConnectLaunch {
984                    config_path: "~/.openclaw/openclaw.json".into(),
985                    address_pointer: "/gateway/url".into(),
986                    port_pointer: None,
987                    default_address: None,
988                    auth_pointer: Some("/gateway/token".into()),
989                    protocol: "acp-v1-jsonrpc".into(),
990                }),
991                capabilities: RuntimeCapabilities {
992                    start_session: true,
993                    resume_session: false,
994                    attach_existing_process: true,
995                    send_input: true,
996                    stream_events: true,
997                    interrupt: false,
998                    steer: false,
999                    respond_to_requests: false,
1000                },
1001            },
1002        };
1003        let encoded = serde_json::to_value(&descriptor).unwrap();
1004        assert_eq!(
1005            encoded["runtime"]["connect_launch"]["address_pointer"],
1006            "/gateway/url"
1007        );
1008        let decoded: HarnessSupportDescriptor = serde_json::from_value(encoded).unwrap();
1009        assert_eq!(decoded, descriptor);
1010    }
1011
1012    #[test]
1013    fn spawn_only_registry_entries_do_not_serialize_a_connect_launch() {
1014        let report = harness_support_registry();
1015        for harness in &report.harnesses {
1016            let encoded = serde_json::to_string(harness).unwrap();
1017            if harness.id.as_str() == HarnessId::OPENCLAW {
1018                // The one declared connect-mode entry (UNI-5): endpoint and
1019                // credential POINTERS plus the harness's DOCUMENTED default
1020                // endpoint — never resolved values or credentials.
1021                assert!(encoded.contains("connect_launch"));
1022                assert!(encoded.contains("/gateway/auth/token"));
1023                assert!(encoded.contains("ws://127.0.0.1:18789"));
1024                assert!(!encoded.contains("token\":\"ws"));
1025            } else {
1026                assert!(
1027                    !encoded.contains("connect_launch"),
1028                    "{} must stay spawn-only",
1029                    harness.id.as_str()
1030                );
1031            }
1032        }
1033        let encoded = serde_json::to_string(&report).unwrap();
1034        let decoded: SupportRegistryReport = serde_json::from_str(&encoded).unwrap();
1035        assert_eq!(decoded, report);
1036    }
1037
1038    /// ORCH-4: every harness carries all twelve concepts; every method a
1039    /// non-Absent tier cites is a real service method.
1040    #[test]
1041    fn orchestration_block_is_complete_and_its_methods_exist() {
1042        let report = harness_support_registry();
1043        for harness in &report.harnesses {
1044            let names: Vec<&str> = harness
1045                .orchestration
1046                .concepts
1047                .iter()
1048                .map(|c| c.concept.as_str())
1049                .collect();
1050            assert_eq!(names, ORCHESTRATION_CONCEPTS, "{}", harness.id.as_str());
1051            for concept in &harness.orchestration.concepts {
1052                let any_built_in = concept.observed == ImplementationKind::BuiltIn
1053                    || concept.controlled == ImplementationKind::BuiltIn;
1054                assert_eq!(
1055                    any_built_in,
1056                    !concept.methods.is_empty(),
1057                    "{}/{}: a BuiltIn tier must cite methods and an Absent one must not",
1058                    harness.id.as_str(),
1059                    concept.concept
1060                );
1061                for method in &concept.methods {
1062                    assert!(
1063                        crate::harness_service::HARNESS_SERVICE_METHODS.contains(&method.as_str()),
1064                        "{}/{}: `{method}` is not a harness service method",
1065                        harness.id.as_str(),
1066                        concept.concept
1067                    );
1068                }
1069            }
1070        }
1071        // Today's honest floor: conversation is observed wherever sessions load
1072        // natively; pending requests are controlled wherever the door responds.
1073        let hermes = report
1074            .harnesses
1075            .iter()
1076            .find(|h| h.id.as_str() == HarnessId::HERMES)
1077            .unwrap();
1078        let conv = &hermes.orchestration.concepts[2];
1079        assert_eq!(conv.concept, "conversation");
1080        assert_eq!(conv.observed, ImplementationKind::BuiltIn);
1081        // ORCH-19: Hermes is controlled through the doors it actually has —
1082        // `/reset` inside a live session, plus `hermes sessions delete`. It
1083        // has no per-session archive verb, and its ACP door does not carry
1084        // `/new` (a gateway-only command), so neither is advertised.
1085        assert_eq!(conv.controlled, ImplementationKind::BuiltIn);
1086        assert_eq!(
1087            conv.methods,
1088            vec![
1089                "harness.v1.sessions.discover",
1090                "harness.v1.sessions.load",
1091                "harness.v1.sessions.reset",
1092                "harness.v1.sessions.delete",
1093            ]
1094        );
1095        // OpenClaw's ACP door advertises both `/new` and `/reset` at the pin,
1096        // and it has neither archive nor delete.
1097        let openclaw_conv = &report
1098            .harnesses
1099            .iter()
1100            .find(|h| h.id.as_str() == HarnessId::OPENCLAW)
1101            .unwrap()
1102            .orchestration
1103            .concepts[2];
1104        assert_eq!(
1105            openclaw_conv.methods,
1106            vec![
1107                "harness.v1.sessions.discover",
1108                "harness.v1.sessions.load",
1109                "harness.v1.sessions.new",
1110                "harness.v1.sessions.reset",
1111            ]
1112        );
1113        // Claude Code loads natively but publishes no lifecycle verb: observed
1114        // only, and the two read methods only.
1115        let claude_conv = &report
1116            .harnesses
1117            .iter()
1118            .find(|h| h.id.as_str() == HarnessId::CLAUDE_CODE)
1119            .unwrap()
1120            .orchestration
1121            .concepts[2];
1122        assert_eq!(claude_conv.observed, ImplementationKind::BuiltIn);
1123        assert_eq!(claude_conv.controlled, ImplementationKind::Absent);
1124        assert_eq!(
1125            claude_conv.methods,
1126            vec!["harness.v1.sessions.discover", "harness.v1.sessions.load"]
1127        );
1128        for harness in &report.harnesses {
1129            let conversation = &harness.orchestration.concepts[2];
1130            let doors = crate::sessions_control::controlled_methods(harness.id.as_str());
1131            assert_eq!(
1132                conversation.controlled == ImplementationKind::BuiltIn,
1133                !doors.is_empty(),
1134                "{}: conversation controlled must track the sessions_control door table",
1135                harness.id.as_str()
1136            );
1137            for method in &doors {
1138                assert!(
1139                    conversation.methods.iter().any(|listed| listed == method),
1140                    "{}: `{method}` has a door but is not advertised",
1141                    harness.id.as_str()
1142                );
1143            }
1144            for listed in &conversation.methods {
1145                assert!(
1146                    listed.ends_with(".discover")
1147                        || listed.ends_with(".load")
1148                        || doors.contains(&listed.as_str()),
1149                    "{}: `{listed}` is advertised with no door behind it",
1150                    harness.id.as_str()
1151                );
1152            }
1153        }
1154        let pending = &hermes.orchestration.concepts[3];
1155        assert_eq!(pending.concept, "pending_request");
1156        assert_eq!(pending.controlled, ImplementationKind::BuiltIn);
1157        // ORCH-7/ORCH-18: scheduled jobs are observed for the three harnesses
1158        // that have them and controlled for the two that publish a
1159        // client-callable cron verb.
1160        let job = &hermes.orchestration.concepts[0];
1161        assert_eq!(job.concept, "scheduled_job");
1162        assert_eq!(job.observed, ImplementationKind::BuiltIn);
1163        assert_eq!(job.controlled, ImplementationKind::BuiltIn);
1164        assert_eq!(
1165            job.methods,
1166            vec![
1167                "harness.v1.jobs.list",
1168                "harness.v1.jobs.get",
1169                "harness.v1.jobs.create",
1170                "harness.v1.jobs.update",
1171                "harness.v1.jobs.pause",
1172                "harness.v1.jobs.resume",
1173                "harness.v1.jobs.run",
1174                "harness.v1.jobs.delete",
1175            ]
1176        );
1177        // Claude Code has jobs but no verb a client can call: observed only.
1178        let claude_job = &report
1179            .harnesses
1180            .iter()
1181            .find(|h| h.id.as_str() == HarnessId::CLAUDE_CODE)
1182            .unwrap()
1183            .orchestration
1184            .concepts[0];
1185        assert_eq!(claude_job.observed, ImplementationKind::BuiltIn);
1186        assert_eq!(claude_job.controlled, ImplementationKind::Absent);
1187        assert_eq!(
1188            claude_job.methods,
1189            vec!["harness.v1.jobs.list", "harness.v1.jobs.get"]
1190        );
1191        for harness in &report.harnesses {
1192            let job = &harness.orchestration.concepts[0];
1193            assert_eq!(
1194                job.observed == ImplementationKind::BuiltIn,
1195                crate::jobs::supports_jobs(harness.id.as_str()),
1196                "{}: scheduled_job observed must track JOB_HARNESSES",
1197                harness.id.as_str()
1198            );
1199            assert_eq!(
1200                job.controlled == ImplementationKind::BuiltIn,
1201                crate::jobs_control::supports_job_control(harness.id.as_str()),
1202                "{}: scheduled_job controlled must track CONTROLLED_JOB_HARNESSES",
1203                harness.id.as_str()
1204            );
1205        }
1206        // ORCH-10/ORCH-21: profiles are observed for the four harnesses with
1207        // the concept, controlled for the two that publish a lifecycle verb,
1208        // and Absent (with no methods) everywhere else.
1209        let profile = &hermes.orchestration.concepts[4];
1210        assert_eq!(profile.concept, "profile");
1211        assert_eq!(profile.observed, ImplementationKind::BuiltIn);
1212        assert_eq!(profile.controlled, ImplementationKind::BuiltIn);
1213        assert_eq!(
1214            profile.methods,
1215            [
1216                "harness.v1.profiles.list",
1217                "harness.v1.profiles.get",
1218                "harness.v1.profiles.create",
1219                "harness.v1.profiles.delete",
1220            ]
1221        );
1222        // Codex HAS profiles but publishes no verb for them — they are tables
1223        // a human authors in `config.toml` — so it is observed only.
1224        let codex_profile = &report
1225            .harnesses
1226            .iter()
1227            .find(|h| h.id.as_str() == HarnessId::CODEX)
1228            .unwrap()
1229            .orchestration
1230            .concepts[4];
1231        assert_eq!(codex_profile.observed, ImplementationKind::BuiltIn);
1232        assert_eq!(codex_profile.controlled, ImplementationKind::Absent);
1233        assert_eq!(
1234            codex_profile.methods,
1235            ["harness.v1.profiles.list", "harness.v1.profiles.get"]
1236        );
1237        for harness in &report.harnesses {
1238            let profile = &harness.orchestration.concepts[4];
1239            assert_eq!(
1240                profile.observed == ImplementationKind::BuiltIn,
1241                crate::profiles::PROFILE_HARNESSES.contains(&harness.id.as_str()),
1242                "{}: profile observed tier disagrees with PROFILE_HARNESSES",
1243                harness.id.as_str()
1244            );
1245            assert_eq!(
1246                profile.controlled == ImplementationKind::BuiltIn,
1247                crate::profiles_control::supports_profile_control(harness.id.as_str()),
1248                "{}: profile controlled tier disagrees with CONTROLLED_PROFILE_HARNESSES",
1249                harness.id.as_str()
1250            );
1251        }
1252    }
1253
1254    /// ORCH-12: memory is observed for the three harnesses that have a
1255    /// persistent memory store at the pinned versions, and stays Absent for
1256    /// the rest — Codex, opencode and pi have no memory store to read.
1257    #[test]
1258    fn memory_is_observed_only_for_the_harnesses_with_a_memory_store() {
1259        let report = harness_support_registry();
1260        for harness in &report.harnesses {
1261            let memory = harness
1262                .orchestration
1263                .concepts
1264                .iter()
1265                .find(|concept| concept.concept == "memory")
1266                .unwrap_or_else(|| panic!("{}: no memory concept row", harness.id.as_str()));
1267            if crate::memory::MEMORY_HARNESSES.contains(&harness.id.as_str()) {
1268                assert_eq!(
1269                    memory.observed,
1270                    ImplementationKind::BuiltIn,
1271                    "{}: memory must be observed",
1272                    harness.id.as_str()
1273                );
1274                assert_eq!(
1275                    memory.methods,
1276                    vec![
1277                        "harness.v1.memory.show".to_string(),
1278                        "harness.v1.memory.search".to_string()
1279                    ]
1280                );
1281            } else {
1282                assert_eq!(
1283                    memory.observed,
1284                    ImplementationKind::Absent,
1285                    "{}: memory must be absent",
1286                    harness.id.as_str()
1287                );
1288                assert!(memory.methods.is_empty(), "{}", harness.id.as_str());
1289            }
1290            // forget / reset stay the harness's own verb.
1291            assert_eq!(memory.controlled, ImplementationKind::Absent);
1292        }
1293    }
1294
1295    /// ORCH-11 + ORCH-22: skills are observed AND controlled for the six
1296    /// harnesses whose skill roots `crate::skills` opens, and stay Absent for
1297    /// the rest — supercode itself included, since it has no root of its own.
1298    #[test]
1299    fn skills_are_observed_and_controlled_for_the_harnesses_with_a_skills_loader() {
1300        let report = harness_support_registry();
1301        for harness in &report.harnesses {
1302            let skills = harness
1303                .orchestration
1304                .concepts
1305                .iter()
1306                .find(|concept| concept.concept == "skills")
1307                .unwrap();
1308            if crate::skills::SKILL_HARNESSES.contains(&harness.id.as_str()) {
1309                assert_eq!(
1310                    skills.observed,
1311                    ImplementationKind::BuiltIn,
1312                    "{}",
1313                    harness.id.as_str()
1314                );
1315                // ORCH-22: the write tier is the harness's OWN door — a CLI
1316                // verb for the two gateway harnesses, the loader's directory
1317                // for the core four.
1318                assert_eq!(
1319                    skills.controlled,
1320                    ImplementationKind::BuiltIn,
1321                    "{}",
1322                    harness.id.as_str()
1323                );
1324                assert_eq!(
1325                    skills.methods,
1326                    vec![
1327                        "harness.v1.skills.list".to_string(),
1328                        "harness.v1.skills.install".to_string(),
1329                        "harness.v1.skills.remove".to_string(),
1330                    ]
1331                );
1332            } else {
1333                assert_eq!(
1334                    skills.observed,
1335                    ImplementationKind::Absent,
1336                    "{}",
1337                    harness.id.as_str()
1338                );
1339                assert_eq!(
1340                    skills.controlled,
1341                    ImplementationKind::Absent,
1342                    "{}",
1343                    harness.id.as_str()
1344                );
1345            }
1346        }
1347    }
1348
1349    /// ORCH-14: channels are observed for the two gateway harnesses whose
1350    /// config files `crate::channels` opens, and stay Absent for the rest —
1351    /// Claude Code included, because its channels are declared over the MCP
1352    /// protocol and not in any file supercode can read.
1353    #[test]
1354    fn channels_are_observed_for_the_gateway_harnesses_only() {
1355        let report = harness_support_registry();
1356        for harness in &report.harnesses {
1357            let channel = harness
1358                .orchestration
1359                .concepts
1360                .iter()
1361                .find(|concept| concept.concept == "channel")
1362                .unwrap();
1363            if crate::channels::CHANNEL_HARNESSES.contains(&harness.id.as_str()) {
1364                assert_eq!(
1365                    channel.observed,
1366                    ImplementationKind::BuiltIn,
1367                    "{}",
1368                    harness.id.as_str()
1369                );
1370                assert_eq!(
1371                    channel.methods,
1372                    ["harness.v1.channels.list", "harness.v1.channels.status"]
1373                );
1374            } else {
1375                assert_eq!(
1376                    channel.observed,
1377                    ImplementationKind::Absent,
1378                    "{}",
1379                    harness.id.as_str()
1380                );
1381                assert!(channel.methods.is_empty(), "{}", harness.id.as_str());
1382            }
1383            // Every channel mutation stays the harness's own verb.
1384            assert_eq!(channel.controlled, ImplementationKind::Absent);
1385        }
1386    }
1387
1388    /// ORCH-8: `run` is observed exactly where a fire STORE exists, which is a
1389    /// strictly smaller set than `scheduled_job`. Claude Code is the case that
1390    /// makes the distinction real: it has jobs but no run store, so it must be
1391    /// built-in for one concept and absent for the other in the same
1392    /// descriptor.
1393    #[test]
1394    fn runs_are_observed_only_where_the_harness_keeps_a_fire_store() {
1395        let report = harness_support_registry();
1396        let concept = |harness: &HarnessSupportDescriptor, name: &str| {
1397            harness
1398                .orchestration
1399                .concepts
1400                .iter()
1401                .find(|concept| concept.concept == name)
1402                .unwrap_or_else(|| panic!("no `{name}` concept for {}", harness.id.as_str()))
1403                .clone()
1404        };
1405        let mut observed = Vec::new();
1406        for harness in &report.harnesses {
1407            let run = concept(harness, "run");
1408            if crate::runs::RUN_HARNESSES.contains(&harness.id.as_str()) {
1409                assert_eq!(
1410                    run.observed,
1411                    ImplementationKind::BuiltIn,
1412                    "{}",
1413                    harness.id.as_str()
1414                );
1415                assert_eq!(
1416                    run.methods,
1417                    vec![
1418                        "harness.v1.runs.list".to_string(),
1419                        "harness.v1.runs.get".to_string()
1420                    ]
1421                );
1422                observed.push(harness.id.as_str().to_string());
1423            } else {
1424                assert_eq!(
1425                    run.observed,
1426                    ImplementationKind::Absent,
1427                    "{}",
1428                    harness.id.as_str()
1429                );
1430                assert!(run.methods.is_empty(), "{}", harness.id.as_str());
1431            }
1432            // Retention is the only write verb either harness has, and it is
1433            // not wired: nothing here claims the controlled tier.
1434            assert_eq!(run.controlled, ImplementationKind::Absent);
1435        }
1436        // ORC-7: the orchestrator keeps its fires in the same
1437        // `cron/executions.db`, one per profile folder, so the same reader
1438        // observes it.
1439        assert_eq!(observed, vec!["hermes", "openclaw", "orchestrator"]);
1440
1441        let claude = report
1442            .harnesses
1443            .iter()
1444            .find(|harness| harness.id.as_str() == HarnessId::CLAUDE_CODE)
1445            .expect("claude-code is in the registry");
1446        assert_eq!(
1447            concept(claude, "scheduled_job").observed,
1448            ImplementationKind::BuiltIn,
1449        );
1450        assert_eq!(concept(claude, "run").observed, ImplementationKind::Absent);
1451    }
1452
1453    /// The block is additive: a v1 descriptor without it still deserializes.
1454    #[test]
1455    fn orchestration_block_is_additive_on_the_wire() {
1456        let report = harness_support_registry();
1457        let mut value = serde_json::to_value(&report.harnesses[0]).unwrap();
1458        value.as_object_mut().unwrap().remove("orchestration");
1459        let back: HarnessSupportDescriptor = serde_json::from_value(value).unwrap();
1460        assert!(back.orchestration.concepts.is_empty());
1461    }
1462}