heddle-cli 0.12.0

An AI-native version control system
// SPDX-License-Identifier: Apache-2.0
use super::*;

fn profile_trace_from_stderr(stderr: &str) -> Value {
    let lines = stderr.lines().collect::<Vec<_>>();
    assert_eq!(
        lines.len(),
        1,
        "jsonl profiling should emit exactly one stderr line: {stderr}"
    );
    serde_json::from_str(lines[0]).expect("profile stderr line should be parseable JSON")
}

fn profile_phase_names(trace: &Value) -> Vec<&str> {
    trace["phases"]
        .as_array()
        .expect("trace should include phases")
        .iter()
        .map(|phase| {
            phase["name"]
                .as_str()
                .expect("phase should include a string name")
        })
        .collect()
}

fn assert_profile_trace_is_sanitized(stderr: &str, temp: &TempDir) {
    let temp_path = temp.path().display().to_string();
    for sensitive in [
        temp_path.as_str(),
        "sensitive-profile-input.txt",
        "HEDDLE_PROFILE",
        "jsonl",
        "--output",
    ] {
        assert!(
            !stderr.contains(sensitive),
            "profile trace should not include sensitive input `{sensitive}`: {stderr}"
        );
    }
}

fn setup_profile_repo_with_sensitive_input() -> TempDir {
    let temp = TempDir::new().unwrap();
    heddle(&["init"], Some(temp.path())).unwrap();
    std::fs::write(temp.path().join("sensitive-profile-input.txt"), "secret").unwrap();
    temp
}

fn seed_stale_monitor_endpoint(temp: &TempDir) {
    let endpoint = temp.path().join(".heddle/state/monitor-helper.json");
    std::fs::create_dir_all(endpoint.parent().expect("monitor state parent")).unwrap();
    std::fs::write(
        endpoint,
        r#"{"version":1,"host":"127.0.0.1","port":9,"pid":null}"#,
    )
    .unwrap();
}

#[test]
fn perf_trace_jsonl_status_keeps_stdout_json_and_stderr_parseable() {
    let temp = setup_profile_repo_with_sensitive_input();

    let output = heddle_output_with_env(
        &["--output", "json", "status"],
        Some(temp.path()),
        &[("HEDDLE_PROFILE", "jsonl")],
    )
    .expect("status should run");
    let stdout = std::str::from_utf8(&output.stdout).unwrap();
    let stderr = std::str::from_utf8(&output.stderr).unwrap();

    assert!(
        output.status.success(),
        "profiled status should succeed; stdout={stdout} stderr={stderr}"
    );
    serde_json::from_str::<Value>(stdout).expect("status stdout should remain valid JSON");

    let trace = profile_trace_from_stderr(stderr);
    assert_eq!(trace["schema"], "heddle-cli-profile/v1");
    assert_eq!(trace["command"], "status");
    assert_eq!(trace["exit_status"], "ok");
    let phases = profile_phase_names(&trace);
    for expected in [
        "status repo open",
        "status current state",
        "status worktree status",
        "status thread summary",
        "status build total",
        "status render",
    ] {
        assert!(
            phases.contains(&expected),
            "trace should include status phase `{expected}`: {trace}"
        );
    }
    assert!(
        !phases.contains(&"status phases"),
        "jsonl profile should split the old grouped status phase: {trace}"
    );
    assert_eq!(trace["totals"]["command_body_ms"]["unit"], "milliseconds");
    assert_eq!(trace["totals"]["total_ms"]["unit"], "milliseconds");
    assert!(
        stderr.contains("\"phases\"") && !stderr.contains("heddle profile:"),
        "jsonl mode should not emit human profile text: {stderr}"
    );
    assert_profile_trace_is_sanitized(stderr, &temp);
}

#[test]
fn perf_trace_jsonl_status_reports_structural_counters() {
    let temp = setup_profile_repo_with_sensitive_input();

    let output = heddle_output_with_env(
        &["--output", "json", "status"],
        Some(temp.path()),
        &[("HEDDLE_PROFILE", "jsonl")],
    )
    .expect("status should run");
    let stderr = std::str::from_utf8(&output.stderr).unwrap();
    assert!(
        output.status.success(),
        "profiled status should succeed: {stderr}"
    );

    let trace = profile_trace_from_stderr(stderr);
    let structural = trace["phases"]
        .as_array()
        .unwrap()
        .iter()
        .find(|phase| phase["name"] == "structural counters")
        .unwrap_or_else(|| panic!("trace should include structural counters: {trace}"));
    let metrics = structural["metrics"].as_object().unwrap();
    for name in [
        "directories_scanned",
        "directories_skipped",
        "files_hashed",
        "monitor_changed_paths",
        "object_decodes",
        "ref_reads",
        "oplog_reads",
        "repository_opens",
        "ancestors_visited",
        "history_objects_decoded",
    ] {
        assert!(metrics.contains_key(name), "missing `{name}` in {trace}");
    }
    assert_eq!(
        metrics["network_client_initialized"]["value"],
        Value::Bool(false),
        "local status must report an actual false boolean: {trace}"
    );
}

#[test]
fn perf_trace_jsonl_version_reports_startup_totals() {
    let temp = TempDir::new().unwrap();
    let output = heddle_output_with_env(
        &["--version"],
        Some(temp.path()),
        &[("HEDDLE_PROFILE", "jsonl")],
    )
    .expect("version should run");
    let stderr = std::str::from_utf8(&output.stderr).unwrap();

    assert!(
        output.status.success(),
        "profiled version should succeed: {stderr}"
    );
    let trace = profile_trace_from_stderr(stderr);
    assert_eq!(trace["command"], "version");
    assert_eq!(trace["totals"]["total_ms"]["unit"], "milliseconds");
    assert_eq!(
        trace["phases"]
            .as_array()
            .unwrap()
            .iter()
            .find(|phase| phase["name"] == "structural counters")
            .unwrap()["metrics"]["network_client_initialized"]["value"],
        Value::Bool(false)
    );
}

#[test]
fn perf_trace_jsonl_thread_list_uses_named_phase_records() {
    let temp = setup_profile_repo_with_sensitive_input();
    seed_stale_monitor_endpoint(&temp);

    let output = heddle_output_with_env(
        &["--output", "json", "thread", "list"],
        Some(temp.path()),
        &[("HEDDLE_PROFILE", "jsonl")],
    )
    .expect("thread list should run");
    let stdout = std::str::from_utf8(&output.stdout).unwrap();
    let stderr = std::str::from_utf8(&output.stderr).unwrap();

    assert!(
        output.status.success(),
        "profiled thread list should succeed; stdout={stdout} stderr={stderr}"
    );
    serde_json::from_str::<Value>(stdout).expect("thread list stdout should remain valid JSON");

    let trace = profile_trace_from_stderr(stderr);
    assert_eq!(trace["schema"], "heddle-cli-profile/v1");
    assert_eq!(trace["command"], "thread list");
    assert_eq!(trace["exit_status"], "ok");
    let phases = profile_phase_names(&trace);
    for expected in [
        "thread list collect summaries",
        "thread list verification",
        "thread list command body",
    ] {
        assert!(
            phases.contains(&expected),
            "trace should include thread list phase `{expected}`: {trace}"
        );
    }
    assert!(
        !phases.contains(&"thread list phases"),
        "jsonl profile should split the old grouped thread list phase: {trace}"
    );
    assert_profile_trace_is_sanitized(stderr, &temp);
}

#[test]
fn perf_trace_jsonl_verify_uses_named_phase_records() {
    let temp = setup_profile_repo_with_sensitive_input();
    heddle(&["capture", "-m", "profile input"], Some(temp.path())).unwrap();
    seed_stale_monitor_endpoint(&temp);

    let output = heddle_output_with_env(
        &["--output", "json", "verify"],
        Some(temp.path()),
        &[("HEDDLE_PROFILE", "jsonl")],
    )
    .expect("verify should run");
    let stdout = std::str::from_utf8(&output.stdout).unwrap();
    let stderr = std::str::from_utf8(&output.stderr).unwrap();

    assert!(
        output.status.success(),
        "profiled verify should succeed; stdout={stdout} stderr={stderr}"
    );
    serde_json::from_str::<Value>(stdout).expect("verify stdout should remain valid JSON");

    let trace = profile_trace_from_stderr(stderr);
    assert_eq!(trace["schema"], "heddle-cli-profile/v1");
    assert_eq!(trace["command"], "verify");
    assert_eq!(trace["exit_status"], "ok");
    let phases = profile_phase_names(&trace);
    for expected in [
        "verify plain git probe",
        "verify repo open",
        "verify repository checks",
        "verify command body",
    ] {
        assert!(
            phases.contains(&expected),
            "trace should include verify phase `{expected}`: {trace}"
        );
    }
    assert!(
        !phases.contains(&"verify phases"),
        "jsonl profile should split the old grouped verify phase: {trace}"
    );
    assert_profile_trace_is_sanitized(stderr, &temp);
}

#[test]
fn perf_trace_jsonl_git_overlay_clone_separates_copy_and_state_store_write() {
    let temp = TempDir::new().unwrap();
    let source = temp.path().join("source");
    let destination = temp.path().join("clone");
    let git = SleyRepository::init(&source).unwrap();
    let tree = git_empty_tree_oid(&git);
    git_commit_with_tree(&git, Some("refs/heads/main"), tree, "seed", &[]);
    let source_arg = source.to_str().unwrap();
    let destination_arg = destination.to_str().unwrap();

    let output = heddle_output_with_env(
        &["--output", "json", "clone", source_arg, destination_arg],
        Some(temp.path()),
        &[("HEDDLE_PROFILE", "jsonl")],
    )
    .expect("profiled Git-overlay clone should run");
    let stderr = std::str::from_utf8(&output.stderr).unwrap();
    assert!(output.status.success(), "clone should succeed: {stderr}");

    let trace = profile_trace_from_stderr(stderr);
    let phase = trace["phases"]
        .as_array()
        .unwrap()
        .iter()
        .find(|phase| phase["name"] == "git overlay clone phases")
        .unwrap_or_else(|| panic!("trace should separate Git copy from Heddle ingest: {trace}"));
    let metrics = phase["metrics"].as_object().unwrap();
    for name in [
        "sley_mirror_copy_ms",
        "heddle_ingest_ms",
        "state_store_write_ms",
    ] {
        assert!(metrics.contains_key(name), "missing `{name}` in {trace}");
        assert_eq!(metrics[name]["unit"], "milliseconds");
    }
}

#[test]
fn perf_trace_human_mode_still_writes_profile_text() {
    let temp = TempDir::new().unwrap();
    heddle(&["init"], Some(temp.path())).unwrap();

    let output = heddle_output_with_env(
        &["--output", "json", "status"],
        Some(temp.path()),
        &[("HEDDLE_PROFILE", "1")],
    )
    .expect("status should run");
    let stdout = std::str::from_utf8(&output.stdout).unwrap();
    let stderr = std::str::from_utf8(&output.stderr).unwrap();

    assert!(
        output.status.success(),
        "human-profiled status should succeed; stdout={stdout} stderr={stderr}"
    );
    serde_json::from_str::<Value>(stdout).expect("status stdout should remain valid JSON");
    assert!(
        stderr.contains("heddle profile:")
            && stderr.contains("command: status phases")
            && stderr.contains("command_body_ms:"),
        "human profile output should be preserved on stderr: {stderr}"
    );
}