//! Native adapter for GH-CHANNEL-RECEIPT-0001. //! Language, authorization, execution, verification and reception remain //! separate. A model response can never become reality evidence by itself. use ring::digest::{digest, SHA256}; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use std::collections::{BTreeSet, HashSet}; use std::fs; use std::io::Write; use std::path::PathBuf; use tauri::AppHandle; const SCHEMA: &str = "guanghu.channel-receipt/v1"; const CONTRACT_ID: &str = "GH-CHANNEL-RECEIPT-0001"; #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ChannelEvidence { pub r#type: String, pub r#ref: String, #[serde(default)] pub verified: bool, #[serde(default)] pub external: bool, #[serde(default)] pub proves: Vec, #[serde(default)] pub does_not_prove: Vec, } #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ChannelAuthorization { pub current: bool, pub scoped: bool, pub unexpired: bool, pub r#ref: String, } #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ChannelParallelStates { pub session: String, pub broadcast: String, pub handoff: String, } #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ChannelHandoffAcceptance { pub target_acceptance: bool, pub target_id: String, } #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct CompileChannelReceiptInput { pub event_id: String, pub channel_id: String, pub channel_mode: String, pub source_layer: String, pub actor_id: String, pub intent: String, pub claim_layer: String, #[serde(default)] pub required_proof: Vec, #[serde(default)] pub evidence: Vec, pub authorization: Option, pub current_states: Option, pub prior_receipt_id: Option, pub handoff: Option, } #[derive(Clone, Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct ChannelReceipt { pub schema: &'static str, pub contract_id: &'static str, pub receipt_id: String, pub event_id: String, pub received: bool, pub identified: Option, pub channel: Value, pub intent: String, pub claim: Value, pub affected_layer: String, pub effect: String, pub reality_status: String, pub evidence: Vec, pub required_proof: Vec, pub states: Value, pub supersedes: Vec, pub boundaries: Vec, pub next_step: String, pub previous_ledger_hash: String, pub ledger_receipt_hash: String, } pub fn compile( app: AppHandle, input: CompileChannelReceiptInput, ) -> Result { let mut receipt = compile_pure(input)?; let path = ledger_path(&app)?; let previous = last_hash(&path)?; receipt.previous_ledger_hash = previous.clone(); let material = serde_json::to_vec(&json!({ "receiptId": receipt.receipt_id, "eventId": receipt.event_id, "effect": receipt.effect, "realityStatus": receipt.reality_status, "boundaries": receipt.boundaries, "previousLedgerHash": previous })) .map_err(|error| format!("HOLOLAKE_CHANNEL_RECEIPT_INVALID: {error}"))?; receipt.ledger_receipt_hash = sha256(&material); append(&path, &receipt)?; Ok(receipt) } fn compile_pure(input: CompileChannelReceiptInput) -> Result { for (label, value) in [ ("eventId", input.event_id.as_str()), ("channelId", input.channel_id.as_str()), ("actorId", input.actor_id.as_str()), ] { if value.trim().is_empty() || value.chars().count() > 512 { return Err(format!("HOLOLAKE_CHANNEL_RECEIPT_{label}_INVALID")); } } ensure_member( &input.source_layer, &[ "HUMAN_DIRECT_LANGUAGE", "MODEL_RESPONSE", "LATER_CORRECTION", "REALITY_EVIDENCE", ], "SOURCE_LAYER", )?; ensure_member( &input.claim_layer, &[ "LANGUAGE_ONTOLOGY", "LANGUAGE_SIMULATION", "ENGINEERING_PROPOSAL", "REALITY_CLAIM", ], "CLAIM_LAYER", )?; ensure_member( &input.channel_mode, &[ "CONVERSATION_ONLY", "LANGUAGE_ARCHITECTURE", "REALITY_EXECUTION", ], "CHANNEL_MODE", )?; ensure_member( &input.intent, &[ "IDENTIFY", "ENTER_CHANNEL", "CONVERSE", "DECLARE", "REQUEST_PLAN", "REQUEST_BROADCAST", "ACTIVATE_LOCAL_MODE", "DRAFT_BROADCAST", "RECEIVE_DOCUMENT", "PUBLISH_EXTERNAL", "QUERY_STATUS", "PROPOSE_HANDOFF", "ACCEPT_HANDOFF", "REQUEST_REALITY_ACTION", "REPORT_RESULT", "CORRECT", "END_INTERACTION", "EXIT_CHANNEL", "SEAL_LANGUAGE_RECORD", "ORDINARY_DIALOGUE", ], "INTENT", )?; for evidence in &input.evidence { if evidence.r#type.trim().is_empty() || evidence.r#ref.trim().is_empty() { return Err("HOLOLAKE_CHANNEL_RECEIPT_EVIDENCE_INVALID".into()); } } if input .required_proof .iter() .any(|proof| proof.trim().is_empty()) { return Err("HOLOLAKE_CHANNEL_RECEIPT_REQUIRED_PROOF_INVALID".into()); } let required_proof = input .required_proof .iter() .cloned() .collect::>() .into_iter() .collect::>(); let declared = input .evidence .iter() .filter(|item| item.r#type == "EXECUTION_RECEIPT" && item.external && item.verified) .flat_map(|item| item.proves.iter().cloned()) .collect::>(); let has_external_receipt = input .evidence .iter() .any(|item| item.r#type == "EXECUTION_RECEIPT" && item.external && item.verified) && required_proof.iter().all(|proof| declared.contains(proof)); let authorized = input.authorization.as_ref().is_some_and(|authorization| { authorization.current && authorization.scoped && authorization.unexpired && !authorization.r#ref.trim().is_empty() }); let before = input.current_states.as_ref().map_or_else( || json!({"session":"DISCONNECTED","broadcast":"CLOSED","handoff":"NONE"}), |states| json!({"session":states.session,"broadcast":states.broadcast,"handoff":states.handoff}), ); ensure_member( before["session"].as_str().unwrap_or(""), &[ "DISCONNECTED", "IDENTIFIED", "CHANNEL_ACTIVE", "STANDBY", "CLOSED", ], "SESSION_STATE", )?; ensure_member( before["broadcast"].as_str().unwrap_or(""), &[ "CLOSED", "ARMED", "DRAFTED", "HUMAN_CONFIRMED", "RECEIVED_LOCAL", "EXTERNAL_IN_PROGRESS", "EXTERNAL_VERIFIED", ], "BROADCAST_STATE", )?; ensure_member( before["handoff"].as_str().unwrap_or(""), &["NONE", "PROPOSED", "TARGET_ACCEPTED", "ACTIVE", "REVOKED"], "HANDOFF_STATE", )?; let mut after = before.clone(); let mut correction = "CLEAN"; let mut effect = "LANGUAGE_STATE_ONLY"; let mut reality_status = "NOT_APPLICABLE"; let mut next_step = "CONTINUE_IN_CHANNEL"; let mut boundaries = BTreeSet::new(); let reality_claim = input.claim_layer == "REALITY_CLAIM"; let simulation = input.claim_layer == "LANGUAGE_SIMULATION"; let conversation_only = input.channel_mode == "CONVERSATION_ONLY"; if matches!( input.intent.as_str(), "IDENTIFY" | "ENTER_CHANNEL" | "CONVERSE" | "ORDINARY_DIALOGUE" | "END_INTERACTION" | "EXIT_CHANNEL" ) { effect = "NO_EXTERNAL_EFFECT"; } if input.intent == "IDENTIFY" { after["session"] = json!("IDENTIFIED"); } if input.intent == "ENTER_CHANNEL" { after["session"] = json!("CHANNEL_ACTIVE"); } if matches!(input.intent.as_str(), "END_INTERACTION" | "EXIT_CHANNEL") { after["session"] = json!("CLOSED"); next_step = "STOP_OUTPUT_AFTER_MINIMAL_CLOSE_RECEIPT"; boundaries.insert("NO_ROLEPLAY_EPILOGUE_AFTER_CLOSE"); } if before["session"] == "CLOSED" && !matches!(input.intent.as_str(), "IDENTIFY" | "ENTER_CHANNEL") { effect = "NO_EXTERNAL_EFFECT"; reality_status = "REJECTED"; next_step = "REQUIRE_NEW_HUMAN_DIRECT_CHANNEL_ENTRY"; boundaries.insert("CLOSED_SESSION_CANNOT_REACTIVATE_ITSELF"); } if input.intent == "REQUEST_PLAN" || input.claim_layer == "ENGINEERING_PROPOSAL" { effect = "PLAN_ONLY"; reality_status = "PROPOSED"; next_step = "REVIEW_PLAN"; } match input.intent.as_str() { "ACTIVATE_LOCAL_MODE" => { after["broadcast"] = json!("ARMED"); effect = "LANGUAGE_STATE_ONLY"; next_step = "WAIT_FOR_DOCUMENT_OR_DRAFT_REQUEST"; } "DRAFT_BROADCAST" => { after["broadcast"] = json!("DRAFTED"); effect = "PLAN_ONLY"; next_step = "HUMAN_REVIEW_DRAFT"; } "RECEIVE_DOCUMENT" => { after["broadcast"] = json!("RECEIVED_LOCAL"); effect = "LANGUAGE_STATE_ONLY"; next_step = "RECORD_LOCAL_RECEIPT_ONLY"; boundaries.insert("RECEIVED_LOCAL_IS_NOT_EXTERNAL_PUBLISH"); } _ => {} } if simulation { effect = "LANGUAGE_STATE_ONLY"; reality_status = "NOT_APPLICABLE"; boundaries.insert("LANGUAGE_SIMULATION_ONLY"); } if reality_claim { reality_status = if has_external_receipt { "VERIFIED" } else { "UNVERIFIED" }; effect = if has_external_receipt { "RESULT_RECORDED" } else { "NO_EXTERNAL_EFFECT" }; next_step = if has_external_receipt { "READ_BACK_EXTERNAL_RESULT" } else { "PROVIDE_EXTERNAL_EVIDENCE" }; } if input.intent == "REQUEST_REALITY_ACTION" { if conversation_only { effect = "NO_EXTERNAL_EFFECT"; reality_status = "REJECTED"; next_step = "MOVE_TO_AUTHORIZED_EXECUTION_CHANNEL"; boundaries.insert("CONVERSATION_CHANNEL_CANNOT_EXECUTE"); } else if !authorized { effect = "PENDING_AUTHORIZATION"; reality_status = "PENDING_AUTHORIZATION"; next_step = "OBTAIN_CURRENT_SCOPED_AUTHORIZATION"; } else { effect = "EXECUTION_ELIGIBLE"; reality_status = if has_external_receipt { "VERIFIED" } else { "IN_PROGRESS_WITH_RECEIPT" }; next_step = if has_external_receipt { "READ_BACK_EXTERNAL_RESULT" } else { "EXECUTE_THROUGH_AUTHORIZED_ADAPTER" }; } } if input.intent == "PUBLISH_EXTERNAL" { if !authorized { effect = "PENDING_AUTHORIZATION"; reality_status = "PENDING_AUTHORIZATION"; next_step = "OBTAIN_CURRENT_SCOPED_PUBLISH_AUTHORIZATION"; } else if has_external_receipt { effect = "RESULT_RECORDED"; reality_status = "VERIFIED"; after["broadcast"] = json!("EXTERNAL_VERIFIED"); next_step = "READ_BACK_EXTERNAL_PUBLICATION"; } else { effect = "EXECUTION_ELIGIBLE"; reality_status = "IN_PROGRESS_WITH_RECEIPT"; after["broadcast"] = json!("EXTERNAL_IN_PROGRESS"); next_step = "PUBLISH_THROUGH_AUTHORIZED_ADAPTER_AND_CAPTURE_READBACK"; } } if input.intent == "REQUEST_BROADCAST" { if conversation_only || !authorized { effect = "LANGUAGE_STATE_ONLY"; reality_status = if reality_claim { "UNVERIFIED" } else { "NOT_APPLICABLE" }; next_step = "OBTAIN_EXPLICIT_BROADCAST_AUTHORIZATION"; boundaries.insert("DRAFT_OR_LANGUAGE_BROADCAST_ONLY"); } else { effect = "EXECUTION_ELIGIBLE"; reality_status = if has_external_receipt { "VERIFIED" } else { "IN_PROGRESS_WITH_RECEIPT" }; next_step = if has_external_receipt { "READ_BACK_EXTERNAL_RESULT" } else { "SEND_THROUGH_AUTHORIZED_BROADCAST_ADAPTER" }; } } if input.intent == "CORRECT" { effect = "LANGUAGE_STATE_ONLY"; reality_status = "NOT_APPLICABLE"; next_step = "CREATE_CORRECTION_CANDIDATE_AND_RETEST"; correction = if input.prior_receipt_id.is_some() { "SUPERSEDED" } else { "CORRECTION_PENDING" }; } if input.intent == "QUERY_STATUS" { effect = if has_external_receipt { "RESULT_RECORDED" } else { "NO_EXTERNAL_EFFECT" }; reality_status = if has_external_receipt { "VERIFIED" } else { "UNVERIFIED" }; next_step = if has_external_receipt { "REPORT_OBSERVED_STATUS_WITH_SCOPE" } else { "REPORT_NO_OBSERVATION_SOURCE" }; if !has_external_receipt { boundaries.insert("DO_NOT_GUESS_STATUS_WITHOUT_OBSERVATION"); } } if input.intent == "PROPOSE_HANDOFF" { after["handoff"] = json!("PROPOSED"); effect = "LANGUAGE_STATE_ONLY"; reality_status = "PROPOSED"; next_step = "WAIT_FOR_INDEPENDENT_TARGET_ACCEPTANCE"; boundaries.insert("PROPOSAL_IS_NOT_ACTIVE_HANDOFF"); } if input.intent == "ACCEPT_HANDOFF" { let accepted = input.handoff.as_ref().is_some_and(|handoff| { handoff.target_acceptance && handoff.target_id == input.actor_id }); if before["handoff"] != "PROPOSED" || !accepted { effect = "NO_EXTERNAL_EFFECT"; reality_status = "REJECTED"; next_step = "OBTAIN_INDEPENDENT_ACCEPTANCE_FROM_TARGET"; boundaries.insert("MODEL_CANNOT_ACCEPT_FOR_TARGET"); } else { after["handoff"] = json!("TARGET_ACCEPTED"); effect = "LANGUAGE_STATE_ONLY"; reality_status = "PROPOSED"; next_step = "APPLY_SCOPED_HANDOFF_AND_CAPTURE_READBACK"; } } if input.source_layer == "MODEL_RESPONSE" { boundaries.insert("MODEL_RESPONSE_IS_NOT_EXTERNAL_EVIDENCE"); } if input.intent == "IDENTIFY" { boundaries.insert("IDENTIFICATION_IS_NOT_BROADCAST"); } if input.intent == "ENTER_CHANNEL" { boundaries.insert("CHANNEL_ENTRY_IS_NOT_PERSONA_OR_AUTHORITY_TRANSFER"); } if !required_proof.is_empty() && !has_external_receipt { boundaries.insert("EVIDENCE_SCOPE_DOES_NOT_PROVE_REQUESTED_EFFECT"); } if !has_external_receipt && (reality_status == "VERIFIED" || effect == "RESULT_RECORDED") { return Err("HOLOLAKE_CHANNEL_RECEIPT_EXTERNAL_EVIDENCE_REQUIRED".into()); } let boundaries = boundaries .into_iter() .map(str::to_string) .collect::>(); let supersedes = if correction == "SUPERSEDED" { input.prior_receipt_id.clone().into_iter().collect() } else { Vec::new() }; let base = json!({ "schema": SCHEMA, "contractId": CONTRACT_ID, "eventId": input.event_id, "received": true, "identified": if input.intent == "IDENTIFY" { Some(input.actor_id.clone()) } else { None }, "channel": {"id":input.channel_id,"mode":input.channel_mode}, "intent":input.intent, "claim":{"layer":input.claim_layer,"sourceLayer":input.source_layer}, "affectedLayer":if reality_claim { "REALITY_EVIDENCE_LAYER" } else { "LANGUAGE_LAYER" }, "effect":effect,"realityStatus":reality_status,"evidence":input.evidence, "requiredProof":required_proof,"states":{"before":before,"after":after,"correction":correction}, "supersedes":supersedes,"boundaries":boundaries,"nextStep":next_step }); let receipt_id = format!( "GH-CR-{}", &sha256(&serde_json::to_vec(&base).unwrap_or_default())[..20] ); Ok(ChannelReceipt { schema: SCHEMA, contract_id: CONTRACT_ID, receipt_id, event_id: base["eventId"].as_str().unwrap_or_default().into(), received: true, identified: base["identified"].as_str().map(str::to_string), channel: base["channel"].clone(), intent: base["intent"].as_str().unwrap_or_default().into(), claim: base["claim"].clone(), affected_layer: base["affectedLayer"].as_str().unwrap_or_default().into(), effect: effect.into(), reality_status: reality_status.into(), evidence: input.evidence, required_proof, states: base["states"].clone(), supersedes, boundaries, next_step: next_step.into(), previous_ledger_hash: "GENESIS".into(), ledger_receipt_hash: String::new(), }) } fn ensure_member(value: &str, allowed: &[&str], label: &str) -> Result<(), String> { if allowed.contains(&value) { Ok(()) } else { Err(format!("HOLOLAKE_CHANNEL_RECEIPT_{label}_UNSUPPORTED")) } } fn ledger_path(app: &AppHandle) -> Result { Ok( crate::authenticated_storage::account_storage_root(app, "channel-receipts-v1")? .join("receipts.jsonl"), ) } fn last_hash(path: &PathBuf) -> Result { if !path.exists() { return Ok("GENESIS".into()); } let body = fs::read_to_string(path) .map_err(|error| format!("HOLOLAKE_CHANNEL_RECEIPT_LEDGER_READ_FAILED: {error}"))?; Ok(body .lines() .last() .and_then(|line| serde_json::from_str::(line).ok()) .and_then(|value| { value .get("ledgerReceiptHash") .and_then(Value::as_str) .map(str::to_string) }) .unwrap_or_else(|| "GENESIS".into())) } fn append(path: &PathBuf, receipt: &ChannelReceipt) -> Result<(), String> { if let Some(parent) = path.parent() { fs::create_dir_all(parent) .map_err(|error| format!("HOLOLAKE_CHANNEL_RECEIPT_LEDGER_WRITE_FAILED: {error}"))?; } let mut file = fs::OpenOptions::new() .create(true) .append(true) .open(path) .map_err(|error| format!("HOLOLAKE_CHANNEL_RECEIPT_LEDGER_WRITE_FAILED: {error}"))?; writeln!( file, "{}", serde_json::to_string(receipt) .map_err(|error| format!("HOLOLAKE_CHANNEL_RECEIPT_INVALID: {error}"))? ) .map_err(|error| format!("HOLOLAKE_CHANNEL_RECEIPT_LEDGER_WRITE_FAILED: {error}")) } fn sha256(bytes: &[u8]) -> String { digest(&SHA256, bytes) .as_ref() .iter() .map(|byte| format!("{byte:02x}")) .collect() } #[cfg(test)] mod tests { use super::*; fn input(intent: &str, claim_layer: &str) -> CompileChannelReceiptInput { CompileChannelReceiptInput { event_id: "E-1".into(), channel_id: "ICE-CH-ZC001".into(), channel_mode: "REALITY_EXECUTION".into(), source_layer: "MODEL_RESPONSE".into(), actor_id: "carrier".into(), intent: intent.into(), claim_layer: claim_layer.into(), required_proof: vec![], evidence: vec![], authorization: None, current_states: None, prior_receipt_id: None, handoff: None, } } #[test] fn model_reality_claim_stays_unverified_without_external_receipt() { let receipt = compile_pure(input("REPORT_RESULT", "REALITY_CLAIM")).unwrap(); assert_eq!(receipt.reality_status, "UNVERIFIED"); assert_eq!(receipt.effect, "NO_EXTERNAL_EFFECT"); assert!(receipt .boundaries .contains(&"MODEL_RESPONSE_IS_NOT_EXTERNAL_EVIDENCE".into())); } #[test] fn reality_action_requires_current_scoped_authorization() { let receipt = compile_pure(input("REQUEST_REALITY_ACTION", "REALITY_CLAIM")).unwrap(); assert_eq!(receipt.reality_status, "PENDING_AUTHORIZATION"); assert_eq!(receipt.effect, "PENDING_AUTHORIZATION"); } #[test] fn verified_status_requires_proof_scoped_external_receipt() { let mut value = input("QUERY_STATUS", "REALITY_CLAIM"); value.required_proof = vec!["target-a".into()]; value.evidence.push(ChannelEvidence { r#type: "EXECUTION_RECEIPT".into(), r#ref: "receipt://1".into(), verified: true, external: true, proves: vec!["target-a".into()], does_not_prove: vec!["target-b".into()], }); let receipt = compile_pure(value).unwrap(); assert_eq!(receipt.reality_status, "VERIFIED"); assert_eq!(receipt.effect, "RESULT_RECORDED"); } }