forge-pilot 0.1.0

Closed-loop orchestrator over runtime advisories, kernel oracles, and canonical Forge export/import lanes
Documentation
mod common;

use common::{
    base_loop_config, import_v3_bundle, open_forge_store, open_memory_store, point_config_at_dir,
    resources, sample_bundle, tempdir, write_patch_fixture, write_source_file,
};
use forge_pilot::{
    canonical_roundtrip, observe_scope, score_targets, ActionFamily, LoopRunner, PilotError,
    PilotHistory,
};
use knowledge_runtime::Scope;

#[tokio::test]
async fn loop_runner_executes_oracle_and_patch_families_with_real_roundtrips() {
    let oracle_dir = tempdir();
    let oracle_memory = open_memory_store(oracle_dir.path());
    let oracle_forge = open_forge_store(oracle_dir.path());
    let oracle_scope = Scope::new("pilot-loop-oracle");
    let mut oracle_config = base_loop_config(oracle_scope.clone());
    point_config_at_dir(&mut oracle_config, oracle_dir.path());
    write_source_file(
        oracle_dir.path(),
        "src/lib.rs",
        "pub fn oracle_loop_fixture() -> bool { true }\n",
    );

    import_v3_bundle(
        &oracle_memory,
        &oracle_forge,
        &oracle_scope.namespace,
        &sample_bundle("loop-oracle"),
    )
    .await;

    let oracle_resources = resources(oracle_memory, oracle_forge, &oracle_config);
    let mut oracle_runner = LoopRunner::new(oracle_config, oracle_resources);
    let oracle_report = oracle_runner.run().await.unwrap();
    assert!(oracle_report.imports_completed >= 1);
    assert_eq!(
        oracle_report.iterations[0].action_family,
        Some(ActionFamily::Oracle)
    );

    let patch_dir = tempdir();
    let patch_memory = open_memory_store(patch_dir.path());
    let patch_forge = open_forge_store(patch_dir.path());
    let patch_scope = Scope::new("pilot-loop-patch");
    let mut patch_config = base_loop_config(patch_scope.clone());
    point_config_at_dir(&mut patch_config, patch_dir.path());
    write_source_file(
        patch_dir.path(),
        "src/lib.rs",
        "pub fn patch_loop_fixture() -> bool { true }\n",
    );

    import_v3_bundle(
        &patch_memory,
        &patch_forge,
        &patch_scope.namespace,
        &sample_bundle("loop-patch"),
    )
    .await;

    let preview_resources = resources(patch_memory.clone(), patch_forge, &patch_config);
    let preview_observation = observe_scope(
        &preview_resources.runtime,
        &preview_resources.memory_store,
        &patch_config,
    )
    .await
    .unwrap();
    let preview_candidates = score_targets(
        &preview_observation,
        &PilotHistory::default(),
        &patch_config,
    );
    let seeded_target_key = preview_candidates.first().unwrap().stable_key.clone();
    let (fixture_path, patch) = write_patch_fixture(patch_dir.path());
    patch_config
        .patch_plan_seeds
        .push(forge_pilot::PatchPlanSeed {
            target_key: seeded_target_key,
            fixture_path: fixture_path.to_string_lossy().to_string(),
            patch,
            experiment_config: forge_engine::ExperimentConfig::default(),
            description: "patch fixture".into(),
        });

    let patch_forge = open_forge_store(&patch_dir.path().join("patch-loop-forge"));
    import_v3_bundle(
        &patch_memory,
        &patch_forge,
        &patch_scope.namespace,
        &sample_bundle("loop-patch-2"),
    )
    .await;
    let patch_resources = resources(patch_memory, patch_forge, &patch_config);
    let mut patch_runner = LoopRunner::new(patch_config, patch_resources);
    let patch_report = patch_runner.run().await.unwrap();
    assert!(patch_report.imports_completed >= 1);
    assert_eq!(
        patch_report.iterations[0].action_family,
        Some(ActionFamily::PairedPatch)
    );
}

#[tokio::test]
async fn canonical_roundtrip_records_durable_failure_receipt_when_import_breaks() {
    let dir = tempdir();
    let memory_store = open_memory_store(dir.path());
    let forge_store = open_forge_store(dir.path());
    let scope = Scope::new("pilot-roundtrip-failure");

    let conn = rusqlite::Connection::open(dir.path().join("memory.db")).unwrap();
    conn.execute_batch("DROP TABLE claim_versions;").unwrap();

    let err = canonical_roundtrip(
        &sample_bundle("roundtrip-failure"),
        &scope.namespace,
        &forge_store,
        &memory_store,
    )
    .await
    .unwrap_err();
    assert!(matches!(err, PilotError::Memory(_)));

    let failures = memory_store
        .query_projection_import_failures(Some(&scope.namespace), 8)
        .await
        .unwrap();
    assert_eq!(failures.len(), 1);
    assert_eq!(failures[0].scope_namespace, scope.namespace);
    assert_eq!(failures[0].source_authority, "forge");
    assert!(failures[0]
        .error_message
        .contains("no such table: claim_versions"));
}