use fuel_ir::{DType, probe::BackendId};
use serde::{Deserialize, Serialize};
use std::sync::OnceLock;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct LedgerRecord {
pub kernel_ref: String,
pub backend: String,
pub dtypes: Vec<String>,
pub kernel_revision_hash: u64,
pub claim: String,
pub result: String,
pub verified_at: String,
pub protocol_version: u32,
#[serde(default)]
pub evidence: serde_json::Value,
}
#[derive(Debug, Clone, Default)]
pub struct VerificationLedger {
records: Vec<LedgerRecord>,
}
const LEDGER_JSON: &str =
include_str!("../../../../docs/kernel-contracts/.fkc-verified-ledger.json");
impl VerificationLedger {
pub fn from_json(s: &str) -> Result<Self, serde_json::Error> {
Ok(Self {
records: serde_json::from_str(s)?,
})
}
#[allow(
dead_code,
reason = "GAP-236 (unpublished verify API): fkc::verify's modules are private, so nothing outside this crate can reach it. Does NOT retire itself -- the expiry lives in GAP-236 and in Unpopped's handback precondition guard, which fires on their side when the API is named."
)]
pub fn from_records(records: Vec<LedgerRecord>) -> Self {
Self { records }
}
#[allow(
dead_code,
reason = "GAP-236 (unpublished verify API): fkc::verify's modules are private, so nothing outside this crate can reach it. Does NOT retire itself -- the expiry lives in GAP-236 and in Unpopped's handback precondition guard, which fires on their side when the API is named."
)]
pub fn records(&self) -> &[LedgerRecord] {
&self.records
}
#[allow(
dead_code,
reason = "GAP-236 (unpublished verify API): fkc::verify's modules are private, so nothing outside this crate can reach it. Does NOT retire itself -- the expiry lives in GAP-236 and in Unpopped's handback precondition guard, which fires on their side when the API is named."
)]
pub fn upsert(&mut self, r: LedgerRecord) {
self.records.retain(|e| {
!(e.backend == r.backend
&& e.dtypes == r.dtypes
&& e.kernel_revision_hash == r.kernel_revision_hash
&& e.claim == r.claim)
});
self.records.push(r);
}
#[allow(
dead_code,
reason = "GAP-236 (unpublished verify API): fkc::verify's modules are private, so nothing outside this crate can reach it. Does NOT retire itself -- the expiry lives in GAP-236 and in Unpopped's handback precondition guard, which fires on their side when the API is named."
)]
pub fn len(&self) -> usize {
self.records.len()
}
#[allow(
dead_code,
reason = "GAP-236 (unpublished verify API): fkc::verify's modules are private, so nothing outside this crate can reach it. Does NOT retire itself -- the expiry lives in GAP-236 and in Unpopped's handback precondition guard, which fires on their side when the API is named."
)]
pub fn is_empty(&self) -> bool {
self.records.is_empty()
}
pub fn embedded() -> &'static VerificationLedger {
static L: OnceLock<VerificationLedger> = OnceLock::new();
L.get_or_init(|| VerificationLedger::from_json(LEDGER_JSON).unwrap_or_default())
}
pub fn has_pass(&self, backend: BackendId, dtypes: &[DType], rev: u64, claim: &str) -> bool {
self.records.iter().any(|r| {
r.result == "pass"
&& r.kernel_revision_hash == rev
&& r.claim == claim
&& backend_label(backend) == r.backend
&& dtypes_match(&r.dtypes, dtypes)
})
}
}
#[cfg(test)]
fn checked_in_ledger_path() -> std::path::PathBuf {
std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../docs/kernel-contracts/.fkc-verified-ledger.json")
}
#[cfg(test)]
fn merge_into_checked_in(fresh: &[LedgerRecord]) -> VerificationLedger {
let mut ledger =
VerificationLedger::from_records(VerificationLedger::embedded().records().to_vec());
for r in fresh {
ledger.upsert(r.clone());
}
ledger
}
#[cfg(test)]
pub(crate) struct LedgerWriteSummary {
pub(crate) before: usize,
pub(crate) after: usize,
pub(crate) fresh: usize,
pub(crate) path: std::path::PathBuf,
}
#[cfg(test)]
pub(crate) fn write_merged_ledger(fresh: &[LedgerRecord]) -> LedgerWriteSummary {
use std::io::Write as _;
let before = VerificationLedger::embedded().len();
let ledger = merge_into_checked_in(fresh);
let path = checked_in_ledger_path();
let json = serde_json::to_string_pretty(ledger.records()).expect("serialize ledger records");
let mut f = std::fs::File::create(&path)
.unwrap_or_else(|e| panic!("failed to open ledger at {path:?} for writing: {e}"));
f.write_all(json.as_bytes()).expect("write ledger json");
f.write_all(b"\n").expect("write trailing newline");
LedgerWriteSummary {
before,
after: ledger.len(),
fresh: fresh.len(),
path,
}
}
fn backend_label(b: BackendId) -> &'static str {
match b {
BackendId::Cpu => "Cpu",
BackendId::Cuda => "Cuda",
BackendId::Vulkan => "Vulkan",
BackendId::Metal => "Metal",
_ => "Unknown",
}
}
fn dtypes_match(rec: &[String], want: &[DType]) -> bool {
rec.len() == want.len() && rec.iter().zip(want).all(|(s, d)| *s == format!("{d:?}"))
}
use crate::fkc::ImportWarning;
use crate::fused::PrecisionGuarantee;
pub struct LedgerQuery<'a> {
pub kernel_ref: &'a str,
pub backend: BackendId,
pub dtypes: &'a [DType],
pub kernel_revision_hash: u64,
}
pub fn gate_precision(
declared: PrecisionGuarantee,
q: &LedgerQuery,
ledger: &VerificationLedger,
warnings: &mut Vec<ImportWarning>,
) -> PrecisionGuarantee {
let mut unbacked: Vec<&'static str> = Vec::new();
let check = |c: &'static str| ledger.has_pass(q.backend, q.dtypes, q.kernel_revision_hash, c);
if declared.bit_stable_on_same_hardware && !check("bit_stable_on_same_hardware") {
unbacked.push("bit_stable_on_same_hardware");
}
if declared.max_ulp.is_some() && !check("max_ulp") {
unbacked.push("max_ulp");
}
if declared.max_relative.is_some() && !check("max_relative") {
unbacked.push("max_relative");
}
if declared.max_absolute.is_some() && !check("max_absolute") {
unbacked.push("max_absolute");
}
if unbacked.is_empty() {
return declared;
}
warnings.push(ImportWarning {
section: q.kernel_ref.to_string(),
message: format!(
"precision claim(s) {unbacked:?} for kernel `{}` ({:?}, dtypes {:?}, rev {}) have no passing \
verification-ledger entry — downgraded to UNAUDITED (run the fkc_verify harness to earn them)",
q.kernel_ref, q.backend, q.dtypes, q.kernel_revision_hash
),
});
PrecisionGuarantee::UNAUDITED
}
#[cfg(test)]
mod tests {
use super::*;
use fuel_ir::{DType, probe::BackendId};
#[test]
fn ledger_from_json_roundtrips_and_has_pass_matches_on_revision_and_claim() {
let json = r#"[{
"kernel_ref": "rope_apply_f32", "backend": "Cuda", "dtypes": ["F32"],
"kernel_revision_hash": 1234567890123456789, "claim": "bit_stable_on_same_hardware",
"result": "pass", "verified_at": "2026-07-11T00:00:00Z", "protocol_version": 1,
"evidence": {"repeat_calls": 150}
}]"#;
let ledger = VerificationLedger::from_json(json).expect("parses");
assert!(ledger.has_pass(
BackendId::Cuda,
&[DType::F32],
1234567890123456789,
"bit_stable_on_same_hardware"
));
assert!(!ledger.has_pass(
BackendId::Cuda,
&[DType::F32],
1234567890123456788,
"bit_stable_on_same_hardware"
));
assert!(!ledger.has_pass(
BackendId::Cuda,
&[DType::F32],
1234567890123456789,
"max_ulp"
));
assert!(!ledger.has_pass(
BackendId::Cpu,
&[DType::F32],
1234567890123456789,
"bit_stable_on_same_hardware"
));
assert!(!ledger.has_pass(
BackendId::Cuda,
&[DType::F16],
1234567890123456789,
"bit_stable_on_same_hardware"
));
let failing = VerificationLedger::from_json(&json.replace("\"pass\"", "\"fail\"")).unwrap();
assert!(!failing.has_pass(
BackendId::Cuda,
&[DType::F32],
1234567890123456789,
"bit_stable_on_same_hardware"
));
assert!(!VerificationLedger::embedded().has_pass(
BackendId::Cuda,
&[DType::F32],
0xDEAD_BEEF_u64,
"bit_stable_on_same_hardware",
));
}
}
#[cfg(test)]
mod gate_tests {
use super::*;
use crate::fused::PrecisionGuarantee;
use fuel_ir::{DType, probe::BackendId};
fn claim() -> PrecisionGuarantee {
PrecisionGuarantee {
bit_stable_on_same_hardware: true,
max_ulp: Some(0),
max_relative: None,
max_absolute: None,
notes: "audited exact f32 add",
}
}
fn q() -> LedgerQuery<'static> {
LedgerQuery {
kernel_ref: "rope_apply_f32",
backend: BackendId::Cuda,
dtypes: &[DType::F32],
kernel_revision_hash: 42,
}
}
fn pass(c: &str) -> LedgerRecord {
LedgerRecord {
kernel_ref: "rope_apply_f32".into(),
backend: "Cuda".into(),
dtypes: vec!["F32".into()],
kernel_revision_hash: 42,
claim: c.into(),
result: "pass".into(),
verified_at: "t".into(),
protocol_version: 1,
evidence: serde_json::Value::Null,
}
}
#[test]
fn no_ledger_entry_downgrades_to_unaudited_and_warns() {
let mut w = Vec::new();
let g = gate_precision(claim(), &q(), &VerificationLedger::default(), &mut w);
assert_eq!(g.notes, PrecisionGuarantee::UNAUDITED.notes);
assert!(!g.bit_stable_on_same_hardware);
assert!(g.max_ulp.is_none());
assert_eq!(w.len(), 1);
assert!(
w[0].message.contains("rope_apply_f32")
&& w[0].message.contains("bit_stable_on_same_hardware")
&& w[0].message.contains("max_ulp")
);
}
#[test]
fn matching_pass_entries_for_every_claim_are_honored() {
let ledger = VerificationLedger::from_records(vec![
pass("bit_stable_on_same_hardware"),
pass("max_ulp"),
]);
let mut w = Vec::new();
let g = gate_precision(claim(), &q(), &ledger, &mut w);
assert!(g.bit_stable_on_same_hardware && g.max_ulp == Some(0) && w.is_empty());
}
#[test]
fn partial_backing_still_downgrades_the_whole_claim() {
let ledger = VerificationLedger::from_records(vec![pass("bit_stable_on_same_hardware")]);
let mut w = Vec::new();
let g = gate_precision(claim(), &q(), &ledger, &mut w);
assert_eq!(g.notes, PrecisionGuarantee::UNAUDITED.notes);
assert!(w[0].message.contains("max_ulp"));
assert!(
!g.bit_stable_on_same_hardware,
"whole-collapse: even the backed bit_stable claim is dropped"
);
assert!(
g.max_ulp.is_none(),
"whole-collapse: the unbacked max_ulp bound is dropped"
);
}
#[test]
fn stale_hash_downgrades_even_with_a_pass_for_the_old_hash() {
let mut old = pass("bit_stable_on_same_hardware");
old.kernel_revision_hash = 41;
let mut w = Vec::new();
let g = gate_precision(
claim(),
&q(),
&VerificationLedger::from_records(vec![old]),
&mut w,
);
assert_eq!(g.notes, PrecisionGuarantee::UNAUDITED.notes);
}
#[test]
fn no_verifiable_bound_passes_through_untouched() {
let declared = PrecisionGuarantee::none("audited; no static bound applies");
let mut w = Vec::new();
let g = gate_precision(declared, &q(), &VerificationLedger::default(), &mut w);
assert_eq!(g.notes, declared.notes);
assert!(w.is_empty());
}
#[test]
fn a_seeding_run_merges_into_the_checked_in_ledger_rather_than_replacing_it() {
let embedded = VerificationLedger::embedded();
assert!(
embedded.len() > 100,
"checked-in ledger holds only {} records — this guard cannot distinguish a merge from a truncation against a population that small. If the ledger really did shrink that far, that is the finding.",
embedded.len()
);
let witness = embedded.records()[0].clone();
let fresh = LedgerRecord {
kernel_ref: "guard-test-synthetic".to_string(),
backend: "Cpu".to_string(),
dtypes: vec!["F32".to_string()],
kernel_revision_hash: 0xDEAD_BEEF_DEAD_BEEF,
claim: "bit_stable_on_same_hardware".to_string(),
result: "pass".to_string(),
verified_at: "epoch:0".to_string(),
protocol_version: 1,
evidence: serde_json::Value::Null,
};
let merged = merge_into_checked_in(std::slice::from_ref(&fresh));
assert_eq!(
merged.len(),
embedded.len() + 1,
"a fresh record with a new key must ADD one row, leaving the other {} untouched — a seeder that rewrites the file from its own results destroys the two backends' records it cannot re-earn (GAP-210)",
embedded.len()
);
assert!(
merged.records().contains(&witness),
"record {:?}/{:?} present before the merge is missing after it",
witness.backend,
witness.kernel_ref
);
let mut again = witness.clone();
again.verified_at = "epoch:1".to_string();
let remerged = merge_into_checked_in(std::slice::from_ref(&again));
assert_eq!(
remerged.len(),
embedded.len(),
"re-verifying an existing key must replace its row, not append a second one"
);
assert!(
remerged
.records()
.iter()
.any(|r| r.verified_at == "epoch:1"),
"the replacement row did not take effect"
);
}
#[test]
fn no_seeder_writes_the_ledger_behind_this_writer() {
const WRITE_SPELLINGS: &[&str] =
&["File::create", "fs::write", "OpenOptions", "File::options"];
fn strip_line_comments(src: &str) -> String {
src.lines()
.filter(|l| !l.trim_start().starts_with("//"))
.collect::<Vec<_>>()
.join("\n")
}
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src/fkc/verify");
let mut scanned = 0usize;
let mut offenders: Vec<String> = Vec::new();
let entries =
std::fs::read_dir(&dir).unwrap_or_else(|e| panic!("cannot read {dir:?}: {e}"));
for entry in entries {
let path = entry.expect("dir entry").path();
if path.extension().and_then(|e| e.to_str()) != Some("rs") {
continue;
}
let name = path
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("")
.to_string();
let src = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("cannot read {path:?}: {e}"));
let src = strip_line_comments(&src);
scanned += 1;
if name != "ledger.rs" {
for spelling in WRITE_SPELLINGS {
if src.contains(spelling) {
offenders.push(format!("{name} ({spelling})"));
}
}
}
}
assert!(
scanned >= 8,
"only scanned {scanned} .rs files under {dir:?} — this scan is looking in the wrong place and would pass vacuously"
);
let ledger_src = strip_line_comments(
&std::fs::read_to_string(dir.join("ledger.rs")).expect("ledger.rs must be readable"),
);
assert!(
WRITE_SPELLINGS.iter().any(|s| ledger_src.contains(s)),
"the scan cannot see a file-opening call even in ledger.rs, where one certainly is — the predicate is broken, not the tree"
);
assert!(
offenders.is_empty(),
"{offenders:?} open the verification ledger directly instead of going through `write_merged_ledger`. A seeder that writes its own results over this file destroys the CUDA and Vulkan records it cannot re-earn — that is GAP-210, and it is the reason there is exactly one writer."
);
}
}