Skip to main content

agent_sdk_core/domain/
refs.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 refs portion of that contract.
5//!
6use core::fmt;
7use serde::{Deserialize, Deserializer, Serialize, de::Error as DeError};
8
9use crate::ids::{
10    AgentId, AgentPoolId, ApprovalRequestId, ArtifactId, AttemptId, ContextItemId,
11    ContextProjectionId, CorrelationEntry, EffectId, EventId, IdValidationError, LineageId,
12    MessageId, RunId, RuntimePackageId, ToolCallId, TopicId, TurnId, WakeConditionId,
13    validate_identifier,
14};
15use crate::privacy::{PrivacyClass, RetentionClass, TrustClass};
16
17#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
18#[serde(rename_all = "snake_case")]
19/// Enumerates the finite entity kind cases.
20/// Serialized names are part of the SDK contract; update fixtures when variants change.
21pub enum EntityKind {
22    /// Use this variant when the contract needs to represent run; selecting it has no side effect by itself.
23    Run,
24    /// Use this variant when the contract needs to represent turn; selecting it has no side effect by itself.
25    Turn,
26    /// Use this variant when the contract needs to represent attempt; selecting it has no side effect by itself.
27    Attempt,
28    /// Use this variant when the contract needs to represent agent; selecting it has no side effect by itself.
29    Agent,
30    /// Use this variant when the contract needs to represent agent pool; selecting it has no side effect by itself.
31    AgentPool,
32    /// Use this variant when the contract needs to represent topic; selecting it has no side effect by itself.
33    Topic,
34    /// Use this variant when the contract needs to represent event; selecting it has no side effect by itself.
35    Event,
36    /// Use this variant when the contract needs to represent message; selecting it has no side effect by itself.
37    Message,
38    /// Use this variant when the contract needs to represent wake condition; selecting it has no side effect by itself.
39    WakeCondition,
40    /// Use this variant when the contract needs to represent context contribution; selecting it has no side effect by itself.
41    ContextContribution,
42    /// Use this variant when the contract needs to represent context item; selecting it has no side effect by itself.
43    ContextItem,
44    /// Use this variant when the contract needs to represent context projection; selecting it has no side effect by itself.
45    ContextProjection,
46    /// Use this variant when the contract needs to represent content; selecting it has no side effect by itself.
47    Content,
48    /// Use this variant when the contract needs to represent artifact; selecting it has no side effect by itself.
49    Artifact,
50    /// Use this variant when the contract needs to represent capability; selecting it has no side effect by itself.
51    Capability,
52    /// Use this variant when the contract needs to represent package sidecar; selecting it has no side effect by itself.
53    PackageSidecar,
54    /// Use this variant when the contract needs to represent runtime package; selecting it has no side effect by itself.
55    RuntimePackage,
56    /// Use this variant when the contract needs to represent policy decision; selecting it has no side effect by itself.
57    PolicyDecision,
58    /// Use this variant when the contract needs to represent effect; selecting it has no side effect by itself.
59    Effect,
60    /// Use this variant when the contract needs to represent effect intent; selecting it has no side effect by itself.
61    EffectIntent,
62    /// Use this variant when the contract needs to represent effect result; selecting it has no side effect by itself.
63    EffectResult,
64    /// Use this variant when the contract needs to represent tool call; selecting it has no side effect by itself.
65    ToolCall,
66    /// Use this variant when the contract needs to represent approval request; selecting it has no side effect by itself.
67    ApprovalRequest,
68    /// Use this variant when the contract needs to represent stream rule; selecting it has no side effect by itself.
69    StreamRule,
70    /// Use this variant when the contract needs to represent realtime session; selecting it has no side effect by itself.
71    RealtimeSession,
72    /// Use this variant when the contract needs to represent hook; selecting it has no side effect by itself.
73    Hook,
74    /// Use this variant when the contract needs to represent execution environment; selecting it has no side effect by itself.
75    ExecutionEnvironment,
76    /// Use this variant when the contract needs to represent child artifact; selecting it has no side effect by itself.
77    ChildArtifact,
78    /// Use this variant when the contract needs to represent subagent run; selecting it has no side effect by itself.
79    SubagentRun,
80    /// Use this variant when the contract needs to represent extension action; selecting it has no side effect by itself.
81    ExtensionAction,
82    /// Use this variant when the contract needs to represent output delivery; selecting it has no side effect by itself.
83    OutputDelivery,
84}
85
86#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
87#[serde(transparent)]
88/// Defines the entity id SDK value.
89/// Construction records local state only; documented runtimes, executors, or ports own side effects.
90pub struct EntityId(String);
91
92impl EntityId {
93    /// Creates a new domain::refs value with explicit caller-provided
94    /// inputs. This constructor is data-only and performs no I/O or
95    /// external side effects.
96    ///
97    /// # Panics
98    ///
99    /// Panics if constructor invariants fail, such as invalid identifier
100    /// text or constructor-specific bounds. Use a fallible constructor such as
101    /// `try_new` when one is available for untrusted input.
102    pub fn new(value: impl Into<String>) -> Self {
103        Self::try_new(value).expect("EntityId must be valid")
104    }
105
106    /// Creates a new domain::refs value after validation. Returns an
107    /// SDK error instead of panicking when the identifier or input does
108    /// not satisfy the contract.
109    pub fn try_new(value: impl Into<String>) -> Result<Self, IdValidationError> {
110        let value = value.into();
111        validate_identifier(&value)?;
112        Ok(Self(value))
113    }
114
115    /// Returns this value as str. The accessor is side-effect free and
116    /// keeps ownership with the caller.
117    pub fn as_str(&self) -> &str {
118        &self.0
119    }
120}
121
122impl fmt::Debug for EntityId {
123    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
124        formatter.write_str("EntityId(redacted)")
125    }
126}
127
128impl fmt::Display for EntityId {
129    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
130        formatter.write_str("EntityId(redacted)")
131    }
132}
133
134impl From<&str> for EntityId {
135    fn from(value: &str) -> Self {
136        Self::try_new(value).expect("EntityId must be valid")
137    }
138}
139
140impl<'de> Deserialize<'de> for EntityId {
141    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
142    where
143        D: Deserializer<'de>,
144    {
145        let value = String::deserialize(deserializer)?;
146        Self::try_new(value).map_err(D::Error::custom)
147    }
148}
149
150impl From<RunId> for EntityId {
151    fn from(value: RunId) -> Self {
152        Self::new(value.as_str())
153    }
154}
155
156impl From<TurnId> for EntityId {
157    fn from(value: TurnId) -> Self {
158        Self::new(value.as_str())
159    }
160}
161
162impl From<AttemptId> for EntityId {
163    fn from(value: AttemptId) -> Self {
164        Self::new(value.as_str())
165    }
166}
167
168impl From<AgentId> for EntityId {
169    fn from(value: AgentId) -> Self {
170        Self::new(value.as_str())
171    }
172}
173
174impl From<AgentPoolId> for EntityId {
175    fn from(value: AgentPoolId) -> Self {
176        Self::new(value.as_str())
177    }
178}
179
180impl From<TopicId> for EntityId {
181    fn from(value: TopicId) -> Self {
182        Self::new(value.as_str())
183    }
184}
185
186impl From<EventId> for EntityId {
187    fn from(value: EventId) -> Self {
188        Self::new(value.as_str())
189    }
190}
191
192impl From<MessageId> for EntityId {
193    fn from(value: MessageId) -> Self {
194        Self::new(value.as_str())
195    }
196}
197
198impl From<WakeConditionId> for EntityId {
199    fn from(value: WakeConditionId) -> Self {
200        Self::new(value.as_str())
201    }
202}
203
204impl From<ContextItemId> for EntityId {
205    fn from(value: ContextItemId) -> Self {
206        Self::new(value.as_str())
207    }
208}
209
210impl From<ContextProjectionId> for EntityId {
211    fn from(value: ContextProjectionId) -> Self {
212        Self::new(value.as_str())
213    }
214}
215
216impl From<ArtifactId> for EntityId {
217    fn from(value: ArtifactId) -> Self {
218        Self::new(value.as_str())
219    }
220}
221
222impl From<RuntimePackageId> for EntityId {
223    fn from(value: RuntimePackageId) -> Self {
224        Self::new(value.as_str())
225    }
226}
227
228impl From<EffectId> for EntityId {
229    fn from(value: EffectId) -> Self {
230        Self::new(value.as_str())
231    }
232}
233
234impl From<ToolCallId> for EntityId {
235    fn from(value: ToolCallId) -> Self {
236        Self::new(value.as_str())
237    }
238}
239
240impl From<ApprovalRequestId> for EntityId {
241    fn from(value: ApprovalRequestId) -> Self {
242        Self::new(value.as_str())
243    }
244}
245
246#[derive(Clone, Deserialize, Eq, PartialEq, Serialize)]
247/// Defines the entity ref SDK value.
248/// Construction records local state only; documented runtimes, executors, or ports own side effects.
249pub struct EntityRef {
250    /// Kind/category for this record, capability, event, or detected
251    /// resource.
252    pub kind: EntityKind,
253    /// Stable identifier for this record.
254    pub id: EntityId,
255    #[serde(skip_serializing_if = "Option::is_none")]
256    /// Source label or ref for this item; it is metadata and does not fetch
257    /// content by itself.
258    pub source: Option<SourceRef>,
259    /// Privacy class used for projection, telemetry, and raw-content access
260    /// decisions.
261    pub privacy: PrivacyClass,
262    #[serde(skip_serializing_if = "Option::is_none")]
263    /// Redacted human-readable summary safe for events, telemetry, and logs.
264    pub redacted_summary: Option<String>,
265}
266
267impl EntityRef {
268    /// Creates a new domain::refs value with explicit caller-provided
269    /// inputs. This constructor is data-only and performs no I/O or
270    /// external side effects.
271    pub fn new(kind: EntityKind, id: impl Into<EntityId>) -> Self {
272        Self {
273            kind,
274            id: id.into(),
275            source: None,
276            privacy: PrivacyClass::ContentRefsOnly,
277            redacted_summary: None,
278        }
279    }
280
281    /// Builds the run value with the documented defaults.
282    /// This is data-only and does not perform I/O, call host ports, append journals, publish
283    /// events, or start processes.
284    pub fn run(id: RunId) -> Self {
285        Self::new(EntityKind::Run, id)
286    }
287
288    /// Returns agent for the current value.
289    /// This is a read-only or data-construction helper unless the method body explicitly calls
290    /// a port or store.
291    pub fn agent(id: AgentId) -> Self {
292        Self::new(EntityKind::Agent, id)
293    }
294
295    /// Builds the agent pool value.
296    /// This is data construction and performs no I/O, journal append, event publication, or
297    /// process work.
298    pub fn agent_pool(id: AgentPoolId) -> Self {
299        Self::new(EntityKind::AgentPool, id)
300    }
301
302    /// Returns an updated value with topic configured.
303    /// This is data-only and does not perform I/O, call host ports, append journals, publish
304    /// events, or start processes.
305    pub fn topic(id: TopicId) -> Self {
306        Self::new(EntityKind::Topic, id)
307    }
308
309    /// Builds the message value.
310    /// This is data construction and performs no I/O, journal append, event publication, or
311    /// process work.
312    pub fn message(id: MessageId) -> Self {
313        Self::new(EntityKind::Message, id)
314    }
315
316    /// Builds the wake condition value.
317    /// This is data construction and performs no I/O, journal append, event publication, or
318    /// process work.
319    pub fn wake_condition(id: WakeConditionId) -> Self {
320        Self::new(EntityKind::WakeCondition, id)
321    }
322
323    /// Returns this value as str. The accessor is side-effect free and
324    /// keeps ownership with the caller.
325    pub fn as_str(&self) -> &str {
326        self.id.as_str()
327    }
328}
329
330impl fmt::Debug for EntityRef {
331    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
332        formatter
333            .debug_struct("EntityRef")
334            .field("kind", &self.kind)
335            .field("id", &"redacted")
336            .field("source", &self.source)
337            .field("privacy", &self.privacy)
338            .field("redacted_summary", &self.redacted_summary)
339            .finish()
340    }
341}
342
343impl fmt::Display for EntityRef {
344    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
345        write!(formatter, "{:?}:redacted", self.kind)
346    }
347}
348
349#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
350#[serde(rename_all = "snake_case")]
351/// Enumerates the finite source kind cases.
352/// Serialized names are part of the SDK contract; update fixtures when variants change.
353pub enum SourceKind {
354    /// Use this variant when the contract needs to represent sdk; selecting it has no side effect by itself.
355    Sdk,
356    /// Use this variant when the contract needs to represent host; selecting it has no side effect by itself.
357    Host,
358    /// Use this variant when the contract needs to represent user; selecting it has no side effect by itself.
359    User,
360    /// Use this variant when the contract needs to represent system; selecting it has no side effect by itself.
361    System,
362    /// Use this variant when the contract needs to represent developer; selecting it has no side effect by itself.
363    Developer,
364    /// Use this variant when the contract needs to represent memory; selecting it has no side effect by itself.
365    Memory,
366    /// Use this variant when the contract needs to represent compaction; selecting it has no side effect by itself.
367    Compaction,
368    /// Use this variant when the contract needs to represent hook; selecting it has no side effect by itself.
369    Hook,
370    /// Use this variant when the contract needs to represent extension; selecting it has no side effect by itself.
371    Extension,
372    /// Use this variant when the contract needs to represent tool; selecting it has no side effect by itself.
373    Tool,
374    /// Use this variant when the contract needs to represent remote channel; selecting it has no side effect by itself.
375    RemoteChannel,
376    /// Use this variant when the contract needs to represent scheduled task; selecting it has no side effect by itself.
377    ScheduledTask,
378    /// Use this variant when the contract needs to represent subagent; selecting it has no side effect by itself.
379    Subagent,
380    /// Use this variant when the contract needs to represent external runtime; selecting it has no side effect by itself.
381    ExternalRuntime,
382    /// Use this variant when the contract needs to represent replay; selecting it has no side effect by itself.
383    Replay,
384}
385
386#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
387#[serde(transparent)]
388/// Defines the source id SDK value.
389/// Construction records local state only; documented runtimes, executors, or ports own side effects.
390pub struct SourceId(String);
391
392impl SourceId {
393    /// Creates a new domain::refs value with explicit caller-provided
394    /// inputs. This constructor is data-only and performs no I/O or
395    /// external side effects.
396    ///
397    /// # Panics
398    ///
399    /// Panics if constructor invariants fail, such as invalid identifier
400    /// text or constructor-specific bounds. Use a fallible constructor such as
401    /// `try_new` when one is available for untrusted input.
402    pub fn new(value: impl Into<String>) -> Self {
403        Self::try_new(value).expect("SourceId must be valid")
404    }
405
406    /// Creates a new domain::refs value after validation. Returns an
407    /// SDK error instead of panicking when the identifier or input does
408    /// not satisfy the contract.
409    pub fn try_new(value: impl Into<String>) -> Result<Self, IdValidationError> {
410        let value = value.into();
411        validate_identifier(&value)?;
412        Ok(Self(value))
413    }
414
415    /// Returns this value as str. The accessor is side-effect free and
416    /// keeps ownership with the caller.
417    pub fn as_str(&self) -> &str {
418        &self.0
419    }
420}
421
422impl<'de> Deserialize<'de> for SourceId {
423    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
424    where
425        D: Deserializer<'de>,
426    {
427        let value = String::deserialize(deserializer)?;
428        Self::try_new(value).map_err(D::Error::custom)
429    }
430}
431
432impl fmt::Debug for SourceId {
433    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
434        formatter.write_str("SourceId(redacted)")
435    }
436}
437
438impl fmt::Display for SourceId {
439    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
440        formatter.write_str("SourceId(redacted)")
441    }
442}
443
444#[derive(Clone, Deserialize, Eq, PartialEq, Serialize)]
445/// Defines the source ref SDK value.
446/// Construction records local state only; documented runtimes, executors, or ports own side effects.
447pub struct SourceRef {
448    /// Kind/category for this record, capability, event, or detected
449    /// resource.
450    pub kind: SourceKind,
451    /// Stable identifier for this record.
452    pub id: SourceId,
453    /// Trust class used when deciding whether context or capabilities may be
454    /// admitted.
455    pub trust: TrustClass,
456    /// Privacy class used for projection, telemetry, and raw-content access
457    /// decisions.
458    pub privacy: PrivacyClass,
459    #[serde(default, skip_serializing_if = "Vec::is_empty")]
460    /// Collection of correlation values.
461    /// Ordering and membership should be treated as part of the serialized contract when
462    /// relevant.
463    pub correlation: Vec<CorrelationEntry>,
464    #[serde(skip_serializing_if = "Option::is_none")]
465    /// Redacted human-readable summary safe for events, telemetry, and logs.
466    pub redacted_summary: Option<String>,
467}
468
469impl SourceRef {
470    /// Creates a new domain::refs value with explicit caller-provided
471    /// inputs. This constructor is data-only and performs no I/O or
472    /// external side effects.
473    pub fn new(id: impl Into<String>) -> Self {
474        Self::with_kind(SourceKind::Host, id)
475    }
476
477    /// Returns this value with its kind setting replaced. The method
478    /// follows builder-style data construction and does not execute
479    /// external work.
480    pub fn with_kind(kind: SourceKind, id: impl Into<String>) -> Self {
481        Self {
482            kind,
483            id: SourceId::new(id),
484            trust: TrustClass::HostProvided,
485            privacy: PrivacyClass::ContentRefsOnly,
486            correlation: Vec::new(),
487            redacted_summary: None,
488        }
489    }
490
491    /// Returns this value as str. The accessor is side-effect free and
492    /// keeps ownership with the caller.
493    pub fn as_str(&self) -> &str {
494        self.id.as_str()
495    }
496}
497
498impl fmt::Debug for SourceRef {
499    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
500        formatter
501            .debug_struct("SourceRef")
502            .field("kind", &self.kind)
503            .field("id", &"redacted")
504            .field("trust", &self.trust)
505            .field("privacy", &self.privacy)
506            .field("correlation", &self.correlation)
507            .field("redacted_summary", &self.redacted_summary)
508            .finish()
509    }
510}
511
512impl fmt::Display for SourceRef {
513    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
514        write!(formatter, "{:?}:redacted", self.kind)
515    }
516}
517
518#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
519#[serde(rename_all = "snake_case")]
520/// Enumerates the finite destination kind cases.
521/// Serialized names are part of the SDK contract; update fixtures when variants change.
522pub enum DestinationKind {
523    /// Use this variant when the contract needs to represent agent; selecting it has no side effect by itself.
524    Agent,
525    /// Use this variant when the contract needs to represent agent pool; selecting it has no side effect by itself.
526    AgentPool,
527    /// Use this variant when the contract needs to represent topic; selecting it has no side effect by itself.
528    Topic,
529    /// Use this variant when the contract needs to represent provider; selecting it has no side effect by itself.
530    Provider,
531    /// Use this variant when the contract needs to represent context projection; selecting it has no side effect by itself.
532    ContextProjection,
533    /// Use this variant when the contract needs to represent journal; selecting it has no side effect by itself.
534    Journal,
535    /// Use this variant when the contract needs to represent event stream; selecting it has no side effect by itself.
536    EventStream,
537    /// Use this variant when the contract needs to represent telemetry; selecting it has no side effect by itself.
538    Telemetry,
539    /// Use this variant when the contract needs to represent output sink; selecting it has no side effect by itself.
540    OutputSink,
541    /// Use this variant when the contract needs to represent host; selecting it has no side effect by itself.
542    Host,
543    /// Use this variant when the contract needs to represent user; selecting it has no side effect by itself.
544    User,
545    /// Use this variant when the contract needs to represent remote channel; selecting it has no side effect by itself.
546    RemoteChannel,
547    /// Use this variant when the contract needs to represent tool; selecting it has no side effect by itself.
548    Tool,
549    /// Use this variant when the contract needs to represent extension; selecting it has no side effect by itself.
550    Extension,
551    /// Use this variant when the contract needs to represent subagent; selecting it has no side effect by itself.
552    Subagent,
553    /// Use this variant when the contract needs to represent external runtime; selecting it has no side effect by itself.
554    ExternalRuntime,
555}
556
557#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
558#[serde(transparent)]
559/// Defines the destination id SDK value.
560/// Construction records local state only; documented runtimes, executors, or ports own side effects.
561pub struct DestinationId(String);
562
563impl DestinationId {
564    /// Creates a new domain::refs value with explicit caller-provided
565    /// inputs. This constructor is data-only and performs no I/O or
566    /// external side effects.
567    ///
568    /// # Panics
569    ///
570    /// Panics if constructor invariants fail, such as invalid identifier
571    /// text or constructor-specific bounds. Use a fallible constructor such as
572    /// `try_new` when one is available for untrusted input.
573    pub fn new(value: impl Into<String>) -> Self {
574        Self::try_new(value).expect("DestinationId must be valid")
575    }
576
577    /// Creates a new domain::refs value after validation. Returns an
578    /// SDK error instead of panicking when the identifier or input does
579    /// not satisfy the contract.
580    pub fn try_new(value: impl Into<String>) -> Result<Self, IdValidationError> {
581        let value = value.into();
582        validate_identifier(&value)?;
583        Ok(Self(value))
584    }
585
586    /// Returns this value as str. The accessor is side-effect free and
587    /// keeps ownership with the caller.
588    pub fn as_str(&self) -> &str {
589        &self.0
590    }
591}
592
593impl<'de> Deserialize<'de> for DestinationId {
594    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
595    where
596        D: Deserializer<'de>,
597    {
598        let value = String::deserialize(deserializer)?;
599        Self::try_new(value).map_err(D::Error::custom)
600    }
601}
602
603impl fmt::Debug for DestinationId {
604    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
605        formatter.write_str("DestinationId(redacted)")
606    }
607}
608
609impl fmt::Display for DestinationId {
610    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
611        formatter.write_str("DestinationId(redacted)")
612    }
613}
614
615#[derive(Clone, Deserialize, Eq, PartialEq, Serialize)]
616/// Defines the destination ref SDK value.
617/// Construction records local state only; documented runtimes, executors, or ports own side effects.
618pub struct DestinationRef {
619    /// Kind/category for this record, capability, event, or detected
620    /// resource.
621    pub kind: DestinationKind,
622    /// Stable identifier for this record.
623    pub id: DestinationId,
624    /// Privacy class used for projection, telemetry, and raw-content access
625    /// decisions.
626    pub privacy: PrivacyClass,
627    /// Retention class used by hosts and sinks when storing or exporting this
628    /// item.
629    pub retention: RetentionClass,
630    #[serde(default, skip_serializing_if = "Vec::is_empty")]
631    /// Collection of correlation values.
632    /// Ordering and membership should be treated as part of the serialized contract when
633    /// relevant.
634    pub correlation: Vec<CorrelationEntry>,
635    #[serde(skip_serializing_if = "Option::is_none")]
636    /// Redacted human-readable summary safe for events, telemetry, and logs.
637    pub redacted_summary: Option<String>,
638}
639
640impl DestinationRef {
641    /// Creates a new domain::refs value with explicit caller-provided
642    /// inputs. This constructor is data-only and performs no I/O or
643    /// external side effects.
644    pub fn new(id: impl Into<String>) -> Self {
645        Self::with_kind(DestinationKind::Host, id)
646    }
647
648    /// Returns this value with its kind setting replaced. The method
649    /// follows builder-style data construction and does not execute
650    /// external work.
651    pub fn with_kind(kind: DestinationKind, id: impl Into<String>) -> Self {
652        Self {
653            kind,
654            id: DestinationId::new(id),
655            privacy: PrivacyClass::ContentRefsOnly,
656            retention: RetentionClass::HostPolicy,
657            correlation: Vec::new(),
658            redacted_summary: None,
659        }
660    }
661
662    /// Returns this value as str. The accessor is side-effect free and
663    /// keeps ownership with the caller.
664    pub fn as_str(&self) -> &str {
665        self.id.as_str()
666    }
667}
668
669impl fmt::Debug for DestinationRef {
670    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
671        formatter
672            .debug_struct("DestinationRef")
673            .field("kind", &self.kind)
674            .field("id", &"redacted")
675            .field("privacy", &self.privacy)
676            .field("retention", &self.retention)
677            .field("correlation", &self.correlation)
678            .field("redacted_summary", &self.redacted_summary)
679            .finish()
680    }
681}
682
683impl fmt::Display for DestinationRef {
684    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
685        write!(formatter, "{:?}:redacted", self.kind)
686    }
687}
688
689#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
690#[serde(rename_all = "snake_case")]
691/// Enumerates the finite policy kind cases.
692/// Serialized names are part of the SDK contract; update fixtures when variants change.
693pub enum PolicyKind {
694    /// Use this variant when the contract needs to represent approval; selecting it has no side effect by itself.
695    Approval,
696    /// Use this variant when the contract needs to represent permission; selecting it has no side effect by itself.
697    Permission,
698    /// Use this variant when the contract needs to represent sandbox; selecting it has no side effect by itself.
699    Sandbox,
700    /// Use this variant when the contract needs to represent context; selecting it has no side effect by itself.
701    Context,
702    /// Use this variant when the contract needs to represent privacy; selecting it has no side effect by itself.
703    Privacy,
704    /// Use this variant when the contract needs to represent retention; selecting it has no side effect by itself.
705    Retention,
706    /// Use this variant when the contract needs to represent redaction; selecting it has no side effect by itself.
707    Redaction,
708    /// Use this variant when the contract needs to represent runtime package; selecting it has no side effect by itself.
709    RuntimePackage,
710    /// Use this variant when the contract needs to represent host; selecting it has no side effect by itself.
711    Host,
712}
713
714#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
715#[serde(transparent)]
716/// Defines the policy id SDK value.
717/// Construction records local state only; documented runtimes, executors, or ports own side effects.
718pub struct PolicyId(String);
719
720impl PolicyId {
721    /// Creates a new domain::refs value with explicit caller-provided
722    /// inputs. This constructor is data-only and performs no I/O or
723    /// external side effects.
724    ///
725    /// # Panics
726    ///
727    /// Panics if constructor invariants fail, such as invalid identifier
728    /// text or constructor-specific bounds. Use a fallible constructor such as
729    /// `try_new` when one is available for untrusted input.
730    pub fn new(value: impl Into<String>) -> Self {
731        Self::try_new(value).expect("PolicyId must be valid")
732    }
733
734    /// Creates a new domain::refs value after validation. Returns an
735    /// SDK error instead of panicking when the identifier or input does
736    /// not satisfy the contract.
737    pub fn try_new(value: impl Into<String>) -> Result<Self, IdValidationError> {
738        let value = value.into();
739        validate_identifier(&value)?;
740        Ok(Self(value))
741    }
742
743    /// Returns this value as str. The accessor is side-effect free and
744    /// keeps ownership with the caller.
745    pub fn as_str(&self) -> &str {
746        &self.0
747    }
748}
749
750impl<'de> Deserialize<'de> for PolicyId {
751    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
752    where
753        D: Deserializer<'de>,
754    {
755        let value = String::deserialize(deserializer)?;
756        Self::try_new(value).map_err(D::Error::custom)
757    }
758}
759
760#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
761#[serde(transparent)]
762/// Defines the adapter ref SDK value.
763/// Construction records local state only; documented runtimes, executors, or ports own side effects.
764pub struct AdapterRef(String);
765
766impl AdapterRef {
767    /// Creates a new domain::refs value with explicit caller-provided
768    /// inputs. This constructor is data-only and performs no I/O or
769    /// external side effects.
770    ///
771    /// # Panics
772    ///
773    /// Panics if constructor invariants fail, such as invalid identifier
774    /// text or constructor-specific bounds. Use a fallible constructor such as
775    /// `try_new` when one is available for untrusted input.
776    pub fn new(value: impl Into<String>) -> Self {
777        Self::try_new(value).expect("AdapterRef must be valid")
778    }
779
780    /// Creates a new domain::refs value after validation. Returns an
781    /// SDK error instead of panicking when the identifier or input does
782    /// not satisfy the contract.
783    pub fn try_new(value: impl Into<String>) -> Result<Self, IdValidationError> {
784        let value = value.into();
785        validate_identifier(&value)?;
786        Ok(Self(value))
787    }
788
789    /// Returns this value as str. The accessor is side-effect free and
790    /// keeps ownership with the caller.
791    pub fn as_str(&self) -> &str {
792        &self.0
793    }
794}
795
796impl fmt::Debug for AdapterRef {
797    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
798        formatter.write_str("AdapterRef(redacted)")
799    }
800}
801
802impl fmt::Display for AdapterRef {
803    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
804        formatter.write_str("AdapterRef(redacted)")
805    }
806}
807
808impl From<&str> for AdapterRef {
809    fn from(value: &str) -> Self {
810        Self::new(value)
811    }
812}
813
814impl<'de> Deserialize<'de> for AdapterRef {
815    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
816    where
817        D: Deserializer<'de>,
818    {
819        let value = String::deserialize(deserializer)?;
820        Self::try_new(value).map_err(D::Error::custom)
821    }
822}
823
824impl fmt::Debug for PolicyId {
825    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
826        formatter.write_str("PolicyId(redacted)")
827    }
828}
829
830impl fmt::Display for PolicyId {
831    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
832        formatter.write_str("PolicyId(redacted)")
833    }
834}
835
836#[derive(Clone, Deserialize, Eq, PartialEq, Serialize)]
837/// Defines the policy ref SDK value.
838/// Construction records local state only; documented runtimes, executors, or ports own side effects.
839pub struct PolicyRef {
840    /// Kind/category for this record, capability, event, or detected
841    /// resource.
842    pub kind: PolicyKind,
843    /// Stable identifier for this record.
844    pub id: PolicyId,
845    #[serde(skip_serializing_if = "Option::is_none")]
846    /// Version string for this capability, package, or protocol surface.
847    /// Use it for compatibility checks during package or adapter resolution.
848    pub version: Option<String>,
849}
850
851impl PolicyRef {
852    /// Creates a new domain::refs value with explicit caller-provided
853    /// inputs. This constructor is data-only and performs no I/O or
854    /// external side effects.
855    pub fn new(id: impl Into<String>) -> Self {
856        Self::with_kind(PolicyKind::Host, id)
857    }
858
859    /// Returns this value with its kind setting replaced. The method
860    /// follows builder-style data construction and does not execute
861    /// external work.
862    pub fn with_kind(kind: PolicyKind, id: impl Into<String>) -> Self {
863        Self {
864            kind,
865            id: PolicyId::new(id),
866            version: None,
867        }
868    }
869
870    /// Returns this value as str. The accessor is side-effect free and
871    /// keeps ownership with the caller.
872    pub fn as_str(&self) -> &str {
873        self.id.as_str()
874    }
875}
876
877impl fmt::Debug for PolicyRef {
878    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
879        formatter
880            .debug_struct("PolicyRef")
881            .field("kind", &self.kind)
882            .field("id", &"redacted")
883            .field("version", &self.version)
884            .finish()
885    }
886}
887
888impl fmt::Display for PolicyRef {
889    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
890        write!(formatter, "{:?}:redacted", self.kind)
891    }
892}
893
894#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
895/// Defines the lineage ref SDK value.
896/// Construction records local state only; documented runtimes, executors, or ports own side effects.
897pub struct LineageRef {
898    /// Stable lineage id used for typed lineage, lookup, or dedupe.
899    pub lineage_id: LineageId,
900    /// Source label or ref for this item; it is metadata and does not fetch
901    /// content by itself.
902    pub source: SourceRef,
903    #[serde(skip_serializing_if = "Option::is_none")]
904    /// Destination label or ref for this item; it is metadata and does not
905    /// deliver content by itself.
906    pub destination: Option<DestinationRef>,
907    #[serde(default, skip_serializing_if = "Vec::is_empty")]
908    /// Policy references that govern admission, projection, execution, or
909    /// delivery.
910    pub policy_refs: Vec<PolicyRef>,
911}