use serde::{Deserialize, Serialize};
// ---------- Common ----------
pub type Sha256 = String; // "sha256:<64hex>"
pub type IsoTime = String; // RFC3339 (UTC, ms)
pub type Uri = String;
pub type Did = String; // e.g., "did:key:..."
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Signature {
pub alg: String, // "ed25519"
pub kid: String,
pub sig: String, // base64url
}
// ---------- PoSH ----------
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MethodShapeManifest {
pub schema_version: String, // "method.v1"
pub method_id: String,
pub version: String, // semver
pub method_shape_root: Sha256,
#[serde(skip_serializing_if = "Option::is_none")]
pub method_dag_hash: Option<Sha256>,
pub runtime: RuntimePins,
#[serde(default)]
pub checker_refs: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_policy_id: Option<String>,
pub publisher_sig: Signature,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RuntimePins {
pub image_digest: Sha256, // OCI/WASM
pub method_fingerprint: String, // "git:<commit>"
}
// ---------- PoX: Trace ----------
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Trace {
pub schema_version: String, // "trace.v2"
pub trace_id: String,
pub method_ref: MethodRef,
pub data_shape_hash: Sha256,
pub policy_id: String,
pub identity_route: Did,
pub content_route: Uri,
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_route: Option<ExecutionRoute>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MethodRef {
pub method_id: String,
pub version: String,
pub method_shape_root: Sha256,
pub image_digest: Sha256,
pub method_fingerprint: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutionRoute {
pub provider: String, // "aws" | "gcp" | "azure" | "onprem"
#[serde(skip_serializing_if = "Option::is_none")]
pub account: Option<String>,
pub region: String,
pub runtime_digest: Sha256,
}
// ---------- PoX: Span Commitment ----------
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SpanCommitment {
pub schema_version: String, // "proof.v2"
pub trace_id: String,
pub span_id: String,
pub method_ref: MethodRef,
pub data_shape_hash: Sha256,
pub span_shape_hash: Sha256,
pub inputs: Vec<ArtifactRef>,
pub outputs: Vec<ArtifactRef>,
pub start_time: IsoTime,
pub end_time: IsoTime,
pub status: SpanStatus,
#[serde(skip_serializing_if = "Option::is_none")]
pub meta: Option<SpanMeta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum SpanStatus {
OK,
ERROR,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArtifactRef {
pub name: String,
pub content_hash: Sha256,
#[serde(skip_serializing_if = "Option::is_none")]
pub uri: Option<Uri>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SpanMeta {
#[serde(skip_serializing_if = "Option::is_none")]
pub lamport: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parents: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_index: Option<u64>,
}
// Transport envelope for posting proofs
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignedSpan {
pub commitment: SpanCommitment,
pub signature: Signature, // ed25519 over sha256(canonical(commitment))
}
// ---------- PoX: Trace Roots ----------
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TraceRoots {
pub trace_id: String,
pub span_commitments: Vec<Sha256>, // hashes of canonical SpanCommitment
pub trace_set_root: Sha256,
#[serde(skip_serializing_if = "Option::is_none")]
pub identity_root: Option<Sha256>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trace_seq_root: Option<Sha256>,
pub method_shape_root: Sha256, // carried from method_ref
#[serde(skip_serializing_if = "Option::is_none")]
pub tier01_status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub server_sig: Option<Signature>,
}