1use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9
10use crate::{
11 AxiomConstraint, ClaimCeiling, ContextPackId, ProofClosureReport, ProvenanceClass,
12 SemanticTrustClass,
13};
14
15pub const BOUNDARY_SCHEMA_VERSION: u16 = 1;
17
18pub const CORTEX_TO_AXIOM_CONSTRAINT_ENVELOPE_V1: &str = "cortex.boundary.constraint_envelope.v1";
20
21pub const PAI_AXIOM_TO_CORTEX_EXECUTION_RECEIPT_V1: &str =
23 "pai_axiom.boundary.execution_receipt.v1";
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
27#[serde(rename_all = "snake_case")]
28pub enum BoundaryContradictionState {
29 Resolved,
31 MultiHypothesis,
33 Unknown,
35 Blocked,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
41#[serde(rename_all = "snake_case")]
42pub enum BoundaryQuarantineState {
43 Clean,
45 DiagnosticOnly,
47 Quarantined,
49 Contaminated,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
55#[serde(rename_all = "snake_case")]
56pub enum BoundaryRedactionState {
57 RawOperatorOptIn,
59 Redacted,
61 Abstracted,
63 ExportSafe,
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
69#[serde(rename_all = "snake_case")]
70pub enum AllowedClaimLanguage {
71 CandidateClaim,
73 EvidenceReference,
75 Constraint,
77 ResidualRisk,
79 VerificationRequest,
81 Refusal,
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
87#[serde(rename_all = "snake_case")]
88pub enum ForbiddenBoundaryUse {
89 Promotion,
91 TrustedHistory,
93 ComplianceEvidence,
95 Export,
97 Release,
99 ExternalReporting,
101 ExecutionAuthority,
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
107pub struct CortexAxiomConstraintEnvelopeV1 {
108 pub schema_version: u16,
110 pub envelope_type: String,
112 pub context_pack_id: ContextPackId,
114 pub proof_state: ProofClosureReport,
116 pub truth_ceiling: ClaimCeiling,
118 pub semantic_trust: SemanticTrustClass,
120 pub provenance_class: ProvenanceClass,
122 pub contradiction_state: BoundaryContradictionState,
124 pub quarantine_state: BoundaryQuarantineState,
126 pub redaction_state: BoundaryRedactionState,
128 pub allowed_claim_language: Vec<AllowedClaimLanguage>,
130 pub forbidden_uses: Vec<ForbiddenBoundaryUse>,
132 pub constraints: Vec<AxiomConstraint>,
134}
135
136impl CortexAxiomConstraintEnvelopeV1 {
137 #[must_use]
139 pub fn new(
140 context_pack_id: ContextPackId,
141 proof_state: ProofClosureReport,
142 truth_ceiling: ClaimCeiling,
143 semantic_trust: SemanticTrustClass,
144 provenance_class: ProvenanceClass,
145 ) -> Self {
146 Self {
147 schema_version: BOUNDARY_SCHEMA_VERSION,
148 envelope_type: CORTEX_TO_AXIOM_CONSTRAINT_ENVELOPE_V1.to_string(),
149 context_pack_id,
150 proof_state,
151 truth_ceiling,
152 semantic_trust,
153 provenance_class,
154 contradiction_state: BoundaryContradictionState::Unknown,
155 quarantine_state: BoundaryQuarantineState::DiagnosticOnly,
156 redaction_state: BoundaryRedactionState::Abstracted,
157 allowed_claim_language: default_allowed_claim_language(),
158 forbidden_uses: default_forbidden_boundary_uses(),
159 constraints: Vec::new(),
160 }
161 }
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
166#[serde(rename_all = "snake_case")]
167pub enum CapabilityTokenDecision {
168 Allowed,
170 Warned,
172 Rejected,
174 Expired,
176 Revoked,
178}
179
180#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
182pub struct CapabilityTokenState {
183 pub decision: CapabilityTokenDecision,
185 pub valid_structure: bool,
187 pub audience_bound: bool,
189 pub scope_bound: bool,
191 pub operation_bound: bool,
193 pub not_expired: bool,
195 pub not_revoked: bool,
197 pub policy_allowed: bool,
199 pub attestation_linked: bool,
201}
202
203#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
205#[serde(rename_all = "snake_case")]
206pub enum RuntimeIntegrityState {
207 Unverified,
209 VerifiedRelease,
211 VerifiedProvenance,
213 Compromised,
215}
216
217#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
219pub struct ExecutionTrustState {
220 pub runtime_integrity: RuntimeIntegrityState,
222 pub evidence_ref: Option<String>,
224}
225
226#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
228#[serde(rename_all = "snake_case")]
229pub enum OperatorApprovalState {
230 NotRequired,
232 RequiredMissing,
234 ApprovedBound,
236 ApprovedUnbound,
238}
239
240#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
242#[serde(rename_all = "snake_case")]
243pub enum BoundaryToolOutcome {
244 Succeeded,
246 Failed,
248 Blocked,
250}
251
252#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
254pub struct BoundaryToolInvocation {
255 pub tool_name: String,
257 pub invocation_id: String,
259 pub input_ref: Option<String>,
261 pub output_ref: Option<String>,
263 pub outcome: BoundaryToolOutcome,
265}
266
267#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
269pub struct BoundarySourceAnchor {
270 pub reference: String,
272 pub kind: String,
274}
275
276#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
278pub struct PaiAxiomExecutionReceiptV1 {
279 pub schema_version: u16,
281 pub receipt_type: String,
283 pub runtime_id: String,
285 pub capability_token_state: CapabilityTokenState,
287 pub execution_trust_state: ExecutionTrustState,
289 pub tool_provenance: Vec<BoundaryToolInvocation>,
291 pub operator_approval_state: OperatorApprovalState,
293 pub quarantine_state: BoundaryQuarantineState,
295 pub source_anchors: Vec<BoundarySourceAnchor>,
297 pub residual_risk: Vec<String>,
299 pub explicit_non_promotion: bool,
301}
302
303impl PaiAxiomExecutionReceiptV1 {
304 #[must_use]
306 pub fn new(
307 runtime_id: impl Into<String>,
308 capability_token_state: CapabilityTokenState,
309 execution_trust_state: ExecutionTrustState,
310 operator_approval_state: OperatorApprovalState,
311 ) -> Self {
312 Self {
313 schema_version: BOUNDARY_SCHEMA_VERSION,
314 receipt_type: PAI_AXIOM_TO_CORTEX_EXECUTION_RECEIPT_V1.to_string(),
315 runtime_id: runtime_id.into(),
316 capability_token_state,
317 execution_trust_state,
318 tool_provenance: Vec::new(),
319 operator_approval_state,
320 quarantine_state: BoundaryQuarantineState::DiagnosticOnly,
321 source_anchors: Vec::new(),
322 residual_risk: Vec::new(),
323 explicit_non_promotion: true,
324 }
325 }
326}
327
328#[must_use]
330pub fn default_allowed_claim_language() -> Vec<AllowedClaimLanguage> {
331 vec![
332 AllowedClaimLanguage::CandidateClaim,
333 AllowedClaimLanguage::EvidenceReference,
334 AllowedClaimLanguage::Constraint,
335 AllowedClaimLanguage::ResidualRisk,
336 AllowedClaimLanguage::VerificationRequest,
337 AllowedClaimLanguage::Refusal,
338 ]
339}
340
341#[must_use]
343pub fn default_forbidden_boundary_uses() -> Vec<ForbiddenBoundaryUse> {
344 vec![
345 ForbiddenBoundaryUse::Promotion,
346 ForbiddenBoundaryUse::TrustedHistory,
347 ForbiddenBoundaryUse::ComplianceEvidence,
348 ForbiddenBoundaryUse::Export,
349 ForbiddenBoundaryUse::Release,
350 ForbiddenBoundaryUse::ExternalReporting,
351 ForbiddenBoundaryUse::ExecutionAuthority,
352 ]
353}
354
355#[cfg(test)]
356mod tests {
357 use serde_json::json;
358
359 use super::*;
360
361 fn token_state(decision: CapabilityTokenDecision) -> CapabilityTokenState {
362 CapabilityTokenState {
363 decision,
364 valid_structure: true,
365 audience_bound: true,
366 scope_bound: true,
367 operation_bound: true,
368 not_expired: true,
369 not_revoked: true,
370 policy_allowed: true,
371 attestation_linked: true,
372 }
373 }
374
375 #[test]
376 fn boundary_type_strings_are_stable() {
377 assert_eq!(
378 CORTEX_TO_AXIOM_CONSTRAINT_ENVELOPE_V1,
379 "cortex.boundary.constraint_envelope.v1"
380 );
381 assert_eq!(
382 PAI_AXIOM_TO_CORTEX_EXECUTION_RECEIPT_V1,
383 "pai_axiom.boundary.execution_receipt.v1"
384 );
385 }
386
387 #[test]
388 fn boundary_enum_wire_strings_are_stable() {
389 assert_eq!(
390 serde_json::to_value(BoundaryContradictionState::MultiHypothesis).unwrap(),
391 json!("multi_hypothesis")
392 );
393 assert_eq!(
394 serde_json::to_value(BoundaryQuarantineState::DiagnosticOnly).unwrap(),
395 json!("diagnostic_only")
396 );
397 assert_eq!(
398 serde_json::to_value(BoundaryRedactionState::RawOperatorOptIn).unwrap(),
399 json!("raw_operator_opt_in")
400 );
401 assert_eq!(
402 serde_json::to_value(AllowedClaimLanguage::VerificationRequest).unwrap(),
403 json!("verification_request")
404 );
405 assert_eq!(
406 serde_json::to_value(ForbiddenBoundaryUse::TrustedHistory).unwrap(),
407 json!("trusted_history")
408 );
409 assert_eq!(
410 serde_json::to_value(CapabilityTokenDecision::Revoked).unwrap(),
411 json!("revoked")
412 );
413 assert_eq!(
414 serde_json::to_value(RuntimeIntegrityState::VerifiedProvenance).unwrap(),
415 json!("verified_provenance")
416 );
417 assert_eq!(
418 serde_json::to_value(OperatorApprovalState::ApprovedBound).unwrap(),
419 json!("approved_bound")
420 );
421 assert_eq!(
422 serde_json::to_value(BoundaryToolOutcome::Blocked).unwrap(),
423 json!("blocked")
424 );
425 }
426
427 #[test]
428 fn constraint_envelope_defaults_forbid_authority_bearing_uses() {
429 let envelope = CortexAxiomConstraintEnvelopeV1::new(
430 ContextPackId::new(),
431 ProofClosureReport::full_chain_verified(Vec::new()),
432 ClaimCeiling::LocalUnsigned,
433 SemanticTrustClass::CandidateOnly,
434 ProvenanceClass::RuntimeDerived,
435 );
436
437 assert_eq!(envelope.schema_version, BOUNDARY_SCHEMA_VERSION);
438 assert_eq!(
439 envelope.envelope_type,
440 CORTEX_TO_AXIOM_CONSTRAINT_ENVELOPE_V1
441 );
442 assert!(envelope
443 .forbidden_uses
444 .contains(&ForbiddenBoundaryUse::ExecutionAuthority));
445 assert!(envelope
446 .allowed_claim_language
447 .contains(&AllowedClaimLanguage::Refusal));
448 }
449
450 #[test]
451 fn execution_receipt_defaults_to_candidate_only_non_promotion() {
452 let receipt = PaiAxiomExecutionReceiptV1::new(
453 "axiom-runtime:v3.1",
454 token_state(CapabilityTokenDecision::Allowed),
455 ExecutionTrustState {
456 runtime_integrity: RuntimeIntegrityState::Unverified,
457 evidence_ref: None,
458 },
459 OperatorApprovalState::NotRequired,
460 );
461
462 assert_eq!(receipt.schema_version, BOUNDARY_SCHEMA_VERSION);
463 assert_eq!(
464 receipt.receipt_type,
465 PAI_AXIOM_TO_CORTEX_EXECUTION_RECEIPT_V1
466 );
467 assert!(receipt.explicit_non_promotion);
468 assert_eq!(
469 receipt.quarantine_state,
470 BoundaryQuarantineState::DiagnosticOnly
471 );
472 }
473}