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