Skip to main content

aidens_contracts/
lib.rs

1//! Versioned base contracts for AiDENs.
2//!
3//! This crate defines shared primitive artifact shapes. Semantic crates own
4//! their deeper behavior; this crate prevents duplicate wire-visible types.
5
6use chrono::{DateTime, Duration, SecondsFormat, Utc};
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9use std::collections::{BTreeMap, BTreeSet};
10use std::fmt;
11use std::sync::atomic::{AtomicU64, Ordering};
12
13mod agent_bundle;
14mod app_status;
15mod artifact;
16mod boundary;
17mod capability_turn;
18mod daemon_queue;
19mod execution;
20mod mechanism_display;
21mod operator;
22mod proof;
23mod provider;
24mod release_completion;
25mod reserved_v11;
26mod schema_catalog;
27mod semantic;
28mod tool_artifacts;
29pub mod view_disclosure;
30mod view_runtime;
31
32pub use agent_bundle::*;
33pub use app_status::*;
34pub use artifact::*;
35pub use boundary::*;
36pub use capability_turn::*;
37pub use daemon_queue::*;
38pub use execution::*;
39pub use mechanism_display::*;
40pub use operator::*;
41pub use proof::*;
42pub use provider::*;
43pub use release_completion::*;
44pub use reserved_v11::*;
45pub use schema_catalog::*;
46pub use semantic::*;
47pub use tool_artifacts::*;
48pub use view_runtime::*;
49
50use schema_catalog::{sorted_unique_artifact_ids, sorted_unique_invariants, sorted_unique_strings};
51
52/// Canonical identity and digest surfaces from the shared stack.
53///
54/// AiDENs re-exports the real stack ID crate. App-only constructors that need a
55/// non-replay display ID use `display_only_unstable_id`.
56pub mod canonical_stack {
57    pub use kernel_execution::{
58        ExecutionReport as CanonicalKernelExecutionReport,
59        ExecutionStopReason as CanonicalKernelStopReason,
60    };
61    pub use kernel_oracles::OracleAssessment as CanonicalOracleAssessment;
62    pub use llm_tool_runtime::ToolSideEffectClass as CanonicalToolSideEffectClass;
63    pub use recursive_kernel_core::KernelRun as CanonicalKernelRun;
64    pub use semantic_memory_forge::{
65        DispatchOutcomeV1 as ForgeDispatchOutcomeV1, EpisodeBundleV1 as ForgeEpisodeBundleV1,
66        ExecutionContextV1 as ForgeExecutionContextV1,
67    };
68    pub use stack_ids::{
69        ArtifactId, AttemptId, BoundaryRepairRecordId, ClaimId, ClaimVersionId, ContentDigest,
70        ControlReceiptId, DegradationRecordId, DigestBuilder, EnvelopeId, EpisodeId, ImportBatchId,
71        KernelRunId, ProjectionId, RegionId, ResidualId, Scope, ScopeKey, SyndromeId,
72        ToolEffectDispatchReceiptId, TraceCtx, TrialId,
73    };
74    pub use verification_adjudication::VerificationDisposition as CanonicalVerificationDisposition;
75    pub use verification_control::{
76        BoundaryRepairRecord as CanonicalBoundaryRepairRecord,
77        CheckPlan as CanonicalVerificationPlan, ControlReceipt as CanonicalControlReceipt,
78        VerificationCase as CanonicalVerificationCase,
79    };
80
81    pub fn digest_json(value: &serde_json::Value) -> Result<ContentDigest, stack_ids::DigestError> {
82        ContentDigest::compute_json(value)
83    }
84}
85
86pub use attestation_exchange::AttestationEnvelopeV1;
87pub use canonical_stack::CanonicalVerificationDisposition;
88pub use canonical_stack::{
89    ArtifactId, ArtifactId as StackArtifactId, AttemptId as StackAttemptId,
90    BoundaryRepairRecordId as StackBoundaryRepairRecordId, CanonicalKernelStopReason,
91    CanonicalToolSideEffectClass, ClaimId as StackClaimId, ClaimVersionId as StackClaimVersionId,
92    ContentDigest as StackContentDigest, ControlReceiptId as StackControlReceiptId,
93    DegradationRecordId as StackDegradationRecordId, DigestBuilder as StackDigestBuilder,
94    EnvelopeId as StackEnvelopeId, EpisodeId as StackEpisodeId,
95    ImportBatchId as StackImportBatchId, KernelRunId as StackKernelRunId,
96    ProjectionId as StackProjectionId, RegionId as StackRegionId, ResidualId as StackResidualId,
97    Scope as StackScope, ScopeKey as StackScopeKey, SyndromeId as StackSyndromeId,
98    ToolEffectDispatchReceiptId as StackToolEffectDispatchReceiptId, TraceCtx as StackTraceCtx,
99    TrialId as StackTrialId,
100};
101pub use federated_settlement::{SettlementCaseV1, SharedDispositionV1};
102pub use mechanism_runtime::{HypothesisLibraryV1, TheoryRefuterSuiteV1, TheoryVersionV1};
103
104static DISPLAY_ONLY_UNSTABLE_ID_COUNTER: AtomicU64 = AtomicU64::new(1);
105
106/// Construct a deterministic AiDENs-local artifact ID from explicit material.
107///
108/// This helper is for replay-sensitive local display artifacts. Canonical IDs
109/// and digests remain owned by `stack-ids`.
110pub fn generated_artifact_id_from_material(prefix: &str, material: &str) -> ArtifactId {
111    local_artifact_id_from_stack_digest(prefix, material)
112}
113
114/// Construct a process-local AiDENs display ID for non-replay equality paths.
115///
116/// This deliberately avoids random UUIDs. Callers that need replay equality
117/// must use `generated_artifact_id_from_material` with stable material.
118pub fn display_only_unstable_id(prefix: &str) -> ArtifactId {
119    let sequence = DISPLAY_ONLY_UNSTABLE_ID_COUNTER.fetch_add(1, Ordering::Relaxed);
120    ArtifactId::new(format!("{prefix}:local-process-seq-{sequence}"))
121}
122
123/// AiDENs-local wrapper pointer to a canonical owner artifact or owner type.
124///
125/// This does not make AiDENs authoritative for the pointed-to concept; it
126/// records where a display/report DTO must be reconciled for canonical truth.
127#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
128pub struct CanonicalBackpointerV1 {
129    pub owner_crate: String,
130    pub owner_type: String,
131    pub role: String,
132    #[serde(default, skip_serializing_if = "Option::is_none")]
133    pub artifact_id: Option<ArtifactId>,
134    #[serde(default, skip_serializing_if = "Option::is_none")]
135    pub external_id: Option<String>,
136    #[serde(default, skip_serializing_if = "Vec::is_empty")]
137    pub reason_codes: Vec<String>,
138}
139
140impl CanonicalBackpointerV1 {
141    pub fn owner_type(
142        owner_crate: impl Into<String>,
143        owner_type: impl Into<String>,
144        role: impl Into<String>,
145    ) -> Self {
146        Self {
147            owner_crate: owner_crate.into(),
148            owner_type: owner_type.into(),
149            role: role.into(),
150            artifact_id: None,
151            external_id: None,
152            reason_codes: vec!["canonical-owner-backpointer".into()],
153        }
154    }
155
156    pub fn artifact(
157        owner_crate: impl Into<String>,
158        owner_type: impl Into<String>,
159        role: impl Into<String>,
160        artifact_id: ArtifactId,
161    ) -> Self {
162        Self {
163            owner_crate: owner_crate.into(),
164            owner_type: owner_type.into(),
165            role: role.into(),
166            artifact_id: Some(artifact_id),
167            external_id: None,
168            reason_codes: vec!["canonical-artifact-backpointer".into()],
169        }
170    }
171
172    pub fn external(
173        owner_crate: impl Into<String>,
174        owner_type: impl Into<String>,
175        role: impl Into<String>,
176        external_id: impl Into<String>,
177    ) -> Self {
178        Self {
179            owner_crate: owner_crate.into(),
180            owner_type: owner_type.into(),
181            role: role.into(),
182            artifact_id: None,
183            external_id: Some(external_id.into()),
184            reason_codes: vec!["canonical-external-id-backpointer".into()],
185        }
186    }
187}
188
189fn canonical_owner_backpointer(
190    owner_crate: &'static str,
191    owner_type: &'static str,
192    role: &'static str,
193) -> Vec<CanonicalBackpointerV1> {
194    vec![CanonicalBackpointerV1::owner_type(
195        owner_crate,
196        owner_type,
197        role,
198    )]
199}
200
201fn json_digest(value: &serde_json::Value) -> String {
202    non_authoritative_json_display_digest(value)
203}
204
205pub fn non_authoritative_json_display_digest(value: &serde_json::Value) -> String {
206    let digest = canonical_stack::digest_json(value)
207        .expect("serde_json::Value serialization is infallible for stack digesting");
208    non_authoritative_display_digest_string(&digest)
209}
210
211pub fn non_authoritative_text_display_digest(text: &str) -> String {
212    let digest = StackContentDigest::compute_str(text);
213    non_authoritative_display_digest_string(&digest)
214}
215
216fn non_authoritative_display_digest_string(digest: &StackContentDigest) -> String {
217    format!("blake3:{}", digest.hex())
218}
219
220fn local_artifact_id_from_stack_digest(prefix: &str, material: &str) -> ArtifactId {
221    let digest = StackContentDigest::compute_str(material);
222    ArtifactId::new(format!("{prefix}:{}", digest.hex()))
223}
224
225// Display formatting only. Stack-owned digest computation must go through
226// `stack_ids::ContentDigest` and this string must not be used as identity.
227fn display_json_string(value: &serde_json::Value) -> String {
228    serde_json::to_string(value).unwrap_or_default()
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
232#[serde(rename_all = "kebab-case")]
233pub enum ArtifactVersion {
234    V1,
235}
236
237#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
238pub struct AidensRunContextV1 {
239    pub run_id: ArtifactId,
240    pub trace_id: ArtifactId,
241    pub attempt_family_id: ArtifactId,
242    pub attempt_id: ArtifactId,
243    pub started_at: DateTime<Utc>,
244    pub app_id: String,
245    pub config_generation: Option<String>,
246}
247
248impl AidensRunContextV1 {
249    pub fn new(app_id: impl Into<String>) -> Self {
250        Self {
251            run_id: display_only_unstable_id("run"),
252            trace_id: display_only_unstable_id("trace"),
253            attempt_family_id: display_only_unstable_id("attempt-family"),
254            attempt_id: display_only_unstable_id("attempt"),
255            started_at: Utc::now(),
256            app_id: app_id.into(),
257            config_generation: None,
258        }
259    }
260
261    pub fn stack_trace_ctx(&self) -> StackTraceCtx {
262        StackTraceCtx::from_trace_id(self.trace_id.0.clone())
263    }
264
265    pub fn stack_attempt_id(&self) -> StackAttemptId {
266        StackAttemptId::new(self.attempt_id.0.clone())
267    }
268}
269
270#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
271#[serde(rename_all = "kebab-case")]
272pub enum ArtifactKindV1 {
273    Run,
274    Turn,
275    ProviderRoute,
276    ProviderReadiness,
277    ToolExposure,
278    ToolAttempt,
279    ToolInvocation,
280    StopRule,
281    BudgetExhaustion,
282    Approval,
283    PermitUse,
284    BoundaryRepair,
285    SchemaValidation,
286    RepoRead,
287    RepoList,
288    PatchProposal,
289    PatchApply,
290    CommandRun,
291    CodexPacket,
292    SandboxTruth,
293    MemoryWrite,
294    MemoryQuery,
295    Job,
296    QueueLease,
297    ScheduleOccurrence,
298    WakeSignal,
299    DaemonNamespace,
300    SafeMode,
301    DuplicateSuppression,
302    RuntimeViewRequest,
303    QueryWidening,
304    RetrievalPolicy,
305    ProjectionDigest,
306    DegradationEvent,
307    ReleaseReadinessReport,
308    OperatorStatusReport,
309    ExampleAppManifest,
310    InstallSmokeReport,
311    CompiledRegionGraph,
312    RegionContract,
313    Syndrome,
314    Residual,
315    OracleSliceRequest,
316    KernelRunReport,
317    ConvergenceReport,
318    BoundaryMessage,
319    BoundaryReceipt,
320    SubtractionPlan,
321    SupportCore,
322    RemovalFrontier,
323    InvariantBudget,
324    CompactionReport,
325    HistoryPreservationReport,
326    Backfill,
327    ConfigApply,
328    ApiHonesty,
329    PlanRuntimeParity,
330    CapabilityTruth,
331    AttestationEnvelope,
332    AdmissionDecision,
333    TrustRoot,
334    Treaty,
335    RemoteOracleReport,
336    SettlementCase,
337    SharedDisposition,
338    MechanismReport,
339    TheoryVersion,
340    HypothesisLibrary,
341    SimulatorContract,
342    FitRunReport,
343    InvarianceReport,
344    TheoryRefuterSuite,
345    CompletionAuditReport,
346    ReleaseArtifactManifest,
347    CrossPassTraceabilityMatrix,
348    KnownLimitationsRegister,
349    RegressionDebtLedger,
350    QueueHop,
351    Schedule,
352    ViewDisclosure,
353}
354
355impl JsonSchema for ArtifactKindV1 {
356    fn schema_name() -> String {
357        "ArtifactKindV1".into()
358    }
359
360    fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
361        let mut schema = schemars::schema::SchemaObject {
362            instance_type: Some(schemars::schema::SingleOrVec::Single(Box::new(
363                schemars::schema::InstanceType::String,
364            ))),
365            ..Default::default()
366        };
367        schema.metadata = Some(Box::new(schemars::schema::Metadata {
368            description: Some(
369                "AiDENs-local display discriminator; not a canonical artifact family schema."
370                    .into(),
371            ),
372            ..Default::default()
373        }));
374        schemars::schema::Schema::Object(schema)
375    }
376}
377
378impl fmt::Display for ArtifactKindV1 {
379    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380        f.write_str(match self {
381            Self::Run => "run",
382            Self::Turn => "turn",
383            Self::ProviderRoute => "provider-route",
384            Self::ProviderReadiness => "provider-readiness",
385            Self::ToolExposure => "tool-exposure",
386            Self::ToolAttempt => "tool-attempt",
387            Self::ToolInvocation => "tool-invocation",
388            Self::StopRule => "stop-rule",
389            Self::BudgetExhaustion => "budget-exhaustion",
390            Self::Approval => "approval",
391            Self::PermitUse => "permit-use",
392            Self::BoundaryRepair => "boundary-repair",
393            Self::SchemaValidation => "schema-validation",
394            Self::RepoRead => "repo-read",
395            Self::RepoList => "repo-list",
396            Self::PatchProposal => "patch-proposal",
397            Self::PatchApply => "patch-apply",
398            Self::CommandRun => "command-run",
399            Self::CodexPacket => "codex-packet",
400            Self::SandboxTruth => "sandbox-truth",
401            Self::MemoryWrite => "memory-write",
402            Self::MemoryQuery => "memory-query",
403            Self::Job => "job",
404            Self::QueueLease => "queue-lease",
405            Self::ScheduleOccurrence => "schedule-occurrence",
406            Self::WakeSignal => "wake-signal",
407            Self::DaemonNamespace => "daemon-namespace",
408            Self::SafeMode => "safe-mode",
409            Self::DuplicateSuppression => "duplicate-suppression",
410            Self::RuntimeViewRequest => "runtime-view-request",
411            Self::QueryWidening => "query-widening",
412            Self::RetrievalPolicy => "retrieval-policy",
413            Self::ProjectionDigest => "projection-digest",
414            Self::DegradationEvent => "degradation-event",
415            Self::ReleaseReadinessReport => "release-readiness-report",
416            Self::OperatorStatusReport => "operator-status-report",
417            Self::ExampleAppManifest => "example-app-manifest",
418            Self::InstallSmokeReport => "install-smoke-report",
419            Self::CompiledRegionGraph => "compiled-region-graph",
420            Self::RegionContract => "region-contract",
421            Self::Syndrome => "syndrome",
422            Self::Residual => "residual",
423            Self::OracleSliceRequest => "oracle-slice-request",
424            Self::KernelRunReport => "kernel-run-report",
425            Self::ConvergenceReport => "convergence-report",
426            Self::BoundaryMessage => "boundary-message",
427            Self::BoundaryReceipt => "boundary-receipt",
428            Self::SubtractionPlan => "subtraction-plan",
429            Self::SupportCore => "support-core",
430            Self::RemovalFrontier => "removal-frontier",
431            Self::InvariantBudget => "invariant-budget",
432            Self::CompactionReport => "compaction-report",
433            Self::HistoryPreservationReport => "history-preservation-report",
434            Self::Backfill => "backfill",
435            Self::ConfigApply => "config-apply",
436            Self::ApiHonesty => "api-honesty",
437            Self::PlanRuntimeParity => "plan-runtime-parity",
438            Self::CapabilityTruth => "capability-truth",
439            Self::AttestationEnvelope => "attestation-envelope",
440            Self::AdmissionDecision => "admission-decision",
441            Self::TrustRoot => "trust-root",
442            Self::Treaty => "treaty",
443            Self::RemoteOracleReport => "remote-oracle-report",
444            Self::SettlementCase => "settlement-case",
445            Self::SharedDisposition => "shared-disposition",
446            Self::MechanismReport => "mechanism-report",
447            Self::TheoryVersion => "theory-version",
448            Self::HypothesisLibrary => "hypothesis-library",
449            Self::SimulatorContract => "simulator-contract",
450            Self::FitRunReport => "fit-run-report",
451            Self::InvarianceReport => "invariance-report",
452            Self::TheoryRefuterSuite => "theory-refuter-suite",
453            Self::CompletionAuditReport => "completion-audit-report",
454            Self::ReleaseArtifactManifest => "release-artifact-manifest",
455            Self::CrossPassTraceabilityMatrix => "cross-pass-traceability-matrix",
456            Self::KnownLimitationsRegister => "known-limitations-register",
457            Self::RegressionDebtLedger => "regression-debt-ledger",
458            Self::QueueHop => "queue-hop",
459            Self::Schedule => "schedule",
460            Self::ViewDisclosure => "view-disclosure",
461        })
462    }
463}
464
465#[cfg(test)]
466mod tests;