fp-conformance 0.4.0

Differential conformance harness for frankenpandas against a live pandas oracle — packet fixtures + fuzz seed tests + live-oracle parity gates.
#![forbid(unsafe_code)]

use std::path::PathBuf;

use fp_conformance::{
    E2eConfig, FixtureGenerationRequest, HarnessConfig, NoopHooks, OracleMode, SuiteOptions,
    append_phase2c_drift_history, build_compat_closure_e2e_scenario_report,
    build_compat_closure_final_evidence_pack, enforce_packet_gates, generate_fixture_pilot_bundle,
    run_differential_by_id, run_e2e_suite, run_fault_injection_validation_by_id,
    run_packets_grouped, write_case_evidence_jsonl, write_compat_closure_e2e_scenario_report,
    write_compat_closure_final_evidence_pack, write_differential_validation_log,
    write_fault_injection_validation_report, write_grouped_artifacts,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let raw_args = std::env::args().collect::<Vec<_>>();
    let mut packet_filter: Option<String> = None;
    let mut oracle_mode = OracleMode::FixtureExpected;
    let mut python_bin: Option<String> = None;
    let mut write_artifacts = false;
    let mut require_green = false;
    let mut write_drift_history = false;
    let mut allow_system_pandas_fallback = false;
    let mut allow_fixture_fallback = false;
    let mut write_differential_validation = false;
    let mut write_fault_injection = false;
    let mut write_e2e_scenarios = false;
    let mut write_final_evidence_pack = false;
    let mut print_mismatches = false;
    let mut emit_evidence = false;
    let mut generate_fixture_pilot: Option<String> = None;
    let mut generated_packet_id: Option<String> = None;
    let mut generated_case_id: Option<String> = None;
    let mut generated_fixture_path: Option<PathBuf> = None;
    let mut generator_artifact_dir: Option<PathBuf> = None;
    let mut input_matrix = Vec::new();
    let mut intentional_divergence_notes = Vec::new();
    let mut repair_packets_per_block = 8_u32;

    let mut args = raw_args.iter().skip(1).cloned().peekable();
    while let Some(arg) = args.next() {
        match arg.as_str() {
            "--packet-id" => {
                let value = args
                    .next()
                    .ok_or("--packet-id requires a value (e.g. FP-P2C-001)")?;
                packet_filter = Some(value);
            }
            "--oracle" => {
                let value = args.next().ok_or("--oracle requires fixture or live")?;
                oracle_mode = match value.as_str() {
                    "fixture" => OracleMode::FixtureExpected,
                    "live" => OracleMode::LiveLegacyPandas,
                    _ => return Err(format!("unsupported oracle mode: {value}").into()),
                };
            }
            "--python-bin" => {
                let value = args.next().ok_or("--python-bin requires a value")?;
                python_bin = Some(value);
            }
            "--write-artifacts" => {
                write_artifacts = true;
            }
            "--require-green" => {
                require_green = true;
            }
            "--write-drift-history" => {
                write_drift_history = true;
            }
            "--allow-system-pandas-fallback" => {
                allow_system_pandas_fallback = true;
            }
            "--allow-fixture-fallback" => {
                allow_fixture_fallback = true;
            }
            "--write-differential-validation" => {
                write_differential_validation = true;
            }
            "--write-fault-injection" => {
                write_fault_injection = true;
            }
            "--write-e2e-scenarios" => {
                write_e2e_scenarios = true;
            }
            "--write-final-evidence-pack" => {
                write_final_evidence_pack = true;
            }
            "--print-mismatches" => {
                print_mismatches = true;
            }
            "--emit-evidence" => {
                emit_evidence = true;
            }
            "--generate-fixture-pilot" => {
                let value = args
                    .next()
                    .ok_or("--generate-fixture-pilot requires a method family")?;
                generate_fixture_pilot = Some(value);
            }
            "--generated-packet-id" => {
                let value = args
                    .next()
                    .ok_or("--generated-packet-id requires a value")?;
                generated_packet_id = Some(value);
            }
            "--generated-case-id" => {
                let value = args.next().ok_or("--generated-case-id requires a value")?;
                generated_case_id = Some(value);
            }
            "--generated-fixture-path" => {
                let value = args
                    .next()
                    .ok_or("--generated-fixture-path requires a path")?;
                generated_fixture_path = Some(PathBuf::from(value));
            }
            "--generator-artifact-dir" => {
                let value = args
                    .next()
                    .ok_or("--generator-artifact-dir requires a path")?;
                generator_artifact_dir = Some(PathBuf::from(value));
            }
            "--input-matrix" => {
                let value = args.next().ok_or("--input-matrix requires a value")?;
                input_matrix.push(value);
            }
            "--intentional-divergence-note" => {
                let value = args
                    .next()
                    .ok_or("--intentional-divergence-note requires a value")?;
                intentional_divergence_notes.push(value);
            }
            "--repair-packets-per-block" => {
                let value = args
                    .next()
                    .ok_or("--repair-packets-per-block requires an integer")?;
                repair_packets_per_block = value.parse()?;
            }
            "--help" | "-h" => {
                print_help();
                return Ok(());
            }
            other => {
                return Err(format!("unknown argument: {other}").into());
            }
        }
    }

    let mut config = HarnessConfig::default_paths();
    config.allow_system_pandas_fallback = allow_system_pandas_fallback;
    config.allow_fixture_fallback = allow_fixture_fallback;
    if let Some(python_bin) = python_bin {
        config.python_bin = python_bin;
    }

    if let Some(method_family) = generate_fixture_pilot {
        let packet_id = generated_packet_id.unwrap_or_else(|| "FP-GEN-TN6QB2-001".to_owned());
        let case_id = generated_case_id
            .unwrap_or_else(|| "series_add_generated_alignment_strict_tn6qb2".to_owned());
        let fixture_path = generated_fixture_path.unwrap_or_else(|| {
            config
                .packet_fixture_root()
                .join(format!("fp_generated_tn6qb2_{case_id}.json"))
        });
        let artifact_dir = generator_artifact_dir.unwrap_or_else(|| {
            config
                .repo_root
                .join("artifacts/conformance")
                .join(format!("fixture-generator-tn6qb2-{packet_id}"))
        });
        let request = FixtureGenerationRequest {
            method_family,
            packet_id,
            case_id,
            output_fixture_path: fixture_path,
            artifact_dir,
            generation_command: raw_args.join(" "),
            input_matrix,
            intentional_divergence_notes,
            repair_packets_per_block,
        };
        let bundle = generate_fixture_pilot_bundle(&config, &request)?;
        println!(
            "generated packet={} case={} fixture={} manifest={} repair_symbols={} sidecar={} scrub={} decode_proof={}",
            bundle.packet_id,
            bundle.case_id,
            bundle.fixture_path.display(),
            bundle.manifest_path.display(),
            bundle.repair_symbol_manifest_path.display(),
            bundle.raptorq_sidecar_path.display(),
            bundle.integrity_scrub_path.display(),
            bundle.decode_proof_path.display()
        );
        return Ok(());
    }

    let options = SuiteOptions {
        packet_filter,
        oracle_mode,
    };

    let reports = run_packets_grouped(&config, &options)?;
    for report in &reports {
        println!(
            "packet={} suite={} fixtures={} passed={} failed={} green={}",
            report.packet_id.as_deref().unwrap_or("<all>"),
            report.suite,
            report.fixture_count,
            report.passed,
            report.failed,
            report.is_green()
        );
        if print_mismatches && report.failed > 0 {
            for case in &report.results {
                if case.status != fp_conformance::CaseStatus::Fail {
                    continue;
                }
                let mismatch = case.mismatch.as_deref().unwrap_or("<no mismatch details>");
                let class = case.mismatch_class.as_deref().unwrap_or("<none>");
                println!(
                    "  mismatch case={} op={:?} class={} details={}",
                    case.case_id, case.operation, class, mismatch
                );
            }
        }
    }

    if require_green {
        enforce_packet_gates(&config, &reports)?;
    }

    if write_artifacts {
        let written = write_grouped_artifacts(&config, &reports)?;
        for artifact in written {
            println!(
                "wrote packet={} parity={} sidecar={} decode_proof={} gate={} mismatch_corpus={}",
                artifact.packet_id,
                artifact.parity_report_path.display(),
                artifact.raptorq_sidecar_path.display(),
                artifact.decode_proof_path.display(),
                artifact.gate_result_path.display(),
                artifact.mismatch_corpus_path.display()
            );
        }
    }

    if write_artifacts || write_drift_history {
        let history_path = append_phase2c_drift_history(&config, &reports)?;
        println!("wrote drift_history={}", history_path.display());
    }

    if emit_evidence {
        for path in write_case_evidence_jsonl(&config, &reports)? {
            println!("wrote case_evidence={}", path.display());
        }
    }

    if write_differential_validation {
        for report in &reports {
            let Some(packet_id) = report.packet_id.as_deref() else {
                continue;
            };
            let differential = run_differential_by_id(&config, packet_id, oracle_mode)?;
            let path = write_differential_validation_log(&config, &differential)?;
            println!(
                "wrote packet={} differential_validation_log={}",
                packet_id,
                path.display()
            );
        }
    }

    if write_fault_injection {
        for report in &reports {
            let Some(packet_id) = report.packet_id.as_deref() else {
                continue;
            };
            let validation = run_fault_injection_validation_by_id(&config, packet_id, oracle_mode)?;
            let path = write_fault_injection_validation_report(&config, &validation)?;
            println!(
                "wrote packet={} fault_injection_validation={}",
                packet_id,
                path.display()
            );
        }
    }

    if write_e2e_scenarios {
        let e2e_config = E2eConfig {
            harness: config.clone(),
            options: options.clone(),
            write_artifacts: false,
            enforce_gates: false,
            append_drift_history: false,
            forensic_log_path: None,
        };
        let mut hooks = NoopHooks;
        let e2e_report = run_e2e_suite(&e2e_config, &mut hooks)?;
        let mut fault_reports = Vec::new();
        if let Some(packet_id) = options.packet_filter.as_deref() {
            fault_reports.push(run_fault_injection_validation_by_id(
                &config,
                packet_id,
                oracle_mode,
            )?);
        }
        let scenario_report = build_compat_closure_e2e_scenario_report(&e2e_report, &fault_reports);
        let path = write_compat_closure_e2e_scenario_report(&config.repo_root, &scenario_report)?;
        println!("wrote compat_closure_e2e_scenarios={}", path.display());
    }

    if write_final_evidence_pack {
        let mut differential_reports = Vec::new();
        let mut fault_reports = Vec::new();
        for report in &reports {
            let Some(packet_id) = report.packet_id.as_deref() else {
                continue;
            };
            differential_reports.push(run_differential_by_id(&config, packet_id, oracle_mode)?);
            fault_reports.push(run_fault_injection_validation_by_id(
                &config,
                packet_id,
                oracle_mode,
            )?);
        }

        let evidence_pack = build_compat_closure_final_evidence_pack(
            &config,
            &reports,
            &differential_reports,
            &fault_reports,
        )?;
        let paths = write_compat_closure_final_evidence_pack(&config, &evidence_pack)?;
        println!(
            "wrote compat_closure_final_evidence_pack={} migration_manifest={} attestation_summary={} all_checks_passed={} signature={}",
            paths.evidence_pack_path.display(),
            paths.migration_manifest_path.display(),
            paths.attestation_summary_path.display(),
            evidence_pack.all_checks_passed,
            evidence_pack.attestation_signature
        );
    }

    Ok(())
}

fn print_help() {
    println!(
        "fp-conformance-cli\n\
         Usage:\n\
         \tfp-conformance-cli [--packet-id FP-P2C-001] [--oracle fixture|live] [--write-artifacts] [--require-green]\n\
         Options:\n\
         \t--packet-id <id>     Run only one packet id\n\
         \t--oracle <mode>      fixture (default) or live\n\
         \t--python-bin <path>  Python executable for live oracle runs (default: FP_PYTHON_BIN or python3)\n\
         \t--write-artifacts    Emit parity + gate + RaptorQ sidecars per packet\n\
         \t--write-drift-history Append packet run summary to artifacts/phase2c/drift_history.jsonl\n\
         \t--write-differential-validation Emit differential validation JSONL per packet\n\
         \t--write-fault-injection Emit deterministic fault-injection validation report per packet\n\
         \t--emit-evidence    Emit per-case machine-readable failure ledgers under artifacts/conformance/<packet>/<case>.jsonl\n\
         \t--write-e2e-scenarios Emit compat-closure E2E scenario matrix + replay bundle report\n\
         \t--write-final-evidence-pack Emit final compatibility evidence pack + migration + attestation bundle\n\
         \t--generate-fixture-pilot <family> Capture a deterministic pilot fixture with live pandas oracle output\n\
         \t--generated-packet-id <id> Packet id for --generate-fixture-pilot (default FP-GEN-TN6QB2-001)\n\
         \t--generated-case-id <id> Case id for --generate-fixture-pilot\n\
         \t--generated-fixture-path <path> Output fixture JSON path for --generate-fixture-pilot\n\
         \t--generator-artifact-dir <path> Output generator proof artifact directory\n\
         \t--input-matrix <entry> Extra input-matrix provenance entry; repeatable\n\
         \t--intentional-divergence-note <note> Divergence provenance note; repeatable\n\
         \t--repair-packets-per-block <n> RaptorQ repair packets per block for generated fixture bundle\n\
         \t--require-green      Fail with non-zero exit when any packet parity/gate check fails\n\
         \t--allow-system-pandas-fallback  Allow non-legacy pandas import when live oracle is enabled\n\
         \t-h, --help           Show this help"
    );
}