Skip to main content

agent_sdk_core/domain/
policy.rs

1//! Domain primitives for stable SDK vocabulary. Use these items for IDs, refs,
2//! policy, privacy, trust, and errors that cross crate or host boundaries. They are
3//! data-only and must not perform provider, filesystem, network, or UI side effects.
4//! This file contains the policy portion of that contract.
5//!
6use crate::domain::{
7    AdapterRef, DestinationRef, EntityRef, PolicyRef, PrivacyClass, RetentionClass, SourceRef,
8    TrustClass,
9};
10use crate::error::{AgentError, AgentErrorKind, CausalIds, RetryClassification};
11use serde::{Deserialize, Serialize};
12
13#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
14/// Enumerates the finite policy decision cases.
15/// Serialized names are part of the SDK contract; update fixtures when variants change.
16pub enum PolicyDecision {
17    /// Use this variant when the contract needs to represent allow; selecting it has no side effect by itself.
18    Allow {
19        /// Redacted explanation for a denial, failure, status, or package
20        /// delta.
21        reason: DecisionReason,
22    },
23    /// Use this variant when the contract needs to represent deny; selecting it has no side effect by itself.
24    Deny {
25        /// Redacted explanation for a denial, failure, status, or package
26        /// delta.
27        reason: DecisionReason,
28    },
29    /// Use this variant when the contract needs to represent ask; selecting it has no side effect by itself.
30    Ask {
31        /// Approval used by this record or request.
32        approval: ApprovalRequestSpec,
33    },
34    /// Use this variant when the contract needs to represent modify; selecting it has no side effect by itself.
35    Modify {
36        /// Modification used by this record or request.
37        modification: ToolRequestModification,
38    },
39    /// Use this variant when the contract needs to represent defer; selecting it has no side effect by itself.
40    Defer {
41        /// Resume policy used by this record or request.
42        resume_policy: ResumePolicy,
43    },
44    /// Use this variant when the contract needs to represent interrupt; selecting it has no side effect by itself.
45    Interrupt {
46        /// Redacted explanation for a denial, failure, status, or package
47        /// delta.
48        reason: DecisionReason,
49    },
50}
51
52impl PolicyDecision {
53    /// Builds the allow value.
54    /// This is data construction and performs no I/O, journal append, event publication, or
55    /// process work.
56    pub fn allow(code: impl Into<String>) -> Self {
57        Self::Allow {
58            reason: DecisionReason::new(code),
59        }
60    }
61
62    /// Returns an updated domain::policy value with deny applied. This is
63    /// data construction only and does not execute the configured behavior.
64    pub fn deny(code: impl Into<String>) -> Self {
65        Self::Deny {
66            reason: DecisionReason::new(code),
67        }
68    }
69
70    /// Interrupt.
71    /// This is data-only and does not perform I/O, call host ports, append journals, publish
72    /// events, or start processes.
73    pub fn interrupt(code: impl Into<String>) -> Self {
74        Self::Interrupt {
75            reason: DecisionReason::new(code),
76        }
77    }
78
79    /// Reports whether this value is allow. The check is pure and does
80    /// not mutate SDK or host state.
81    pub fn is_allow(&self) -> bool {
82        matches!(self, Self::Allow { .. })
83    }
84}
85
86impl Default for PolicyDecision {
87    fn default() -> Self {
88        Self::deny("policy.default_deny")
89    }
90}
91
92#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
93/// Defines the policy outcome SDK value.
94/// Construction records local state only; documented runtimes, executors, or ports own side effects.
95pub struct PolicyOutcome {
96    /// Stage used by this record or request.
97    pub stage: PolicyStage,
98    /// Decision used by this record or request.
99    pub decision: PolicyDecision,
100    /// Optional subject value.
101    /// When absent, callers should use the documented default or skip that optional behavior.
102    pub subject: Option<EntityRef>,
103    /// Source label or ref for this item; it is metadata and does not fetch
104    /// content by itself.
105    pub source: Option<SourceRef>,
106    /// Destination label or ref for this item; it is metadata and does not
107    /// deliver content by itself.
108    pub destination: Option<DestinationRef>,
109    /// Policy references that govern admission, projection, execution, or
110    /// delivery.
111    pub policy_refs: Vec<PolicyRef>,
112    /// Privacy class used for projection, telemetry, and raw-content access
113    /// decisions.
114    pub privacy: PrivacyClass,
115    /// Retention class used by hosts and sinks when storing or exporting this
116    /// item.
117    pub retention: RetentionClass,
118}
119
120impl PolicyOutcome {
121    /// Builds the denied record or result value.
122    /// This is data-only and does not perform I/O, call host ports, append journals, publish
123    /// events, or start processes.
124    pub fn denied(stage: PolicyStage, code: impl Into<String>) -> Self {
125        Self {
126            stage,
127            decision: PolicyDecision::deny(code),
128            subject: None,
129            source: None,
130            destination: None,
131            policy_refs: Vec::new(),
132            privacy: PrivacyClass::Internal,
133            retention: RetentionClass::RunScoped,
134        }
135    }
136
137    /// Builds the fail closed value.
138    /// This is data construction and performs no I/O, journal append, event publication, or
139    /// process work.
140    pub fn fail_closed(stage: PolicyStage, dependency: MissingDependency) -> Self {
141        Self::denied(stage, dependency.reason_code())
142    }
143
144    /// Reports whether this value is allowed. The check is pure and
145    /// does not mutate SDK or host state.
146    pub fn is_allowed(&self) -> bool {
147        self.decision.is_allow()
148    }
149}
150
151#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
152/// Defines the decision reason SDK value.
153/// Construction records local state only; documented runtimes, executors, or ports own side effects.
154pub struct DecisionReason {
155    /// Code used by this record or request.
156    pub code: String,
157    /// Redacted human-readable summary safe for events, telemetry, and logs.
158    pub redacted_summary: Option<String>,
159    /// Policy references that govern admission, projection, execution, or
160    /// delivery.
161    pub policy_refs: Vec<PolicyRef>,
162}
163
164impl DecisionReason {
165    /// Creates a new domain::policy value with explicit caller-provided
166    /// inputs. This constructor is data-only and performs no I/O or
167    /// external side effects.
168    pub fn new(code: impl Into<String>) -> Self {
169        Self {
170            code: code.into(),
171            redacted_summary: None,
172            policy_refs: Vec::new(),
173        }
174    }
175}
176
177#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
178/// Defines the approval request spec SDK value.
179/// Construction records local state only; documented runtimes, executors, or ports own side effects.
180pub struct ApprovalRequestSpec {
181    /// Source label or ref for this item; it is metadata and does not fetch
182    /// content by itself.
183    pub source: SourceRef,
184    /// Destination label or ref for this item; it is metadata and does not
185    /// deliver content by itself.
186    pub destination: DestinationRef,
187    /// Classification value for effect class.
188    /// Policy and projection paths use it for finite routing decisions.
189    pub effect_class: EffectClass,
190    /// Risk classification for the operation or capability.
191    /// Policy uses it to decide whether approval, sandboxing, or denial is required.
192    pub risk_class: RiskClass,
193    /// Dispatcher scope used by this record or request.
194    pub dispatcher_scope: DispatcherScope,
195    /// Timeout budget in milliseconds for the requested operation.
196    pub timeout_ms: u64,
197    /// Allowlist for this policy or contract.
198    /// Validation uses it to reject undeclared or policy-denied values.
199    pub allowed_decisions: Vec<ApprovalDecisionKind>,
200    /// Policy references that govern admission, projection, execution, or
201    /// delivery.
202    pub policy_refs: Vec<PolicyRef>,
203}
204
205#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
206/// Defines the tool request modification SDK value.
207/// Construction records local state only; documented runtimes, executors, or ports own side effects.
208pub struct ToolRequestModification {
209    /// Redacted human-readable summary safe for events, telemetry, and logs.
210    pub redacted_summary: String,
211    /// Policy references that govern admission, projection, execution, or
212    /// delivery.
213    pub policy_refs: Vec<PolicyRef>,
214}
215
216#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
217/// Defines the resume policy SDK value.
218/// Construction records local state only; documented runtimes, executors, or ports own side effects.
219pub struct ResumePolicy {
220    /// resume after ms duration in milliseconds.
221    pub resume_after_ms: Option<u64>,
222    /// Redacted explanation for a denial, failure, status, or package delta.
223    pub reason: DecisionReason,
224}
225
226#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
227/// Enumerates the finite policy stage cases.
228/// Serialized names are part of the SDK contract; update fixtures when variants change.
229pub enum PolicyStage {
230    /// Use this variant when the contract needs to represent input; selecting it has no side effect by itself.
231    Input,
232    /// Use this variant when the contract needs to represent model input projection; selecting it has no side effect by itself.
233    ModelInputProjection,
234    /// Use this variant when the contract needs to represent pre tool; selecting it has no side effect by itself.
235    PreTool,
236    /// Use this variant when the contract needs to represent post tool; selecting it has no side effect by itself.
237    PostTool,
238    /// Use this variant when the contract needs to represent output; selecting it has no side effect by itself.
239    Output,
240    /// Use this variant when the contract needs to represent handoff; selecting it has no side effect by itself.
241    Handoff,
242    /// Use this variant when the contract needs to represent stream; selecting it has no side effect by itself.
243    Stream,
244    /// Use this variant when the contract needs to represent delivery; selecting it has no side effect by itself.
245    Delivery,
246}
247
248#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
249/// Enumerates the finite missing dependency cases.
250/// Serialized names are part of the SDK contract; update fixtures when variants change.
251pub enum MissingDependency {
252    /// Use this variant when the contract needs to represent policy snapshot; selecting it has no side effect by itself.
253    PolicySnapshot,
254    /// Use this variant when the contract needs to represent policy ref; selecting it has no side effect by itself.
255    PolicyRef,
256    /// Use this variant when the contract needs to represent permission evaluator; selecting it has no side effect by itself.
257    PermissionEvaluator,
258    /// Use this variant when the contract needs to represent sandbox evaluator; selecting it has no side effect by itself.
259    SandboxEvaluator,
260    /// Use this variant when the contract needs to represent approval dispatcher; selecting it has no side effect by itself.
261    ApprovalDispatcher,
262    /// Use this variant when the contract needs to represent adapter; selecting it has no side effect by itself.
263    Adapter,
264    /// Use this variant when the contract needs to represent sink; selecting it has no side effect by itself.
265    Sink,
266    /// Use this variant when the contract needs to represent store; selecting it has no side effect by itself.
267    Store,
268    /// Use this variant when the contract needs to represent journal append; selecting it has no side effect by itself.
269    JournalAppend,
270    /// Use this variant when the contract needs to represent executor ref; selecting it has no side effect by itself.
271    ExecutorRef,
272    /// Use this variant when the contract needs to represent isolation runtime; selecting it has no side effect by itself.
273    IsolationRuntime,
274}
275
276impl MissingDependency {
277    /// Returns the reason code currently held by this value.
278    /// This is data-only and does not perform I/O, call host ports, append journals, publish
279    /// events, or start processes.
280    pub fn reason_code(self) -> &'static str {
281        match self {
282            Self::PolicySnapshot => "missing.policy_snapshot",
283            Self::PolicyRef => "missing.policy_ref",
284            Self::PermissionEvaluator => "missing.permission_evaluator",
285            Self::SandboxEvaluator => "missing.sandbox_evaluator",
286            Self::ApprovalDispatcher => "missing.approval_dispatcher",
287            Self::Adapter => "missing.adapter",
288            Self::Sink => "missing.sink",
289            Self::Store => "missing.store",
290            Self::JournalAppend => "missing.journal_append",
291            Self::ExecutorRef => "missing.executor_ref",
292            Self::IsolationRuntime => "missing.isolation_runtime",
293        }
294    }
295
296    /// Converts this value into error data.
297    /// This is data-only and does not perform I/O, call host ports, append journals, publish
298    /// events, or start processes.
299    pub fn to_error(self, causal_ids: CausalIds) -> AgentError {
300        let kind = match self {
301            Self::JournalAppend => AgentErrorKind::JournalFailure,
302            Self::Adapter | Self::IsolationRuntime => AgentErrorKind::IsolationFailure,
303            Self::ApprovalDispatcher => AgentErrorKind::ApprovalFailure,
304            _ => AgentErrorKind::PolicyDenial,
305        };
306
307        AgentError::new(
308            kind,
309            RetryClassification::HostConfigurationNeeded,
310            self.reason_code(),
311        )
312        .with_causal_ids(causal_ids)
313    }
314}
315
316#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
317/// Defines the permission policy SDK value.
318/// Construction records local state only; documented runtimes, executors, or ports own side effects.
319pub struct PermissionPolicy {
320    /// Policy reference that must be resolved by the host or runtime before
321    /// execution.
322    pub policy_ref: PolicyRef,
323    /// Collection of grants values.
324    /// Ordering and membership should be treated as part of the serialized contract when
325    /// relevant.
326    pub grants: Vec<PermissionGrant>,
327    /// Default decision used by this record or request.
328    pub default_decision: PolicyDecision,
329}
330
331impl PermissionPolicy {
332    /// Returns an updated value with deny all configured.
333    /// This is data-only and does not perform I/O, call host ports, append journals, publish
334    /// events, or start processes.
335    pub fn deny_all(policy_ref: PolicyRef) -> Self {
336        Self {
337            policy_ref,
338            grants: Vec::new(),
339            default_decision: PolicyDecision::deny("permission.default_deny"),
340        }
341    }
342
343    /// Builds the check value.
344    /// This is data construction and performs no I/O, journal append, event publication, or
345    /// process work.
346    pub fn check(&self, request: &PermissionRequest) -> PolicyOutcome {
347        let grant = self.grants.iter().find(|grant| grant.matches(request));
348        let decision = grant
349            .map(|grant| grant.decision.clone())
350            .unwrap_or_else(|| self.default_decision.clone());
351
352        PolicyOutcome {
353            stage: request.stage,
354            decision,
355            subject: request.subject.clone(),
356            source: Some(request.source.clone()),
357            destination: Some(request.destination.clone()),
358            policy_refs: vec![self.policy_ref.clone()],
359            privacy: request.privacy,
360            retention: request.retention,
361        }
362    }
363}
364
365#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
366/// Defines the permission grant SDK value.
367/// Construction records local state only; documented runtimes, executors, or ports own side effects.
368pub struct PermissionGrant {
369    /// Source label or ref for this item; it is metadata and does not fetch
370    /// content by itself.
371    pub source: SourceRef,
372    /// Capability used by this record or request.
373    pub capability: CapabilityPermission,
374    /// Decision used by this record or request.
375    pub decision: PolicyDecision,
376}
377
378impl PermissionGrant {
379    fn matches(&self, request: &PermissionRequest) -> bool {
380        self.source == request.source && self.capability == request.capability
381    }
382}
383
384#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
385/// Defines the permission request SDK value.
386/// Construction records local state only; documented runtimes, executors, or ports own side effects.
387pub struct PermissionRequest {
388    /// Stage used by this record or request.
389    pub stage: PolicyStage,
390    /// Source label or ref for this item; it is metadata and does not fetch
391    /// content by itself.
392    pub source: SourceRef,
393    /// Destination label or ref for this item; it is metadata and does not
394    /// deliver content by itself.
395    pub destination: DestinationRef,
396    /// Capability used by this record or request.
397    pub capability: CapabilityPermission,
398    /// Optional subject value.
399    /// When absent, callers should use the documented default or skip that optional behavior.
400    pub subject: Option<EntityRef>,
401    /// Privacy class used for projection, telemetry, and raw-content access
402    /// decisions.
403    pub privacy: PrivacyClass,
404    /// Retention class used by hosts and sinks when storing or exporting this
405    /// item.
406    pub retention: RetentionClass,
407}
408
409#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
410/// Enumerates the finite capability permission cases.
411/// Serialized names are part of the SDK contract; update fixtures when variants change.
412pub enum CapabilityPermission {
413    /// Use this variant when the contract needs to represent filesystem read; selecting it has no side effect by itself.
414    FilesystemRead,
415    /// Use this variant when the contract needs to represent filesystem write; selecting it has no side effect by itself.
416    FilesystemWrite,
417    /// Use this variant when the contract needs to represent network; selecting it has no side effect by itself.
418    Network,
419    /// Use this variant when the contract needs to represent shell; selecting it has no side effect by itself.
420    Shell,
421    /// Use this variant when the contract needs to represent mcp; selecting it has no side effect by itself.
422    Mcp,
423    /// Use this variant when the contract needs to represent media; selecting it has no side effect by itself.
424    Media,
425    /// Use this variant when the contract needs to represent contacts; selecting it has no side effect by itself.
426    Contacts,
427    /// Use this variant when the contract needs to represent memory read; selecting it has no side effect by itself.
428    MemoryRead,
429    /// Use this variant when the contract needs to represent memory write; selecting it has no side effect by itself.
430    MemoryWrite,
431    /// Use this variant when the contract needs to represent output delivery; selecting it has no side effect by itself.
432    OutputDelivery,
433}
434
435#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
436/// Defines the sandbox policy SDK value.
437/// Construction records local state only; documented runtimes, executors, or ports own side effects.
438pub struct SandboxPolicy {
439    /// Policy reference that must be resolved by the host or runtime before
440    /// execution.
441    pub policy_ref: PolicyRef,
442    /// Mode that selects how this operation or contract should behave.
443    /// Callers use it to choose the explicit execution path instead of relying on hidden
444    /// defaults.
445    pub mode: SandboxMode,
446    /// Whether the request asks for network access. Host sandbox policy is
447    /// still authoritative.
448    pub network: NetworkPolicy,
449    /// Missing adapter decision used by this record or request.
450    pub missing_adapter_decision: PolicyDecision,
451}
452
453impl SandboxPolicy {
454    /// Builds the host denied value.
455    /// This is data construction and performs no I/O, journal append, event publication, or
456    /// process work.
457    pub fn host_denied(policy_ref: PolicyRef) -> Self {
458        Self {
459            policy_ref,
460            mode: SandboxMode::DenyHostExecution,
461            network: NetworkPolicy::Disabled,
462            missing_adapter_decision: PolicyDecision::deny("sandbox.missing_adapter"),
463        }
464    }
465
466    /// Builds the evaluate value.
467    /// This is data construction and performs no I/O, journal append, event publication, or
468    /// process work.
469    pub fn evaluate(&self, adapter_available: bool) -> PolicyOutcome {
470        let decision = match (&self.mode, adapter_available) {
471            (SandboxMode::DenyHostExecution, _) => PolicyDecision::deny("sandbox.host_denied"),
472            (SandboxMode::RequireIsolation { .. }, false) => self.missing_adapter_decision.clone(),
473            (SandboxMode::RequireIsolation { .. }, true) | (SandboxMode::AllowHostExecution, _) => {
474                PolicyDecision::allow("sandbox.allowed")
475            }
476        };
477
478        PolicyOutcome {
479            stage: PolicyStage::PreTool,
480            decision,
481            subject: None,
482            source: None,
483            destination: None,
484            policy_refs: vec![self.policy_ref.clone()],
485            privacy: PrivacyClass::Internal,
486            retention: RetentionClass::RunScoped,
487        }
488    }
489}
490
491#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
492/// Enumerates the finite sandbox mode cases.
493/// Serialized names are part of the SDK contract; update fixtures when variants change.
494pub enum SandboxMode {
495    /// Use this variant when the contract needs to represent deny host execution; selecting it has no side effect by itself.
496    DenyHostExecution,
497    /// Use this variant when the contract needs to represent require isolation; selecting it has no side effect by itself.
498    RequireIsolation {
499        /// Typed adapter ref reference. Resolving or executing it is a
500        /// separate policy-gated step.
501        adapter_ref: AdapterRef,
502    },
503    /// Use this variant when the contract needs to represent allow host execution; selecting it has no side effect by itself.
504    AllowHostExecution,
505}
506
507#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
508/// Enumerates the finite network policy cases.
509/// Serialized names are part of the SDK contract; update fixtures when variants change.
510pub enum NetworkPolicy {
511    /// Use this variant when the contract needs to represent disabled; selecting it has no side effect by itself.
512    Disabled,
513    /// Use this variant when the contract needs to represent egress allowlist; selecting it has no side effect by itself.
514    EgressAllowlist(Vec<String>),
515    /// Use this variant when the contract needs to represent enabled; selecting it has no side effect by itself.
516    Enabled,
517}
518
519#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
520/// Defines the approval policy SDK value.
521/// Construction records local state only; documented runtimes, executors, or ports own side effects.
522pub struct ApprovalPolicy {
523    /// Policy reference that must be resolved by the host or runtime before
524    /// execution.
525    pub policy_ref: PolicyRef,
526    /// Default decision used by this record or request.
527    pub default_decision: PolicyDecision,
528}
529
530impl ApprovalPolicy {
531    /// Returns an updated value with ask by default configured.
532    /// This is data-only and does not perform I/O, call host ports, append journals, publish
533    /// events, or start processes.
534    pub fn ask_by_default(policy_ref: PolicyRef, approval: ApprovalRequestSpec) -> Self {
535        Self {
536            policy_ref,
537            default_decision: PolicyDecision::Ask { approval },
538        }
539    }
540
541    /// Builds the classify value.
542    /// This is data construction and performs no I/O, journal append, event publication, or
543    /// process work.
544    pub fn classify(&self) -> PolicyOutcome {
545        PolicyOutcome {
546            stage: PolicyStage::PreTool,
547            decision: self.default_decision.clone(),
548            subject: None,
549            source: None,
550            destination: None,
551            policy_refs: vec![self.policy_ref.clone()],
552            privacy: PrivacyClass::Internal,
553            retention: RetentionClass::RunScoped,
554        }
555    }
556}
557
558#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
559/// Defines the escalation policy SDK value.
560/// Construction records local state only; documented runtimes, executors, or ports own side effects.
561pub struct EscalationPolicy {
562    /// Policy reference that must be resolved by the host or runtime before
563    /// execution.
564    pub policy_ref: PolicyRef,
565    /// Whether dispatcher required is enabled.
566    /// Policy, validation, or routing code uses this flag to choose the explicit behavior.
567    pub dispatcher_required: bool,
568    /// Timeout budget in milliseconds for the requested operation.
569    pub timeout_ms: u64,
570    /// Allowlist for this policy or contract.
571    /// Validation uses it to reject undeclared or policy-denied values.
572    pub allowed_decisions: Vec<ApprovalDecisionKind>,
573}
574
575impl EscalationPolicy {
576    /// Evaluate dispatcher.
577    /// This is data-only and does not perform I/O, call host ports, append journals, publish
578    /// events, or start processes.
579    pub fn evaluate_dispatcher(&self, dispatcher_available: bool) -> PolicyOutcome {
580        let decision = if self.dispatcher_required && !dispatcher_available {
581            PolicyDecision::deny("escalation.missing_dispatcher")
582        } else {
583            PolicyDecision::allow("escalation.dispatcher_ready")
584        };
585
586        PolicyOutcome {
587            stage: PolicyStage::PreTool,
588            decision,
589            subject: None,
590            source: None,
591            destination: None,
592            policy_refs: vec![self.policy_ref.clone()],
593            privacy: PrivacyClass::Internal,
594            retention: RetentionClass::RunScoped,
595        }
596    }
597}
598
599#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
600/// Defines the privacy policy SDK value.
601/// Construction records local state only; documented runtimes, executors, or ports own side effects.
602pub struct PrivacyPolicy {
603    /// Policy reference that must be resolved by the host or runtime before
604    /// execution.
605    pub policy_ref: PolicyRef,
606    /// Privacy classification for the value.
607    /// Projection, telemetry, and delivery paths use it to enforce redaction and retention.
608    pub minimum_privacy: PrivacyClass,
609    /// Retention class used by hosts and sinks when storing or exporting this
610    /// item.
611    pub retention: RetentionClass,
612    /// Whether trust required is enabled.
613    /// Policy, validation, or routing code uses this flag to choose the explicit behavior.
614    pub trust_required: TrustClass,
615}
616
617impl PrivacyPolicy {
618    /// Returns an updated value with safe defaults configured.
619    /// This is data-only and does not perform I/O, call host ports, append journals, publish
620    /// events, or start processes.
621    pub fn safe_defaults(policy_ref: PolicyRef) -> Self {
622        Self {
623            policy_ref,
624            minimum_privacy: PrivacyClass::Internal,
625            retention: RetentionClass::RunScoped,
626            trust_required: TrustClass::Trusted,
627        }
628    }
629}
630
631#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
632/// Defines the content capture policy SDK value.
633/// Construction records local state only; documented runtimes, executors, or ports own side effects.
634pub struct ContentCapturePolicy {
635    /// Policy reference that must be resolved by the host or runtime before
636    /// execution.
637    pub policy_ref: PolicyRef,
638    /// Mode that selects how this operation or contract should behave.
639    /// Callers use it to choose the explicit execution path instead of relying on hidden
640    /// defaults.
641    pub mode: ContentCaptureMode,
642    /// Whether source permits content is enabled.
643    /// Policy, validation, or routing code uses this flag to choose the explicit behavior.
644    pub source_permits_content: bool,
645    /// Whether sink permits content is enabled.
646    /// Policy, validation, or routing code uses this flag to choose the explicit behavior.
647    pub sink_permits_content: bool,
648    /// Whether redaction required is enabled.
649    /// Policy, validation, or routing code uses this flag to choose the explicit behavior.
650    pub redaction_required: bool,
651    /// Retention class for referenced content or records.
652    /// Stores and telemetry sinks use it to decide how long evidence may be kept.
653    pub retention_required: bool,
654    /// Whether sampling required is enabled.
655    /// Policy, validation, or routing code uses this flag to choose the explicit behavior.
656    pub sampling_required: bool,
657    /// Byte size or byte limit for byte limit.
658    /// Use it to enforce bounded reads, writes, summaries, or parser output.
659    pub byte_limit: u64,
660}
661
662impl ContentCapturePolicy {
663    /// Returns an updated value with safe defaults configured.
664    /// This is data-only and does not perform I/O, call host ports, append journals, publish
665    /// events, or start processes.
666    pub fn safe_defaults(policy_ref: PolicyRef) -> Self {
667        Self {
668            policy_ref,
669            mode: ContentCaptureMode::Off,
670            source_permits_content: false,
671            sink_permits_content: false,
672            redaction_required: true,
673            retention_required: true,
674            sampling_required: true,
675            byte_limit: 0,
676        }
677    }
678
679    /// Returns whether allows raw content applies for this state.
680    /// This is data-only and does not perform I/O, call host ports, append journals, publish
681    /// events, or start processes.
682    pub fn allows_raw_content(&self) -> bool {
683        matches!(self.mode, ContentCaptureMode::RawContent)
684            && self.source_permits_content
685            && self.sink_permits_content
686            && self.redaction_required
687            && self.retention_required
688            && self.sampling_required
689            && self.byte_limit > 0
690    }
691}
692
693#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
694/// Enumerates the finite content capture mode cases.
695/// Serialized names are part of the SDK contract; update fixtures when variants change.
696pub enum ContentCaptureMode {
697    /// Use this variant when the contract needs to represent off; selecting it has no side effect by itself.
698    Off,
699    /// Use this variant when the contract needs to represent metadata only; selecting it has no side effect by itself.
700    MetadataOnly,
701    /// Use this variant when the contract needs to represent redacted summary; selecting it has no side effect by itself.
702    RedactedSummary,
703    /// Use this variant when the contract needs to represent raw content; selecting it has no side effect by itself.
704    RawContent,
705}
706
707#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
708/// Enumerates the finite approval decision kind cases.
709/// Serialized names are part of the SDK contract; update fixtures when variants change.
710pub enum ApprovalDecisionKind {
711    /// Use this variant when the contract needs to represent approved; selecting it has no side effect by itself.
712    Approved,
713    /// Use this variant when the contract needs to represent approved for session; selecting it has no side effect by itself.
714    ApprovedForSession,
715    /// Use this variant when the contract needs to represent denied; selecting it has no side effect by itself.
716    Denied,
717}
718
719#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
720/// Enumerates the finite dispatcher scope cases.
721/// Serialized names are part of the SDK contract; update fixtures when variants change.
722pub enum DispatcherScope {
723    /// Use this variant when the contract needs to represent host; selecting it has no side effect by itself.
724    Host,
725    /// Use this variant when the contract needs to represent source scoped; selecting it has no side effect by itself.
726    SourceScoped,
727    /// Use this variant when the contract needs to represent headless; selecting it has no side effect by itself.
728    Headless,
729}
730
731#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
732/// Enumerates the finite effect class cases.
733/// Serialized names are part of the SDK contract; update fixtures when variants change.
734pub enum EffectClass {
735    /// Use this variant when the contract needs to represent read; selecting it has no side effect by itself.
736    Read,
737    /// Use this variant when the contract needs to represent write; selecting it has no side effect by itself.
738    Write,
739    /// Use this variant when the contract needs to represent process; selecting it has no side effect by itself.
740    Process,
741    /// Use this variant when the contract needs to represent network; selecting it has no side effect by itself.
742    Network,
743    /// Use this variant when the contract needs to represent approval dispatch; selecting it has no side effect by itself.
744    ApprovalDispatch,
745    /// Use this variant when the contract needs to represent output delivery; selecting it has no side effect by itself.
746    OutputDelivery,
747}
748
749#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
750/// Enumerates the finite risk class cases.
751/// Serialized names are part of the SDK contract; update fixtures when variants change.
752pub enum RiskClass {
753    /// Use this variant when the contract needs to represent low; selecting it has no side effect by itself.
754    Low,
755    /// Use this variant when the contract needs to represent medium; selecting it has no side effect by itself.
756    Medium,
757    /// Use this variant when the contract needs to represent high; selecting it has no side effect by itself.
758    High,
759    /// Use this variant when the contract needs to represent critical; selecting it has no side effect by itself.
760    Critical,
761}