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