#![cfg(feature = "governance")]
#![allow(clippy::expect_used)]
mod common;
use common::{open_forge_store, open_memory_store, sample_bundle, tempdir};
use forge_pilot::canonical_roundtrip;
use knowledge_runtime::Scope;
#[tokio::test]
async fn canonical_roundtrip_emits_export_receipt() {
let dir = tempdir();
let memory_store = open_memory_store(dir.path());
let forge_store = open_forge_store(dir.path());
let scope = Scope::new("pilot-export-receipt");
let bundle = sample_bundle("export-receipt-bundle");
let roundtrip = canonical_roundtrip(&bundle, &scope.namespace, &forge_store, &memory_store)
.await
.expect("canonical_roundtrip must succeed");
assert_eq!(roundtrip.import_result.status, "complete");
let receipt = roundtrip
.export_receipt
.expect("governance feature must emit export_receipt");
assert_eq!(receipt.operation, "forge_pilot_canonical_roundtrip");
assert_eq!(receipt.status, "success");
assert_eq!(receipt.receipt_version, "ExportReceiptV1");
assert!(!receipt.export_receipt_id.is_empty());
assert!(receipt.output_ref.is_some(), "output must be bound");
assert!(
receipt.output_digest.is_some(),
"output digest must be bound"
);
assert!(
receipt.input_digests.contains_key("bundle"),
"bundle digest must be recorded"
);
}
#[tokio::test]
async fn canonical_roundtrip_receipt_id_is_stable_across_invocations() {
let dir = tempdir();
let memory_store = open_memory_store(dir.path());
let forge_store = open_forge_store(dir.path());
let scope = Scope::new("pilot-export-receipt-determinism");
let bundle = sample_bundle("export-receipt-determinism-bundle");
let r1 = canonical_roundtrip(&bundle, &scope.namespace, &forge_store, &memory_store)
.await
.unwrap();
let r2 = canonical_roundtrip(&bundle, &scope.namespace, &forge_store, &memory_store)
.await
.unwrap();
let r1_receipt = r1.export_receipt.expect("first roundtrip emits receipt");
let r2_receipt = r2.export_receipt.expect("second roundtrip emits receipt");
assert_eq!(r1_receipt.export_receipt_id, r2_receipt.export_receipt_id);
assert_eq!(r1_receipt.operation, r2_receipt.operation);
assert_eq!(r1_receipt.status, r2_receipt.status);
}
#[tokio::test]
async fn canonical_roundtrip_persists_failure_in_import_log() {
let dir = tempdir();
let memory_store = open_memory_store(dir.path());
let forge_store = open_forge_store(dir.path());
let scope = Scope::new("pilot-export-receipt-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("export-receipt-failure-bundle"),
&scope.namespace,
&forge_store,
&memory_store,
)
.await
.expect_err("import must fail when claim_versions table is missing");
assert!(
matches!(err, forge_pilot::PilotError::Memory(_)),
"expected a Memory error, got {err:?}"
);
let failures = memory_store
.query_projection_import_failures(Some(&scope.namespace), 8)
.await
.unwrap();
assert_eq!(
failures.len(),
1,
"the failure must be persisted in the import log"
);
assert!(failures[0]
.error_message
.contains("no such table: claim_versions"));
}
#[tokio::test]
async fn canonical_roundtrip_receipt_status_is_success_after_clean_import() {
let dir = tempdir();
let memory_store = open_memory_store(dir.path());
let forge_store = open_forge_store(dir.path());
let scope = Scope::new("pilot-export-receipt-success-state");
let roundtrip = canonical_roundtrip(
&sample_bundle("export-receipt-success-state-bundle"),
&scope.namespace,
&forge_store,
&memory_store,
)
.await
.expect("clean run must succeed");
let receipt = roundtrip
.export_receipt
.expect("governance feature must emit export_receipt");
assert_eq!(
receipt.status, "success",
"after a clean import, the receipt status must be `success` (not `pending`)"
);
assert!(receipt.output_ref.is_some(), "output must be bound");
}