agent_sdk_core/ports/isolation.rs
1//! Host adapter boundaries for the SDK core. Use these traits and registries when
2//! hosts provide providers, journals, sinks, tools, isolation, extensions, telemetry,
3//! or subscriptions. Implementations may perform external side effects and must honor
4//! policy, redaction, idempotency, and replay contracts. This file contains the
5//! isolation portion of that contract.
6//!
7use std::{
8 collections::BTreeMap,
9 sync::{Arc, Mutex},
10};
11
12use serde::{Deserialize, Serialize};
13
14use crate::{
15 domain::{AgentError, AgentErrorKind, ContentRef, RetryClassification},
16 package_isolation::{
17 CleanupPlanRef, ExecutionEnvironment, ImageRef, ImageRequest, IsolatedProcessRef,
18 IsolatedProcessSpec, IsolationAdapterSessionRef, IsolationCapabilityReportRef,
19 IsolationCapabilitySet, IsolationClass, IsolationRuntimeRef, IsolationSessionRef,
20 IsolationTrustRequirement, MountRef, NetworkNamespaceRef, PreparedEnvironmentRef,
21 ProcessIoStreamRef, ProcessStatsSnapshotRef, ReclaimTicketRef, RootfsRef, RootfsRequest,
22 SecretMountRef,
23 },
24};
25
26/// Port or behavior contract for isolation runtime. Implementors should
27/// preserve policy, redaction, idempotency, and replay expectations
28/// from the surrounding module. Implementations may perform side
29/// effects only as described by the trait methods.
30pub trait IsolationRuntime: Send + Sync {
31 /// Returns runtime ref for the current value.
32 /// This is a read-only or data-construction helper unless the method body explicitly calls
33 /// a port or store.
34 fn runtime_ref(&self) -> &IsolationRuntimeRef;
35
36 /// Returns capability report for the current value.
37 /// This is a read-only or data-construction helper unless the method body explicitly calls
38 /// a port or store.
39 fn capability_report(&self) -> Result<IsolationCapabilityReport, AgentError>;
40
41 /// Prepares or selects an isolation session for the request.
42 /// Implementations allocate or select an isolation session for the request; they may mutate
43 /// adapter sandbox state but must not start the process.
44 fn prepare_session(
45 &self,
46 request: SessionPrepareRequest,
47 ) -> Result<IsolationSessionRef, AgentError>;
48
49 /// Resolves an image request into adapter-specific image metadata.
50 /// Implementations resolve isolation planning data; only process-start methods may launch a
51 /// process.
52 fn resolve_image(&self, request: ImageResolveRequest) -> Result<ImageResolution, AgentError>;
53
54 /// Prepares the root filesystem for the isolation session.
55 /// Implementations materialize or select the requested root filesystem and may touch host
56 /// storage or image caches; they must not start the process.
57 fn prepare_rootfs(&self, request: RootfsPrepareRequest) -> Result<RootfsRef, AgentError>;
58
59 /// Resolves requested mounts into a mount plan for the environment.
60 /// Implementations resolve isolation planning data; only process-start methods may launch a
61 /// process.
62 fn resolve_mounts(&self, request: MountResolveRequest) -> Result<MountPlan, AgentError>;
63
64 /// Configures or selects the network namespace for the environment.
65 /// Implementations resolve isolation planning data; only process-start methods may launch a
66 /// process.
67 fn configure_network(
68 &self,
69 request: NetworkPrepareRequest,
70 ) -> Result<NetworkNamespaceRef, AgentError>;
71
72 /// Prepares secret mounts or handles for the environment.
73 /// Implementations materialize secret mounts or handles for the isolated environment and
74 /// must not return raw secret values.
75 fn prepare_secrets(
76 &self,
77 request: SecretPrepareRequest,
78 ) -> Result<SecretMaterializationPlan, AgentError>;
79
80 /// Combines prepared isolation pieces into an executable environment.
81 /// Implementations combine prepared rootfs, mounts, network, and secrets into an executable
82 /// environment handle; they must not start the process.
83 fn prepare_environment(
84 &self,
85 request: EnvironmentPrepareRequest,
86 ) -> Result<PreparedEnvironmentRef, AgentError>;
87
88 /// Starts the prepared isolated process through the host adapter.
89 /// Implementations may launch a process or container and return process
90 /// handles, but journal intent/result recording stays with the runtime.
91 fn start_process(&self, request: ProcessStartRequest)
92 -> Result<ProcessStartResult, AgentError>;
93
94 /// Reads or writes one bounded I/O frame for an isolated process.
95 /// Implementations may touch host process streams, but must preserve
96 /// redaction and return stream refs or bounded data according to policy.
97 fn stream_io(&self, request: ProcessIoRequest) -> Result<ProcessIoFrame, AgentError>;
98
99 /// Sends a control signal to an already-started isolated process.
100 /// Implementations return the observed signal result and leave lifecycle
101 /// journal evidence to the runtime.
102 fn signal_process(
103 &self,
104 request: ProcessSignalRequest,
105 ) -> Result<ProcessSignalResult, AgentError>;
106
107 /// Collects statistics for an already-started isolated process.
108 /// Implementations may query host process/container state and must return
109 /// bounded metadata rather than raw process output.
110 fn collect_stats(
111 &self,
112 request: ProcessStatsRequest,
113 ) -> Result<ProcessStatsSnapshot, AgentError>;
114
115 /// Cleans up adapter-owned isolation resources for a finished process.
116 /// Implementations may remove sessions, mounts, namespaces, or reclaim
117 /// tickets selected by the cleanup request.
118 fn cleanup(&self, request: CleanupRequest) -> Result<CleanupResult, AgentError>;
119
120 /// Transfers ownership of isolation resources according to a detach plan.
121 /// Implementations may leave processes or resources running under a reclaim
122 /// ticket, but must not silently discard cleanup responsibility.
123 fn detach(&self, request: DetachTransferRequest) -> Result<DetachTransferResult, AgentError>;
124
125 /// Reclaims resources that were previously detached from runtime ownership.
126 /// Implementations may stop processes or remove resources referenced by the
127 /// reclaim ticket and must report any cleanup failure for repair.
128 fn reclaim(&self, request: ReclaimRequest) -> Result<ReclaimResult, AgentError>;
129}
130
131#[derive(Clone, Default)]
132/// Carries isolation runtime registry data across a host-port boundary.
133/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
134pub struct IsolationRuntimeRegistry {
135 runtimes: BTreeMap<String, Arc<dyn IsolationRuntime>>,
136}
137
138impl IsolationRuntimeRegistry {
139 /// Creates a new ports::isolation value with explicit
140 /// caller-provided inputs. This constructor is data-only and
141 /// performs no I/O or external side effects.
142 pub fn new() -> Self {
143 Self::default()
144 }
145
146 /// Adds data to this in-memory ports::isolation collection. It does not
147 /// perform external I/O, execute tools, or append journals.
148 pub fn register(&mut self, runtime: Arc<dyn IsolationRuntime>) -> Result<(), AgentError> {
149 let runtime_ref = runtime.runtime_ref().as_str().to_string();
150 if runtime_ref.is_empty() {
151 return Err(AgentError::missing_required_field(
152 "isolation_runtime.runtime_ref",
153 ));
154 }
155 self.runtimes.insert(runtime_ref, runtime);
156 Ok(())
157 }
158
159 /// Looks up an entry in this local store without registry or runtime work.
160 /// This reads the in-memory isolation runtime registry and does not call the adapter.
161 pub fn get(&self, runtime_ref: &IsolationRuntimeRef) -> Option<Arc<dyn IsolationRuntime>> {
162 self.runtimes.get(runtime_ref.as_str()).cloned()
163 }
164
165 /// Returns first for the current value.
166 /// This is a read-only or data-construction helper unless the method body explicitly calls
167 /// a port or store.
168 pub fn first(&self) -> Option<Arc<dyn IsolationRuntime>> {
169 self.runtimes.values().next().cloned()
170 }
171
172 /// Reports whether this value is empty. The check is pure and does
173 /// not mutate SDK or host state.
174 pub fn is_empty(&self) -> bool {
175 self.runtimes.is_empty()
176 }
177}
178
179#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
180/// Carries isolation capability report data across a host-port boundary.
181/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
182pub struct IsolationCapabilityReport {
183 /// Typed report ref reference. Resolving or executing it is a separate
184 /// policy-gated step.
185 pub report_ref: IsolationCapabilityReportRef,
186 /// Typed adapter ref reference. Resolving or executing it is a separate
187 /// policy-gated step.
188 pub adapter_ref: IsolationRuntimeRef,
189 /// Kind discriminator for adapter kind.
190 /// Use it to route finite match arms without parsing display text.
191 pub adapter_kind: IsolationRuntimeKind,
192 /// Version string for this capability, package, or protocol surface.
193 /// Use it for compatibility checks during package or adapter resolution.
194 pub adapter_version: String,
195 /// Capability version advertised by the provider or package.
196 /// Use it to match compatible feature contracts during package resolution.
197 pub capability_version: String,
198 /// Health used by this record or request.
199 pub health: IsolationRuntimeHealth,
200 #[serde(default, skip_serializing_if = "Vec::is_empty")]
201 /// Classification selectors for supported classes.
202 /// Policy and projection paths use them for finite routing decisions.
203 pub supported_classes: Vec<IsolationClass>,
204 /// Platform used by this record or request.
205 pub platform: PlatformReport,
206 /// Capabilities frozen into the package or returned by an adapter health
207 /// check.
208 pub capabilities: IsolationCapabilitySet,
209 /// Trust class used when deciding whether context or capabilities may be
210 /// admitted.
211 pub trust: IsolationTrustRequirement,
212 #[serde(default, skip_serializing_if = "Vec::is_empty")]
213 /// Collection of unsupported requirements values.
214 /// Ordering and membership should be treated as part of the serialized contract when
215 /// relevant.
216 pub unsupported_requirements: Vec<String>,
217 /// Retention class for referenced content or records.
218 /// Stores and telemetry sinks use it to decide how long evidence may be kept.
219 pub log_retention: crate::domain::RetentionClass,
220}
221
222impl IsolationCapabilityReport {
223 /// Returns sandbox for the current value.
224 /// This is a read-only or data-construction helper unless the method body explicitly calls
225 /// a port or store.
226 pub fn sandbox(adapter_ref: impl Into<IsolationRuntimeRef>) -> Self {
227 let adapter_ref = adapter_ref.into();
228 Self {
229 report_ref: IsolationCapabilityReportRef::new(format!(
230 "report.{}",
231 adapter_ref.as_str()
232 )),
233 adapter_ref,
234 adapter_kind: IsolationRuntimeKind::HostProvided,
235 adapter_version: "fake.v1".to_string(),
236 capability_version: "isolation.capability.v1".to_string(),
237 health: IsolationRuntimeHealth::Healthy,
238 supported_classes: vec![IsolationClass::Sandbox],
239 platform: PlatformReport::portable_fake(),
240 capabilities: IsolationCapabilitySet::default().with_all([
241 crate::IsolationCapability::ReadOnlyRoot,
242 crate::IsolationCapability::NoNetworkGuarantee,
243 crate::IsolationCapability::Cleanup,
244 crate::IsolationCapability::ProcessTimeout,
245 crate::IsolationCapability::ProcessSignal,
246 crate::IsolationCapability::IoRedaction,
247 crate::IsolationCapability::ContentRefIo,
248 crate::IsolationCapability::ProcessStats,
249 crate::IsolationCapability::SecretIsolation,
250 ]),
251 trust: IsolationTrustRequirement::local_dedicated(),
252 unsupported_requirements: Vec::new(),
253 log_retention: crate::domain::RetentionClass::RunScoped,
254 }
255 }
256
257 /// Returns host process for the current value.
258 /// This is a read-only or data-construction helper unless the method body explicitly calls
259 /// a port or store.
260 pub fn host_process(adapter_ref: impl Into<IsolationRuntimeRef>) -> Self {
261 let adapter_ref = adapter_ref.into();
262 Self {
263 report_ref: IsolationCapabilityReportRef::new(format!(
264 "report.{}",
265 adapter_ref.as_str()
266 )),
267 adapter_ref,
268 adapter_kind: IsolationRuntimeKind::TestOnlyFake,
269 adapter_version: "fake.host.v1".to_string(),
270 capability_version: "isolation.capability.host.v1".to_string(),
271 health: IsolationRuntimeHealth::Healthy,
272 supported_classes: vec![IsolationClass::HostProcess],
273 platform: PlatformReport::portable_fake(),
274 capabilities: IsolationCapabilitySet::default().with_all([
275 crate::IsolationCapability::ProcessTimeout,
276 crate::IsolationCapability::IoRedaction,
277 ]),
278 trust: IsolationTrustRequirement::any(),
279 unsupported_requirements: Vec::new(),
280 log_retention: crate::domain::RetentionClass::RunScoped,
281 }
282 }
283
284 /// Returns unsupported for the current value.
285 /// This is a read-only or data-construction helper unless the method body explicitly calls
286 /// a port or store.
287 pub fn unsupported(
288 adapter_ref: impl Into<IsolationRuntimeRef>,
289 missing: impl IntoIterator<Item = impl Into<String>>,
290 ) -> Self {
291 let mut report = Self::sandbox(adapter_ref);
292 let missing = missing.into_iter().map(Into::into).collect::<Vec<_>>();
293 report.health = IsolationRuntimeHealth::UnsupportedHost {
294 missing_prerequisites: missing.clone(),
295 };
296 report.unsupported_requirements = missing;
297 report
298 }
299}
300
301#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
302#[serde(rename_all = "snake_case")]
303/// Enumerates the finite isolation runtime kind cases.
304/// Serialized names are part of the SDK contract; update fixtures when variants change.
305pub enum IsolationRuntimeKind {
306 /// Use this variant when the contract needs to represent host provided; selecting it has no side effect by itself.
307 HostProvided,
308 /// Use this variant when the contract needs to represent host process; selecting it has no side effect by itself.
309 HostProcess,
310 /// Use this variant when the contract needs to represent os sandbox; selecting it has no side effect by itself.
311 OsSandbox,
312 /// Use this variant when the contract needs to represent container; selecting it has no side effect by itself.
313 Container,
314 /// Use this variant when the contract needs to represent lightweight vm; selecting it has no side effect by itself.
315 LightweightVm,
316 /// Use this variant when the contract needs to represent remote sandbox; selecting it has no side effect by itself.
317 RemoteSandbox,
318 /// Use this variant when the contract needs to represent test only fake; selecting it has no side effect by itself.
319 TestOnlyFake,
320}
321
322#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
323#[serde(rename_all = "snake_case")]
324/// Enumerates the finite isolation runtime health cases.
325/// Serialized names are part of the SDK contract; update fixtures when variants change.
326pub enum IsolationRuntimeHealth {
327 /// Use this variant when the contract needs to represent healthy; selecting it has no side effect by itself.
328 Healthy,
329 /// Use this variant when the contract needs to represent degraded; selecting it has no side effect by itself.
330 Degraded {
331 /// Redacted explanation for a denial, failure, status, or package
332 /// delta.
333 reason: String,
334 },
335 /// Use this variant when the contract needs to represent unsupported host; selecting it has no side effect by itself.
336 UnsupportedHost {
337 /// Collection of missing prerequisites values.
338 /// Ordering and membership should be treated as part of the serialized contract when
339 /// relevant.
340 missing_prerequisites: Vec<String>,
341 },
342}
343
344#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
345/// Carries platform report data across a host-port boundary.
346/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
347pub struct PlatformReport {
348 /// Platform used by this record or request.
349 pub platform: String,
350 /// Os used by this record or request.
351 pub os: String,
352 /// Cpu architecture used by this record or request.
353 pub cpu_architecture: String,
354 /// Whether emulation supported is enabled.
355 /// Policy, validation, or routing code uses this flag to choose the explicit behavior.
356 pub emulation_supported: bool,
357}
358
359impl PlatformReport {
360 /// Returns portable fake for the current value.
361 /// This is a read-only or data-construction helper unless the method body explicitly calls
362 /// a port or store.
363 pub fn portable_fake() -> Self {
364 Self {
365 platform: "portable-test".to_string(),
366 os: "test-os".to_string(),
367 cpu_architecture: "test-arch".to_string(),
368 emulation_supported: false,
369 }
370 }
371}
372
373#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
374/// Carries session prepare request data across a host-port boundary.
375/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
376pub struct SessionPrepareRequest {
377 /// Environment used by this record or request.
378 pub environment: ExecutionEnvironment,
379}
380
381#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
382/// Carries image resolve request data across a host-port boundary.
383/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
384pub struct ImageResolveRequest {
385 /// Image used by this record or request.
386 pub image: ImageRequest,
387}
388
389#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
390/// Carries image resolution data across a host-port boundary.
391/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
392pub struct ImageResolution {
393 /// Typed image ref reference. Resolving or executing it is a separate
394 /// policy-gated step.
395 pub image_ref: ImageRef,
396 /// Digest used by this record or request.
397 pub digest: String,
398 /// Optional redacted credential alias value.
399 /// When absent, callers should use the documented default or skip that optional behavior.
400 pub redacted_credential_alias: Option<String>,
401}
402
403#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
404/// Carries rootfs prepare request data across a host-port boundary.
405/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
406pub struct RootfsPrepareRequest {
407 /// Rootfs used by this record or request.
408 pub rootfs: RootfsRequest,
409}
410
411#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
412/// Carries mount resolve request data across a host-port boundary.
413/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
414pub struct MountResolveRequest {
415 /// Environment used by this record or request.
416 pub environment: ExecutionEnvironment,
417}
418
419#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
420/// Carries mount plan data across a host-port boundary.
421/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
422pub struct MountPlan {
423 #[serde(default, skip_serializing_if = "Vec::is_empty")]
424 /// Collection of mounts values.
425 /// Ordering and membership should be treated as part of the serialized contract when
426 /// relevant.
427 pub mounts: Vec<MountRef>,
428 #[serde(default, skip_serializing_if = "Vec::is_empty")]
429 /// Collection of expanded exposure audits values.
430 /// Ordering and membership should be treated as part of the serialized contract when
431 /// relevant.
432 pub expanded_exposure_audits: Vec<String>,
433}
434
435#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
436/// Carries network prepare request data across a host-port boundary.
437/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
438pub struct NetworkPrepareRequest {
439 /// Environment used by this record or request.
440 pub environment: ExecutionEnvironment,
441}
442
443#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
444/// Carries secret prepare request data across a host-port boundary.
445/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
446pub struct SecretPrepareRequest {
447 /// Environment used by this record or request.
448 pub environment: ExecutionEnvironment,
449}
450
451#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
452/// Carries secret materialization plan data across a host-port boundary.
453/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
454pub struct SecretMaterializationPlan {
455 #[serde(default, skip_serializing_if = "Vec::is_empty")]
456 /// Typed secret mount refs references. Resolving them is separate from
457 /// constructing this record.
458 pub secret_mount_refs: Vec<SecretMountRef>,
459 /// Whether teardown required is enabled.
460 /// Policy, validation, or routing code uses this flag to choose the explicit behavior.
461 pub teardown_required: bool,
462}
463
464#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
465/// Carries environment prepare request data across a host-port boundary.
466/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
467pub struct EnvironmentPrepareRequest {
468 /// Environment used by this record or request.
469 pub environment: ExecutionEnvironment,
470}
471
472#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
473/// Carries process start request data across a host-port boundary.
474/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
475pub struct ProcessStartRequest {
476 /// Environment used by this record or request.
477 pub environment: ExecutionEnvironment,
478 /// Process used by this record or request.
479 pub process: IsolatedProcessSpec,
480 /// Effect intent used by this record or request.
481 pub effect_intent: crate::EffectIntent,
482}
483
484#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
485/// Carries process start result data across a host-port boundary.
486/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
487pub struct ProcessStartResult {
488 /// Typed process ref reference. Resolving or executing it is a separate
489 /// policy-gated step.
490 pub process_ref: IsolatedProcessRef,
491 /// Typed adapter session ref reference. Resolving or executing it is a
492 /// separate policy-gated step.
493 pub adapter_session_ref: Option<IsolationAdapterSessionRef>,
494 /// Terminal status used by this record or request.
495 pub terminal_status: crate::EffectTerminalStatus,
496 /// Stable external operation id used for typed lineage, lookup, or
497 /// dedupe.
498 pub external_operation_id: Option<String>,
499 #[serde(default, skip_serializing_if = "Vec::is_empty")]
500 /// Collection of io frames values.
501 /// Ordering and membership should be treated as part of the serialized contract when
502 /// relevant.
503 pub io_frames: Vec<ProcessIoFrame>,
504 /// Redacted human-readable summary safe for events, telemetry, and logs.
505 pub redacted_summary: String,
506}
507
508#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
509/// Carries process io request data across a host-port boundary.
510/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
511pub struct ProcessIoRequest {
512 /// Typed process ref reference. Resolving or executing it is a separate
513 /// policy-gated step.
514 pub process_ref: IsolatedProcessRef,
515 /// Stream used by this record or request.
516 pub stream: ProcessIoStream,
517}
518
519#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
520/// Carries process io frame data across a host-port boundary.
521/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
522pub struct ProcessIoFrame {
523 /// Typed stream ref reference. Resolving or executing it is a separate
524 /// policy-gated step.
525 pub stream_ref: ProcessIoStreamRef,
526 /// Stream used by this record or request.
527 pub stream: ProcessIoStream,
528 /// Cursor identifying a replay, export, or subscription position.
529 /// Use it to resume without widening the original scope.
530 pub cursor: u64,
531 /// Count of byte items observed or included in this record.
532 pub byte_count: u64,
533 /// Stable hash for the bytes or canonical payload used for stale checks
534 /// and fingerprints.
535 pub content_hash: String,
536 #[serde(default, skip_serializing_if = "Vec::is_empty")]
537 /// Content references associated with this record; resolving them is a
538 /// separate policy-gated step.
539 pub content_refs: Vec<ContentRef>,
540 /// Raw content or raw-content control for this value.
541 /// Use it only when policy explicitly allows raw content capture or delivery.
542 pub raw_content_present: bool,
543 /// Whether output was shortened by byte, item, page, archive, or parser
544 /// limits.
545 pub truncated: bool,
546 /// Redacted human-readable summary safe for events, telemetry, and logs.
547 pub redacted_summary: String,
548}
549
550#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
551#[serde(rename_all = "snake_case")]
552/// Enumerates the finite process io stream cases.
553/// Serialized names are part of the SDK contract; update fixtures when variants change.
554pub enum ProcessIoStream {
555 /// Use this variant when the contract needs to represent stdin; selecting it has no side effect by itself.
556 Stdin,
557 /// Use this variant when the contract needs to represent stdout; selecting it has no side effect by itself.
558 Stdout,
559 /// Use this variant when the contract needs to represent stderr; selecting it has no side effect by itself.
560 Stderr,
561}
562
563#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
564/// Carries process signal request data across a host-port boundary.
565/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
566pub struct ProcessSignalRequest {
567 /// Typed process ref reference. Resolving or executing it is a separate
568 /// policy-gated step.
569 pub process_ref: IsolatedProcessRef,
570 /// Signal used by this record or request.
571 pub signal: ProcessSignal,
572 /// Grace period in milliseconds before termination or cleanup escalates.
573 pub grace_ms: u64,
574}
575
576#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
577/// Carries process signal result data across a host-port boundary.
578/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
579pub struct ProcessSignalResult {
580 /// Typed process ref reference. Resolving or executing it is a separate
581 /// policy-gated step.
582 pub process_ref: IsolatedProcessRef,
583 /// Signal used by this record or request.
584 pub signal: ProcessSignal,
585 /// Whether delivered is enabled.
586 /// Policy, validation, or routing code uses this flag to choose the explicit behavior.
587 pub delivered: bool,
588 /// Redacted human-readable summary safe for events, telemetry, and logs.
589 pub redacted_summary: String,
590}
591
592#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
593#[serde(rename_all = "snake_case")]
594/// Enumerates the finite process signal cases.
595/// Serialized names are part of the SDK contract; update fixtures when variants change.
596pub enum ProcessSignal {
597 /// Use this variant when the contract needs to represent interrupt; selecting it has no side effect by itself.
598 Interrupt,
599 /// Use this variant when the contract needs to represent terminate; selecting it has no side effect by itself.
600 Terminate,
601 /// Use this variant when the contract needs to represent kill; selecting it has no side effect by itself.
602 Kill,
603}
604
605#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
606/// Carries process stats request data across a host-port boundary.
607/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
608pub struct ProcessStatsRequest {
609 /// Typed process ref reference. Resolving or executing it is a separate
610 /// policy-gated step.
611 pub process_ref: IsolatedProcessRef,
612}
613
614#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
615/// Carries process stats snapshot data across a host-port boundary.
616/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
617pub struct ProcessStatsSnapshot {
618 /// Typed snapshot ref reference. Resolving or executing it is a separate
619 /// policy-gated step.
620 pub snapshot_ref: ProcessStatsSnapshotRef,
621 /// Typed process ref reference. Resolving or executing it is a separate
622 /// policy-gated step.
623 pub process_ref: IsolatedProcessRef,
624 /// Time value in milliseconds for cpu millis.
625 /// Use it for timeout, ordering, or diagnostic calculations.
626 pub cpu_millis: Option<u64>,
627 /// memory bytes used for bounds checks, summaries, or truncation
628 /// evidence.
629 pub memory_bytes: Option<u64>,
630 /// Count of process items observed or included in this record.
631 pub process_count: Option<u32>,
632 /// filesystem bytes used for bounds checks, summaries, or truncation
633 /// evidence.
634 pub filesystem_bytes: Option<u64>,
635 /// network bytes used for bounds checks, summaries, or truncation
636 /// evidence.
637 pub network_bytes: Option<u64>,
638 /// Process exit status when the process reported one.
639 pub exit_code: Option<i32>,
640 /// Redacted human-readable summary safe for events, telemetry, and logs.
641 pub redacted_summary: String,
642}
643
644#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
645/// Carries cleanup request data across a host-port boundary.
646/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
647pub struct CleanupRequest {
648 /// Environment used by this record or request.
649 pub environment: ExecutionEnvironment,
650 /// Typed cleanup plan ref reference. Resolving or executing it is a
651 /// separate policy-gated step.
652 pub cleanup_plan_ref: CleanupPlanRef,
653}
654
655#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
656/// Carries cleanup result data across a host-port boundary.
657/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
658pub struct CleanupResult {
659 /// Typed cleanup plan ref reference. Resolving or executing it is a
660 /// separate policy-gated step.
661 pub cleanup_plan_ref: CleanupPlanRef,
662 /// Finite status for this record or lifecycle stage.
663 pub status: CleanupStatus,
664 /// Stable external operation id used for typed lineage, lookup, or
665 /// dedupe.
666 pub external_operation_id: Option<String>,
667 /// Redacted human-readable summary safe for events, telemetry, and logs.
668 pub redacted_summary: String,
669}
670
671#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
672#[serde(rename_all = "snake_case")]
673/// Enumerates the finite cleanup status cases.
674/// Serialized names are part of the SDK contract; update fixtures when variants change.
675pub enum CleanupStatus {
676 /// Use this variant when the contract needs to represent completed; selecting it has no side effect by itself.
677 Completed,
678 /// Use this variant when the contract needs to represent repair needed; selecting it has no side effect by itself.
679 RepairNeeded,
680}
681
682#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
683/// Carries detach transfer request data across a host-port boundary.
684/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
685pub struct DetachTransferRequest {
686 /// Environment used by this record or request.
687 pub environment: ExecutionEnvironment,
688}
689
690#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
691/// Carries detach transfer result data across a host-port boundary.
692/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
693pub struct DetachTransferResult {
694 /// Typed host ack ref reference. Resolving or executing it is a separate
695 /// policy-gated step.
696 pub host_ack_ref: String,
697 /// Redacted human-readable summary safe for events, telemetry, and logs.
698 pub redacted_summary: String,
699}
700
701#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
702/// Carries reclaim request data across a host-port boundary.
703/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
704pub struct ReclaimRequest {
705 /// Typed ticket ref reference. Resolving or executing it is a separate
706 /// policy-gated step.
707 pub ticket_ref: ReclaimTicketRef,
708}
709
710#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
711/// Carries reclaim result data across a host-port boundary.
712/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
713pub struct ReclaimResult {
714 /// Typed ticket ref reference. Resolving or executing it is a separate
715 /// policy-gated step.
716 pub ticket_ref: ReclaimTicketRef,
717 /// Finite status for this record or lifecycle stage.
718 pub status: CleanupStatus,
719 /// Redacted human-readable summary safe for events, telemetry, and logs.
720 pub redacted_summary: String,
721}
722
723#[derive(Clone, Debug, Default)]
724/// Carries isolation runtime call log data across a host-port boundary.
725/// Constructing the value does not call the host; the port method that receives it documents any adapter, network, or storage effect.
726pub struct IsolationRuntimeCallLog {
727 calls: Arc<Mutex<Vec<String>>>,
728}
729
730impl IsolationRuntimeCallLog {
731 /// Operates on in-memory or journal-derived ports::isolation state for
732 /// diagnostics and repair evidence. It does not create a second run loop
733 /// or product workflow owner.
734 pub fn push(&self, call: impl Into<String>) {
735 self.calls
736 .lock()
737 .expect("isolation call log")
738 .push(call.into());
739 }
740
741 /// Operates on in-memory or journal-derived ports::isolation state for
742 /// diagnostics and repair evidence. It does not create a second run loop
743 /// or product workflow owner.
744 pub fn calls(&self) -> Vec<String> {
745 self.calls.lock().expect("isolation call log").clone()
746 }
747
748 /// Operates on in-memory or journal-derived ports::isolation state for
749 /// diagnostics and repair evidence. It does not create a second run loop
750 /// or product workflow owner.
751 pub fn count_matching(&self, call: &str) -> usize {
752 self.calls()
753 .into_iter()
754 .filter(|entry| entry == call)
755 .count()
756 }
757}
758
759/// Builds the isolation host configuration needed value.
760/// This is data construction and performs no I/O, journal append, event publication, or process
761pub fn isolation_host_configuration_needed(message: impl Into<String>) -> AgentError {
762 AgentError::new(
763 AgentErrorKind::IsolationFailure,
764 RetryClassification::HostConfigurationNeeded,
765 message,
766 )
767}