car-server-core 0.53.0

Transport-neutral library for the CAR daemon JSON-RPC dispatcher (used by car-server and tokhn-daemon)
//! Deterministic self-heal coder templates.
//!
//! The registry, not a model, owns every acceptance check. V1 deliberately has
//! one registration: recurring builtin-tool failures.

use std::path::Path;

use crate::coder::{ContractCheck, OutcomeContract};

pub(crate) struct TemplateContext<'a> {
    pub dedup_key: &'a str,
    pub detector_id: &'a str,
    pub locator: &'a str,
    pub tool: &'a str,
    pub params_path: &'a Path,
}

#[derive(Debug)]
pub(crate) struct RenderedTemplate {
    pub intent: String,
    pub contract: OutcomeContract,
}

type Renderer = fn(&TemplateContext<'_>) -> Result<RenderedTemplate, String>;

struct TemplateRegistration {
    detector_id: &'static str,
    render: Renderer,
}

const REGISTRY: &[TemplateRegistration] = &[TemplateRegistration {
    detector_id: car_selfheal::detectors::tools::DETECTOR_ID,
    render: render_recurring_tool_failure,
}];

pub(crate) fn render(context: &TemplateContext<'_>) -> Result<RenderedTemplate, String> {
    let registration = REGISTRY
        .iter()
        .find(|registration| registration.detector_id == context.detector_id)
        .ok_or_else(|| {
            format!(
                "self-heal detector '{}' has no auto-fix template",
                context.detector_id
            )
        })?;
    (registration.render)(context)
}

fn render_recurring_tool_failure(
    context: &TemplateContext<'_>,
) -> Result<RenderedTemplate, String> {
    validate_tool_name(context.tool)?;
    let params_path = shell_path(context.params_path);
    let tool_crate = tool_crate(context.tool);
    let intent = format!(
        "selfheal: repair recurring {} builtin failure\n\n\
         Repair the CAR builtin tool failure identified by self-heal key {}. \
         Detector locator: {}. Preserve the supplied outcome contract exactly; \
         do not weaken, replace, or remove any check. The runtime evaluates the \
         contract independently. Changing, adding, or weakening the `car tools call` \
         replay verb or its contract assertion is out of bounds.",
        context.tool, context.dedup_key, context.locator
    );
    let contract = OutcomeContract {
        description: format!(
            "The recurring builtin '{}' call succeeds and its owning crate remains green.",
            context.tool
        ),
        checks: vec![
            ContractCheck {
                name: "build_car_cli".to_string(),
                command: "cd car-rs && cargo build -p car-cli".to_string(),
                expect_exit_zero: true,
                output_contains: None,
                timeout_secs: 600,
            },
            ContractCheck {
                name: "replay_failed_tool_call".to_string(),
                command: format!(
                    "car tools call {} --params-file {params_path}",
                    context.tool
                ),
                expect_exit_zero: true,
                output_contains: Some("$json:/ok=true".to_string()),
                timeout_secs: 120,
            },
            ContractCheck {
                name: "tool_crate_tests".to_string(),
                command: format!("cd car-rs && cargo test -p {tool_crate}"),
                expect_exit_zero: true,
                output_contains: None,
                timeout_secs: 600,
            },
        ],
    };
    let issues = contract.validate();
    if !issues.is_empty() {
        return Err(format!(
            "self-heal template '{}' produced an invalid contract: {}",
            context.detector_id,
            issues.join("; ")
        ));
    }
    Ok(RenderedTemplate { intent, contract })
}

/// The replayed commodity builtins are implemented and tested in car-engine.
/// Keep this as an explicit function: a future detector registration for tools
/// owned elsewhere must add a real mapping rather than asking a model to guess.
fn tool_crate(_tool: &str) -> &'static str {
    "car-engine"
}

fn validate_tool_name(tool: &str) -> Result<(), String> {
    if !tool.is_empty()
        && tool
            .bytes()
            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-'))
    {
        Ok(())
    } else {
        Err(format!(
            "self-heal reconstructed an unsafe builtin tool name '{tool}'"
        ))
    }
}

#[cfg(unix)]
fn shell_path(path: &Path) -> String {
    format!("'{}'", path.to_string_lossy().replace('\'', "'\\''"))
}

#[cfg(windows)]
fn shell_path(path: &Path) -> String {
    format!("\"{}\"", path.to_string_lossy().replace('"', "\"\""))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn recurring_template_contract_commands_are_registry_owned_and_exact() {
        let params = Path::new("/tmp/call.json");
        let rendered = render(&TemplateContext {
            dedup_key: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            detector_id: car_selfheal::detectors::tools::DETECTOR_ID,
            locator: "calculate|tool_error",
            tool: "calculate",
            params_path: params,
        })
        .unwrap();
        assert!(rendered.intent.starts_with("selfheal: "));
        assert!(rendered
            .intent
            .contains("runtime evaluates the contract independently"));
        assert!(rendered
            .intent
            .contains("Changing, adding, or weakening the `car tools call` replay verb"));
        #[cfg(unix)]
        let replay = "car tools call calculate --params-file '/tmp/call.json'";
        #[cfg(windows)]
        let replay = "car tools call calculate --params-file \"/tmp/call.json\"";
        assert_eq!(
            rendered
                .contract
                .checks
                .iter()
                .map(|check| check.command.as_str())
                .collect::<Vec<_>>(),
            [
                "cd car-rs && cargo build -p car-cli",
                replay,
                "cd car-rs && cargo test -p car-engine",
            ]
        );
        assert!(rendered.contract.checks[0]
            .command
            .starts_with("cd car-rs && cargo "));
        assert!(rendered.contract.checks[2]
            .command
            .starts_with("cd car-rs && cargo "));
        assert_eq!(
            rendered.contract.checks[1].output_contains.as_deref(),
            Some("$json:/ok=true")
        );
    }

    #[test]
    fn permissive_replay_verb_cannot_turn_tool_failure_green() {
        let rendered = render(&TemplateContext {
            dedup_key: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            detector_id: car_selfheal::detectors::tools::DETECTOR_ID,
            locator: "read_file|tool_error",
            tool: "read_file",
            params_path: Path::new("params.json"),
        })
        .unwrap();
        let replay = &rendered.contract.checks[1];
        assert!(!crate::coder::contract::check_assertions(
            replay,
            Some(0),
            r#"{"ok":false,"error":"still failed"}"#,
            false,
        ));
        assert!(crate::coder::contract::check_assertions(
            replay,
            Some(0),
            r#"{"ok":true,"result":{}}"#,
            false,
        ));
    }

    #[test]
    fn registry_refuses_untemplated_detector() {
        assert!(render(&TemplateContext {
            dedup_key: "key",
            detector_id: car_selfheal::detectors::metrics::DETECTOR_ID,
            locator: "metric",
            tool: "calculate",
            params_path: Path::new("params.json"),
        })
        .unwrap_err()
        .contains("no auto-fix template"));
    }
}