harn-vm 0.10.118

Async bytecode virtual machine for the Harn programming language
Documentation
use super::*;
use crate::llm_config::{self, ModelRowKind};

#[test]
fn anthropic_sonnet_4_5_selector_and_snapshot_stay_distinct() {
    let overlay = llm_config::parse_config_toml(include_str!(
        "../llm/catalog_sources/60-models/00-anthropic.toml"
    ))
    .expect("anthropic catalog fragment parses");
    let catalog = artifact_embedded(Some(&overlay), None);
    let selector = catalog
        .models
        .iter()
        .find(|model| model.id == "claude-sonnet-4-5")
        .expect("selector row");
    let snapshot = catalog
        .models
        .iter()
        .find(|model| model.id == "claude-sonnet-4-5-20250929")
        .expect("snapshot row");
    assert_eq!(selector.name, snapshot.name);
    assert_eq!(selector.display_name, snapshot.display_name);
    assert_eq!(selector.row_kind, Some(ModelRowKind::Selector));
    assert_eq!(snapshot.row_kind, Some(ModelRowKind::Snapshot));
    assert_eq!(
        selector.current_snapshot.as_deref(),
        Some("claude-sonnet-4-5-20250929")
    );
    assert_eq!(snapshot.released.as_deref(), Some("2025-09-29"));
    assert!(selector.released.is_none());
}

#[test]
fn dated_sonnet_3_5_snapshots_order_by_released() {
    let overlay = llm_config::parse_config_toml(include_str!(
        "../llm/catalog_sources/60-models/00-anthropic.toml"
    ))
    .expect("anthropic catalog fragment parses");
    let catalog = artifact_embedded(Some(&overlay), None);
    let june = catalog
        .models
        .iter()
        .find(|model| model.id == "claude-3-5-sonnet-20240620")
        .expect("june snapshot");
    let october = catalog
        .models
        .iter()
        .find(|model| model.id == "claude-3-5-sonnet-20241022")
        .expect("october snapshot");
    assert_eq!(june.row_kind, Some(ModelRowKind::Snapshot));
    assert_eq!(october.row_kind, Some(ModelRowKind::Snapshot));
    assert_eq!(june.released.as_deref(), Some("2024-06-20"));
    assert_eq!(october.released.as_deref(), Some("2024-10-22"));
    assert!(june.released.as_deref().unwrap() < october.released.as_deref().unwrap());
}

#[test]
fn overlay_can_author_released_and_row_kind() {
    let overlay = llm_config::parse_config_toml(
        r#"
[models."fixture/dated-snapshot"]
name = "Fixture Twin"
provider = "openai"
context_window = 8192
released = "2026-01-15"
row_kind = "snapshot"

[models."fixture/moving-selector"]
name = "Fixture Twin"
provider = "openai"
context_window = 8192
row_kind = "selector"
current_snapshot = "fixture/dated-snapshot"
"#,
    )
    .expect("overlay parses");
    let catalog = artifact_embedded(Some(&overlay), None);
    let snapshot = catalog
        .models
        .iter()
        .find(|model| model.id == "fixture/dated-snapshot")
        .expect("overlay snapshot");
    let selector = catalog
        .models
        .iter()
        .find(|model| model.id == "fixture/moving-selector")
        .expect("overlay selector");
    assert_eq!(snapshot.name, selector.name);
    assert_eq!(snapshot.released.as_deref(), Some("2026-01-15"));
    assert_eq!(snapshot.row_kind, Some(ModelRowKind::Snapshot));
    assert_eq!(selector.row_kind, Some(ModelRowKind::Selector));
    assert_eq!(
        selector.current_snapshot.as_deref(),
        Some("fixture/dated-snapshot")
    );
}

#[test]
fn validation_rejects_invalid_released_and_dangling_current_snapshot() {
    let mut catalog = artifact();
    catalog.models[0].released = Some("not-a-date".to_string());
    catalog.models[0].current_snapshot = Some("no-such-model".to_string());
    catalog.models[0].row_kind = Some(ModelRowKind::Snapshot);
    let report = validate_artifact(&catalog);
    assert!(
        report
            .errors
            .iter()
            .any(|message| message.contains("released must be an ISO 8601 date")),
        "expected released date error, got {:?}",
        report.errors
    );
    assert!(
        report
            .errors
            .iter()
            .any(|message| message.contains("current_snapshot references unknown model")),
        "expected dangling snapshot error, got {:?}",
        report.errors
    );
    assert!(
        report
            .errors
            .iter()
            .any(|message| message.contains("is a snapshot and cannot name a current_snapshot")),
        "expected snapshot/current_snapshot conflict, got {:?}",
        report.errors
    );
}

#[test]
fn downstream_bindings_project_released_and_row_kind() {
    let schema = schema_value();
    assert_eq!(
        schema["$defs"]["model"]["properties"]["released"]["pattern"],
        "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
    );
    assert_eq!(
        schema["$defs"]["model"]["properties"]["row_kind"]["enum"],
        serde_json::json!(["snapshot", "selector"])
    );
    assert!(schema["$defs"]["model"]["properties"]["current_snapshot"].is_object());

    let typescript = typescript_declarations();
    assert!(typescript.contains("released?: string"));
    assert!(typescript.contains(r#"row_kind?: "snapshot" | "selector""#));
    assert!(typescript.contains("current_snapshot?: string"));

    let swift = swift_binding().expect("swift binding renders");
    assert!(swift.contains("public let released: String?"));
    assert!(swift.contains("public let rowKind: String?"));
    assert!(swift.contains("public let currentSnapshot: String?"));
    assert!(swift.contains("case released"));
    assert!(swift.contains("case rowKind = \"row_kind\""));
    assert!(swift.contains("case currentSnapshot = \"current_snapshot\""));
}