use anyhow::{anyhow, bail, Result};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use ulid::Ulid;
pub(crate) const RUNTIME_API_FAMILY: &str = "ccd-runtime";
pub(crate) const RUNTIME_API_VERSION: u32 = 1;
pub(crate) const EVALUATE_CONTEXT_REFRESH_OPERATION: &str = "evaluate_context_refresh";
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub(crate) struct RuntimeApiView {
family: &'static str,
version: u32,
status: &'static str,
discovery_command: &'static str,
transport_support: RuntimeTransportSupportView,
operations: Vec<RuntimeOperationView>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
struct RuntimeTransportSupportView {
cli: RuntimeTransportView,
mcp: RuntimeTransportView,
library: RuntimeTransportView,
daemon: RuntimeTransportView,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
struct RuntimeTransportView {
status: &'static str,
supports_events: bool,
event_families: Vec<&'static str>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
struct RuntimeOperationView {
name: &'static str,
family: &'static str,
status: &'static str,
current_surfaces: Vec<&'static str>,
canonical_owner: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
current_gap: Option<&'static str>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct RuntimeRequestMetadata {
api_family: String,
api_version: u32,
request_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
actor_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
supervisor_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
host_session_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
host_run_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
host_task_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
approval_request_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
idempotency_key: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub(crate) struct RuntimeResponseMetadata {
api_family: String,
api_version: u32,
operation: String,
request_id: String,
actor_id: Option<String>,
supervisor_id: Option<String>,
host_session_id: Option<String>,
host_run_id: Option<String>,
host_task_id: Option<String>,
approval_request_id: Option<String>,
idempotency_key: Option<String>,
retry_class: &'static str,
}
pub(crate) fn describe_runtime_api() -> RuntimeApiView {
#[cfg(feature = "daemon")]
let daemon_transport = RuntimeTransportView {
status: "available",
supports_events: true,
event_families: crate::runtime_events::advertised_families(),
};
#[cfg(not(feature = "daemon"))]
let daemon_transport = RuntimeTransportView {
status: "planned",
supports_events: false,
event_families: Vec::new(),
};
#[cfg(feature = "daemon")]
let stream_runtime_events = RuntimeOperationView {
name: "stream_runtime_events",
family: "startup_and_inspection",
status: "available",
current_surfaces: vec!["daemon:/events"],
canonical_owner: "kernel_runtime_state",
current_gap: None,
};
#[cfg(not(feature = "daemon"))]
let stream_runtime_events = RuntimeOperationView {
name: "stream_runtime_events",
family: "startup_and_inspection",
status: "planned",
current_surfaces: Vec::new(),
canonical_owner: "kernel_runtime_state",
current_gap: Some(
"implementation removed — event streaming is planned for daemon transport",
),
};
RuntimeApiView {
family: RUNTIME_API_FAMILY,
version: RUNTIME_API_VERSION,
status: "draft",
discovery_command: "describe",
transport_support: RuntimeTransportSupportView {
cli: RuntimeTransportView {
status: "available",
supports_events: false,
event_families: Vec::new(),
},
mcp: RuntimeTransportView {
status: "available",
supports_events: false,
event_families: Vec::new(),
},
library: RuntimeTransportView {
status: "available",
supports_events: false,
event_families: Vec::new(),
},
daemon: daemon_transport,
},
operations: vec![
RuntimeOperationView {
name: "describe_contract",
family: "discovery",
status: "available",
current_surfaces: vec!["describe"],
canonical_owner: "kernel_command_metadata",
current_gap: None,
},
RuntimeOperationView {
name: "describe_runtime_capabilities",
family: "discovery",
status: "available",
current_surfaces: vec!["describe"],
canonical_owner: "kernel_command_metadata",
current_gap: None,
},
RuntimeOperationView {
name: "describe_active_extensions",
family: "discovery",
status: "available",
current_surfaces: vec!["describe", "start", "status", "runtime-state export"],
canonical_owner: "typed_extension_envelopes",
current_gap: None,
},
RuntimeOperationView {
name: "load_startup_context",
family: "startup_and_inspection",
status: "partial",
current_surfaces: vec![
"host-hook on-session-start",
"start",
"status",
"runtime-state export",
"mcp:ccd_session/start",
],
canonical_owner: "kernel_startup_context",
current_gap: Some(
"wrapper-first startup remains CLI-only; MCP exposes the lower-level context loader",
),
},
RuntimeOperationView {
name: "load_runtime_status",
family: "startup_and_inspection",
status: "partial",
current_surfaces: vec!["status", "runtime-state export", "doctor"],
canonical_owner: "kernel_runtime_state",
current_gap: Some("no one runtime-shaped status response exists yet"),
},
RuntimeOperationView {
name: "export_projection",
family: "startup_and_inspection",
status: "available",
current_surfaces: vec!["runtime-state export"],
canonical_owner: "kernel_runtime_state",
current_gap: Some("projection formats are still command-shaped"),
},
RuntimeOperationView {
name: "load_child_bootstrap",
family: "startup_and_inspection",
status: "available",
current_surfaces: vec![
"runtime-state child-bootstrap",
"mcp:ccd_delegation/child-bootstrap",
],
canonical_owner: "kernel_startup_context",
current_gap: Some(
"runtime still owns delegation lifecycle and isolated workspace provisioning",
),
},
stream_runtime_events,
RuntimeOperationView {
name: "start_session",
family: "session_lifecycle",
status: "available",
current_surfaces: vec![
"session-state start",
"mcp:ccd_session_lifecycle/start-session",
],
canonical_owner: "kernel_session_lifecycle",
current_gap: Some("retry envelopes are not yet surfaced"),
},
RuntimeOperationView {
name: "heartbeat_session",
family: "session_lifecycle",
status: "available",
current_surfaces: vec![
"session-state heartbeat",
"mcp:ccd_session_lifecycle/heartbeat-session",
],
canonical_owner: "kernel_session_lifecycle",
current_gap: Some("retry envelopes are not yet surfaced"),
},
RuntimeOperationView {
name: "clear_session",
family: "session_lifecycle",
status: "available",
current_surfaces: vec![
"session-state clear",
"mcp:ccd_session_lifecycle/clear-session",
],
canonical_owner: "kernel_session_lifecycle",
current_gap: Some("idempotency and ownership semantics remain command-shaped"),
},
RuntimeOperationView {
name: "takeover_session",
family: "session_lifecycle",
status: "available",
current_surfaces: vec![
"session-state takeover",
"mcp:ccd_session_lifecycle/takeover-session",
],
canonical_owner: "kernel_session_lifecycle",
current_gap: Some("retry envelopes are not yet surfaced"),
},
RuntimeOperationView {
name: "list_execution_gates",
family: "protected_surfaces",
status: "available",
current_surfaces: vec![
"session-state gates list",
"mcp:ccd_session_gates/list-gates",
],
canonical_owner: "kernel_execution_gates",
current_gap: Some("the shared response envelope is not yet surfaced"),
},
RuntimeOperationView {
name: "replace_execution_gates",
family: "protected_surfaces",
status: "available",
current_surfaces: vec![
"session-state gates replace",
"mcp:ccd_session_gates/replace-gates",
],
canonical_owner: "kernel_execution_gates",
current_gap: Some("retry envelopes are not yet surfaced"),
},
RuntimeOperationView {
name: "seed_execution_gates",
family: "protected_surfaces",
status: "available",
current_surfaces: vec![
"session-state gates seed",
"mcp:ccd_session_gates/seed-gates",
],
canonical_owner: "kernel_execution_gates",
current_gap: Some("retry envelopes are not yet surfaced"),
},
RuntimeOperationView {
name: "set_execution_gate_status",
family: "protected_surfaces",
status: "available",
current_surfaces: vec![
"session-state gates set-status",
"mcp:ccd_session_gates/set-gate-status",
],
canonical_owner: "kernel_execution_gates",
current_gap: Some("retry envelopes are not yet surfaced"),
},
RuntimeOperationView {
name: "advance_execution_gates",
family: "protected_surfaces",
status: "available",
current_surfaces: vec![
"session-state gates advance",
"mcp:ccd_session_gates/advance-gates",
],
canonical_owner: "kernel_execution_gates",
current_gap: Some("retry envelopes are not yet surfaced"),
},
RuntimeOperationView {
name: "clear_execution_gates",
family: "protected_surfaces",
status: "available",
current_surfaces: vec![
"session-state gates clear",
"mcp:ccd_session_gates/clear-gates",
],
canonical_owner: "kernel_execution_gates",
current_gap: Some("retry envelopes are not yet surfaced"),
},
RuntimeOperationView {
name: "refresh_handoff_view",
family: "continuity_and_recovery",
status: "partial",
current_surfaces: vec!["handoff refresh", "start --refresh"],
canonical_owner: "kernel_continuity",
current_gap: Some("refresh semantics remain split across surfaces"),
},
RuntimeOperationView {
name: "write_handoff",
family: "continuity_and_recovery",
status: "partial",
current_surfaces: vec!["handoff write", "handover", "checkpoint"],
canonical_owner: "kernel_continuity",
current_gap: Some("overwrite and retry posture remain command-shaped"),
},
RuntimeOperationView {
name: "write_recovery",
family: "continuity_and_recovery",
status: "available",
current_surfaces: vec!["recovery write", "mcp:ccd_recovery/write-recovery"],
canonical_owner: "kernel_recovery_artifact",
current_gap: Some("CLI, MCP, and daemon event adapters remain follow-on"),
},
RuntimeOperationView {
name: "evaluate_checkpoint",
family: "evaluation",
status: "partial",
current_surfaces: vec!["handover", "checkpoint"],
canonical_owner: "kernel_runtime_evaluation",
current_gap: Some("pure evaluation and conditional write remain coupled"),
},
RuntimeOperationView {
name: EVALUATE_CONTEXT_REFRESH_OPERATION,
family: "evaluation",
status: "available",
current_surfaces: vec!["context-check", "mcp:ccd_context/context-check"],
canonical_owner: "kernel_runtime_evaluation",
current_gap: Some("runtime reminder rendering remains external"),
},
RuntimeOperationView {
name: "evaluate_closeout",
family: "evaluation",
status: "partial",
current_surfaces: vec!["handover"],
canonical_owner: "kernel_runtime_evaluation",
current_gap: Some("no explicit close-out operation response exists yet"),
},
RuntimeOperationView {
name: "list_escalations",
family: "escalation",
status: "available",
current_surfaces: vec![
"escalation-state list",
"mcp:ccd_escalation/list-escalations",
"mcp:ccd_state/escalation-state-list",
],
canonical_owner: "kernel_escalation_state",
current_gap: Some("legacy aliases still exist on `ccd_state`"),
},
RuntimeOperationView {
name: "set_escalation",
family: "escalation",
status: "available",
current_surfaces: vec![
"escalation-state set",
"mcp:ccd_escalation/set-escalation",
"mcp:ccd_state/escalation-state-set",
],
canonical_owner: "kernel_escalation_state",
current_gap: Some("approval-resolution events are not yet surfaced"),
},
RuntimeOperationView {
name: "clear_escalation",
family: "escalation",
status: "available",
current_surfaces: vec![
"escalation-state clear",
"mcp:ccd_escalation/clear-escalation",
],
canonical_owner: "kernel_escalation_state",
current_gap: Some("approval-resolution events are not yet surfaced"),
},
RuntimeOperationView {
name: "submit_memory_evidence",
family: "memory_follow_through",
status: "available",
current_surfaces: vec![
"memory evidence submit",
"mcp:ccd_memory_capture/memory-evidence-submit",
],
canonical_owner: "kernel_governed_memory",
current_gap: Some("runtime adapters still own raw transcript and prompt history"),
},
RuntimeOperationView {
name: "extract_memory_candidates",
family: "memory_follow_through",
status: "available",
current_surfaces: vec![
"memory candidate extract",
"mcp:ccd_memory_capture/memory-candidate-extract",
],
canonical_owner: "kernel_governed_memory",
current_gap: Some(
"broader-scope evidence remains staged until later automation phases",
),
},
RuntimeOperationView {
name: "probe_ingest_sync_status",
family: "memory_follow_through",
status: "available",
current_surfaces: vec![
"memory sync-status",
"mcp:ccd_memory_recall/memory-sync-status",
],
canonical_owner: "kernel_governed_memory",
current_gap: Some("raw transcript and event ingestion remain provider-owned"),
},
RuntimeOperationView {
name: "export_ingest_source_map",
family: "memory_follow_through",
status: "available",
current_surfaces: vec![
"memory source-map",
"mcp:ccd_memory_recall/memory-source-map",
],
canonical_owner: "kernel_governed_memory",
current_gap: Some("raw transcript and event ingestion remain provider-owned"),
},
RuntimeOperationView {
name: "admit_memory_candidate",
family: "memory_follow_through",
status: "available",
current_surfaces: vec![
"memory candidate admit",
"mcp:ccd_memory/memory-candidate-admit",
],
canonical_owner: "kernel_governed_memory",
current_gap: Some(
"the shared runtime request/response envelope is not exposed yet",
),
},
RuntimeOperationView {
name: "promote_memory",
family: "memory_follow_through",
status: "available",
current_surfaces: vec!["memory promote"],
canonical_owner: "kernel_governed_memory",
current_gap: Some("the shared conflict and idempotency model is not exposed yet"),
},
RuntimeOperationView {
name: "compact_memory",
family: "memory_follow_through",
status: "available",
current_surfaces: vec!["memory compact"],
canonical_owner: "kernel_governed_memory",
current_gap: Some("event metadata are not yet surfaced"),
},
],
}
}
pub(crate) fn parse_runtime_request(args: &Value) -> Result<Option<RuntimeRequestMetadata>> {
let Some(request) = args.get("runtime_request") else {
return Ok(None);
};
let request = request
.as_object()
.ok_or_else(|| anyhow!("invalid argument runtime_request: expected an object"))?;
let api_family = request
.get("api_family")
.ok_or_else(|| anyhow!("missing required argument: runtime_request.api_family"))?
.as_str()
.ok_or_else(|| anyhow!("invalid argument runtime_request.api_family: expected a string"))?;
if api_family != RUNTIME_API_FAMILY {
bail!("invalid runtime_request.api_family: expected {RUNTIME_API_FAMILY}");
}
let api_version = request
.get("api_version")
.ok_or_else(|| anyhow!("missing required argument: runtime_request.api_version"))?
.as_u64()
.ok_or_else(|| {
anyhow!("invalid argument runtime_request.api_version: expected an unsigned integer")
})?;
if api_version != RUNTIME_API_VERSION as u64 {
bail!("invalid runtime_request.api_version: expected {RUNTIME_API_VERSION}");
}
let request_id = request
.get("request_id")
.and_then(Value::as_str)
.ok_or_else(|| anyhow!("missing required argument: runtime_request.request_id"))?;
Ok(Some(RuntimeRequestMetadata {
api_family: api_family.to_owned(),
api_version: api_version as u32,
request_id: request_id.to_owned(),
actor_id: opt_object_string(request, "actor_id"),
supervisor_id: opt_object_string(request, "supervisor_id"),
host_session_id: opt_object_string(request, "host_session_id"),
host_run_id: opt_object_string(request, "host_run_id"),
host_task_id: opt_object_string(request, "host_task_id"),
approval_request_id: opt_object_string(request, "approval_request_id"),
idempotency_key: opt_object_string(request, "idempotency_key"),
}))
}
pub(crate) fn runtime_retry_class(operation: &str) -> &'static str {
match operation {
EVALUATE_CONTEXT_REFRESH_OPERATION
| "load_startup_context"
| "load_runtime_status"
| "export_projection"
| "heartbeat_session" => "safe_retry",
"takeover_session" => "do_not_retry",
"start_session"
| "clear_session"
| "replace_execution_gates"
| "seed_execution_gates"
| "set_execution_gate_status"
| "advance_execution_gates"
| "clear_execution_gates"
| "refresh_handoff_view"
| "write_handoff"
| "write_recovery"
| "evaluate_checkpoint"
| "evaluate_closeout"
| "set_escalation"
| "clear_escalation"
| "submit_memory_evidence"
| "extract_memory_candidates"
| "probe_ingest_sync_status"
| "export_ingest_source_map"
| "admit_memory_candidate"
| "promote_memory"
| "compact_memory" => "retry_after_reread",
_ => "safe_retry",
}
}
pub(crate) fn synthetic_response_metadata(operation: &str) -> RuntimeResponseMetadata {
RuntimeResponseMetadata {
api_family: RUNTIME_API_FAMILY.to_owned(),
api_version: RUNTIME_API_VERSION,
operation: operation.to_owned(),
request_id: format!("evt_{}", Ulid::new()),
actor_id: None,
supervisor_id: None,
host_session_id: None,
host_run_id: None,
host_task_id: None,
approval_request_id: None,
idempotency_key: None,
retry_class: runtime_retry_class(operation),
}
}
fn opt_object_string(request: &serde_json::Map<String, Value>, key: &str) -> Option<String> {
request.get(key).and_then(Value::as_str).map(str::to_owned)
}
impl RuntimeRequestMetadata {
pub(crate) fn response_metadata(
&self,
operation: &str,
retry_class: &'static str,
) -> RuntimeResponseMetadata {
RuntimeResponseMetadata {
api_family: self.api_family.clone(),
api_version: self.api_version,
operation: operation.to_owned(),
request_id: self.request_id.clone(),
actor_id: self.actor_id.clone(),
supervisor_id: self.supervisor_id.clone(),
host_session_id: self.host_session_id.clone(),
host_run_id: self.host_run_id.clone(),
host_task_id: self.host_task_id.clone(),
approval_request_id: self.approval_request_id.clone(),
idempotency_key: self.idempotency_key.clone(),
retry_class,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn runtime_manifest_reports_daemon_event_support_truthfully() {
let manifest = describe_runtime_api();
let stream = manifest
.operations
.iter()
.find(|operation| operation.name == "stream_runtime_events")
.expect("stream runtime events operation");
assert_eq!(manifest.transport_support.library.status, "available");
assert!(!manifest.transport_support.library.supports_events);
assert!(manifest.transport_support.library.event_families.is_empty());
if cfg!(feature = "daemon") {
assert_eq!(manifest.transport_support.daemon.status, "available");
assert!(manifest.transport_support.daemon.supports_events);
assert_eq!(
manifest.transport_support.daemon.event_families,
vec![
"runtime.status",
"runtime.approval_required",
"runtime.checkpoint",
"runtime.memory_compaction"
]
);
assert_eq!(stream.status, "available");
assert_eq!(stream.current_surfaces, vec!["daemon:/events"]);
} else {
assert_eq!(manifest.transport_support.daemon.status, "planned");
assert!(!manifest.transport_support.daemon.supports_events);
assert!(manifest.transport_support.daemon.event_families.is_empty());
assert_eq!(stream.status, "planned");
assert!(stream.current_surfaces.is_empty());
}
}
#[test]
fn runtime_manifest_reports_memory_evidence_operations() {
let manifest = describe_runtime_api();
let operation_names = manifest
.operations
.iter()
.map(|operation| operation.name)
.collect::<Vec<_>>();
assert!(operation_names.contains(&"submit_memory_evidence"));
assert!(operation_names.contains(&"extract_memory_candidates"));
assert!(operation_names.contains(&"probe_ingest_sync_status"));
assert!(operation_names.contains(&"export_ingest_source_map"));
}
#[test]
fn parse_runtime_request_requires_api_identity_fields() {
let missing_family = json!({
"runtime_request": {
"api_version": RUNTIME_API_VERSION,
"request_id": "req-runtime-stream"
}
});
let error = parse_runtime_request(&missing_family).expect_err("missing api_family");
assert_eq!(
error.to_string(),
"missing required argument: runtime_request.api_family"
);
let missing_version = json!({
"runtime_request": {
"api_family": RUNTIME_API_FAMILY,
"request_id": "req-runtime-stream"
}
});
let error = parse_runtime_request(&missing_version).expect_err("missing api_version");
assert_eq!(
error.to_string(),
"missing required argument: runtime_request.api_version"
);
}
#[test]
fn response_metadata_serializes_optional_fields_as_null() {
let request = RuntimeRequestMetadata {
api_family: RUNTIME_API_FAMILY.to_owned(),
api_version: RUNTIME_API_VERSION,
request_id: "req-runtime-stream".to_owned(),
actor_id: None,
supervisor_id: None,
host_session_id: None,
host_run_id: None,
host_task_id: None,
approval_request_id: None,
idempotency_key: None,
};
let value = serde_json::to_value(request.response_metadata(
EVALUATE_CONTEXT_REFRESH_OPERATION,
runtime_retry_class(EVALUATE_CONTEXT_REFRESH_OPERATION),
))
.expect("serialize response metadata");
assert!(value.get("actor_id").is_some());
assert!(value["actor_id"].is_null());
assert!(value.get("supervisor_id").is_some());
assert!(value["supervisor_id"].is_null());
assert!(value.get("host_session_id").is_some());
assert!(value["host_session_id"].is_null());
assert!(value.get("host_run_id").is_some());
assert!(value["host_run_id"].is_null());
assert!(value.get("host_task_id").is_some());
assert!(value["host_task_id"].is_null());
assert!(value.get("approval_request_id").is_some());
assert!(value["approval_request_id"].is_null());
assert!(value.get("idempotency_key").is_some());
assert!(value["idempotency_key"].is_null());
}
}