magi-code 0.77.1

Repository-aware CLI coding agent for terminal work
Documentation
//! Bounded daemon-lifetime mutation evidence. No request payloads are retained.
use super::wire::Request;
use crate::service::protocol::ServiceErrorCode;
use serde_json::{Value, json};
use sha2::{Digest, Sha256};
use std::{
    collections::HashMap,
    time::{Duration, Instant},
};

const RETENTION: Duration = Duration::from_secs(600);
const CAPACITY: usize = 256;

struct Entry {
    digest: [u8; 32],
    outcome: Value,
    settled: Option<Instant>,
}

pub(super) struct Operations {
    key: [u8; 32],
    entries: HashMap<String, Entry>,
}

impl Operations {
    pub(super) fn new() -> Self {
        let mut key = [0; 32];
        key[..16].copy_from_slice(uuid::Uuid::new_v4().as_bytes());
        key[16..].copy_from_slice(uuid::Uuid::new_v4().as_bytes());
        Self {
            key,
            entries: HashMap::new(),
        }
    }

    pub(super) fn expire(&mut self, now: Instant) {
        self.entries.retain(|_, entry| {
            let Some(settled) = entry.settled else { return true };
            let age = now.saturating_duration_since(settled);
            if age >= RETENTION * 2 { return false; }
            if age >= RETENTION {
                entry.outcome = json!({"state":"expired", "method":null,"session_id":null,"result":null,"error":null});
                entry.digest = [0; 32];
            }
            true
        });
    }

    // HMAC-SHA256 with a fresh daemon-local key. Canonicalization is explicit so enabling
    // serde_json's preserve_order feature cannot change immutable-intent comparisons.
    fn digest(&self, request: &Request) -> [u8; 32] {
        let intent = canonical_json(&json!([
            request.method,
            request.session_id,
            request.payload
        ]));
        let mut inner_pad = [0x36; 64];
        let mut outer_pad = [0x5c; 64];
        for (index, byte) in self.key.iter().enumerate() {
            inner_pad[index] ^= byte;
            outer_pad[index] ^= byte;
        }
        let mut inner = Sha256::new();
        inner.update(inner_pad);
        inner.update(intent.to_string().as_bytes());
        let mut outer = Sha256::new();
        outer.update(outer_pad);
        outer.update(inner.finalize());
        outer.finalize().into()
    }

    pub(super) fn reserve(
        &mut self,
        request: &Request,
        now: Instant,
    ) -> Result<(), ServiceErrorCode> {
        self.expire(now);
        let id = request
            .operation_id
            .as_ref()
            .ok_or(ServiceErrorCode::InvalidPayload)?;
        let digest = self.digest(request);
        if let Some(entry) = self.entries.get(id) {
            return Err(if entry.outcome["state"] == "expired" {
                ServiceErrorCode::OperationExpired
            } else if entry.digest == digest {
                ServiceErrorCode::OperationAlreadyKnown
            } else {
                ServiceErrorCode::OperationIdentityMismatch
            });
        }
        if self.entries.len() >= CAPACITY {
            return Err(ServiceErrorCode::OperationCapacity);
        }
        self.entries.insert(id.clone(), Entry {
            digest,
            outcome: json!({"state":"in_progress","method":request.method,"session_id":request.session_id,"result":null,"error":null}),
            settled: None,
        });
        Ok(())
    }

    pub(super) fn update(
        &mut self,
        id: &str,
        state: &str,
        result: Value,
        error: Value,
        now: Instant,
    ) {
        if let Some(entry) = self.entries.get_mut(id) {
            entry.outcome["state"] = json!(state);
            entry.outcome["result"] = result;
            entry.outcome["error"] = error;
            if state == "terminal" || state == "rejected" {
                entry.settled = Some(now);
            }
        }
    }

    pub(super) fn lookup(&self, instance: &str, target: &str, id: &str) -> Value {
        let mut outcome = if target == instance {
            self.entries.get(id).map(|entry| entry.outcome.clone())
        } else { None }.unwrap_or_else(|| json!({"state":"unknown","method":null,"session_id":null,"result":null,"error":null}));
        outcome["target_instance_id"] = json!(target);
        outcome["operation_id"] = json!(id);
        outcome
    }

    pub(super) fn retained(&self, id: &str) -> bool {
        self.entries
            .get(id)
            .is_some_and(|entry| entry.outcome["state"] != "expired")
    }

    pub(super) fn admitted(&self) -> usize {
        self.entries
            .values()
            .filter(|entry| entry.settled.is_none())
            .count()
    }
}

fn canonical_json(value: &Value) -> Value {
    match value {
        Value::Object(fields) => {
            let mut ordered: Vec<_> = fields.iter().collect();
            ordered.sort_unstable_by_key(|(key, _)| *key);
            Value::Object(
                ordered
                    .into_iter()
                    .map(|(key, value)| (key.clone(), canonical_json(value)))
                    .collect(),
            )
        }
        Value::Array(values) => Value::Array(values.iter().map(canonical_json).collect()),
        _ => value.clone(),
    }
}