weavatrix-rust 2.16.2

Protocol-independent Rust repository intelligence: typed evidence graphs for impact, architecture, APIs, Git, n8n, Dify, Agent catalogs, Mermaid, and Web3 ABI
Documentation
#[allow(dead_code)]
mod agent_support;

use agent_support::{Fixture, dump};
use blazingly_json::json;
use weavatrix_rust::{Weavatrix, tools};

#[test]
fn type_change_is_not_proven_compatible() {
    let fixture = Fixture::empty();
    write_schema(
        &fixture,
        "catalogs/before.json",
        r#"{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]}"#,
        true,
    );
    write_schema(
        &fixture,
        "catalogs/after.json",
        r#"{"type":"object","properties":{"id":{"type":"integer"}},"required":["id"]}"#,
        true,
    );
    let mut engine = Weavatrix::open(&fixture.root).unwrap();
    let report = tools::call(
        &mut engine,
        "agent_change_impact",
        json!({"before": "catalogs/before.json", "after": "catalogs/after.json"}),
    )
    .unwrap();
    let change = report["changes"].as_array().unwrap()[0].clone();
    assert_eq!(
        change["compatibility"],
        "proven-incompatible",
        "{}",
        dump(&report)
    );
    assert_eq!(change["direction"], "before-request-accepted-by-after");
}

#[test]
fn unsupported_union_is_undetermined() {
    let fixture = Fixture::empty();
    write_schema(
        &fixture,
        "catalogs/before.json",
        r#"{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]}"#,
        true,
    );
    write_schema(
        &fixture,
        "catalogs/after.json",
        r#"{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"integer"}]}},"required":["id"]}"#,
        true,
    );
    let mut engine = Weavatrix::open(&fixture.root).unwrap();
    let report = tools::call(
        &mut engine,
        "agent_change_impact",
        json!({"before": "catalogs/before.json", "after": "catalogs/after.json"}),
    )
    .unwrap();
    assert_eq!(
        report["changes"][0]["compatibility"],
        "undetermined",
        "{}",
        dump(&report)
    );
}

#[test]
fn missing_tool_in_partial_after_is_unconfirmed() {
    let fixture = Fixture::empty();
    write_named(
        &fixture,
        "catalogs/before.json",
        "lookup",
        r#"{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]}"#,
        true,
    );
    fixture.write(
        "catalogs/after.json",
        r#"{
          "$schema": "https://weavatrix.dev/schemas/agent-catalog/1.json",
          "scope": "after",
          "complete": false,
          "nextCursor": "page-2",
          "tools": []
        }"#,
    );
    let mut engine = Weavatrix::open(&fixture.root).unwrap();
    let report = tools::call(
        &mut engine,
        "agent_change_impact",
        json!({"before": "catalogs/before.json", "after": "catalogs/after.json"}),
    )
    .unwrap();
    let change = &report["changes"][0];
    assert_eq!(change["change"], "unconfirmed", "{}", dump(&report));
    assert_eq!(change["compatibility"], "undetermined", "{}", dump(&report));
}

#[test]
fn empty_catalog_path_is_not_complete_removal() {
    let fixture = Fixture::empty();
    write_named(
        &fixture,
        "catalogs/before.json",
        "lookup",
        r#"{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]}"#,
        true,
    );
    fixture.write("readme.md", "no catalog here\n");
    let mut engine = Weavatrix::open(&fixture.root).unwrap();
    let report = tools::call(
        &mut engine,
        "agent_change_impact",
        json!({"before": "catalogs/before.json", "after": "readme.md"}),
    )
    .unwrap();
    assert_eq!(
        report["changes"][0]["change"],
        "unconfirmed",
        "{}",
        dump(&report)
    );
}

#[test]
fn foreign_package_skill_is_not_a_proven_consumer() {
    let fixture = Fixture::empty();
    write_named(
        &fixture,
        "pkg-a/catalogs/before.json",
        "search",
        r#"{"type":"object","properties":{"q":{"type":"string"}}}"#,
        true,
    );
    write_named(
        &fixture,
        "pkg-a/catalogs/after.json",
        "search",
        r#"{"type":"object","properties":{"q":{"type":"string"}}}"#,
        true,
    );
    fixture.write(
        "pkg-a/skills/alpha/SKILL.md",
        "---\nname: alpha\nallowed-tools: search\n---\nA\n",
    );
    fixture.write(
        "pkg-b/skills/beta/SKILL.md",
        "---\nname: beta\nallowed-tools: search\n---\nB\n",
    );
    let mut engine = Weavatrix::open(&fixture.root).unwrap();
    let report = tools::call(
        &mut engine,
        "agent_change_impact",
        json!({
            "before": "pkg-a/catalogs/before.json",
            "after": "pkg-a/catalogs/after.json"
        }),
    )
    .unwrap();
    let consumers = report["consumers"].as_array().unwrap();
    assert!(
        consumers.iter().any(|item| item["label"] == "alpha"),
        "{}",
        dump(&report)
    );
    assert!(
        consumers.iter().all(|item| item["label"] != "beta"),
        "{}",
        dump(&report)
    );
}

#[test]
fn observation_keeps_event_time_and_does_not_promote_success() {
    let fixture = Fixture::empty();
    fixture.write(
        "catalogs/events.json",
        r#"{
          "$schema": "https://weavatrix.dev/schemas/agent-observation/1.json",
          "events": [
            {
              "id": "inv-1",
              "producer": "granttap",
              "kind": "invocation",
              "target": "lookup",
              "result": "success",
              "event_time": 42,
              "sequence": 7,
              "boot_epoch": 3,
              "phase": "request",
              "evidence": "obs-1"
            }
          ]
        }"#,
    );
    let engine = Weavatrix::open(&fixture.root).unwrap();
    let labels = engine
        .state()
        .graph()
        .nodes()
        .iter()
        .map(|node| node.label.as_str())
        .collect::<Vec<_>>();
    assert!(labels.contains(&"event_time:42"), "{labels:?}");
    assert!(labels.contains(&"sequence:7"), "{labels:?}");
    assert!(labels.contains(&"phase:request"), "{labels:?}");
    assert!(labels.contains(&"result_is_not_effect"), "{labels:?}");
}

fn write_schema(fixture: &Fixture, path: &str, schema: &str, complete: bool) {
    write_named(fixture, path, "lookup", schema, complete);
}

fn write_named(fixture: &Fixture, path: &str, name: &str, schema: &str, complete: bool) {
    fixture.write(
        path,
        &format!(
            r#"{{
              "$schema": "https://weavatrix.dev/schemas/agent-catalog/1.json",
              "scope": "{name}",
              "complete": {complete},
              "tools": [{{ "name": "{name}", "description": "lookup", "inputSchema": {schema} }}]
            }}"#
        ),
    );
}