use serde::{Deserialize, Serialize};
use crate::schema::{IsoDateTime, NonEmptyString, RunxSchema};
use crate::{
ActForm, AuthorityAttenuation, AuthorityTerm, Closure, ClosureDisposition, CriterionBinding,
Decision, HashAlgorithm, Intent, JsonObject, Reference, RevisionDetails, VerificationDetails,
};
pub const RECEIPT_SCHEMA: &str = "runx.receipt.v1";
pub const EFFECT_FINALITY_RECEIPT_SCHEMA: &str = "runx.effect_finality_receipt.v1";
pub const RECEIPT_CANONICALIZATION: &str = "runx.receipt.c14n.v1";
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
pub enum ReceiptSchema {
#[serde(rename = "runx.receipt.v1")]
V1,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
pub enum EffectFinalityReceiptSchema {
#[serde(rename = "runx.effect_finality_receipt.v1")]
V1,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(rename_all = "snake_case")]
pub enum EffectFinalityPhase {
Provisional,
InFlight,
Sealed,
Failed,
Reversed,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
#[runx_schema(id = "runx.effect_finality_receipt.v1")]
pub struct EffectFinalityReceipt {
pub schema: EffectFinalityReceiptSchema,
pub id: NonEmptyString,
pub created_at: IsoDateTime,
pub family: NonEmptyString,
pub phase: EffectFinalityPhase,
pub original_receipt_ref: Reference,
pub criterion_id: NonEmptyString,
#[serde(skip_serializing_if = "Option::is_none")]
pub proof_ref: Option<Reference>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub evidence_refs: Vec<Reference>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub norm_refs: Vec<NonEmptyString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub confirmation_depth: Option<u64>,
#[serde(default, skip_serializing_if = "JsonObject::is_empty")]
pub payload: JsonObject,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(rename_all = "snake_case")]
pub enum FanoutReceiptStrategy {
All,
Any,
Quorum,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(rename_all = "snake_case")]
pub enum FanoutReceiptDecision {
Proceed,
Halt,
Pause,
Escalate,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct FanoutReceiptSyncPoint {
pub group_id: NonEmptyString,
pub strategy: FanoutReceiptStrategy,
pub decision: FanoutReceiptDecision,
pub rule_fired: NonEmptyString,
pub reason: NonEmptyString,
pub branch_count: usize,
pub success_count: usize,
pub failure_count: usize,
pub required_successes: usize,
#[serde(default)]
pub branch_receipts: Vec<NonEmptyString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub gate: Option<JsonObject>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(rename_all = "snake_case")]
pub enum ReceiptCommitmentScope {
Input,
Output,
Stdout,
Stderr,
Error,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ReceiptCommitment {
pub scope: ReceiptCommitmentScope,
pub algorithm: HashAlgorithm,
pub value: NonEmptyString,
pub canonicalization: NonEmptyString,
}
pub mod receipt_subject_kind {
pub const SKILL: &str = "skill";
pub const GRAPH: &str = "graph";
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ReceiptInputContext {
pub source: NonEmptyString,
pub preview: String,
pub value_hash: NonEmptyString,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct Subject {
pub kind: NonEmptyString,
#[serde(rename = "ref")]
pub reference: Reference,
#[serde(skip_serializing_if = "Option::is_none")]
pub input_context: Option<ReceiptInputContext>,
#[serde(default)]
pub commitments: Vec<ReceiptCommitment>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ReceiptEnforcement {
pub profile_hash: NonEmptyString,
#[serde(default)]
pub redaction_refs: Vec<Reference>,
#[serde(default)]
pub setup_refs: Vec<Reference>,
#[serde(default)]
pub teardown_refs: Vec<Reference>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ReceiptAuthority {
pub actor_ref: Reference,
#[serde(default)]
pub grant_refs: Vec<Reference>,
#[serde(default)]
pub scope_refs: Vec<Reference>,
#[serde(default)]
pub authority_proof_refs: Vec<Reference>,
pub attenuation: AuthorityAttenuation,
#[serde(skip_serializing_if = "Option::is_none")]
pub mandate_ref: Option<Reference>,
#[serde(default)]
pub terms: Vec<AuthorityTerm>,
pub enforcement: ReceiptEnforcement,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ReceiptIdempotency {
pub intent_key: NonEmptyString,
pub trigger_fingerprint: NonEmptyString,
pub content_hash: NonEmptyString,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct RunnerProvenance {
pub provider: Option<String>,
pub model: Option<String>,
pub prompt_version: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ReceiptAct {
pub id: NonEmptyString,
pub form: ActForm,
pub intent: Intent,
pub summary: NonEmptyString,
#[serde(default)]
pub criterion_bindings: Vec<CriterionBinding>,
#[serde(skip_serializing_if = "Option::is_none")]
pub by: Option<RunnerProvenance>,
#[serde(default)]
pub source_refs: Vec<Reference>,
#[serde(default)]
pub target_refs: Vec<Reference>,
#[serde(default)]
pub artifact_refs: Vec<Reference>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context_ref: Option<Reference>,
pub closure: Closure,
#[serde(skip_serializing_if = "Option::is_none")]
pub revision: Option<RevisionDetails>,
#[serde(skip_serializing_if = "Option::is_none")]
pub verification: Option<VerificationDetails>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct Seal {
pub disposition: ClosureDisposition,
pub reason_code: NonEmptyString,
pub summary: NonEmptyString,
pub closed_at: IsoDateTime,
pub last_observed_at: IsoDateTime,
#[serde(default)]
pub criteria: Vec<CriterionBinding>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct Lineage {
#[serde(skip_serializing_if = "Option::is_none")]
pub parent: Option<Reference>,
#[serde(skip_serializing_if = "Option::is_none")]
pub previous: Option<Reference>,
#[serde(default)]
pub children: Vec<Reference>,
#[serde(default)]
pub sync: Vec<FanoutReceiptSyncPoint>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resume_ref: Option<Reference>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(rename_all = "snake_case")]
pub enum ReceiptIssuerType {
Local,
Hosted,
Ci,
Verifier,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ReceiptIssuer {
#[serde(rename = "type")]
pub issuer_type: ReceiptIssuerType,
pub kid: NonEmptyString,
pub public_key_sha256: NonEmptyString,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(rename_all = "PascalCase")]
pub enum SignatureAlgorithm {
Ed25519,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ReceiptSignature {
pub alg: SignatureAlgorithm,
pub value: NonEmptyString,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
#[runx_schema(id = "runx.receipt.v1")]
pub struct Receipt {
pub schema: ReceiptSchema,
pub id: NonEmptyString,
pub created_at: IsoDateTime,
pub canonicalization: NonEmptyString,
pub issuer: ReceiptIssuer,
pub signature: ReceiptSignature,
pub digest: NonEmptyString,
pub idempotency: ReceiptIdempotency,
pub subject: Subject,
pub authority: ReceiptAuthority,
#[serde(default)]
pub signals: Vec<Reference>,
#[serde(default)]
pub decisions: Vec<Decision>,
#[serde(default)]
pub acts: Vec<ReceiptAct>,
pub seal: Seal,
#[serde(skip_serializing_if = "Option::is_none")]
pub lineage: Option<Lineage>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<JsonObject>,
}