koala-drift 1.0.4

Wiki ↔ code drift detector.
Documentation
//! `koala-core drift --format github` emits GitHub Actions
//! annotation lines that reference the right file:line.

use koala_core::invariant::Context;
use koala_drift::{format_github_annotations, Registry as DriftRegistry};
use std::fs;
use tempfile::TempDir;

fn write(dir: &std::path::Path, rel: &str, body: &str) {
    let p = dir.join(rel);
    fs::create_dir_all(p.parent().unwrap()).unwrap();
    fs::write(p, body).unwrap();
}

#[test]
fn cli_emits_annotations_with_line() {
    let tmp = TempDir::new().unwrap();
    let body = "---\n\
id: x\n\
status: in-progress\n\
---\n\
# X\n\n\
## Acceptance criteria(机械可验证)\n\n\
- [ ] does the thing\n\
  → crates/x/tests/missing.rs#none\n";
    write(tmp.path(), "wiki/features/x.md", body);

    let ctx = Context::new(tmp.path().to_path_buf());
    let reg = DriftRegistry::builtin();
    let findings = reg.run_all(&ctx);
    let out = format_github_annotations(&findings);

    assert!(
        out.contains("::error"),
        "expected ::error annotation: {out}"
    );
    assert!(
        out.contains("file=wiki/features/x.md"),
        "expected file= field: {out}"
    );
    assert!(
        out.contains("line=10"),
        "expected line=10 (the `→` row): {out}"
    );
    assert!(
        out.contains("[feature.acceptance-test-ref]"),
        "expected check id label: {out}"
    );
}

#[test]
fn empty_findings_emits_no_lines() {
    let tmp = TempDir::new().unwrap();
    let ctx = Context::new(tmp.path().to_path_buf());
    let reg = DriftRegistry::builtin();
    let findings = reg.run_all(&ctx);
    let out = format_github_annotations(&findings);
    assert!(
        out.is_empty(),
        "expected empty output for clean repo: {out}"
    );
}

#[test]
fn advisory_findings_use_warning_level() {
    let tmp = TempDir::new().unwrap();
    // Construct a synthetic Advisory finding through the kind
    // `AdrDormancy` flow. Easiest: drop an accepted ADR with no refs.
    let dir = tmp.path().join("wiki/decisions");
    fs::create_dir_all(&dir).unwrap();
    fs::write(
        dir.join("0001-bootstrap.md"),
        "---\n\
id: 0001\n\
title: Bootstrap\n\
status: accepted\n\
date: 2024-01-01\n\
---\n\n\
# ADR-0001\n",
    )
    .unwrap();
    let ctx = Context::new(tmp.path().to_path_buf());
    let reg = DriftRegistry::builtin();
    let findings = reg.run_all(&ctx);
    let out = format_github_annotations(&findings);
    if findings
        .iter()
        .any(|f| matches!(f.severity, koala_drift::Severity::Advisory))
    {
        assert!(
            out.contains("::warning"),
            "advisory finding should map to ::warning: {out}"
        );
    }
}