Skip to main content

semantic_memory_forge/
v9.rs

1use crate::VerificationSummary;
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4use stack_ids::{AttemptId, ContentDigest, EnvelopeId, EpisodeId, ScopeKey, TraceCtx, TrialId};
5
6pub const EPISODE_BUNDLE_V1_SCHEMA: &str = "episode_bundle_v1";
7pub const EXECUTION_CONTEXT_V1_SCHEMA: &str = "execution_context_v1";
8
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
10#[serde(rename_all = "snake_case")]
11pub enum DispatchOutcomeV1 {
12    Succeeded,
13    Failed,
14    Degraded,
15    Cancelled,
16    Exhausted,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
20pub struct ExecutionContextV1 {
21    pub schema_version: String,
22    pub trace_ctx: TraceCtx,
23    #[serde(default, skip_serializing_if = "Option::is_none")]
24    pub attempt_id: Option<AttemptId>,
25    #[serde(default, skip_serializing_if = "Option::is_none")]
26    pub trial_id: Option<TrialId>,
27    #[serde(default, skip_serializing_if = "Option::is_none")]
28    pub replay_link: Option<String>,
29    #[serde(default, skip_serializing_if = "Option::is_none")]
30    pub workload_class: Option<String>,
31    #[serde(default, skip_serializing_if = "Vec::is_empty")]
32    pub queue_hops: Vec<String>,
33    #[serde(default, skip_serializing_if = "Option::is_none")]
34    pub deadline: Option<String>,
35    #[serde(default, skip_serializing_if = "Option::is_none")]
36    pub cost_budget_units: Option<u64>,
37    #[serde(default, skip_serializing_if = "Vec::is_empty")]
38    pub degradation_markers: Vec<String>,
39    pub dispatch_outcome: DispatchOutcomeV1,
40    #[serde(default, skip_serializing_if = "Option::is_none")]
41    pub environment_fingerprint: Option<String>,
42    #[serde(default, skip_serializing_if = "Option::is_none")]
43    pub provider_route: Option<String>,
44    #[serde(default, skip_serializing_if = "Option::is_none")]
45    pub cancellation_reason: Option<String>,
46    /// Backpointer to the tool receipt that produced this execution context.
47    #[serde(default, skip_serializing_if = "Option::is_none")]
48    pub tool_receipt_ref: Option<String>,
49    /// Backpointer to the provider call that fulfilled this execution.
50    #[serde(default, skip_serializing_if = "Option::is_none")]
51    pub provider_call_ref: Option<String>,
52    /// Backpointer to the replay parent execution context, if this is a retry.
53    #[serde(default, skip_serializing_if = "Option::is_none")]
54    pub replay_parent_ref: Option<String>,
55}
56
57impl ExecutionContextV1 {
58    /// Creates an execution context anchored to the supplied trace context.
59    pub fn new(trace_ctx: TraceCtx) -> Self {
60        Self {
61            schema_version: EXECUTION_CONTEXT_V1_SCHEMA.into(),
62            trace_ctx,
63            attempt_id: None,
64            trial_id: None,
65            replay_link: None,
66            workload_class: None,
67            queue_hops: Vec::new(),
68            deadline: None,
69            cost_budget_units: None,
70            degradation_markers: Vec::new(),
71            dispatch_outcome: DispatchOutcomeV1::Succeeded,
72            environment_fingerprint: None,
73            provider_route: None,
74            cancellation_reason: None,
75            tool_receipt_ref: None,
76            provider_call_ref: None,
77            replay_parent_ref: None,
78        }
79    }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
83pub struct EpisodeBundleV1 {
84    pub schema_version: String,
85    pub bundle_id: String,
86    pub episode_id: EpisodeId,
87    pub primary_document_id: String,
88    pub namespace: String,
89    pub scope_key: ScopeKey,
90    #[serde(default, skip_serializing_if = "Option::is_none")]
91    pub valid_from: Option<String>,
92    #[serde(default, skip_serializing_if = "Option::is_none")]
93    pub valid_to: Option<String>,
94    pub exported_at: String,
95    #[serde(default, skip_serializing_if = "Option::is_none")]
96    pub recorded_at: Option<String>,
97    pub source_envelope_id: EnvelopeId,
98    pub content_digest: ContentDigest,
99    #[serde(default, skip_serializing_if = "Vec::is_empty")]
100    pub source_evidence_pointers: Vec<String>,
101    #[serde(default, skip_serializing_if = "Vec::is_empty")]
102    pub source_receipt_digests: Vec<String>,
103    #[serde(default, skip_serializing_if = "Vec::is_empty")]
104    pub claim_version_ids: Vec<String>,
105    #[serde(default, skip_serializing_if = "Vec::is_empty")]
106    pub relation_version_ids: Vec<String>,
107    #[serde(default, skip_serializing_if = "Option::is_none")]
108    pub verification_summary: Option<VerificationSummary>,
109    #[serde(default, skip_serializing_if = "Vec::is_empty")]
110    pub refutation_artifact_ids: Vec<String>,
111    #[serde(default, skip_serializing_if = "Vec::is_empty")]
112    pub control_plane_refs: Vec<String>,
113    pub execution_context: ExecutionContextV1,
114    pub thin_export: bool,
115    #[serde(default, skip_serializing_if = "Option::is_none")]
116    pub supersedes_bundle_id: Option<String>,
117    #[serde(default, skip_serializing_if = "Option::is_none")]
118    pub evidence_bundle_id: Option<String>,
119}