magi-code 0.96.2

Repository-aware CLI coding agent for terminal work
Documentation
//! Monotonic execution evidence, independent of model summaries and the current diff.
//! Tool-result records are truth; compaction folds only the removed prefix.
use super::{SessionEvent, SessionEventKind};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::path::PathBuf;

const MAX_SAMPLES: usize = 24;
const MAX_PATH_BYTES: usize = 512;
const MAX_ID_BYTES: usize = 256;

#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub(crate) struct ExecutionEffects {
    mutation_calls: u64,
    shell_calls: u64,
    incomplete: bool,
    samples: Vec<MutationSample>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct MutationSample {
    call_id: String,
    path: String,
}

/// Recorded atomically with the result, including partial/failed committed edits.
/// Explicit counts distinguish bounded samples from an empty mutation result.
pub(crate) fn mutation_evidence(paths: &[PathBuf]) -> Value {
    serde_json::json!({
        "changed_path_count": paths.len(),
        "paths": paths.iter().take(MAX_SAMPLES).map(|path| {
            bounded(&path.to_string_lossy(), MAX_PATH_BYTES)
        }).collect::<Vec<_>>(),
    })
}

fn bounded(value: &str, bytes: usize) -> String {
    let value = crate::output::redact_sensitive_text(value);
    let mut end = value.len().min(bytes);
    while !value.is_char_boundary(end) {
        end -= 1;
    }
    value[..end].to_string()
}

impl ExecutionEffects {
    pub(crate) fn from_checkpoint(value: Option<&Value>) -> Self {
        // Reject oversized/unrecognized snapshots instead of projecting unbounded text.
        let Some(value) = value else {
            return Self {
                incomplete: true,
                ..Self::default()
            };
        };
        let valid = value
            .get("samples")
            .and_then(Value::as_array)
            .is_some_and(|samples| {
                samples.len() <= MAX_SAMPLES
                    && samples.iter().all(|sample| {
                        sample
                            .get("path")
                            .and_then(Value::as_str)
                            .is_some_and(|s| s.len() <= MAX_PATH_BYTES)
                            && sample
                                .get("call_id")
                                .and_then(Value::as_str)
                                .is_some_and(|s| s.len() <= MAX_ID_BYTES)
                    })
            });
        if valid && let Ok(mut effects) = serde_json::from_value::<Self>(value.clone()) {
            for sample in &mut effects.samples {
                sample.path = bounded(&sample.path, MAX_PATH_BYTES);
                sample.call_id = bounded(&sample.call_id, MAX_ID_BYTES);
            }
            effects.incomplete |= effects.mutation_calls == 0 && !effects.samples.is_empty();
            return effects;
        }
        Self {
            incomplete: true,
            ..Self::default()
        }
    }

    pub(crate) fn mark_incomplete(&mut self) {
        self.incomplete = true;
    }

    pub(crate) fn from_events(session_id: &str, events: &[SessionEvent]) -> Self {
        let mut effects = Self::default();
        for (index, event) in events.iter().enumerate() {
            effects.observe_event(session_id, index, event);
        }
        effects
    }

    pub(crate) fn observe_event(&mut self, session_id: &str, index: usize, event: &SessionEvent) {
        if event.session_id != session_id {
            return;
        }
        if event.kind() == Some(SessionEventKind::Compaction) {
            match super::metadata::validate_compaction_checkpoint(
                session_id,
                event,
                index,
                index + 1,
            ) {
                Ok(_) if index == 0 => {
                    *self = Self::from_checkpoint(event.payload.get("execution_effects"));
                }
                // Only the leading rotation checkpoint represents unavailable history.
                // Legacy inline checkpoints must not reset or duplicate observed results.
                Ok(_) => {}
                Err(_) => self.mark_incomplete(),
            }
        } else {
            self.observe_tool_result(event);
        }
    }

    pub(crate) fn observe_tool_result(&mut self, event: &SessionEvent) {
        if !matches!(
            event.kind(),
            Some(SessionEventKind::ToolResult | SessionEventKind::CodeModeToolResult)
        ) {
            return;
        }
        let payload = &event.payload;
        // Nested records without dispatch evidence were never executed (hook-blocked or unavailable).
        if event.kind() == Some(SessionEventKind::CodeModeToolResult)
            && payload.get("execution_effects").is_none()
        {
            return;
        }
        let result = &payload["result"];
        let name = result["tool_name"].as_str().unwrap_or("");
        // Nested records own mutation counts; the parent repeats paths for UI display only.
        if name == "code_mode" {
            return;
        }
        if name == "bash" {
            self.shell_calls = self.shell_calls.saturating_add(1);
        }
        let mut paths = Vec::new();
        let changed = if let Some(evidence) = payload.get("execution_effects") {
            let count = evidence["changed_path_count"].as_u64();
            if let Some(values) = evidence["paths"].as_array() {
                paths.extend(values.iter().take(MAX_SAMPLES).filter_map(Value::as_str));
                self.incomplete |= values.len() > MAX_SAMPLES || paths.len() != values.len();
            } else {
                self.incomplete = true;
            }
            self.incomplete |= count.is_none() || (count == Some(0) && !paths.is_empty());
            count.unwrap_or_default() > 0
        } else {
            // Older logs already contain structured write/hash-edit commit evidence.
            let metadata = &result["metadata"];
            if name == "write"
                && (result["success"] == true || metadata["outcome"] == "committed_but_undurable")
            {
                if let Some(path) = metadata["path"].as_str() {
                    paths.push(path);
                }
                true
            } else if name == "hash_edit" {
                if let Some(files) = metadata["files"].as_array() {
                    for file in files {
                        let committed = matches!(
                            file["status"].as_str(),
                            Some(
                                "committed"
                                    | "committed_but_undurable"
                                    | "committed_with_error"
                                    | "destination_written_source_retained"
                            )
                        );
                        if committed
                            && file["operation"] != "noop"
                            && let Some(path) = file["path"].as_str()
                        {
                            paths.push(path);
                        }
                        if paths.len() == MAX_SAMPLES {
                            break;
                        }
                    }
                }
                if paths.is_empty() && result["success"] == true {
                    // Legacy metadata cannot establish whether success was a no-op.
                    self.incomplete = true;
                }
                !paths.is_empty()
            } else {
                false
            }
        };
        if changed {
            self.mutation_calls = self.mutation_calls.saturating_add(1);
            let id = bounded(
                payload["call_id"].as_str().unwrap_or("unknown"),
                MAX_ID_BYTES,
            );
            for path in paths {
                if self.samples.len() == MAX_SAMPLES {
                    break;
                }
                self.samples.push(MutationSample {
                    call_id: id.clone(),
                    path: bounded(path, MAX_PATH_BYTES),
                });
            }
        }
    }

    pub(crate) fn provider_note(&self) -> Option<String> {
        if self.mutation_calls == 0 && self.shell_calls == 0 && !self.incomplete {
            return None;
        }
        let mutations = if self.mutation_calls > 0 {
            "Recorded file mutations occurred even if later reverted. A clean status does not mean no edits were made. Preserve and disclose recorded edit/revert incidents; do not replace them with a claim that no changes occurred."
        } else {
            "No file mutations are established by these counters; they do not prove that no edits occurred."
        };
        Some(format!(
            "[Recorded execution evidence — not a model summary]\n{}\nThese are historical observations, not the current working-tree diff. {mutations} Shell side effects and whether a restore fully reverted them are not independently verified here. Samples are bounded; full evidence remains in tool-call/result history. An incomplete record cannot prove absence of mutations.\n[/Recorded execution evidence]",
            serde_json::to_string(self).expect("execution evidence serialization")
        ))
    }
}