agent-file-tools 0.51.0

Agent File Tools — tree-sitter powered code analysis for AI agents
Documentation
use std::collections::BTreeSet;

use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct CompositionFixture {
    assertions: Vec<GoldenAssertion>,
    fleet_line: String,
    without_fleet: ResponseGolden,
    with_fleet: ResponseGolden,
    shown_alert_identities: Vec<String>,
    counted_only_alert_identities: Vec<String>,
}

#[derive(Debug, Deserialize)]
struct ResponseGolden {
    response_text: String,
}

#[derive(Debug, Deserialize)]
struct GoldenAssertion {
    id: String,
    target: String,
}

fn fixture() -> CompositionFixture {
    serde_json::from_str(include_str!(
        "fixtures/alert_fleet_compose/composition.json"
    ))
    .expect("fleet-composition fixture is valid JSON")
}

fn retired_health_shape_in(line: &str) -> bool {
    let tokens = line.split_whitespace().collect::<Vec<_>>();
    tokens.windows(8).any(|window| {
        count_token(window[0], "E")
            && count_token(window[1], "W")
            && window[2] == "|"
            && count_token(window[3].strip_prefix('~').unwrap_or(window[3]), "D")
            && count_token(window[4], "U")
            && count_token(window[5], "C")
            && window[6] == "|"
            && count_token(window[7], "T")
    })
}

fn count_token(token: &str, prefix: &str) -> bool {
    token
        .strip_prefix(prefix)
        .map(|suffix| {
            let suffix = suffix.trim_end_matches(']');
            !suffix.is_empty() && suffix.bytes().all(|byte| byte.is_ascii_digit())
        })
        .unwrap_or(false)
}

fn more_count(response_text: &str) -> Option<usize> {
    let suffixes = response_text
        .lines()
        .filter_map(|line| {
            line.strip_prefix("(+")
                .and_then(|line| line.strip_suffix(" more)"))
                .and_then(|count| count.parse::<usize>().ok())
        })
        .collect::<Vec<_>>();
    match suffixes.as_slice() {
        [count] => Some(*count),
        _ => None,
    }
}

fn validate_gate_three_no_freeze(assertions: &[GoldenAssertion]) -> Result<(), String> {
    for assertion in assertions {
        match assertion.target.as_str() {
            "alert-composition" | "fleet-values-computation" => {}
            "fleet-published-text" | "fleet-publish-condition" => {
                return Err(format!(
                    "Gate 3 forbids `{}` assertion `{}`",
                    assertion.target, assertion.id
                ));
            }
            target => return Err(format!("unknown golden target `{target}`")),
        }
    }
    Ok(())
}

#[test]
fn alert_block_composes_byte_identically_with_or_without_the_fleet_line() {
    let fixture = fixture();
    let without_fleet = &fixture.without_fleet.response_text;
    let with_fleet = &fixture.with_fleet.response_text;

    assert_eq!(
        without_fleet, with_fleet,
        "fleet publication must not alter the server-rendered alert bytes"
    );
    assert!(
        retired_health_shape_in(&fixture.fleet_line),
        "the exemption is meaningful only when the fleet line has the retained count shape"
    );
    for response in [without_fleet, with_fleet] {
        assert!(
            !response.lines().any(retired_health_shape_in),
            "retired health-count shapes are legal only in the fleet line"
        );
        assert!(
            response.contains("E0308"),
            "a diagnostic code is alert content, not a retired health-count token"
        );
    }
}

#[test]
fn more_suffix_counts_unshown_alert_identities() {
    let fixture = fixture();
    let all_identities = fixture
        .shown_alert_identities
        .iter()
        .chain(&fixture.counted_only_alert_identities)
        .collect::<BTreeSet<_>>();

    assert_eq!(
        all_identities.len(),
        fixture.shown_alert_identities.len() + fixture.counted_only_alert_identities.len(),
        "shown and counted-only identities must not overlap"
    );
    assert_eq!(
        more_count(&fixture.without_fleet.response_text),
        Some(fixture.counted_only_alert_identities.len()),
        "the suffix is a count of identities omitted from the rendered lines"
    );
}

#[test]
fn gate_three_no_freeze_uses_assertion_targets_not_descriptive_words() {
    let fixture = fixture();
    validate_gate_three_no_freeze(&fixture.assertions).expect("fixture has only legal goldens");

    let text_named_value_assertion = GoldenAssertion {
        id: "text mentions fleet values without freezing fleet output".to_string(),
        target: "fleet-values-computation".to_string(),
    };
    validate_gate_three_no_freeze(&[text_named_value_assertion])
        .expect("a descriptive word must not determine the policy");

    for target in ["fleet-published-text", "fleet-publish-condition"] {
        let error = validate_gate_three_no_freeze(&[GoldenAssertion {
            id: "value-chain continuity".to_string(),
            target: target.to_string(),
        }])
        .expect_err("Gate 3 must reject frozen fleet output assertions");
        assert!(error.contains(target));
    }
}