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}