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/EXPORT stay
634                    // Absent — writing a live, shared, WAL, single-writer
635                    // store is gated by UNI-22 (not fired), and the tier
636                    // stays driven (matrix membership is UNI-17's flip).
637                    discover: ImplementationKind::BuiltIn,
638                    load: ImplementationKind::BuiltIn,
639                    follow: ImplementationKind::Absent,
640                    import: ImplementationKind::Absent,
641                    export: ImplementationKind::Absent,
642                },
643                runtime: RuntimeSupport {
644                    implementation: ImplementationKind::GenericProtocol,
645                    protocol: "acp-v1-jsonrpc".into(),
646                    default_launch: Some(hermes_launch),
647                    connect_launch: None,
648                    capabilities: hermes.capabilities(),
649                },
650            },
651            HarnessSupportDescriptor {
652                id: HarnessId::from(HarnessId::OPENCLAW),
653                display_name: "OpenClaw".into(),
654                orchestration: OrchestrationSupport::default(),
655                native: NativeSupport {
656                    // UNI-16 read-only tier: discovery over
657                    // `agents/<id>/sessions/*.jsonl` and the pi-v3-dialect
658                    // loader (`from_openclaw_str`). Import (translate IN),
659                    // export (write OUT), and follow stay Absent — the write
660                    // path is a permanent skip, and the TIER stays `driven`:
661                    // matrix membership remains UNI-17's priced flip.
662                    discover: ImplementationKind::BuiltIn,
663                    load: ImplementationKind::BuiltIn,
664                    follow: ImplementationKind::Absent,
665                    import: ImplementationKind::Absent,
666                    export: ImplementationKind::Absent,
667                },
668                runtime: RuntimeSupport {
669                    implementation: ImplementationKind::GenericProtocol,
670                    protocol: "acp-v1-jsonrpc".into(),
671                    default_launch: Some(openclaw_launch),
672                    // Blind-walk finding 2026-08-31: `gateway.url` is NOT a
673                    // key openclaw's config schema accepts (the gateway
674                    // rejects the whole file as invalid config). The real
675                    // shape: an optional full URL at `gateway.remote.url`, a
676                    // bare `gateway.port` number, or nothing at all — the
677                    // documented out-of-the-box endpoint is ws://127.0.0.1:18789.
678                    connect_launch: Some(RuntimeConnectLaunch {
679                        config_path: "~/.openclaw/openclaw.json".into(),
680                        address_pointer: "/gateway/remote/url".into(),
681                        port_pointer: Some("/gateway/port".into()),
682                        default_address: Some("ws://127.0.0.1:18789".into()),
683                        auth_pointer: Some("/gateway/auth/token".into()),
684                        protocol: "acp-v1-jsonrpc".into(),
685                    }),
686                    capabilities: openclaw.capabilities(),
687                },
688            },
689            // ORC-7: the orchestrator is a harness id so the EXISTING
690            // orchestration readers list its state — its folder is a
691            // Hermes-shaped home (`docs/ORCHESTRATOR-IR.md` §6) and each
692            // reader is pointed at it with no new reader code. It has no
693            // native session tier of its own: it keeps no transcripts, only
694            // BINDINGS that address a WORKER harness's session, which is read
695            // through that harness's own door. It has no runtime either — the
696            // daemon is a Node process the operator verbs start and stop, not
697            // an adapter supercode connects a turn to.
698            HarnessSupportDescriptor {
699                id: HarnessId::from(HarnessId::ORCHESTRATOR),
700                display_name: "Orchestrator".into(),
701                orchestration: OrchestrationSupport::default(),
702                native: NativeSupport {
703                    discover: ImplementationKind::Absent,
704                    load: ImplementationKind::Absent,
705                    follow: ImplementationKind::Absent,
706                    import: ImplementationKind::Absent,
707                    export: ImplementationKind::Absent,
708                },
709                runtime: RuntimeSupport {
710                    implementation: ImplementationKind::Absent,
711                    protocol: "none".into(),
712                    default_launch: None,
713                    connect_launch: None,
714                    capabilities: RuntimeCapabilities {
715                        start_session: false,
716                        resume_session: false,
717                        attach_existing_process: false,
718                        send_input: false,
719                        stream_events: false,
720                        interrupt: false,
721                        steer: false,
722                        respond_to_requests: false,
723                    },
724                },
725            },
726            HarnessSupportDescriptor {
727                id: HarnessId::from(HarnessId::SUPERCODE),
728                display_name: "Supercode".into(),
729                orchestration: OrchestrationSupport::default(),
730                native: built_in_native(),
731                runtime: RuntimeSupport {
732                    implementation: ImplementationKind::GenericProtocol,
733                    protocol: "acp-v1-jsonrpc".into(),
734                    default_launch: Some(supercode_launch),
735                    connect_launch: None,
736                    capabilities: supercode.capabilities(),
737                },
738            },
739        ],
740    };
741    for descriptor in &mut report.harnesses {
742        descriptor.orchestration = orchestration_support(descriptor);
743    }
744    report
745}
746
747/// Look up one harness in the compiled registry.
748pub fn harness_support(id: &str) -> Option<HarnessSupportDescriptor> {
749    harness_support_registry()
750        .harnesses
751        .into_iter()
752        .find(|harness| harness.id.as_str() == id)
753}
754
755#[cfg(test)]
756mod tests {
757    use super::*;
758
759    #[test]
760    fn claude_code_default_launch_is_the_stream_json_prefix() {
761        let claude = harness_support_registry()
762            .harnesses
763            .into_iter()
764            .find(|h| h.id.as_str() == HarnessId::CLAUDE_CODE)
765            .unwrap();
766        let launch = claude.runtime.default_launch.unwrap();
767        assert_eq!(launch.program, "claude");
768        let joined = launch.arguments.join(" ");
769        assert!(joined.contains("--input-format stream-json"), "{joined}");
770        assert!(joined.contains("--output-format stream-json"), "{joined}");
771        assert!(
772            joined.contains("--permission-prompt-tool stdio"),
773            "{joined}"
774        );
775    }
776
777    #[test]
778    fn grok_asks_for_a_self_sandbox_only_where_one_is_possible() {
779        let arguments = grok_arguments();
780        assert_eq!(
781            arguments.iter().any(|argument| argument == "--sandbox"),
782            self_sandbox_supported(),
783        );
784        assert!(
785            arguments.ends_with(&["agent".into(), "--no-leader".into(), "stdio".into()]),
786            "{arguments:?}",
787        );
788    }
789
790    #[test]
791    fn registry_is_unique_and_reports_all_native_support() {
792        let report = harness_support_registry();
793        assert_eq!(report.schema, SUPPORT_REGISTRY_SCHEMA);
794        // Ten harnesses plus the orchestrator (ORC-7), which is a registry id
795        // with orchestration tiers and no native or runtime tier of its own.
796        assert_eq!(report.harnesses.len(), 11);
797        let ids = report
798            .harnesses
799            .iter()
800            .map(|harness| harness.id.as_str())
801            .collect::<std::collections::BTreeSet<_>>();
802        assert_eq!(ids.len(), report.harnesses.len());
803
804        let grok = report
805            .harnesses
806            .iter()
807            .find(|harness| harness.id.as_str() == HarnessId::GROK)
808            .unwrap();
809        assert_eq!(grok.native.discover, ImplementationKind::BuiltIn);
810        assert_eq!(grok.native.load, ImplementationKind::BuiltIn);
811        assert_eq!(grok.native.follow, ImplementationKind::BuiltIn);
812        assert_eq!(grok.native.import, ImplementationKind::BuiltIn);
813        for id in [HarnessId::GEMINI, HarnessId::SUPERCODE] {
814            let harness = report
815                .harnesses
816                .iter()
817                .find(|harness| harness.id.as_str() == id)
818                .unwrap();
819            assert_eq!(harness.native.discover, ImplementationKind::BuiltIn);
820            assert_eq!(harness.native.load, ImplementationKind::BuiltIn);
821            assert_eq!(harness.native.follow, ImplementationKind::BuiltIn);
822        }
823        assert_eq!(grok.native.export, ImplementationKind::BuiltIn);
824        assert_eq!(
825            grok.runtime.implementation,
826            ImplementationKind::GenericProtocol
827        );
828        let expected: Vec<&str> = if self_sandbox_supported() {
829            vec!["--sandbox", "workspace", "agent", "--no-leader", "stdio"]
830        } else {
831            vec!["agent", "--no-leader", "stdio"]
832        };
833        assert_eq!(
834            grok.runtime.default_launch.as_ref().unwrap().arguments,
835            expected
836        );
837        assert!(!grok
838            .runtime
839            .default_launch
840            .as_ref()
841            .unwrap()
842            .arguments
843            .iter()
844            .any(|argument| argument == "--always-approve"));
845        assert!(grok.runtime.capabilities.resume_session);
846    }
847
848    /// UNI-5 dev/03: every OpenClaw path is gateway-mediated — the registry
849    /// declares NO native primitive, so no supercode code path can open the
850    /// openclaw-agent SQLite store (direct-DB-write-as-product is a permanent
851    /// skip; the read tier is UNI-16's gated wave). The connect launch stores
852    /// pointers into openclaw's config, never endpoint or credential values.
853    #[test]
854    fn openclaw_registers_gateway_mediated_with_no_store_access() {
855        let report = harness_support_registry();
856        let openclaw = report
857            .harnesses
858            .iter()
859            .find(|harness| harness.id.as_str() == HarnessId::OPENCLAW)
860            .expect("openclaw must be registered");
861        assert_eq!(openclaw.display_name, "OpenClaw");
862        // UNI-16 read tier: discover + load are BuiltIn (pi-v3-dialect
863        // files); follow/import/EXPORT stay Absent — no code path can WRITE
864        // the openclaw store, and the tier stays driven (matrix membership
865        // remains UNI-17's priced flip).
866        assert_eq!(openclaw.native.discover, ImplementationKind::BuiltIn);
867        assert_eq!(openclaw.native.load, ImplementationKind::BuiltIn);
868        for kind in [
869            openclaw.native.follow,
870            openclaw.native.import,
871            openclaw.native.export,
872        ] {
873            assert_eq!(kind, ImplementationKind::Absent);
874        }
875        assert_eq!(
876            openclaw.runtime.implementation,
877            ImplementationKind::GenericProtocol
878        );
879        assert_eq!(openclaw.runtime.protocol, "acp-v1-jsonrpc");
880        let launch = openclaw.runtime.default_launch.as_ref().unwrap();
881        assert_eq!(launch.program, "openclaw");
882        assert_eq!(launch.arguments, ["acp"]);
883        let connect = openclaw.runtime.connect_launch.as_ref().unwrap();
884        assert_eq!(connect.config_path, "~/.openclaw/openclaw.json");
885        // Blind-walk correction 2026-08-31: openclaw's schema has no
886        // `gateway.url`; the real chain is remote.url -> port -> the
887        // documented default endpoint.
888        assert_eq!(connect.address_pointer, "/gateway/remote/url");
889        assert_eq!(connect.port_pointer.as_deref(), Some("/gateway/port"));
890        assert_eq!(
891            connect.default_address.as_deref(),
892            Some("ws://127.0.0.1:18789")
893        );
894        assert_eq!(connect.auth_pointer.as_deref(), Some("/gateway/auth/token"));
895        // Executed dialect probe
896        // (docs/interop/research/openclaw-acp-dialect-2026-08-30.json):
897        // resume + list advertised on >= 2026.7.
898        assert!(openclaw.runtime.capabilities.resume_session);
899    }
900
901    #[test]
902    fn hermes_registers_as_a_driven_tier_acp_entry_without_native_claims() {
903        let report = harness_support_registry();
904        let hermes = report
905            .harnesses
906            .iter()
907            .find(|harness| harness.id.as_str() == HarnessId::HERMES)
908            .expect("hermes must be registered");
909        assert_eq!(hermes.display_name, "Hermes Agent");
910        // UNI-15 read tier: discover + load BuiltIn over state.db;
911        // follow/import/EXPORT stay Absent (write gated by UNI-22, tier
912        // stays driven).
913        assert_eq!(hermes.native.discover, ImplementationKind::BuiltIn);
914        assert_eq!(hermes.native.load, ImplementationKind::BuiltIn);
915        for kind in [
916            hermes.native.follow,
917            hermes.native.import,
918            hermes.native.export,
919        ] {
920            assert_eq!(kind, ImplementationKind::Absent);
921        }
922        assert_eq!(
923            hermes.runtime.implementation,
924            ImplementationKind::GenericProtocol
925        );
926        assert_eq!(hermes.runtime.protocol, "acp-v1-jsonrpc");
927        let launch = hermes.runtime.default_launch.as_ref().unwrap();
928        assert_eq!(launch.program, "hermes-acp");
929        assert!(launch.arguments.is_empty());
930        assert!(hermes.runtime.connect_launch.is_none());
931        // Verified against the executed dialect probe
932        // (docs/interop/research/hermes-acp-dialect-2026-08-30.json):
933        // loadSession + sessionCapabilities.resume are advertised.
934        assert!(hermes.runtime.capabilities.resume_session);
935        assert!(!hermes.runtime.capabilities.attach_existing_process);
936    }
937
938    #[test]
939    fn connect_mode_descriptor_round_trips_the_registry_schema() {
940        let descriptor = HarnessSupportDescriptor {
941            id: HarnessId::from("openclaw"),
942            display_name: "OpenClaw".into(),
943            orchestration: OrchestrationSupport::default(),
944            native: NativeSupport {
945                discover: ImplementationKind::Absent,
946                load: ImplementationKind::Absent,
947                follow: ImplementationKind::Absent,
948                import: ImplementationKind::Absent,
949                export: ImplementationKind::Absent,
950            },
951            runtime: RuntimeSupport {
952                implementation: ImplementationKind::GenericProtocol,
953                protocol: "acp-v1-jsonrpc".into(),
954                default_launch: None,
955                connect_launch: Some(RuntimeConnectLaunch {
956                    config_path: "~/.openclaw/openclaw.json".into(),
957                    address_pointer: "/gateway/url".into(),
958                    port_pointer: None,
959                    default_address: None,
960                    auth_pointer: Some("/gateway/token".into()),
961                    protocol: "acp-v1-jsonrpc".into(),
962                }),
963                capabilities: RuntimeCapabilities {
964                    start_session: true,
965                    resume_session: false,
966                    attach_existing_process: true,
967                    send_input: true,
968                    stream_events: true,
969                    interrupt: false,
970                    steer: false,
971                    respond_to_requests: false,
972                },
973            },
974        };
975        let encoded = serde_json::to_value(&descriptor).unwrap();
976        assert_eq!(
977            encoded["runtime"]["connect_launch"]["address_pointer"],
978            "/gateway/url"
979        );
980        let decoded: HarnessSupportDescriptor = serde_json::from_value(encoded).unwrap();
981        assert_eq!(decoded, descriptor);
982    }
983
984    #[test]
985    fn spawn_only_registry_entries_do_not_serialize_a_connect_launch() {
986        let report = harness_support_registry();
987        for harness in &report.harnesses {
988            let encoded = serde_json::to_string(harness).unwrap();
989            if harness.id.as_str() == HarnessId::OPENCLAW {
990                // The one declared connect-mode entry (UNI-5): endpoint and
991                // credential POINTERS plus the harness's DOCUMENTED default
992                // endpoint — never resolved values or credentials.
993                assert!(encoded.contains("connect_launch"));
994                assert!(encoded.contains("/gateway/auth/token"));
995                assert!(encoded.contains("ws://127.0.0.1:18789"));
996                assert!(!encoded.contains("token\":\"ws"));
997            } else {
998                assert!(
999                    !encoded.contains("connect_launch"),
1000                    "{} must stay spawn-only",
1001                    harness.id.as_str()
1002                );
1003            }
1004        }
1005        let encoded = serde_json::to_string(&report).unwrap();
1006        let decoded: SupportRegistryReport = serde_json::from_str(&encoded).unwrap();
1007        assert_eq!(decoded, report);
1008    }
1009
1010    /// ORCH-4: every harness carries all twelve concepts; every method a
1011    /// non-Absent tier cites is a real service method.
1012    #[test]
1013    fn orchestration_block_is_complete_and_its_methods_exist() {
1014        let report = harness_support_registry();
1015        for harness in &report.harnesses {
1016            let names: Vec<&str> = harness
1017                .orchestration
1018                .concepts
1019                .iter()
1020                .map(|c| c.concept.as_str())
1021                .collect();
1022            assert_eq!(names, ORCHESTRATION_CONCEPTS, "{}", harness.id.as_str());
1023            for concept in &harness.orchestration.concepts {
1024                let any_built_in = concept.observed == ImplementationKind::BuiltIn
1025                    || concept.controlled == ImplementationKind::BuiltIn;
1026                assert_eq!(
1027                    any_built_in,
1028                    !concept.methods.is_empty(),
1029                    "{}/{}: a BuiltIn tier must cite methods and an Absent one must not",
1030                    harness.id.as_str(),
1031                    concept.concept
1032                );
1033                for method in &concept.methods {
1034                    assert!(
1035                        crate::harness_service::HARNESS_SERVICE_METHODS.contains(&method.as_str()),
1036                        "{}/{}: `{method}` is not a harness service method",
1037                        harness.id.as_str(),
1038                        concept.concept
1039                    );
1040                }
1041            }
1042        }
1043        // Today's honest floor: conversation is observed wherever sessions load
1044        // natively; pending requests are controlled wherever the door responds.
1045        let hermes = report
1046            .harnesses
1047            .iter()
1048            .find(|h| h.id.as_str() == HarnessId::HERMES)
1049            .unwrap();
1050        let conv = &hermes.orchestration.concepts[2];
1051        assert_eq!(conv.concept, "conversation");
1052        assert_eq!(conv.observed, ImplementationKind::BuiltIn);
1053        // ORCH-19: Hermes is controlled through the doors it actually has —
1054        // `/reset` inside a live session, plus `hermes sessions delete`. It
1055        // has no per-session archive verb, and its ACP door does not carry
1056        // `/new` (a gateway-only command), so neither is advertised.
1057        assert_eq!(conv.controlled, ImplementationKind::BuiltIn);
1058        assert_eq!(
1059            conv.methods,
1060            vec![
1061                "harness.v1.sessions.discover",
1062                "harness.v1.sessions.load",
1063                "harness.v1.sessions.reset",
1064                "harness.v1.sessions.delete",
1065            ]
1066        );
1067        // OpenClaw's ACP door advertises both `/new` and `/reset` at the pin,
1068        // and it has neither archive nor delete.
1069        let openclaw_conv = &report
1070            .harnesses
1071            .iter()
1072            .find(|h| h.id.as_str() == HarnessId::OPENCLAW)
1073            .unwrap()
1074            .orchestration
1075            .concepts[2];
1076        assert_eq!(
1077            openclaw_conv.methods,
1078            vec![
1079                "harness.v1.sessions.discover",
1080                "harness.v1.sessions.load",
1081                "harness.v1.sessions.new",
1082                "harness.v1.sessions.reset",
1083            ]
1084        );
1085        // Claude Code loads natively but publishes no lifecycle verb: observed
1086        // only, and the two read methods only.
1087        let claude_conv = &report
1088            .harnesses
1089            .iter()
1090            .find(|h| h.id.as_str() == HarnessId::CLAUDE_CODE)
1091            .unwrap()
1092            .orchestration
1093            .concepts[2];
1094        assert_eq!(claude_conv.observed, ImplementationKind::BuiltIn);
1095        assert_eq!(claude_conv.controlled, ImplementationKind::Absent);
1096        assert_eq!(
1097            claude_conv.methods,
1098            vec!["harness.v1.sessions.discover", "harness.v1.sessions.load"]
1099        );
1100        for harness in &report.harnesses {
1101            let conversation = &harness.orchestration.concepts[2];
1102            let doors = crate::sessions_control::controlled_methods(harness.id.as_str());
1103            assert_eq!(
1104                conversation.controlled == ImplementationKind::BuiltIn,
1105                !doors.is_empty(),
1106                "{}: conversation controlled must track the sessions_control door table",
1107                harness.id.as_str()
1108            );
1109            for method in &doors {
1110                assert!(
1111                    conversation.methods.iter().any(|listed| listed == method),
1112                    "{}: `{method}` has a door but is not advertised",
1113                    harness.id.as_str()
1114                );
1115            }
1116            for listed in &conversation.methods {
1117                assert!(
1118                    listed.ends_with(".discover")
1119                        || listed.ends_with(".load")
1120                        || doors.contains(&listed.as_str()),
1121                    "{}: `{listed}` is advertised with no door behind it",
1122                    harness.id.as_str()
1123                );
1124            }
1125        }
1126        let pending = &hermes.orchestration.concepts[3];
1127        assert_eq!(pending.concept, "pending_request");
1128        assert_eq!(pending.controlled, ImplementationKind::BuiltIn);
1129        // ORCH-7/ORCH-18: scheduled jobs are observed for the three harnesses
1130        // that have them and controlled for the two that publish a
1131        // client-callable cron verb.
1132        let job = &hermes.orchestration.concepts[0];
1133        assert_eq!(job.concept, "scheduled_job");
1134        assert_eq!(job.observed, ImplementationKind::BuiltIn);
1135        assert_eq!(job.controlled, ImplementationKind::BuiltIn);
1136        assert_eq!(
1137            job.methods,
1138            vec![
1139                "harness.v1.jobs.list",
1140                "harness.v1.jobs.get",
1141                "harness.v1.jobs.create",
1142                "harness.v1.jobs.update",
1143                "harness.v1.jobs.pause",
1144                "harness.v1.jobs.resume",
1145                "harness.v1.jobs.run",
1146                "harness.v1.jobs.delete",
1147            ]
1148        );
1149        // Claude Code has jobs but no verb a client can call: observed only.
1150        let claude_job = &report
1151            .harnesses
1152            .iter()
1153            .find(|h| h.id.as_str() == HarnessId::CLAUDE_CODE)
1154            .unwrap()
1155            .orchestration
1156            .concepts[0];
1157        assert_eq!(claude_job.observed, ImplementationKind::BuiltIn);
1158        assert_eq!(claude_job.controlled, ImplementationKind::Absent);
1159        assert_eq!(
1160            claude_job.methods,
1161            vec!["harness.v1.jobs.list", "harness.v1.jobs.get"]
1162        );
1163        for harness in &report.harnesses {
1164            let job = &harness.orchestration.concepts[0];
1165            assert_eq!(
1166                job.observed == ImplementationKind::BuiltIn,
1167                crate::jobs::supports_jobs(harness.id.as_str()),
1168                "{}: scheduled_job observed must track JOB_HARNESSES",
1169                harness.id.as_str()
1170            );
1171            assert_eq!(
1172                job.controlled == ImplementationKind::BuiltIn,
1173                crate::jobs_control::supports_job_control(harness.id.as_str()),
1174                "{}: scheduled_job controlled must track CONTROLLED_JOB_HARNESSES",
1175                harness.id.as_str()
1176            );
1177        }
1178        // ORCH-10/ORCH-21: profiles are observed for the four harnesses with
1179        // the concept, controlled for the two that publish a lifecycle verb,
1180        // and Absent (with no methods) everywhere else.
1181        let profile = &hermes.orchestration.concepts[4];
1182        assert_eq!(profile.concept, "profile");
1183        assert_eq!(profile.observed, ImplementationKind::BuiltIn);
1184        assert_eq!(profile.controlled, ImplementationKind::BuiltIn);
1185        assert_eq!(
1186            profile.methods,
1187            [
1188                "harness.v1.profiles.list",
1189                "harness.v1.profiles.get",
1190                "harness.v1.profiles.create",
1191                "harness.v1.profiles.delete",
1192            ]
1193        );
1194        // Codex HAS profiles but publishes no verb for them — they are tables
1195        // a human authors in `config.toml` — so it is observed only.
1196        let codex_profile = &report
1197            .harnesses
1198            .iter()
1199            .find(|h| h.id.as_str() == HarnessId::CODEX)
1200            .unwrap()
1201            .orchestration
1202            .concepts[4];
1203        assert_eq!(codex_profile.observed, ImplementationKind::BuiltIn);
1204        assert_eq!(codex_profile.controlled, ImplementationKind::Absent);
1205        assert_eq!(
1206            codex_profile.methods,
1207            ["harness.v1.profiles.list", "harness.v1.profiles.get"]
1208        );
1209        for harness in &report.harnesses {
1210            let profile = &harness.orchestration.concepts[4];
1211            assert_eq!(
1212                profile.observed == ImplementationKind::BuiltIn,
1213                crate::profiles::PROFILE_HARNESSES.contains(&harness.id.as_str()),
1214                "{}: profile observed tier disagrees with PROFILE_HARNESSES",
1215                harness.id.as_str()
1216            );
1217            assert_eq!(
1218                profile.controlled == ImplementationKind::BuiltIn,
1219                crate::profiles_control::supports_profile_control(harness.id.as_str()),
1220                "{}: profile controlled tier disagrees with CONTROLLED_PROFILE_HARNESSES",
1221                harness.id.as_str()
1222            );
1223        }
1224    }
1225
1226    /// ORCH-12: memory is observed for the three harnesses that have a
1227    /// persistent memory store at the pinned versions, and stays Absent for
1228    /// the rest — Codex, opencode and pi have no memory store to read.
1229    #[test]
1230    fn memory_is_observed_only_for_the_harnesses_with_a_memory_store() {
1231        let report = harness_support_registry();
1232        for harness in &report.harnesses {
1233            let memory = harness
1234                .orchestration
1235                .concepts
1236                .iter()
1237                .find(|concept| concept.concept == "memory")
1238                .unwrap_or_else(|| panic!("{}: no memory concept row", harness.id.as_str()));
1239            if crate::memory::MEMORY_HARNESSES.contains(&harness.id.as_str()) {
1240                assert_eq!(
1241                    memory.observed,
1242                    ImplementationKind::BuiltIn,
1243                    "{}: memory must be observed",
1244                    harness.id.as_str()
1245                );
1246                assert_eq!(
1247                    memory.methods,
1248                    vec![
1249                        "harness.v1.memory.show".to_string(),
1250                        "harness.v1.memory.search".to_string()
1251                    ]
1252                );
1253            } else {
1254                assert_eq!(
1255                    memory.observed,
1256                    ImplementationKind::Absent,
1257                    "{}: memory must be absent",
1258                    harness.id.as_str()
1259                );
1260                assert!(memory.methods.is_empty(), "{}", harness.id.as_str());
1261            }
1262            // forget / reset stay the harness's own verb.
1263            assert_eq!(memory.controlled, ImplementationKind::Absent);
1264        }
1265    }
1266
1267    /// ORCH-11 + ORCH-22: skills are observed AND controlled for the six
1268    /// harnesses whose skill roots `crate::skills` opens, and stay Absent for
1269    /// the rest — supercode itself included, since it has no root of its own.
1270    #[test]
1271    fn skills_are_observed_and_controlled_for_the_harnesses_with_a_skills_loader() {
1272        let report = harness_support_registry();
1273        for harness in &report.harnesses {
1274            let skills = harness
1275                .orchestration
1276                .concepts
1277                .iter()
1278                .find(|concept| concept.concept == "skills")
1279                .unwrap();
1280            if crate::skills::SKILL_HARNESSES.contains(&harness.id.as_str()) {
1281                assert_eq!(
1282                    skills.observed,
1283                    ImplementationKind::BuiltIn,
1284                    "{}",
1285                    harness.id.as_str()
1286                );
1287                // ORCH-22: the write tier is the harness's OWN door — a CLI
1288                // verb for the two gateway harnesses, the loader's directory
1289                // for the core four.
1290                assert_eq!(
1291                    skills.controlled,
1292                    ImplementationKind::BuiltIn,
1293                    "{}",
1294                    harness.id.as_str()
1295                );
1296                assert_eq!(
1297                    skills.methods,
1298                    vec![
1299                        "harness.v1.skills.list".to_string(),
1300                        "harness.v1.skills.install".to_string(),
1301                        "harness.v1.skills.remove".to_string(),
1302                    ]
1303                );
1304            } else {
1305                assert_eq!(
1306                    skills.observed,
1307                    ImplementationKind::Absent,
1308                    "{}",
1309                    harness.id.as_str()
1310                );
1311                assert_eq!(
1312                    skills.controlled,
1313                    ImplementationKind::Absent,
1314                    "{}",
1315                    harness.id.as_str()
1316                );
1317            }
1318        }
1319    }
1320
1321    /// ORCH-14: channels are observed for the two gateway harnesses whose
1322    /// config files `crate::channels` opens, and stay Absent for the rest —
1323    /// Claude Code included, because its channels are declared over the MCP
1324    /// protocol and not in any file supercode can read.
1325    #[test]
1326    fn channels_are_observed_for_the_gateway_harnesses_only() {
1327        let report = harness_support_registry();
1328        for harness in &report.harnesses {
1329            let channel = harness
1330                .orchestration
1331                .concepts
1332                .iter()
1333                .find(|concept| concept.concept == "channel")
1334                .unwrap();
1335            if crate::channels::CHANNEL_HARNESSES.contains(&harness.id.as_str()) {
1336                assert_eq!(
1337                    channel.observed,
1338                    ImplementationKind::BuiltIn,
1339                    "{}",
1340                    harness.id.as_str()
1341                );
1342                assert_eq!(
1343                    channel.methods,
1344                    ["harness.v1.channels.list", "harness.v1.channels.status"]
1345                );
1346            } else {
1347                assert_eq!(
1348                    channel.observed,
1349                    ImplementationKind::Absent,
1350                    "{}",
1351                    harness.id.as_str()
1352                );
1353                assert!(channel.methods.is_empty(), "{}", harness.id.as_str());
1354            }
1355            // Every channel mutation stays the harness's own verb.
1356            assert_eq!(channel.controlled, ImplementationKind::Absent);
1357        }
1358    }
1359
1360    /// ORCH-8: `run` is observed exactly where a fire STORE exists, which is a
1361    /// strictly smaller set than `scheduled_job`. Claude Code is the case that
1362    /// makes the distinction real: it has jobs but no run store, so it must be
1363    /// built-in for one concept and absent for the other in the same
1364    /// descriptor.
1365    #[test]
1366    fn runs_are_observed_only_where_the_harness_keeps_a_fire_store() {
1367        let report = harness_support_registry();
1368        let concept = |harness: &HarnessSupportDescriptor, name: &str| {
1369            harness
1370                .orchestration
1371                .concepts
1372                .iter()
1373                .find(|concept| concept.concept == name)
1374                .unwrap_or_else(|| panic!("no `{name}` concept for {}", harness.id.as_str()))
1375                .clone()
1376        };
1377        let mut observed = Vec::new();
1378        for harness in &report.harnesses {
1379            let run = concept(harness, "run");
1380            if crate::runs::RUN_HARNESSES.contains(&harness.id.as_str()) {
1381                assert_eq!(
1382                    run.observed,
1383                    ImplementationKind::BuiltIn,
1384                    "{}",
1385                    harness.id.as_str()
1386                );
1387                assert_eq!(
1388                    run.methods,
1389                    vec![
1390                        "harness.v1.runs.list".to_string(),
1391                        "harness.v1.runs.get".to_string()
1392                    ]
1393                );
1394                observed.push(harness.id.as_str().to_string());
1395            } else {
1396                assert_eq!(
1397                    run.observed,
1398                    ImplementationKind::Absent,
1399                    "{}",
1400                    harness.id.as_str()
1401                );
1402                assert!(run.methods.is_empty(), "{}", harness.id.as_str());
1403            }
1404            // Retention is the only write verb either harness has, and it is
1405            // not wired: nothing here claims the controlled tier.
1406            assert_eq!(run.controlled, ImplementationKind::Absent);
1407        }
1408        // ORC-7: the orchestrator keeps its fires in the same
1409        // `cron/executions.db`, one per profile folder, so the same reader
1410        // observes it.
1411        assert_eq!(observed, vec!["hermes", "openclaw", "orchestrator"]);
1412
1413        let claude = report
1414            .harnesses
1415            .iter()
1416            .find(|harness| harness.id.as_str() == HarnessId::CLAUDE_CODE)
1417            .expect("claude-code is in the registry");
1418        assert_eq!(
1419            concept(claude, "scheduled_job").observed,
1420            ImplementationKind::BuiltIn,
1421        );
1422        assert_eq!(concept(claude, "run").observed, ImplementationKind::Absent);
1423    }
1424
1425    /// The block is additive: a v1 descriptor without it still deserializes.
1426    #[test]
1427    fn orchestration_block_is_additive_on_the_wire() {
1428        let report = harness_support_registry();
1429        let mut value = serde_json::to_value(&report.harnesses[0]).unwrap();
1430        value.as_object_mut().unwrap().remove("orchestration");
1431        let back: HarnessSupportDescriptor = serde_json::from_value(value).unwrap();
1432        assert!(back.orchestration.concepts.is_empty());
1433    }
1434}