#[derive(Debug, Clone)]
pub struct ProvabilityConfig {
pub project_path: PathBuf,
pub functions: Vec<String>,
pub analysis_depth: usize,
pub format: ProvabilityOutputFormat,
pub high_confidence_only: bool,
pub include_evidence: bool,
pub output: Option<PathBuf>,
pub top_files: usize,
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub async fn handle_analyze_provability(config: ProvabilityConfig) -> Result<()> {
use crate::services::lightweight_provability_analyzer::LightweightProvabilityAnalyzer;
use crate::cli::colors as c;
eprintln!("{}", c::dim("🔬 Analyzing function provability..."));
let analyzer = LightweightProvabilityAnalyzer::new();
let function_ids = resolve_function_targets(&config).await?;
let summaries = run_provability_analysis(&analyzer, &function_ids).await?;
let filtered_summaries = prepare_filtered_summaries(&summaries, config.high_confidence_only);
let content = format_provability_output(&function_ids, &filtered_summaries, &config)?;
write_provability_output(&content, &config.output).await?;
Ok(())
}
async fn resolve_function_targets(
config: &ProvabilityConfig,
) -> Result<Vec<crate::services::lightweight_provability_analyzer::FunctionId>> {
use crate::cli::provability_helpers::{discover_project_functions, parse_function_spec};
if config.functions.is_empty() {
discover_project_functions(&config.project_path).await
} else {
let mut ids = Vec::new();
for spec in &config.functions {
ids.push(parse_function_spec(spec, &config.project_path)?);
}
Ok(ids)
}
}
async fn run_provability_analysis(
analyzer: &crate::services::lightweight_provability_analyzer::LightweightProvabilityAnalyzer,
function_ids: &[crate::services::lightweight_provability_analyzer::FunctionId],
) -> Result<Vec<ProofSummary>> {
let summaries = analyzer.analyze_incrementally(function_ids).await;
use crate::cli::colors as c;
eprintln!("{} Analyzed {} functions", c::pass(""), c::number(&summaries.len().to_string()));
Ok(summaries)
}
fn prepare_filtered_summaries(
summaries: &[ProofSummary],
high_confidence_only: bool,
) -> Vec<ProofSummary> {
use crate::cli::provability_helpers::filter_summaries;
let filtered = filter_summaries(summaries, high_confidence_only);
filtered.into_iter().cloned().collect()
}
fn format_provability_output(
function_ids: &[crate::services::lightweight_provability_analyzer::FunctionId],
summaries: &[ProofSummary],
config: &ProvabilityConfig,
) -> Result<String> {
use crate::cli::provability_helpers::{
format_provability_detailed, format_provability_json, format_provability_sarif,
format_provability_summary,
};
match config.format {
ProvabilityOutputFormat::Json => {
format_provability_json(function_ids, summaries, config.include_evidence)
}
ProvabilityOutputFormat::Summary => {
format_provability_summary(function_ids, summaries, config.top_files)
}
ProvabilityOutputFormat::Full => {
format_provability_detailed(function_ids, summaries, config.include_evidence)
}
ProvabilityOutputFormat::Sarif => format_provability_sarif(function_ids, summaries),
ProvabilityOutputFormat::Markdown => {
format_provability_detailed(function_ids, summaries, config.include_evidence)
}
}
}
async fn write_provability_output(content: &str, output_path: &Option<PathBuf>) -> Result<()> {
if let Some(output_path) = output_path {
tokio::fs::write(output_path, content).await?;
use crate::cli::colors as c;
eprintln!(
"{} Provability analysis written to: {}",
c::pass(""), c::path(&output_path.display().to_string())
);
} else {
println!("{content}");
}
Ok(())
}