sim-lib-forge 0.1.0

Compiled intent records and one-shot BRIDGE lifts for reusable packet programs.
Documentation
use sim_kernel::{Args, Cx, Export, Expr, Lib, Symbol, testing::bare_cx};

use crate::{ForgeLib, forge_entrypoint_symbol, forge_verb};

fn payload(args: &[&str]) -> Expr {
    Expr::List(
        args.iter()
            .copied()
            .map(str::to_owned)
            .map(Expr::String)
            .collect(),
    )
}

fn map_field<'a>(expr: &'a Expr, name: &str) -> &'a Expr {
    let Expr::Map(entries) = expr else {
        panic!("report is not a map: {expr:?}");
    };
    let key = Expr::Symbol(Symbol::new(name));
    entries
        .iter()
        .find_map(|(entry_key, value)| (entry_key == &key).then_some(value))
        .unwrap_or_else(|| panic!("missing report field {name}"))
}

fn number_field<'a>(expr: &'a Expr, name: &str) -> &'a str {
    match map_field(expr, name) {
        Expr::Number(number) => number.canonical.as_str(),
        other => panic!("{name} is not a number: {other:?}"),
    }
}

fn bool_field(expr: &Expr, name: &str) -> bool {
    match map_field(expr, name) {
        Expr::Bool(value) => *value,
        other => panic!("{name} is not a bool: {other:?}"),
    }
}

fn string_field<'a>(expr: &'a Expr, name: &str) -> &'a str {
    match map_field(expr, name) {
        Expr::String(value) => value,
        other => panic!("{name} is not a string: {other:?}"),
    }
}

fn symbol_field(expr: &Expr, name: &str) -> Symbol {
    match map_field(expr, name) {
        Expr::Symbol(symbol) => symbol.clone(),
        other => panic!("{name} is not a symbol: {other:?}"),
    }
}

fn cli_envelope(cx: &mut Cx, args: &[&str]) -> sim_kernel::Value {
    let arg_values = args
        .iter()
        .copied()
        .map(|arg| cx.factory().string(arg.to_owned()).unwrap())
        .collect::<Vec<_>>();
    let arg_values = cx.factory().list(arg_values).unwrap();
    cx.factory()
        .table(vec![
            (
                Symbol::new("verb"),
                cx.factory().string("forge".to_owned()).unwrap(),
            ),
            (Symbol::new("args"), arg_values),
        ])
        .unwrap()
}

#[test]
fn forge_lib_exports_cli_entrypoint() {
    let lib = ForgeLib;
    let manifest = lib.manifest();

    assert_eq!(manifest.id, Symbol::qualified("sim", "forge"));
    assert!(manifest.exports.contains(&Export::Function {
        symbol: forge_entrypoint_symbol(),
        function_id: None,
    }));
}

#[test]
fn forge_loaded_entrypoint_accepts_cli_envelope() {
    let mut cx = bare_cx();
    let lib = ForgeLib;
    cx.load_lib(&lib).unwrap();
    let envelope = cli_envelope(&mut cx, &["forge", "show", "summarize-contract"]);

    let result = cx
        .call_function(&forge_entrypoint_symbol(), Args::new(vec![envelope]))
        .unwrap();

    assert!(result.object().truth(&mut cx).unwrap());
}

#[test]
fn run_on_golden_skips_lift_call() {
    let mut cx = bare_cx();

    let report = forge_verb(
        &mut cx,
        &payload(&["forge", "run", "summarize-contract", "input.json"]),
    )
    .unwrap();

    assert_eq!(
        symbol_field(&report, "status"),
        Symbol::qualified("forge", "golden")
    );
    assert_eq!(number_field(&report, "compiler-calls"), "0");
    assert!(bool_field(&report, "artifact-cache-hit"));
}

#[test]
fn identical_replayed_run_makes_no_execution_call() {
    let mut cx = bare_cx();

    let report = forge_verb(
        &mut cx,
        &payload(&["forge", "run", "summarize-contract", "input.json"]),
    )
    .unwrap();

    assert_eq!(number_field(&report, "execution-calls"), "0");
    assert_eq!(number_field(&report, "replay-hits"), "1");
    assert!(bool_field(&report, "answer-replay-hit"));
}

#[test]
fn lift_surfaces_inferred_shape_for_approval() {
    let mut cx = bare_cx();

    let report = forge_verb(
        &mut cx,
        &payload(&["forge", "lift", "summarize the contract and flag risks"]),
    )
    .unwrap();

    assert_eq!(
        symbol_field(&report, "status"),
        Symbol::qualified("forge", "candidate")
    );
    assert!(string_field(&report, "inferred-return-shape").contains("Shape Summary"));
    assert_eq!(
        string_field(&report, "review-surface"),
        "surface://forge/summarize-contract"
    );
    assert!(matches!(map_field(&report, "review-fields"), Expr::List(fields) if fields.len() == 2));
}