magi-code 0.101.1

Repository-aware CLI coding agent for terminal work
Documentation
//! Read-snapshot evidence, not a loaded-skill cache. Ranges address the original
//! tool output; replay redaction/truncation must be validated before projection.

use serde::{Deserialize, Serialize};
use serde_json::Value;
use sha2::{Digest, Sha256};

const PROVENANCE_VERSION: u8 = 1;
const MAX_SKILL_READS: usize = 8;
const MAX_SOURCE_BYTES: usize = 1024;

/// `identity` commits to the selected descriptor path, access policy, skill and
/// reference, full snapshot digest, and exact selector/raw mode. `sha256` binds
/// the delivered selection; neither digest alone establishes context coverage.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub(crate) struct SkillReadProvenance {
    pub(crate) version: u8,
    pub(crate) identity: String,
    pub(crate) source: String,
    pub(crate) start: usize,
    pub(crate) end: usize,
    pub(crate) sha256: String,
}

impl SkillReadProvenance {
    pub(crate) fn validates(&self, output: &str) -> bool {
        self.version == PROVENANCE_VERSION
            && valid_digest(&self.identity)
            && valid_digest(&self.sha256)
            && self.source.starts_with("skill://")
            && self.source.len() <= MAX_SOURCE_BYTES
            && !self.source.chars().any(char::is_control)
            && self.start < self.end
            && output.is_char_boundary(self.start)
            && output.is_char_boundary(self.end)
            && output
                .get(self.start..self.end)
                .is_some_and(|slice| digest_hex(slice.as_bytes()) == self.sha256)
    }
}

pub(crate) fn validated_skill_reads(
    tool_name: &str,
    success: bool,
    output: &str,
    metadata: &Value,
) -> Vec<SkillReadProvenance> {
    if tool_name != "read" || !success {
        return Vec::new();
    }
    let Some(values) = metadata.get("skill_reads").and_then(Value::as_array) else {
        return Vec::new();
    };
    if values.len() > MAX_SKILL_READS {
        return Vec::new();
    }
    let Ok(reads) = values
        .iter()
        .cloned()
        .map(serde_json::from_value)
        .collect::<Result<Vec<SkillReadProvenance>, _>>()
    else {
        return Vec::new();
    };
    if reads.iter().any(|read| !read.validates(output))
        || reads.windows(2).any(|pair| pair[0].end > pair[1].start)
    {
        return Vec::new();
    }
    reads
}

pub(crate) fn digest_hex(bytes: &[u8]) -> String {
    crate::support::hex::lower_hex(Sha256::digest(bytes))
}

fn valid_digest(value: &str) -> bool {
    value.len() == 64
        && value
            .bytes()
            .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
}

pub(super) fn finalize_skill_provenance(
    metadata: &mut serde_json::Map<String, Value>,
    source: &str,
    selector: &Value,
    raw: bool,
    selected: &str,
) -> Option<SkillReadProvenance> {
    let seed = metadata.remove("_skill_provenance")?;
    if source.len() > 1024 || source.chars().any(char::is_control) {
        return None;
    }
    let identity_material = serde_json::json!({
        "version": 1,
        "access_policy_version": seed.get("access_policy_version")?,
        "descriptor_path_sha256": seed.get("descriptor_path_sha256")?,
        "snapshot_sha256": seed.get("snapshot_sha256")?,
        "skill": seed.get("skill")?,
        "reference": seed.get("reference")?,
        "selector": selector,
        "raw": raw,
    });
    let encoded = serde_json::to_vec(&identity_material).ok()?;
    Some(SkillReadProvenance {
        version: 1,
        identity: digest_hex(&encoded),
        source: source.to_string(),
        start: 0,
        end: selected.len(),
        sha256: digest_hex(selected.as_bytes()),
    })
}