use serde_json::Value; use time::format_description::well_known::Rfc3339; use crate::state::EventEnvelope; use super::receipt_v1::{ genesis_prev_blake3, ReceiptRequest, ReceiptResponse, ReceiptTarget, ReceiptV1, }; /// Map an existing canonical EventEnvelope into a schema-valid Receipt V1. pub fn map_event_envelope_to_receipt(envelope: &EventEnvelope) -> ReceiptV1 { let mut canon = envelope.clone(); canon.canonicalize_in_place(); let created_at = canon .ts .format(&Rfc3339) .expect("EventEnvelope ts should format to RFC3339"); // Payload is already canonicalized by EventEnvelope rules (sorted object keys, arrays preserved). let payload: Value = canon.payload.clone(); let target = canon .node_id .as_ref() .map(|id| ReceiptTarget { id: id.to_string(), name: None, ip: None, }); let mut receipt = ReceiptV1 { receipt_version: "1".to_string(), created_at, source: "command-center".to_string(), action: canon.kind.clone(), reason: None, target, request: ReceiptRequest { method: "POST".to_string(), path: "/api/events".to_string(), body: payload.clone(), }, response: ReceiptResponse { status: 200, ok: true, data: payload, raw: String::new(), }, prev_blake3: genesis_prev_blake3(), hash_alg: String::new(), blake3: String::new(), sha256: String::new(), plan_file: None, plan_blake3: None, plan_sha256: None, lock_file: None, lock_started_at: None, force: None, cwd: None, user: None, hostname: None, argv: None, sig_alg: None, signer_pub: None, signature: None, signed_at: None, }; receipt.compute_hashes().expect("hash computation must succeed"); receipt }