xlog-cli 0.9.2

Command-line interface for deterministic and probabilistic XLOG execution
use assert_cmd::cargo::cargo_bin_cmd;

#[test]
fn xlog_genrule_002_explain_json_reports_row_decisions_and_thresholds() {
    let program =
        std::env::temp_dir().join(format!("xlog_genrule_002_{}.xlog", std::process::id()));
    std::fs::write(
        &program,
        r#"
pred generated_candidate(symbol, i32, i32).
pred generated_accept(symbol).

generated_candidate("accepted", 4, 0).
generated_candidate("low_support", 1, 0).
generated_candidate("label_leak", 5, 1).

generated_accept(Name) :- generated_candidate(Name, Support, Leak), Support >= 3, Leak == 0.
?- generated_accept(Name).
"#,
    )
    .expect("write generated-rule fixture");

    let output = cargo_bin_cmd!("xlog")
        .args([
            "explain",
            "--format",
            "json",
            program.to_str().expect("valid path"),
        ])
        .output()
        .expect("run xlog explain json");
    assert!(
        output.status.success(),
        "xlog explain failed: {}",
        String::from_utf8_lossy(&output.stderr)
    );
    let stdout = String::from_utf8(output.stdout).expect("utf8 stdout");
    assert!(
        stdout.contains("\"generated_rule_diagnostics\""),
        "{stdout}"
    );
    assert!(stdout.contains("\"row_decisions\""), "{stdout}");
    assert!(stdout.contains("\"row_key\": \"accepted\""), "{stdout}");
    assert!(stdout.contains("\"accepted\": true"), "{stdout}");
    assert!(stdout.contains("\"row_key\": \"low_support\""), "{stdout}");
    assert!(stdout.contains("\"accepted\": false"), "{stdout}");
    assert!(stdout.contains("\"failed_predicates\""), "{stdout}");
    assert!(stdout.contains("\"threshold_comparisons\""), "{stdout}");
    assert!(stdout.contains("\"aggregate_inputs\""), "{stdout}");
}

#[test]
fn xlog_genrule_002_explain_json_reports_bfo_external_candidate_rows() {
    let dir = std::env::temp_dir().join(format!("xlog_genrule_002_bfo_{}", std::process::id()));
    std::fs::create_dir_all(dir.join("xlog")).expect("create fixture dir");
    let program = dir.join("xlog/generated_hf_discovery_rules.xlog");
    std::fs::write(
        &program,
        r#"
pred hf_candidate_input(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64).
pred xlog_accepted_candidate(i64, i64, i64, i64, i64).
pred xlog_rejected_candidate(i64, u32).

xlog_accepted_candidate(Hypothesis, Rank, NeuralMilli, SymbolicMilli, GraphMilli) :-
    hf_candidate_input(Hypothesis, Rank, 1, 1, 1, 0, NeuralMilli, SymbolicMilli, GraphMilli, SupportCount, ResistanceRatioMilli, SeedContext),
    NeuralMilli >= 620,
    SymbolicMilli >= 540,
    GraphMilli >= 480,
    SupportCount >= 80,
    ResistanceRatioMilli >= 50.

xlog_rejected_candidate(Hypothesis, 4) :-
    hf_candidate_input(Hypothesis, Rank, 1, 1, 1, 0, NeuralMilli, SymbolicMilli, GraphMilli, SupportCount, ResistanceRatioMilli, SeedContext),
    SupportCount < 80.

?- xlog_accepted_candidate(Hypothesis, Rank, NeuralMilli, SymbolicMilli, GraphMilli).
?- xlog_rejected_candidate(Hypothesis, Reason).
"#,
    )
    .expect("write BFO generated-rule fixture");
    std::fs::write(
        dir.join("xlog/hf_candidate_relation.json"),
        r#"{
  "rows": [
    {
      "hypothesis_num": 36,
      "preliminary_rank": 1,
      "derived_from_huggingface": 1,
      "bfo_valid": 1,
      "novelty_valid": 1,
      "neural_contradicts": 0,
      "neural_milli": 936,
      "symbolic_milli": 833,
      "graph_milli": 734,
      "support_count": 2013,
      "resistance_ratio_milli": 820,
      "seed_context": 0
    },
    {
      "hypothesis_num": 1011,
      "preliminary_rank": 1011,
      "derived_from_huggingface": 1,
      "bfo_valid": 1,
      "novelty_valid": 1,
      "neural_contradicts": 0,
      "neural_milli": 884,
      "symbolic_milli": 670,
      "graph_milli": 590,
      "support_count": 79,
      "resistance_ratio_milli": 49,
      "seed_context": 0
    }
  ]
}
"#,
    )
    .expect("write BFO candidate relation fixture");
    let relation_path = dir.join("xlog/hf_candidate_relation.json");
    std::fs::write(
        dir.join("xlog_hypothesis_execution.json"),
        format!(
            r#"{{
  "relation_input_path": "{}",
  "relation_input_columns": [
    "hypothesis_num",
    "preliminary_rank",
    "derived_from_huggingface",
    "bfo_valid",
    "novelty_valid",
    "neural_contradicts",
    "neural_milli",
    "symbolic_milli",
    "graph_milli",
    "support_count",
    "resistance_ratio_milli",
    "seed_context"
  ]
}}
"#,
            relation_path.display()
        ),
    )
    .expect("write BFO execution manifest");

    let output = cargo_bin_cmd!("xlog")
        .args([
            "explain",
            "--format",
            "json",
            program.to_str().expect("valid path"),
        ])
        .output()
        .expect("run xlog explain json");
    assert!(
        output.status.success(),
        "xlog explain failed: {}",
        String::from_utf8_lossy(&output.stderr)
    );
    let stdout = String::from_utf8(output.stdout).expect("utf8 stdout");
    assert!(
        stdout.contains("\"generated_rule_diagnostics\""),
        "{stdout}"
    );
    assert!(
        stdout.contains("\"source_relation\": \"hf_candidate_input\""),
        "{stdout}"
    );
    assert!(stdout.contains("\"row_key\": \"36\""), "{stdout}");
    assert!(stdout.contains("\"accepted\": true"), "{stdout}");
    assert!(stdout.contains("\"row_key\": \"1011\""), "{stdout}");
    assert!(stdout.contains("\"accepted\": false"), "{stdout}");
    assert!(stdout.contains("SupportCount >= 80"), "{stdout}");
    assert!(stdout.contains("\"aggregate_inputs\""), "{stdout}");
}