crtx 0.1.0

CLI for the Cortex supervisory memory substrate.
//! `cortex proof ...` — proof-closure diagnostics.

use clap::{Args, Subcommand};
use cortex_core::{AuthorityClass, ClaimCeiling, ClaimProofState, MemoryId, RuntimeMode};
use cortex_runtime::{compile_runtime_claim, RuntimeClaimKind};
use cortex_store::verify_memory_proof_closure;

use crate::cmd::open_default_store;
use crate::exit::Exit;

/// `cortex proof ...` subcommands.
#[derive(Debug, Subcommand)]
pub enum ProofSub {
    /// Verify proof closure for a memory row.
    Memory(MemoryProofArgs),
}

/// `cortex proof memory <memory_id>` arguments.
#[derive(Debug, Args)]
pub struct MemoryProofArgs {
    /// Memory identifier to verify.
    #[arg(value_name = "MEMORY_ID")]
    pub memory_id: MemoryId,
}

/// Run a `cortex proof ...` command.
pub fn run(sub: ProofSub) -> Exit {
    match sub {
        ProofSub::Memory(args) => memory(args),
    }
}

fn memory(args: MemoryProofArgs) -> Exit {
    let pool = match open_default_store("proof memory") {
        Ok(pool) => pool,
        Err(exit) => return exit,
    };

    match verify_memory_proof_closure(&pool, &args.memory_id) {
        Ok(report) => match proof_memory_payload(&report) {
            Ok(payload) => match serde_json::to_string_pretty(&payload) {
                Ok(serialized) => {
                    println!("{serialized}");
                    Exit::Ok
                }
                Err(err) => {
                    eprintln!("cortex proof memory: failed to serialize report: {err}");
                    Exit::Internal
                }
            },
            Err(err) => {
                eprintln!("cortex proof memory: failed to build report payload: {err}");
                Exit::Internal
            }
        },
        Err(err) => {
            eprintln!("cortex proof memory: {err}");
            Exit::Internal
        }
    }
}

fn proof_memory_payload(
    report: &cortex_core::ProofClosureReport,
) -> Result<serde_json::Value, serde_json::Error> {
    let proof_state = ClaimProofState::from(report.state());
    let claim = compile_runtime_claim(
        "store-local memory proof closure",
        RuntimeClaimKind::Advisory,
        RuntimeMode::LocalUnsigned,
        AuthorityClass::Observed,
        proof_state,
        ClaimCeiling::LocalUnsigned,
    );
    let policy = report.policy_decision();
    let mut payload = serde_json::to_value(report)?;
    if let serde_json::Value::Object(fields) = &mut payload {
        fields.insert(
            "runtime_mode".into(),
            serde_json::to_value(claim.runtime_mode)?,
        );
        fields.insert(
            "claim_ceiling".into(),
            serde_json::to_value(claim.effective_ceiling)?,
        );
        fields.insert(
            "downgrade_reasons".into(),
            serde_json::to_value(claim.reasons)?,
        );
        fields.insert("claim_allowed".into(), serde_json::to_value(claim.allowed)?);
        fields.insert(
            "policy_outcome".into(),
            serde_json::to_value(policy.final_outcome)?,
        );
        fields.insert(
            "policy_contributing".into(),
            serde_json::to_value(policy.contributing)?,
        );
    }
    Ok(payload)
}