1use std::collections::HashSet;
43use std::path::Path;
44use std::sync::{Mutex, OnceLock};
45
46use fuel_graph::registry::FusedOpParams;
47use fuel_ir::Shape;
48use fuel_ir::backend::BackendCapabilities;
49use fuel_ir::probe::BackendId;
50
51use crate::fkc::error::FkcError;
52use crate::fkc::lower::{LinkRegistry, Resolved, ResolvedFused, ResolvedPrimitive, lower_file};
53use crate::fkc::parse::parse_file;
54use crate::fused::{BackendImpl, CostEstimate, FusedKernelRegistry};
55use crate::kernel::{KernelBindingTable, unknown_cost};
56
57pub(crate) fn intern(s: &str) -> &'static str {
80 static POOL: OnceLock<Mutex<HashSet<&'static str>>> = OnceLock::new();
81 let pool = POOL.get_or_init(|| Mutex::new(HashSet::new()));
82 let mut guard = pool.lock().expect("kernel_source interner poisoned");
83 if let Some(existing) = guard.get(s) {
84 return existing;
85 }
86 let leaked: &'static str = Box::leak(s.to_string().into_boxed_str());
87 guard.insert(leaked);
88 leaked
89}
90
91fn intern_dtypes(dtypes: &[fuel_ir::DType]) -> &'static [fuel_ir::DType] {
97 use fuel_ir::DType;
98 static POOL: OnceLock<Mutex<HashSet<&'static [DType]>>> = OnceLock::new();
99 let pool = POOL.get_or_init(|| Mutex::new(HashSet::new()));
100 let mut guard = pool.lock().expect("fused dtypes interner poisoned");
101 if let Some(existing) = guard.get(dtypes) {
102 return existing;
103 }
104 let leaked: &'static [DType] = Box::leak(dtypes.to_vec().into_boxed_slice());
105 guard.insert(leaked);
106 leaked
107}
108
109pub fn fused_unknown_cost(
125 _shapes: &[Shape],
126 _params: &FusedOpParams,
127 _caps: &BackendCapabilities,
128) -> CostEstimate {
129 CostEstimate::default()
130}
131
132#[derive(Debug, Clone)]
142pub struct ImportedProvider {
143 pub name: String,
145 pub backend: BackendId,
147 pub kernel_source: &'static str,
149 pub revision_base: Option<String>,
161 pub link_registry: Option<String>,
171 pub primitives: Vec<ResolvedPrimitive>,
173 pub fused: Vec<ResolvedFused>,
175 pub warnings: Vec<crate::fkc::ImportWarning>,
177}
178
179impl ImportedProvider {
180 fn from_resolved(
182 name: String,
183 backend: BackendId,
184 kernel_source: &'static str,
185 revision_base: Option<String>,
186 link_registry: Option<String>,
187 resolved: Vec<Resolved>,
188 warnings: Vec<crate::fkc::ImportWarning>,
189 ) -> Self {
190 let mut primitives = Vec::new();
191 let mut fused = Vec::new();
192 for r in resolved {
193 match r {
194 Resolved::Primitive(p) => primitives.push(p),
195 Resolved::Fused(f) => fused.push(f),
196 }
197 }
198 ImportedProvider {
199 name,
200 backend,
201 kernel_source,
202 revision_base,
203 link_registry,
204 primitives,
205 fused,
206 warnings,
207 }
208 }
209
210 pub fn register_into(
235 &self,
236 table: &mut KernelBindingTable,
237 fused: &mut FusedKernelRegistry,
238 ) -> Result<(), FkcError> {
239 for p in &self.primitives {
241 let kernel_source: &'static str = intern(&p.kernel_source);
242 let cost_fn = p.cost_fn.unwrap_or(unknown_cost);
253 let cost_expr = crate::fkc::cost_compile::stamp_primitive_cost_expr(p);
258 let is_generic = crate::fkc::is_generic_contract(&p.layouts);
264 table.register_full_with_source_generic(
269 p.op,
270 &p.dtypes,
271 p.backend,
272 p.kernel,
273 p.caps,
274 p.precision,
275 cost_fn,
276 kernel_source,
277 is_generic,
278 p.revision.0,
279 cost_expr,
283 );
284 }
285
286 for f in &self.fused {
288 let dtypes: &'static [fuel_ir::DType] = intern_dtypes(&f.dtypes);
295 fused.register(
296 f.id,
297 f.backend,
298 BackendImpl {
299 kernel: f.kernel,
300 dtypes,
301 cost: fused_unknown_cost,
302 precision: f.precision,
303 caps: f.caps,
304 revision: f.revision,
305 cost_expr: crate::fkc::cost_compile::stamp_fused_cost_expr(f),
306 },
307 );
308 if !f.bundle_slot_names.is_empty() {
314 fused.record_bundle_slot_names(f.id, f.backend, dtypes, &f.bundle_slot_names);
315 }
316 }
317
318 table
324 .finalize()
325 .map_err(|e| FkcError::DuplicateKernelRef(e.to_string()))?;
326
327 Ok(())
328 }
329}
330
331pub fn import_bundle_str(src: &str, link: &dyn LinkRegistry) -> Result<ImportedProvider, FkcError> {
341 let file = parse_file(src)?;
342 crate::fkc::validate::validate_file(&file)?;
354 let mut warnings: Vec<crate::fkc::ImportWarning> = Vec::new();
357 let mut resolved = lower_file(&file, link, &mut warnings)?;
358 let provider = &file.front_matter.provider;
359 let backend = lower_backend_str(&provider.backend)?;
360 let kernel_source = intern(&provider.kernel_source);
361
362 let ledger = crate::fkc::verify::embedded();
378 for r in &mut resolved {
379 match r {
380 Resolved::Primitive(p) => {
381 let q = crate::fkc::verify::LedgerQuery {
382 kernel_ref: p.kernel_source.as_str(),
383 backend: p.backend,
384 dtypes: p.dtypes.as_slice(),
385 kernel_revision_hash: p.revision.0,
386 };
387 p.precision =
388 crate::fkc::verify::gate_precision(p.precision, &q, ledger, &mut warnings);
389 }
390 Resolved::Fused(f) => {
391 let q = crate::fkc::verify::LedgerQuery {
392 kernel_ref: f.kernel_source.as_str(),
393 backend: f.backend,
394 dtypes: f.dtypes.as_slice(),
395 kernel_revision_hash: f.revision.0,
396 };
397 f.precision =
398 crate::fkc::verify::gate_precision(f.precision, &q, ledger, &mut warnings);
399 }
400 }
401 }
402
403 Ok(ImportedProvider::from_resolved(
404 provider.name.clone(),
405 backend,
406 kernel_source,
407 provider.revision_base.clone(),
408 provider.link_registry.clone(),
409 resolved,
410 warnings,
411 ))
412}
413
414pub fn import_bundle(
416 path: impl AsRef<Path>,
417 link: &dyn LinkRegistry,
418) -> Result<ImportedProvider, FkcError> {
419 let path = path.as_ref();
420 let src = std::fs::read_to_string(path).map_err(|e| FkcError::Io {
421 path: path.display().to_string(),
422 reason: e.to_string(),
423 })?;
424 import_bundle_str(&src, link)
425}
426
427pub fn import_glob(pattern: &str, link: &dyn LinkRegistry) -> Result<ImportedProvider, FkcError> {
444 let mut paths = glob_files(pattern)?;
445 paths.sort(); if paths.is_empty() {
448 return Err(FkcError::Io {
449 path: pattern.to_string(),
450 reason: "glob pattern matched no files".to_string(),
451 });
452 }
453
454 let mut merged: Option<ImportedProvider> = None;
455 for path in &paths {
456 let file_label = path.display().to_string();
457 let provider = import_bundle(path, link)?;
458 match merged.as_mut() {
459 None => merged = Some(provider),
460 Some(acc) => {
461 if provider.name != acc.name {
463 return Err(FkcError::ProviderMismatch {
464 field: "provider.name".to_string(),
465 expected: acc.name.clone(),
466 found: provider.name.clone(),
467 file: file_label,
468 });
469 }
470 if provider.backend != acc.backend {
471 return Err(FkcError::ProviderMismatch {
472 field: "provider.backend".to_string(),
473 expected: format!("{:?}", acc.backend),
474 found: format!("{:?}", provider.backend),
475 file: file_label,
476 });
477 }
478 if provider.kernel_source != acc.kernel_source {
481 return Err(FkcError::ProviderMismatch {
482 field: "provider.kernel_source".to_string(),
483 expected: acc.kernel_source.to_string(),
484 found: provider.kernel_source.to_string(),
485 file: file_label,
486 });
487 }
488 if provider.revision_base != acc.revision_base {
496 return Err(FkcError::ProviderMismatch {
497 field: "provider.revision_base".to_string(),
498 expected: format!("{:?}", acc.revision_base),
499 found: format!("{:?}", provider.revision_base),
500 file: file_label.clone(),
501 });
502 }
503 if provider.link_registry != acc.link_registry {
512 return Err(FkcError::ProviderMismatch {
513 field: "provider.link_registry".to_string(),
514 expected: format!("{:?}", acc.link_registry),
515 found: format!("{:?}", provider.link_registry),
516 file: file_label.clone(),
517 });
518 }
519 acc.primitives.extend(provider.primitives);
521 acc.fused.extend(provider.fused);
522 acc.warnings.extend(provider.warnings);
523 }
524 }
525 }
526
527 Ok(merged.expect("non-empty path list yields a provider"))
528}
529
530fn lower_backend_str(s: &str) -> Result<BackendId, FkcError> {
538 match s {
539 "Cpu" => Ok(BackendId::Cpu),
540 "Cuda" => Ok(BackendId::Cuda),
541 "Vulkan" => Ok(BackendId::Vulkan),
542 "Metal" => Ok(BackendId::Metal),
543 other => Err(FkcError::UnknownBackend {
544 section: "<front-matter provider>".to_string(),
545 backend: other.to_string(),
546 }),
547 }
548}
549
550fn glob_files(pattern: &str) -> Result<Vec<std::path::PathBuf>, FkcError> {
554 let p = Path::new(pattern);
556 let file_pat = p
557 .file_name()
558 .map(|n| n.to_string_lossy().to_string())
559 .ok_or_else(|| FkcError::Io {
560 path: pattern.to_string(),
561 reason: "glob pattern has no filename component".to_string(),
562 })?;
563 let dir = p.parent().filter(|d| !d.as_os_str().is_empty());
564 let dir = dir.unwrap_or_else(|| Path::new("."));
565
566 let read = std::fs::read_dir(dir).map_err(|e| FkcError::Io {
567 path: dir.display().to_string(),
568 reason: e.to_string(),
569 })?;
570
571 let mut out = Vec::new();
572 for entry in read {
573 let entry = entry.map_err(|e| FkcError::Io {
574 path: dir.display().to_string(),
575 reason: e.to_string(),
576 })?;
577 let path = entry.path();
578 if !path.is_file() {
579 continue;
580 }
581 let name = entry.file_name().to_string_lossy().to_string();
582 if matches_glob(&file_pat, &name) {
583 out.push(path);
584 }
585 }
586 Ok(out)
587}
588
589fn matches_glob(pattern: &str, name: &str) -> bool {
593 let parts: Vec<&str> = pattern.split('*').collect();
597 if parts.len() == 1 {
598 return pattern == name;
600 }
601 let mut pos = 0usize;
602 for (i, part) in parts.iter().enumerate() {
603 if part.is_empty() {
604 continue;
605 }
606 if i == 0 {
607 if !name[pos..].starts_with(part) {
609 return false;
610 }
611 pos += part.len();
612 } else if i == parts.len() - 1 {
613 let rest = &name[pos..];
616 return rest.len() >= part.len() && rest.ends_with(part);
617 } else {
618 match name[pos..].find(part) {
620 Some(idx) => pos += idx + part.len(),
621 None => return false,
622 }
623 }
624 }
625 true
626}
627
628#[cfg(test)]
629mod tests {
630 use super::*;
631 use crate::fkc::caps_map::{ResolvedLayout, Tri};
632 use crate::fkc::cost_expr::CompiledCostExpr;
633 use crate::fkc::lower::ResolvedFused;
634 use crate::fused::{KernelRevisionHash, PrecisionGuarantee};
635 use crate::kernel::{KernelCaps, KernelDTypes, KernelRef};
636 use fuel_graph::registry::FusedOps;
637 use fuel_ir::DType;
638 use fuel_ir::dispatch::OpKind;
639 use smallvec::SmallVec;
640 use std::sync::{Arc, RwLock};
641
642 const ELEMENTWISE_BINARY: &str =
643 include_str!("../../kernel-contracts/cpu/elementwise-binary.fkc.md");
644
645 #[allow(
656 dead_code,
657 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."
658 )]
659 fn all_cpu_contracts() -> Vec<(String, String)> {
660 let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("kernel-contracts/cpu");
661 let mut out = Vec::new();
662 for e in std::fs::read_dir(&dir).unwrap_or_else(|e| panic!("read {dir:?}: {e}")) {
663 let path = e.expect("dir entry").path();
664 if path.extension().and_then(|x| x.to_str()) != Some("md") {
665 continue;
666 }
667 let name = path
668 .file_name()
669 .and_then(|n| n.to_str())
670 .unwrap_or_default()
671 .to_string();
672 if let Ok(text) = std::fs::read_to_string(&path) {
673 out.push((name, text));
674 }
675 }
676 out.sort();
677 assert!(
678 out.len() >= 10,
679 "only {} CPU contracts found under {dir:?} — the search below would be over \
680 a subset, and a 'nothing is downgraded' result would then be about the \
681 wrong population",
682 out.len()
683 );
684 out
685 }
686
687 #[allow(
690 dead_code,
691 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."
692 )]
693 fn find_downgraded() -> Option<(String, Vec<String>)> {
694 for (_name, text) in all_cpu_contracts() {
695 let link = EntryPointLink::new();
696 let Ok(provider) = import_bundle_str(&text, &link) else {
697 continue;
698 };
699 for w in provider.warnings.iter() {
700 if !w.message.contains("downgraded to UNAUDITED") {
701 continue;
702 }
703 let claims = match (w.message.find('['), w.message.find(']')) {
704 (Some(a), Some(b)) if b > a => w.message[a + 1..b]
705 .split(',')
706 .map(|c| c.trim().trim_matches('"').to_string())
707 .collect(),
708 _ => continue,
709 };
710 return Some((w.message.clone(), claims));
711 }
712 }
713 None
714 }
715
716 fn dummy_a(
719 _i: &[Arc<RwLock<fuel_memory::Storage>>],
720 _o: &mut [Arc<RwLock<fuel_memory::Storage>>],
721 _l: &[fuel_ir::Layout],
722 _p: &crate::kernel::OpParams,
723 ) -> fuel_ir::Result<()> {
724 Ok(())
725 }
726 fn dummy_b(
727 _i: &[Arc<RwLock<fuel_memory::Storage>>],
728 _o: &mut [Arc<RwLock<fuel_memory::Storage>>],
729 _l: &[fuel_ir::Layout],
730 _p: &crate::kernel::OpParams,
731 ) -> fuel_ir::Result<()> {
732 Ok(())
733 }
734
735 struct DistinctLink {
742 seen: Mutex<std::collections::HashMap<String, KernelRef>>,
743 }
744 impl DistinctLink {
745 fn new() -> Self {
746 Self {
747 seen: Mutex::new(std::collections::HashMap::new()),
748 }
749 }
750 fn resolve(&self, symbol: &str) -> Option<KernelRef> {
751 let mut g = self.seen.lock().unwrap();
752 if let Some(k) = g.get(symbol) {
753 return Some(*k);
754 }
755 let k: KernelRef = if g.len().is_multiple_of(2) {
760 dummy_a
761 } else {
762 dummy_b
763 };
764 g.insert(symbol.to_string(), k);
765 Some(k)
766 }
767 }
768 impl LinkRegistry for DistinctLink {
769 fn resolve_primitive(&self, symbol: &str) -> Option<KernelRef> {
770 self.resolve(symbol)
771 }
772 fn resolve_fused(&self, symbol: &str) -> Option<KernelRef> {
773 self.resolve(symbol)
774 }
775 }
776
777 struct SameLink;
780 impl LinkRegistry for SameLink {
781 fn resolve_primitive(&self, _symbol: &str) -> Option<KernelRef> {
782 Some(dummy_a)
783 }
784 fn resolve_fused(&self, _symbol: &str) -> Option<KernelRef> {
785 Some(dummy_a)
786 }
787 }
788
789 #[test]
794 fn import_real_elementwise_binary_registers_add_f32_end_to_end() {
795 let link = DistinctLink::new();
799 let provider = import_bundle_str(ELEMENTWISE_BINARY, &link)
800 .expect("authored elementwise-binary.fkc.md imports");
801
802 assert_eq!(provider.name, "fuel-cpu-backend");
803 assert_eq!(provider.backend, BackendId::Cpu);
804 assert_eq!(provider.kernel_source, "portable-cpu");
805 assert!(
806 !provider.primitives.is_empty(),
807 "elementwise-binary yields primitives"
808 );
809 assert!(provider.fused.is_empty(), "no fused ops in this bundle");
810
811 let mut table = KernelBindingTable::new();
812 let mut fused = FusedKernelRegistry::new();
813 provider
814 .register_into(&mut table, &mut fused)
815 .expect("register_into a fresh table succeeds");
816
817 let key_dtypes = [DType::F32, DType::F32, DType::F32];
819 let looked_up = table.lookup(OpKind::AddElementwise, &key_dtypes, BackendId::Cpu);
820 assert!(
821 looked_up.is_ok(),
822 "AddElementwise/[F32,F32,F32]/Cpu must be registered: {looked_up:?}"
823 );
824
825 assert!(table.finalize().is_ok(), "finalize is Ok after import");
827 assert!(table.len() >= provider.primitives.len());
828 }
829
830 struct EntryPointLink {
842 seen: Mutex<std::collections::HashMap<String, KernelRef>>,
843 }
844 impl EntryPointLink {
845 fn new() -> Self {
846 Self {
847 seen: Mutex::new(std::collections::HashMap::new()),
848 }
849 }
850 fn resolve(&self, symbol: &str) -> Option<KernelRef> {
851 if symbol == "fuel_cpu_backend::byte_kernels::add_f32" {
852 return Some(crate::dispatch::add_elementwise_f32_cpu_wrapper as KernelRef);
854 }
855 let mut g = self.seen.lock().unwrap();
856 if let Some(k) = g.get(symbol) {
857 return Some(*k);
858 }
859 let k: KernelRef = if g.len().is_multiple_of(2) {
860 dummy_a
861 } else {
862 dummy_b
863 };
864 g.insert(symbol.to_string(), k);
865 Some(k)
866 }
867 }
868 impl LinkRegistry for EntryPointLink {
869 fn resolve_primitive(&self, symbol: &str) -> Option<KernelRef> {
870 self.resolve(symbol)
871 }
872 fn resolve_fused(&self, symbol: &str) -> Option<KernelRef> {
873 self.resolve(symbol)
874 }
875 }
876
877 #[test]
878 fn import_add_f32_through_real_link_registry_binds_the_real_kernel() {
879 let link = EntryPointLink::new();
885 let provider = import_bundle_str(ELEMENTWISE_BINARY, &link)
886 .expect("authored elementwise-binary.fkc.md imports through the real link");
887
888 let mut table = KernelBindingTable::new();
889 let mut fused = FusedKernelRegistry::new();
890 provider
891 .register_into(&mut table, &mut fused)
892 .expect("register_into a fresh table succeeds");
893
894 let key = [DType::F32, DType::F32, DType::F32];
895 let expected: KernelRef = crate::dispatch::add_elementwise_f32_cpu_wrapper;
900 let alts = table.lookup_alternatives(OpKind::AddElementwise, &key, BackendId::Cpu);
901 assert!(
902 !alts.is_empty(),
903 "AddElementwise/[F32,F32,F32]/Cpu present after FKC import"
904 );
905
906 let resolved: KernelRef = alts
909 .iter()
910 .map(|e| e.kernel)
911 .find(|k| *k as usize == expected as usize)
912 .expect("FKC import must bind the real add_f32 wrapper among the alternatives");
913
914 let a = Arc::new(RwLock::new(fuel_memory::from_slice_cpu(&[
916 1.0f32, 2.0, 3.0,
917 ])));
918 let b = Arc::new(RwLock::new(fuel_memory::from_slice_cpu(&[
919 4.0f32, 5.0, 6.0,
920 ])));
921 let out = Arc::new(RwLock::new(
922 fuel_memory::alloc_cpu_zeroed(DType::F32, 3).expect("alloc out"),
923 ));
924 let inputs = [a, b];
925 let mut outputs = [out];
926 let shape = fuel_ir::Shape::from_dims(&[3]);
927 let layouts = [
928 fuel_ir::Layout::contiguous(shape.clone()),
929 fuel_ir::Layout::contiguous(shape),
930 ];
931 resolved(
932 &inputs,
933 &mut outputs,
934 &layouts,
935 &crate::kernel::OpParams::None,
936 )
937 .expect("the FKC-resolved add_f32 kernel executes on real storage");
938 }
939
940 #[test]
961 fn the_import_gate_downgrades_an_entry_whose_claims_are_not_all_backed() {
962 use crate::fkc::verify::{LedgerQuery, VerificationLedger, gate_precision};
963 use crate::fused::PrecisionGuarantee;
964
965 let declared = PrecisionGuarantee {
966 bit_stable_on_same_hardware: true,
967 max_ulp: Some(0),
968 ..PrecisionGuarantee::UNAUDITED
969 };
970 let dtypes = [DType::F32, DType::F32, DType::F32];
971 let q = LedgerQuery {
972 kernel_ref: "constructed",
973 backend: fuel_ir::probe::BackendId::Cpu,
974 dtypes: &dtypes,
975 kernel_revision_hash: 0xDEAD_BEEF,
976 };
977 let mut warnings = Vec::new();
978 let gated = gate_precision(declared, &q, &VerificationLedger::default(), &mut warnings);
979
980 assert!(
981 !gated.bit_stable_on_same_hardware && gated.max_ulp.is_none(),
982 "an entry whose claims are backed by NOTHING must be downgraded whole"
983 );
984 assert_eq!(
985 gated.notes,
986 PrecisionGuarantee::UNAUDITED.notes,
987 "the downgrade must land on the UNAUDITED sentinel, not a partial edit"
988 );
989 assert!(
990 warnings
991 .iter()
992 .any(|w| w.message.contains("bit_stable_on_same_hardware")
993 && w.message.contains("max_ulp")),
994 "the warning must NAME both unbacked claims, or a census keyed on those \
995 names reads a subset: {warnings:?}"
996 );
997 }
998
999 #[test]
1012 fn a_backed_claim_does_not_rescue_an_entry_whose_sibling_claim_is_unbacked() {
1013 use crate::fkc::verify::{LedgerQuery, LedgerRecord, VerificationLedger, gate_precision};
1017 use crate::fused::PrecisionGuarantee;
1018
1019 let dtypes = [DType::F32, DType::F32, DType::F32];
1020 let rev = 0xDEAD_BEEF_u64;
1021 let ledger = VerificationLedger::from_records(vec![LedgerRecord {
1023 kernel_ref: "constructed".to_string(),
1024 backend: "Cpu".to_string(),
1025 dtypes: dtypes.iter().map(|d| format!("{d:?}")).collect(),
1026 kernel_revision_hash: rev,
1027 claim: "bit_stable_on_same_hardware".to_string(),
1028 result: "pass".to_string(),
1029 verified_at: "epoch:0".to_string(),
1030 protocol_version: 1,
1031 evidence: serde_json::Value::Null,
1032 }]);
1033
1034 let q = LedgerQuery {
1035 kernel_ref: "constructed",
1036 backend: fuel_ir::probe::BackendId::Cpu,
1037 dtypes: &dtypes,
1038 kernel_revision_hash: rev,
1039 };
1040
1041 assert!(
1044 ledger.has_pass(q.backend, q.dtypes, rev, "bit_stable_on_same_hardware"),
1045 "precondition: the constructed ledger must back bit-stability"
1046 );
1047
1048 let declared = PrecisionGuarantee {
1049 bit_stable_on_same_hardware: true,
1050 max_ulp: Some(0),
1051 ..PrecisionGuarantee::UNAUDITED
1052 };
1053 let mut warnings = Vec::new();
1054 let gated = gate_precision(declared, &q, &ledger, &mut warnings);
1055
1056 assert!(
1057 !gated.bit_stable_on_same_hardware,
1058 "ONE backed claim must not rescue an entry whose sibling is unbacked — the \
1059 whole guarantee collapses"
1060 );
1061 let named: Vec<&str> = warnings.iter().map(|w| w.message.as_str()).collect();
1062 assert!(
1063 named.iter().any(|m| m.contains("max_ulp")),
1064 "the warning must cite the UNBACKED sibling: {named:?}"
1065 );
1066 assert!(
1067 !named
1068 .iter()
1069 .any(|m| m.contains("[\"bit_stable_on_same_hardware\"")),
1070 "the BACKED claim must not be reported unbacked — that would mean the gate \
1071 does not discriminate per claim: {named:?}"
1072 );
1073 }
1074
1075 #[test]
1076 fn cpu_link_registry_binds_elementwise_binary_to_live_kernels() {
1077 let provider = import_bundle_str(ELEMENTWISE_BINARY, &crate::fkc::CpuLinkRegistry)
1083 .expect("elementwise-binary imports through the production CpuLinkRegistry");
1084 let mut table = KernelBindingTable::new();
1085 let mut fused = FusedKernelRegistry::new();
1086 provider
1087 .register_into(&mut table, &mut fused)
1088 .expect("register_into a fresh table succeeds");
1089
1090 let ops = [
1092 OpKind::AddElementwise,
1093 OpKind::SubElementwise,
1094 OpKind::MulElementwise,
1095 OpKind::DivElementwise,
1096 OpKind::MaximumElementwise,
1097 OpKind::MinimumElementwise,
1098 OpKind::PowElementwise,
1099 OpKind::RemElementwise,
1100 ];
1101 let dts = [DType::F32, DType::F64, DType::F16, DType::BF16];
1102 for op in ops {
1103 for dt in dts {
1104 assert!(
1105 table.lookup(op, &[dt, dt, dt], BackendId::Cpu).is_ok(),
1106 "{op:?}/{dt:?} must be bound from the imported contract",
1107 );
1108 }
1109 }
1110
1111 let add_f32 = table
1114 .lookup(OpKind::AddElementwise, &[DType::F32; 3], BackendId::Cpu)
1115 .unwrap();
1116 assert_eq!(
1117 add_f32 as usize,
1118 crate::dispatch::add_elementwise_f32_cpu_wrapper as *const () as usize,
1119 );
1120 let pow_bf16 = table
1121 .lookup(OpKind::PowElementwise, &[DType::BF16; 3], BackendId::Cpu)
1122 .unwrap();
1123 assert_eq!(
1124 pow_bf16 as usize,
1125 crate::dispatch::pow_elementwise_bf16_cpu_wrapper as *const () as usize,
1126 );
1127
1128 assert!(
1129 table.finalize().is_ok(),
1130 "finalize is Ok after a real-link import"
1131 );
1132 }
1133
1134 const FUSED_NORM_SOFTMAX: &str =
1143 include_str!("../../kernel-contracts/fused/norm-softmax.fkc.md");
1144
1145 #[test]
1146 fn cpu_link_registry_binds_norm_softmax_fused_ops_to_live_kernels() {
1147 let provider = import_bundle_str(FUSED_NORM_SOFTMAX, &crate::fkc::CpuLinkRegistry).expect(
1158 "authored norm-softmax fused bundle imports through the production CpuLinkRegistry",
1159 );
1160 assert!(
1163 provider.primitives.is_empty(),
1164 "norm-softmax declares only fused ops",
1165 );
1166 assert_eq!(
1167 provider.fused.len(),
1168 32,
1169 "8 fused sections × 4 dtypes = 32 per-dtype impls (fused dtype-fan)",
1170 );
1171
1172 let mut table = KernelBindingTable::new();
1173 let mut fused = FusedKernelRegistry::new();
1174 provider
1175 .register_into(&mut table, &mut fused)
1176 .expect("register_into fresh registries succeeds");
1177
1178 let dts = [DType::F32, DType::F64, DType::BF16, DType::F16];
1179
1180 let forward = [
1184 (
1185 FusedOps::SOFTMAX_LAST_DIM,
1186 [
1187 crate::dispatch::softmax_last_dim_f32_cpu_wrapper as *const () as usize,
1188 crate::dispatch::softmax_last_dim_f64_cpu_wrapper as *const () as usize,
1189 crate::dispatch::softmax_last_dim_bf16_cpu_wrapper as *const () as usize,
1190 crate::dispatch::softmax_last_dim_f16_cpu_wrapper as *const () as usize,
1191 ],
1192 ),
1193 (
1194 FusedOps::RMS_NORM_LAST_DIM,
1195 [
1196 crate::dispatch::rms_norm_last_dim_f32_cpu_wrapper as *const () as usize,
1197 crate::dispatch::rms_norm_last_dim_f64_cpu_wrapper as *const () as usize,
1198 crate::dispatch::rms_norm_last_dim_bf16_cpu_wrapper as *const () as usize,
1199 crate::dispatch::rms_norm_last_dim_f16_cpu_wrapper as *const () as usize,
1200 ],
1201 ),
1202 (
1203 FusedOps::LAYER_NORM_LAST_DIM,
1204 [
1205 crate::dispatch::layer_norm_last_dim_f32_cpu_wrapper as *const () as usize,
1206 crate::dispatch::layer_norm_last_dim_f64_cpu_wrapper as *const () as usize,
1207 crate::dispatch::layer_norm_last_dim_bf16_cpu_wrapper as *const () as usize,
1208 crate::dispatch::layer_norm_last_dim_f16_cpu_wrapper as *const () as usize,
1209 ],
1210 ),
1211 ];
1212 for (id, wrappers) in forward {
1213 for (dt, expected) in dts.iter().zip(wrappers) {
1214 let got = fused
1215 .lookup_by_dtypes(id, BackendId::Cpu, &[*dt, *dt])
1216 .unwrap_or_else(|| panic!("{id:?} {dt:?} fused impl bound from the contract"));
1217 assert_eq!(
1218 got.kernel as usize, expected,
1219 "{id:?} {dt:?} binds its exact per-dtype production wrapper",
1220 );
1221 assert_ne!(
1222 got.revision,
1223 KernelRevisionHash::UNTRACKED,
1224 "FKC import stamps the contract's real revision (hand-written stamps UNTRACKED)",
1225 );
1226 }
1227 }
1228
1229 let backward = [
1232 (
1233 FusedOps::SOFTMAX_LAST_DIM_BACKWARD,
1234 [
1235 crate::dispatch::softmax_last_dim_backward_f32_cpu_wrapper as *const ()
1236 as usize,
1237 crate::dispatch::softmax_last_dim_backward_f64_cpu_wrapper as *const ()
1238 as usize,
1239 crate::dispatch::softmax_last_dim_backward_bf16_cpu_wrapper as *const ()
1240 as usize,
1241 crate::dispatch::softmax_last_dim_backward_f16_cpu_wrapper as *const ()
1242 as usize,
1243 ],
1244 ),
1245 (
1246 FusedOps::LAYER_NORM_LAST_DIM_BACKWARD,
1247 [
1248 crate::dispatch::layer_norm_last_dim_backward_f32_cpu_wrapper as *const ()
1249 as usize,
1250 crate::dispatch::layer_norm_last_dim_backward_f64_cpu_wrapper as *const ()
1251 as usize,
1252 crate::dispatch::layer_norm_last_dim_backward_bf16_cpu_wrapper as *const ()
1253 as usize,
1254 crate::dispatch::layer_norm_last_dim_backward_f16_cpu_wrapper as *const ()
1255 as usize,
1256 ],
1257 ),
1258 (
1259 FusedOps::RMS_NORM_LAST_DIM_BACKWARD,
1260 [
1261 crate::dispatch::rms_norm_last_dim_backward_f32_cpu_wrapper as *const ()
1262 as usize,
1263 crate::dispatch::rms_norm_last_dim_backward_f64_cpu_wrapper as *const ()
1264 as usize,
1265 crate::dispatch::rms_norm_last_dim_backward_bf16_cpu_wrapper as *const ()
1266 as usize,
1267 crate::dispatch::rms_norm_last_dim_backward_f16_cpu_wrapper as *const ()
1268 as usize,
1269 ],
1270 ),
1271 (
1272 FusedOps::REDUCE_MAX_TO_BACKWARD,
1273 [
1274 crate::dispatch::reduce_max_to_backward_f32_cpu_wrapper as *const () as usize,
1275 crate::dispatch::reduce_max_to_backward_f64_cpu_wrapper as *const () as usize,
1276 crate::dispatch::reduce_max_to_backward_bf16_cpu_wrapper as *const () as usize,
1277 crate::dispatch::reduce_max_to_backward_f16_cpu_wrapper as *const () as usize,
1278 ],
1279 ),
1280 (
1281 FusedOps::POWI_BACKWARD,
1282 [
1283 crate::dispatch::powi_backward_f32_cpu_wrapper as *const () as usize,
1284 crate::dispatch::powi_backward_f64_cpu_wrapper as *const () as usize,
1285 crate::dispatch::powi_backward_bf16_cpu_wrapper as *const () as usize,
1286 crate::dispatch::powi_backward_f16_cpu_wrapper as *const () as usize,
1287 ],
1288 ),
1289 ];
1290 for (id, wrappers) in backward {
1291 for (dt, expected) in dts.iter().zip(wrappers) {
1292 let got = fused
1293 .lookup_by_dtypes(id, BackendId::Cpu, &[*dt, *dt, *dt])
1294 .unwrap_or_else(|| panic!("{id:?} {dt:?} fused impl bound from the contract"));
1295 assert_eq!(
1296 got.kernel as usize, expected,
1297 "{id:?} {dt:?} binds its exact per-dtype production wrapper",
1298 );
1299 }
1300 }
1301 }
1302
1303 #[test]
1310 fn fused_contract_shape_rule_disagreeing_with_registered_fn_is_rejected() {
1311 let mutated =
1315 FUSED_NORM_SOFTMAX.replacen("dtype_rule: passthrough(x)", "dtype_rule: fixed(F16)", 1);
1316 let err = import_bundle_str(&mutated, &crate::fkc::CpuLinkRegistry).expect_err(
1317 "a return rule that disagrees with the registered fused fn must be rejected",
1318 );
1319 assert!(
1320 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1321 "expected ShapeRuleMismatch, got {err:?}"
1322 );
1323 }
1324
1325 #[test]
1326 fn unmutated_fused_corpus_still_imports_after_return_check() {
1327 import_bundle_str(FUSED_NORM_SOFTMAX, &crate::fkc::CpuLinkRegistry)
1328 .expect("real corpus return rules agree with the registered fused fns");
1329 }
1330
1331 const SYNTH_FLASH_ATTN_3IN: &str = r#"---
1355fkc_version: 1
1356provider:
1357 name: synth-attn-3input
1358 backend: Cpu
1359 kernel_source: "portable-cpu"
1360---
1361
1362# synthetic 3-input FLASH_ATTN (Finding 1 arity pre-check)
1363
1364## flash_attn_3in
1365
1366Synthetic 3-input flash attention (q, k, v) to exercise the arity pre-check.
1367
1368```fkc
1369kernel: flash_attn_3in
1370fused_op: FLASH_ATTN
1371blurb: "synthetic 3-input flash attn (q,k,v) to exercise the arity pre-check"
1372backend: Cpu
1373kernel_source: "portable-cpu"
1374entry_point: "synthetic::flash_attn_3in_cpu"
1375kernel_revision_hash: auto
1376
1377accept:
1378 inputs:
1379 - name: q
1380 dtypes: [F32]
1381 layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
1382 rank: 4
1383 - name: k
1384 dtypes: [F32]
1385 layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
1386 rank: 4
1387 - name: v
1388 dtypes: [F32]
1389 layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
1390 rank: 4
1391 op_params:
1392 variant: FlashAttn
1393 fields:
1394 softmax_scale: { kind: f32 }
1395 causal: { kind: bool }
1396 window_size_left: { kind: "Option<usize>" }
1397 window_size_right: { kind: "Option<usize>" }
1398 softcap: { kind: "Option<f32>" }
1399 k_len: { kind: DynScalar }
1400
1401return:
1402 outputs:
1403 - name: out
1404 dtype_rule: passthrough(q)
1405 shape_rule: same_as(q)
1406 layout_guarantee: contiguous
1407 aliasing: none
1408
1409caps:
1410 awkward_layout_strategy: requires_contiguous
1411 in_place: false
1412
1413cost:
1414 provenance: judge_measured
1415 class: attention
1416
1417precision:
1418 bit_stable_on_same_hardware: false
1419 max_ulp: ~
1420 max_relative: ~
1421 max_absolute: ~
1422 audited: false
1423 notes: "synthetic"
1424
1425determinism: same_hardware_bitwise
1426```
1427"#;
1428
1429 const FUSED_ATTENTION: &str = include_str!("../../kernel-contracts/fused/attention.fkc.md");
1431 const FUSED_LINEAR_QUANT: &str =
1432 include_str!("../../kernel-contracts/fused/linear-quant.fkc.md");
1433 const FUSED_CONV_ROPE: &str = include_str!("../../kernel-contracts/fused/conv-rope.fkc.md");
1434
1435 fn mutate_once(src: &str, from: &str, to: &str) -> String {
1444 let spans = find_ws_tolerant(src, from);
1445 assert_eq!(
1446 spans.len(),
1447 1,
1448 "mutation anchor `{from}` must occur EXACTLY once (got {}). \
1449 NOTE (GAP-175): anchors are matched WHITESPACE-TOLERANTLY — a run \
1450 of spaces matches one-or-more — so a count of 0 is NOT a column \
1451 alignment problem in the .fkc.md. Look for a changed token, a \
1452 reworded comment, or a removed contract section instead.",
1453 spans.len()
1454 );
1455 let (start, end) = spans[0];
1456 format!("{}{}{}", &src[..start], to, &src[end..])
1457 }
1458
1459 fn find_ws_tolerant(hay: &str, needle: &str) -> Vec<(usize, usize)> {
1476 let h: Vec<(usize, char)> = hay.char_indices().collect();
1477 let n: Vec<char> = needle.chars().collect();
1478 let mut out = Vec::new();
1479 if n.is_empty() {
1480 return out;
1481 }
1482 let mut i = 0usize;
1483 while i < h.len() {
1484 let mut hi = i;
1485 let mut ni = 0usize;
1486 let matched = loop {
1487 if ni == n.len() {
1488 break true;
1489 }
1490 if n[ni] == ' ' {
1491 let mut seen = 0usize;
1493 while hi < h.len() && h[hi].1 == ' ' {
1494 hi += 1;
1495 seen += 1;
1496 }
1497 if seen == 0 {
1498 break false;
1499 }
1500 while ni < n.len() && n[ni] == ' ' {
1501 ni += 1;
1502 }
1503 } else {
1504 if hi >= h.len() || h[hi].1 != n[ni] {
1505 break false;
1506 }
1507 hi += 1;
1508 ni += 1;
1509 }
1510 };
1511 if matched {
1512 let start = h[i].0;
1513 let end = if hi < h.len() { h[hi].0 } else { hay.len() };
1514 out.push((start, end));
1515 i = hi.max(i + 1); } else {
1517 i += 1;
1518 }
1519 }
1520 out
1521 }
1522
1523 #[test]
1528 fn mutation_anchor_survives_a_contract_reflow() {
1529 let aligned = " - { name: dq, dtype_rule: passthrough(q), \
1530 shape_rule: same_as(q) # FusedOp.shape_rule_q\n";
1531 let reflowed = " - { name: dq, dtype_rule: passthrough(q), \
1534 shape_rule: same_as(q) # FusedOp.shape_rule_q\n";
1535 let anchor = "shape_rule: same_as(q) # FusedOp.shape_rule_q";
1536
1537 assert_eq!(
1540 aligned.matches(anchor).count(),
1541 1,
1542 "exact match works on the aligned text"
1543 );
1544 assert_eq!(
1545 reflowed.matches(anchor).count(),
1546 0,
1547 "exact match FAILS after a reflow — this is the defect GAP-175 names"
1548 );
1549
1550 assert_eq!(find_ws_tolerant(aligned, anchor).len(), 1);
1552 assert_eq!(
1553 find_ws_tolerant(reflowed, anchor).len(),
1554 1,
1555 "GAP-175: a column reflow must NOT break the anchor"
1556 );
1557 let out = mutate_once(
1558 reflowed,
1559 anchor,
1560 "shape_rule: const(9) # FusedOp.shape_rule_q",
1561 );
1562 assert!(
1563 out.contains("const(9)"),
1564 "the mutation applies to the reflowed text"
1565 );
1566 assert!(!out.contains("same_as(q)"), "and the original rule is gone");
1567 }
1568
1569 #[test]
1573 #[should_panic(expected = "must occur EXACTLY once")]
1574 fn mutate_once_still_rejects_a_zero_count() {
1575 mutate_once("shape_rule: same_as(q)\n", "shape_rule: same_as(NOPE)", "x");
1576 }
1577
1578 #[test]
1581 #[should_panic(expected = "must occur EXACTLY once")]
1582 fn mutate_once_still_rejects_a_multiple_count() {
1583 mutate_once("a b\nand again a b\n", "a b", "x");
1584 }
1585
1586 struct StubResolveAll;
1596 fn stub_kernel(
1597 _inputs: &[std::sync::Arc<std::sync::RwLock<fuel_memory::Storage>>],
1598 _outputs: &mut [std::sync::Arc<std::sync::RwLock<fuel_memory::Storage>>],
1599 _layouts: &[fuel_ir::Layout],
1600 _params: &crate::kernel::OpParams,
1601 ) -> fuel_ir::Result<()> {
1602 Ok(())
1603 }
1604 impl crate::fkc::lower::LinkRegistry for StubResolveAll {
1605 fn resolve_primitive(&self, _symbol: &str) -> Option<crate::kernel::KernelRef> {
1606 Some(stub_kernel)
1607 }
1608 fn resolve_fused(&self, _symbol: &str) -> Option<crate::kernel::KernelRef> {
1609 Some(stub_kernel)
1610 }
1611 }
1612
1613 #[test]
1616 fn inplace_affine_cross_check_fires() {
1617 let mutated = mutate_once(
1621 FUSED_LINEAR_QUANT,
1622 "shape_rule: same_as(x)",
1623 "shape_rule: const(9)",
1624 );
1625 let err = import_bundle_str(&mutated, &crate::fkc::CpuLinkRegistry).expect_err(
1626 "a mutated InplaceAffine shape_rule must be rejected (proves the check FIRES)",
1627 );
1628 assert!(
1629 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1630 "expected ShapeRuleMismatch, got {err:?}"
1631 );
1632 }
1633
1634 #[test]
1635 fn fused_linear_matmul_cross_check_fires() {
1636 let mutated = mutate_once(
1642 FUSED_LINEAR_QUANT,
1643 "shape_rule: matmul(a, b)",
1644 "shape_rule: same_as(bias)",
1645 );
1646 let err = import_bundle_str(&mutated, &crate::fkc::CpuLinkRegistry).expect_err(
1647 "a mutated fused_linear shape_rule must be rejected (proves the matmul check FIRES)",
1648 );
1649 assert!(
1650 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1651 "expected ShapeRuleMismatch, got {err:?}"
1652 );
1653 }
1654
1655 #[test]
1656 fn flash_attn_cross_check_fires() {
1657 let anchor = "same_as(q) # FusedOp.shape_rule = q shape";
1662 let mutated = mutate_once(
1663 FUSED_ATTENTION,
1664 anchor,
1665 "const(9) # FusedOp.shape_rule = q shape",
1666 );
1667 let err = import_bundle_str(&mutated, &StubResolveAll)
1668 .expect_err("a mutated FlashAttn shape_rule must be rejected (proves the check FIRES)");
1669 assert!(
1670 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1671 "expected ShapeRuleMismatch, got {err:?}"
1672 );
1673 }
1674
1675 #[test]
1676 fn paged_attn_cross_check_fires() {
1677 let anchor = "same_as(q) # FusedOp.shape_rule = q (decode)";
1681 let mutated = mutate_once(
1682 FUSED_ATTENTION,
1683 anchor,
1684 "const(9) # FusedOp.shape_rule = q (decode)",
1685 );
1686 let err = import_bundle_str(&mutated, &StubResolveAll)
1687 .expect_err("a mutated PagedAttn shape_rule must be rejected (proves the check FIRES)");
1688 assert!(
1689 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1690 "expected ShapeRuleMismatch, got {err:?}"
1691 );
1692 }
1693
1694 #[test]
1695 fn flash_attn_backward_q_cross_check_fires() {
1696 let mutated = mutate_once(
1700 FUSED_ATTENTION,
1701 "shape_rule: same_as(q) # FusedOp.shape_rule_q",
1702 "shape_rule: const(9) # FusedOp.shape_rule_q",
1703 );
1704 let err = import_bundle_str(&mutated, &StubResolveAll)
1705 .expect_err("a mutated FlashAttnBackwardQ shape_rule must be rejected");
1706 assert!(
1707 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1708 "expected ShapeRuleMismatch, got {err:?}"
1709 );
1710 }
1711
1712 #[test]
1713 fn flash_attn_backward_k_cross_check_fires() {
1714 let mutated = mutate_once(
1716 FUSED_ATTENTION,
1717 "shape_rule: same_as(k)",
1718 "shape_rule: const(9)",
1719 );
1720 let err = import_bundle_str(&mutated, &StubResolveAll)
1721 .expect_err("a mutated FlashAttnBackwardK shape_rule must be rejected");
1722 assert!(
1723 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1724 "expected ShapeRuleMismatch, got {err:?}"
1725 );
1726 }
1727
1728 #[test]
1729 fn flash_attn_backward_v_cross_check_fires() {
1730 let mutated = mutate_once(
1732 FUSED_ATTENTION,
1733 "shape_rule: same_as(v)",
1734 "shape_rule: const(9)",
1735 );
1736 let err = import_bundle_str(&mutated, &StubResolveAll)
1737 .expect_err("a mutated FlashAttnBackwardV shape_rule must be rejected");
1738 assert!(
1739 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1740 "expected ShapeRuleMismatch, got {err:?}"
1741 );
1742 }
1743
1744 #[test]
1745 fn selective_scan_bundle_cross_check_fires() {
1746 let ys = "- { name: y, dtype_rule: passthrough(u), shape_rule: same_as(u), layout_guarantee: contiguous }";
1749 let mutated = mutate_once(
1750 FUSED_CONV_ROPE,
1751 ys,
1752 &format!(
1753 "{ys}\n - {{ name: phantom, dtype_rule: passthrough(u), shape_rule: same_as(u), layout_guarantee: contiguous }}"
1754 ),
1755 );
1756 let err = import_bundle_str(&mutated, &crate::fkc::CpuLinkRegistry)
1757 .expect_err("a SelectiveScan bundle with a phantom slot must be rejected");
1758 assert!(
1759 matches!(err, FkcError::BundleArityMismatch { .. }),
1760 "expected BundleArityMismatch, got {err:?}"
1761 );
1762 }
1763
1764 #[test]
1765 fn ssd_chunk_scan_bundle_cross_check_fires() {
1766 let ys = "- { name: y, dtype_rule: passthrough(x), shape_rule: same_as(x), layout_guarantee: contiguous }";
1768 let mutated = mutate_once(
1769 FUSED_CONV_ROPE,
1770 ys,
1771 &format!(
1772 "{ys}\n - {{ name: phantom, dtype_rule: passthrough(x), shape_rule: same_as(x), layout_guarantee: contiguous }}"
1773 ),
1774 );
1775 let err = import_bundle_str(&mutated, &crate::fkc::CpuLinkRegistry)
1776 .expect_err("an SsdChunkScan bundle with a phantom slot must be rejected");
1777 assert!(
1778 matches!(err, FkcError::BundleArityMismatch { .. }),
1779 "expected BundleArityMismatch, got {err:?}"
1780 );
1781 }
1782
1783 #[test]
1784 fn unmutated_c3_bundles_still_import_after_activation() {
1785 import_bundle_str(FUSED_LINEAR_QUANT, &crate::fkc::CpuLinkRegistry)
1788 .expect("linear-quant bundle return rules agree with the registered fused fns");
1789 import_bundle_str(FUSED_CONV_ROPE, &crate::fkc::CpuLinkRegistry)
1790 .expect("conv-rope bundle return rules agree with the registered fused fns");
1791 import_bundle_str(FUSED_ATTENTION, &StubResolveAll)
1794 .expect("attention bundle return rules agree with the registered fused fns");
1795 }
1796
1797 #[test]
1803 fn under_arity_flash_attn_skips_differential_consistently_and_warns() {
1804 let provider = import_bundle_str(SYNTH_FLASH_ATTN_3IN, &StubResolveAll)
1811 .expect("a 3-input FLASH_ATTN contract imports (no panic, no debug-only silent skip)");
1812 assert!(
1813 provider
1814 .warnings
1815 .iter()
1816 .any(|w| w.message.contains("requires >= 4") && w.message.contains("skipped")),
1817 "the under-arity attention differential must be skipped WITH a warning \
1818 (consistent debug/release): {:?}",
1819 provider.warnings,
1820 );
1821 }
1822
1823 #[test]
1829 fn flash_attn_backward_k_operand_role_swap_is_rejected() {
1830 let mutated = mutate_once(
1838 FUSED_ATTENTION,
1839 "shape_rule: same_as(k)",
1840 "shape_rule: same_as(q)",
1841 );
1842 let err = import_bundle_str(&mutated, &StubResolveAll).expect_err(
1843 "dK same_as(k) mis-declared as same_as(q) must be rejected (operand-role drift)",
1844 );
1845 assert!(
1846 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1847 "expected ShapeRuleMismatch, got {err:?}"
1848 );
1849 }
1850
1851 #[test]
1857 fn selective_scan_bundle_slot_content_drift_is_rejected() {
1858 let mutated = mutate_once(
1866 FUSED_CONV_ROPE,
1867 "shape_rule: same_as(u)",
1868 "shape_rule: same_as(b)",
1869 );
1870 let err = import_bundle_str(&mutated, &crate::fkc::CpuLinkRegistry).expect_err(
1871 "a same-rank bundle slot content drift (same_as(u) -> same_as(b)) must be rejected",
1872 );
1873 assert!(
1874 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1875 "expected ShapeRuleMismatch, got {err:?}"
1876 );
1877 }
1878
1879 fn lf(src: &str) -> String {
1897 src.replace("\r\n", "\n")
1898 }
1899
1900 #[test]
1901 fn fsce_dtype_differential_fires() {
1902 let mutated = mutate_once(
1909 FUSED_LINEAR_QUANT,
1910 "dtype_rule: fixed(F32) # ALWAYS F32 regardless of input dtype",
1911 "dtype_rule: fixed(F16) # ALWAYS F32 regardless of input dtype",
1912 );
1913 let err = import_bundle_str(&mutated, &crate::fkc::CpuLinkRegistry).expect_err(
1914 "an FSCE dtype_rule disagreeing with the constant-F32 real fn must be rejected",
1915 );
1916 assert!(
1917 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1918 "expected ShapeRuleMismatch, got {err:?}"
1919 );
1920 }
1921
1922 #[test]
1923 fn qmatmul_dtype_differential_fires() {
1924 let mutated = mutate_once(
1927 FUSED_LINEAR_QUANT,
1928 "dtype_rule: fixed(F32) # output is always F32 (dequant-and-contract); = a (F32)",
1929 "dtype_rule: fixed(F16) # output is always F32 (dequant-and-contract); = a (F32)",
1930 );
1931 let err = import_bundle_str(&mutated, &crate::fkc::CpuLinkRegistry).expect_err(
1932 "a QMatMul dtype_rule disagreeing with the real passthrough fn must be rejected",
1933 );
1934 assert!(
1935 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1936 "expected ShapeRuleMismatch, got {err:?}"
1937 );
1938 }
1939
1940 #[test]
1941 fn conv2d_dtype_differential_fires() {
1942 let mutated = mutate_once(
1947 &lf(FUSED_CONV_ROPE),
1948 "dtype_rule: passthrough(x)\n shape_rule: conv2d(params)",
1949 "dtype_rule: fixed(F64)\n shape_rule: conv2d(params)",
1950 );
1951 let err = import_bundle_str(&mutated, &crate::fkc::CpuLinkRegistry).expect_err(
1952 "a Conv2D dtype_rule disagreeing with the real passthrough fn must be rejected",
1953 );
1954 assert!(
1955 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1956 "expected ShapeRuleMismatch, got {err:?}"
1957 );
1958 }
1959
1960 #[test]
1961 fn conv_transpose2d_dtype_differential_fires() {
1962 let mutated = mutate_once(
1969 &lf(FUSED_CONV_ROPE),
1970 "dtype_rule: passthrough(x)\n shape_rule: conv_transpose2d(params)",
1971 "dtype_rule: fixed(F64)\n shape_rule: conv_transpose2d(params)",
1972 );
1973 let err = import_bundle_str(&mutated, &crate::fkc::CpuLinkRegistry)
1974 .expect_err("a ConvTranspose2D dtype_rule disagreeing with the real passthrough fn must be rejected");
1975 assert!(
1976 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1977 "expected ShapeRuleMismatch, got {err:?}"
1978 );
1979 }
1980
1981 #[test]
1982 fn causal_conv1d_dtype_differential_fires() {
1983 let mutated = mutate_once(
1984 &lf(FUSED_CONV_ROPE),
1985 "dtype_rule: passthrough(x)\n shape_rule: from_params(seq_out)",
1986 "dtype_rule: fixed(F64)\n shape_rule: from_params(seq_out)",
1987 );
1988 let err = import_bundle_str(&mutated, &crate::fkc::CpuLinkRegistry).expect_err(
1989 "a CausalConv1d dtype_rule disagreeing with the real passthrough fn must be rejected",
1990 );
1991 assert!(
1992 matches!(err, FkcError::ShapeRuleMismatch { .. }),
1993 "expected ShapeRuleMismatch, got {err:?}"
1994 );
1995 }
1996
1997 #[test]
2004 fn unmutated_corpus_dtype_differentials_run_without_guard_panics() {
2005 for (src, name) in [
2006 (FUSED_LINEAR_QUANT, "linear-quant"),
2007 (FUSED_CONV_ROPE, "conv-rope"),
2008 ] {
2009 let provider = import_bundle_str(src, &crate::fkc::CpuLinkRegistry)
2010 .unwrap_or_else(|e| panic!("{name} must import clean: {e:?}"));
2011 let panicked: Vec<_> = provider
2012 .warnings
2013 .iter()
2014 .filter(|w| w.message.contains("panicked"))
2015 .collect();
2016 assert!(
2017 panicked.is_empty(),
2018 "{name}: live differentials must not rely on guard-caught panics \
2019 (debug-only skips): {panicked:?}",
2020 );
2021 }
2022 }
2023
2024 const SYNTH_CONV2D_1IN: &str = r#"---
2031fkc_version: 1
2032provider:
2033 name: synth-conv2d-1input
2034 backend: Cpu
2035 kernel_source: "portable-cpu"
2036---
2037
2038# synthetic 1-input CONV2D (C-4 T3 arity pre-check)
2039
2040## conv2d_1in
2041
2042Synthetic 1-input Conv2D (x only, no weight) to exercise the arity pre-check.
2043
2044```fkc
2045kernel: conv2d_1in
2046fused_op: CONV2D
2047blurb: "synthetic 1-input conv2d (x only) to exercise the arity pre-check"
2048backend: Cpu
2049kernel_source: "portable-cpu"
2050entry_point: "synthetic::conv2d_1in_cpu"
2051kernel_revision_hash: auto
2052
2053accept:
2054 inputs:
2055 - name: x
2056 dtypes: [F32]
2057 layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
2058 rank: 4
2059 op_params:
2060 variant: Conv2D
2061 fields:
2062 stride: { kind: "(usize, usize)" }
2063 padding: { kind: "(usize, usize)" }
2064 groups: { kind: usize }
2065
2066return:
2067 outputs:
2068 - name: out
2069 dtype_rule: passthrough(x)
2070 shape_rule: conv2d(params)
2071 layout_guarantee: contiguous
2072
2073caps:
2074 awkward_layout_strategy: requires_contiguous
2075 in_place: false
2076
2077cost:
2078 provenance: judge_measured
2079 class: conv
2080
2081precision:
2082 bit_stable_on_same_hardware: false
2083 max_ulp: ~
2084 max_relative: ~
2085 max_absolute: ~
2086 audited: false
2087 notes: "synthetic"
2088
2089determinism: same_hardware_bitwise
2090```
2091"#;
2092
2093 #[test]
2094 fn under_arity_conv2d_skips_differential_consistently_and_warns() {
2095 let provider = import_bundle_str(SYNTH_CONV2D_1IN, &StubResolveAll)
2099 .expect("a 1-input CONV2D contract imports (never-panic; differential skipped)");
2100 assert!(
2101 provider
2102 .warnings
2103 .iter()
2104 .any(|w| w.message.contains("requires >= 2") && w.message.contains("skipped")),
2105 "the under-arity Conv2D differential must be skipped WITH a warning \
2106 (consistent debug/release): {:?}",
2107 provider.warnings,
2108 );
2109 }
2110
2111 const SYNTH_CONV2D_RANK3: &str = r#"---
2120fkc_version: 1
2121provider:
2122 name: synth-conv2d-rank3
2123 backend: Cpu
2124 kernel_source: "portable-cpu"
2125---
2126
2127# synthetic rank-3 CONV2D (review fix: empty-param-points warning)
2128
2129## conv2d_rank3
2130
2131Synthetic 2-input Conv2D whose `x` declares rank 3 (the shape-coupled synth needs rank 4), to
2132exercise the empty-points warning.
2133
2134```fkc
2135kernel: conv2d_rank3
2136fused_op: CONV2D
2137blurb: "synthetic rank-3-x conv2d to exercise the empty-param-points warning"
2138backend: Cpu
2139kernel_source: "portable-cpu"
2140entry_point: "synthetic::conv2d_rank3_cpu"
2141kernel_revision_hash: auto
2142
2143accept:
2144 inputs:
2145 - name: x
2146 dtypes: [F32]
2147 layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
2148 rank: 3
2149 - name: weight
2150 dtypes: [F32]
2151 layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
2152 rank: 4
2153 op_params:
2154 variant: Conv2D
2155 fields:
2156 stride: { kind: "(usize, usize)" }
2157 padding: { kind: "(usize, usize)" }
2158 groups: { kind: usize }
2159
2160return:
2161 outputs:
2162 - name: out
2163 dtype_rule: passthrough(x)
2164 shape_rule: conv2d(params)
2165 layout_guarantee: contiguous
2166
2167caps:
2168 awkward_layout_strategy: requires_contiguous
2169 in_place: false
2170
2171cost:
2172 provenance: judge_measured
2173 class: conv
2174
2175precision:
2176 bit_stable_on_same_hardware: false
2177 max_ulp: ~
2178 max_relative: ~
2179 max_absolute: ~
2180 audited: false
2181 notes: "synthetic"
2182
2183determinism: same_hardware_bitwise
2184```
2185"#;
2186
2187 #[test]
2188 fn empty_param_points_for_params_dependent_variant_warns() {
2189 let provider = import_bundle_str(SYNTH_CONV2D_RANK3, &StubResolveAll)
2190 .expect("a rank-3-x CONV2D contract imports (never-panic; differentials skipped)");
2191 assert!(
2192 provider
2193 .warnings
2194 .iter()
2195 .any(|w| w.message.contains("no param point") && w.message.contains("skipped")),
2196 "an unreadable combo for a params-dependent variant must skip its \
2197 differentials WITH a warning, not silently: {:?}",
2198 provider.warnings,
2199 );
2200 }
2201
2202 #[test]
2207 fn same_pointer_on_one_key_surfaces_duplicate_kernel_ref() {
2211 let src = "\
2216---
2217fkc_version: 1
2218provider:
2219 name: dup-provider
2220 backend: Cpu
2221 kernel_source: \"dup-cpu\"
2222---
2223
2224# dup bundle
2225
2226## add_a
2227
2228A.
2229
2230```fkc
2231kernel: add_a
2232op_kind: AddElementwise
2233blurb: \"a\"
2234entry_point: \"x::add_a\"
2235accept:
2236 inputs:
2237 - name: lhs
2238 dtypes: [F32]
2239 layout: { contiguous: required, strided: rejected }
2240 - name: rhs
2241 dtypes: [F32]
2242 layout: { contiguous: required, strided: rejected }
2243 op_params: { variant: None }
2244return:
2245 outputs:
2246 - name: out
2247 dtype_rule: passthrough(lhs)
2248cost:
2249 provenance: declared
2250 class: cheap_elementwise
2251 flops: \"n\"
2252precision:
2253 bit_stable_on_same_hardware: true
2254 audited: true
2255determinism: same_hardware_bitwise
2256```
2257
2258## add_b
2259
2260B.
2261
2262```fkc
2263kernel: add_b
2264op_kind: AddElementwise
2265blurb: \"b\"
2266entry_point: \"x::add_b\"
2267accept:
2268 inputs:
2269 - name: lhs
2270 dtypes: [F32]
2271 layout: { contiguous: required, strided: rejected }
2272 - name: rhs
2273 dtypes: [F32]
2274 layout: { contiguous: required, strided: rejected }
2275 op_params: { variant: None }
2276return:
2277 outputs:
2278 - name: out
2279 dtype_rule: passthrough(lhs)
2280cost:
2281 provenance: declared
2282 class: cheap_elementwise
2283 flops: \"n\"
2284precision:
2285 bit_stable_on_same_hardware: true
2286 audited: true
2287determinism: same_hardware_bitwise
2288```
2289";
2290 let provider =
2291 import_bundle_str(src, &SameLink).expect("the dup bundle imports (lowering is fine)");
2292 let mut table = KernelBindingTable::new();
2295 let mut fused = FusedKernelRegistry::new();
2296 let err = provider
2297 .register_into(&mut table, &mut fused)
2298 .expect_err("same pointer on one key must error");
2299 assert!(
2300 matches!(err, FkcError::DuplicateKernelRef(_)),
2301 "got {err:?}"
2302 );
2303 }
2304
2305 #[test]
2312 fn imported_contract_declared_cost_reaches_binding_cost_fn() {
2313 let src = "---\nfkc_version: 1\nprovider:\n name: cost-provider\n backend: Cpu\n kernel_source: \"cost-cpu\"\n---\n\n# cost bundle\n\n## add_f32\n\nA.\n\n```fkc\nkernel: add_f32\nop_kind: AddElementwise\nblurb: \"a\"\nentry_point: \"x::add_f32\"\naccept:\n inputs:\n - name: lhs\n dtypes: [F32]\n layout: { contiguous: required, strided: rejected }\n - name: rhs\n dtypes: [F32]\n layout: { contiguous: required, strided: rejected }\n op_params: { variant: None }\nreturn:\n outputs:\n - name: out\n dtype_rule: passthrough(lhs)\ncost:\n provenance: declared\n class: cheap_elementwise\n flops: \"n\"\nprecision:\n bit_stable_on_same_hardware: true\n audited: true\ndeterminism: same_hardware_bitwise\n```\n";
2314 let provider = import_bundle_str(src, &SameLink).expect("declared-cost contract imports");
2315 let mut table = KernelBindingTable::new();
2316 let mut fused = FusedKernelRegistry::new();
2317 provider
2318 .register_into(&mut table, &mut fused)
2319 .expect("registers");
2320 let alts = table.lookup_alternatives(
2321 OpKind::AddElementwise,
2322 &[DType::F32, DType::F32, DType::F32],
2323 BackendId::Cpu,
2324 );
2325 let entry = alts.first().expect("binding present");
2326 let expr = entry
2327 .cost_expr
2328 .expect("declared flops formula reaches the binding as a compiled AST");
2329 let est = crate::fkc::cost_estimate(
2330 expr,
2331 OpKind::AddElementwise,
2332 &[fuel_ir::Shape::from_dims(&[4])],
2333 &[DType::F32, DType::F32, DType::F32],
2334 &crate::kernel::OpParams::None,
2335 )
2336 .expect("declared cost evaluates");
2337 assert_eq!(est.flops, 4, "flops = n = elem_count([4])");
2338 }
2339
2340 fn write_temp(dir: &Path, name: &str, contents: &str) {
2345 std::fs::write(dir.join(name), contents).expect("write temp fkc file");
2346 }
2347
2348 fn bundle_with(provider_backend: &str, kernel: &str, op_kind: &str, entry: &str) -> String {
2349 bundle_with_revision_base(provider_backend, kernel, op_kind, entry, None)
2350 }
2351
2352 fn bundle_with_revision_base(
2353 provider_backend: &str,
2354 kernel: &str,
2355 op_kind: &str,
2356 entry: &str,
2357 revision_base: Option<&str>,
2358 ) -> String {
2359 bundle_with_front_matter(
2360 provider_backend,
2361 kernel,
2362 op_kind,
2363 entry,
2364 revision_base,
2365 None,
2366 )
2367 }
2368
2369 fn bundle_with_link_registry(
2370 provider_backend: &str,
2371 kernel: &str,
2372 op_kind: &str,
2373 entry: &str,
2374 link_registry: Option<&str>,
2375 ) -> String {
2376 bundle_with_front_matter(
2377 provider_backend,
2378 kernel,
2379 op_kind,
2380 entry,
2381 None,
2382 link_registry,
2383 )
2384 }
2385
2386 fn bundle_with_front_matter(
2387 provider_backend: &str,
2388 kernel: &str,
2389 op_kind: &str,
2390 entry: &str,
2391 revision_base: Option<&str>,
2392 link_registry: Option<&str>,
2393 ) -> String {
2394 let template = r#"---
2397fkc_version: 1
2398provider:
2399 name: glob-provider
2400 backend: __BACKEND__
2401 kernel_source: "glob-cpu"__REVISION_BASE____LINK_REGISTRY__
2402---
2403
2404# glob bundle
2405
2406## __KERNEL__
2407
2408blurb.
2409
2410```fkc
2411kernel: __KERNEL__
2412op_kind: __OP_KIND__
2413blurb: "k"
2414entry_point: "__ENTRY__"
2415accept:
2416 inputs:
2417 - name: lhs
2418 dtypes: [F32]
2419 layout: { contiguous: required, strided: rejected }
2420 - name: rhs
2421 dtypes: [F32]
2422 layout: { contiguous: required, strided: rejected }
2423 op_params: { variant: None }
2424return:
2425 outputs:
2426 - name: out
2427 dtype_rule: passthrough(lhs)
2428cost:
2429 provenance: declared
2430 class: cheap_elementwise
2431 flops: "n"
2432precision:
2433 bit_stable_on_same_hardware: true
2434 audited: true
2435determinism: same_hardware_bitwise
2436```
2437"#;
2438 let rev_line = match revision_base {
2439 Some(r) => format!("\n revision_base: \"{r}\""),
2440 None => String::new(),
2441 };
2442 let link_line = match link_registry {
2443 Some(r) => format!("\n link_registry: \"{r}\""),
2444 None => String::new(),
2445 };
2446 template
2447 .replace("__REVISION_BASE__", &rev_line)
2448 .replace("__LINK_REGISTRY__", &link_line)
2449 .replace("__BACKEND__", provider_backend)
2450 .replace("__KERNEL__", kernel)
2451 .replace("__OP_KIND__", op_kind)
2452 .replace("__ENTRY__", entry)
2453 }
2454
2455 #[test]
2456 fn import_glob_merges_agreeing_files() {
2457 let dir = std::env::temp_dir().join(format!("fkc_glob_ok_{}", std::process::id()));
2458 let _ = std::fs::remove_dir_all(&dir);
2459 std::fs::create_dir_all(&dir).unwrap();
2460
2461 write_temp(
2462 &dir,
2463 "a.fkc.md",
2464 &bundle_with("Cpu", "add_f32", "AddElementwise", "x::add"),
2465 );
2466 write_temp(
2467 &dir,
2468 "b.fkc.md",
2469 &bundle_with("Cpu", "sub_f32", "SubElementwise", "x::sub"),
2470 );
2471
2472 let link = DistinctLink::new();
2473 let pattern = dir.join("*.fkc.md").display().to_string();
2474 let provider = import_glob(&pattern, &link).expect("two agreeing files merge");
2475
2476 assert_eq!(provider.name, "glob-provider");
2477 assert_eq!(provider.backend, BackendId::Cpu);
2478 assert_eq!(provider.primitives.len(), 2, "both kernels present");
2479
2480 let mut table = KernelBindingTable::new();
2482 let mut fused = FusedKernelRegistry::new();
2483 provider
2484 .register_into(&mut table, &mut fused)
2485 .expect("merged provider registers");
2486 assert!(
2487 table
2488 .lookup(
2489 OpKind::AddElementwise,
2490 &[DType::F32, DType::F32, DType::F32],
2491 BackendId::Cpu
2492 )
2493 .is_ok()
2494 );
2495 assert!(
2496 table
2497 .lookup(
2498 OpKind::SubElementwise,
2499 &[DType::F32, DType::F32, DType::F32],
2500 BackendId::Cpu
2501 )
2502 .is_ok()
2503 );
2504
2505 let _ = std::fs::remove_dir_all(&dir);
2506 }
2507
2508 #[test]
2520 fn import_glob_mismatched_revision_base_is_provider_mismatch() {
2521 let dir = std::env::temp_dir().join(format!("fkc_glob_rev_{}", std::process::id()));
2522 let _ = std::fs::remove_dir_all(&dir);
2523 std::fs::create_dir_all(&dir).unwrap();
2524
2525 write_temp(
2526 &dir,
2527 "a.fkc.md",
2528 &bundle_with_revision_base(
2529 "Cpu",
2530 "add_f32",
2531 "AddElementwise",
2532 "x::add",
2533 Some("git:aaaaaaaa"),
2534 ),
2535 );
2536 write_temp(
2537 &dir,
2538 "b.fkc.md",
2539 &bundle_with_revision_base(
2540 "Cpu",
2541 "sub_f32",
2542 "SubElementwise",
2543 "x::sub",
2544 Some("git:bbbbbbbb"),
2545 ),
2546 );
2547
2548 let link = DistinctLink::new();
2549 let pattern = dir.join("*.fkc.md").display().to_string();
2550 let err = import_glob(&pattern, &link)
2551 .expect_err("a revision_base drift across a globbed provider must error");
2552 let msg = err.to_string();
2553 assert!(
2554 msg.contains("revision_base"),
2555 "the error must name the drifted field, got: {msg}"
2556 );
2557
2558 let _ = std::fs::remove_dir_all(&dir);
2559 }
2560
2561 #[test]
2564 fn import_glob_matching_revision_base_still_merges() {
2565 let dir = std::env::temp_dir().join(format!("fkc_glob_rev_ok_{}", std::process::id()));
2566 let _ = std::fs::remove_dir_all(&dir);
2567 std::fs::create_dir_all(&dir).unwrap();
2568
2569 for (f, k, op, e) in [
2570 ("a.fkc.md", "add_f32", "AddElementwise", "x::add"),
2571 ("b.fkc.md", "sub_f32", "SubElementwise", "x::sub"),
2572 ] {
2573 write_temp(
2574 &dir,
2575 f,
2576 &bundle_with_revision_base("Cpu", k, op, e, Some("git:deadbeef")),
2577 );
2578 }
2579
2580 let link = DistinctLink::new();
2581 let pattern = dir.join("*.fkc.md").display().to_string();
2582 let provider =
2583 import_glob(&pattern, &link).expect("agreeing revision_base must still merge");
2584 assert_eq!(provider.primitives.len(), 2, "both kernels present");
2585 assert_eq!(
2586 provider.revision_base.as_deref(),
2587 Some("git:deadbeef"),
2588 "the merged provider must retain the agreed revision_base"
2589 );
2590
2591 let _ = std::fs::remove_dir_all(&dir);
2592 }
2593
2594 #[test]
2602 fn import_glob_mismatched_link_registry_is_provider_mismatch() {
2603 let dir = std::env::temp_dir().join(format!("fkc_glob_link_{}", std::process::id()));
2604 let _ = std::fs::remove_dir_all(&dir);
2605 std::fs::create_dir_all(&dir).unwrap();
2606
2607 write_temp(
2608 &dir,
2609 "a.fkc.md",
2610 &bundle_with_link_registry(
2611 "Cpu",
2612 "add_f32",
2613 "AddElementwise",
2614 "x::add",
2615 Some("fuel_cpu_backend::fkc::ENTRY_POINTS"),
2616 ),
2617 );
2618 write_temp(
2619 &dir,
2620 "b.fkc.md",
2621 &bundle_with_link_registry(
2622 "Cpu",
2623 "sub_f32",
2624 "SubElementwise",
2625 "x::sub",
2626 Some("fuel_other_backend::fkc::ENTRY_POINTS"),
2627 ),
2628 );
2629
2630 let link = DistinctLink::new();
2631 let pattern = dir.join("*.fkc.md").display().to_string();
2632 let err = import_glob(&pattern, &link)
2633 .expect_err("a link_registry drift across a globbed provider must error");
2634 let msg = err.to_string();
2635 assert!(
2636 msg.contains("link_registry"),
2637 "the error must name the drifted field, got: {msg}"
2638 );
2639
2640 let _ = std::fs::remove_dir_all(&dir);
2641 }
2642
2643 #[test]
2646 fn import_glob_matching_link_registry_still_merges() {
2647 let dir = std::env::temp_dir().join(format!("fkc_glob_link_ok_{}", std::process::id()));
2648 let _ = std::fs::remove_dir_all(&dir);
2649 std::fs::create_dir_all(&dir).unwrap();
2650
2651 for (f, k, op, e) in [
2652 ("a.fkc.md", "add_f32", "AddElementwise", "x::add"),
2653 ("b.fkc.md", "sub_f32", "SubElementwise", "x::sub"),
2654 ] {
2655 write_temp(
2656 &dir,
2657 f,
2658 &bundle_with_link_registry(
2659 "Cpu",
2660 k,
2661 op,
2662 e,
2663 Some("fuel_cpu_backend::fkc::ENTRY_POINTS"),
2664 ),
2665 );
2666 }
2667
2668 let link = DistinctLink::new();
2669 let pattern = dir.join("*.fkc.md").display().to_string();
2670 let provider =
2671 import_glob(&pattern, &link).expect("agreeing link_registry must still merge");
2672 assert_eq!(
2673 provider.link_registry.as_deref(),
2674 Some("fuel_cpu_backend::fkc::ENTRY_POINTS"),
2675 "the merged provider must retain the agreed link_registry"
2676 );
2677
2678 let _ = std::fs::remove_dir_all(&dir);
2679 }
2680
2681 #[test]
2682 fn import_glob_mismatched_backend_is_provider_mismatch() {
2683 let dir = std::env::temp_dir().join(format!("fkc_glob_bad_{}", std::process::id()));
2684 let _ = std::fs::remove_dir_all(&dir);
2685 std::fs::create_dir_all(&dir).unwrap();
2686
2687 write_temp(
2689 &dir,
2690 "a.fkc.md",
2691 &bundle_with("Cpu", "add_f32", "AddElementwise", "x::add"),
2692 );
2693 write_temp(
2694 &dir,
2695 "b.fkc.md",
2696 &bundle_with("Cpu", "sub_f32", "SubElementwise", "x::sub"),
2697 );
2698 write_temp(
2699 &dir,
2700 "c.fkc.md",
2701 &bundle_with("Vulkan", "mul_f32", "MulElementwise", "x::mul"),
2702 );
2703
2704 let link = DistinctLink::new();
2705 let pattern = dir.join("*.fkc.md").display().to_string();
2706 let err = import_glob(&pattern, &link).expect_err("mismatched backend must error");
2707 assert!(
2708 matches!(
2709 err,
2710 FkcError::ProviderMismatch { ref field, .. } if field == "provider.backend"
2711 ),
2712 "got {err:?}"
2713 );
2714
2715 let _ = std::fs::remove_dir_all(&dir);
2716 }
2717
2718 #[test]
2724 fn describe_only_section_is_excluded_from_register_into() {
2725 let src = "\
2730---
2731fkc_version: 1
2732provider:
2733 name: describe-provider
2734 backend: Cpu
2735 kernel_source: \"describe-cpu\"
2736---
2737
2738# describe bundle
2739
2740## binary
2741
2742The shared chassis (documentation umbrella).
2743
2744```fkc
2745kernel: binary
2746registrable: false
2747op_kind: binary
2748blurb: \"shared binary chassis\"
2749entry_point: \"x::chassis\"
2750accept:
2751 inputs:
2752 - name: lhs
2753 dtypes: [F32, F64, BF16, F16]
2754 layout: { contiguous: required, strided: rejected }
2755 - name: rhs
2756 dtypes: [F32, F64, BF16, F16]
2757 layout: { contiguous: required, strided: rejected }
2758return:
2759 outputs:
2760 - name: out
2761 dtype_rule: passthrough(lhs)
2762cost:
2763 provenance: judge_measured
2764 class: cheap_elementwise
2765precision:
2766 bit_stable_on_same_hardware: true
2767 audited: true
2768determinism: same_hardware_bitwise
2769```
2770
2771## add_f32
2772
2773The real F32 addition thunk.
2774
2775```fkc
2776kernel: add_f32
2777op_kind: AddElementwise
2778blurb: \"F32 add\"
2779entry_point: \"x::add_f32\"
2780accept:
2781 inputs:
2782 - name: lhs
2783 dtypes: [F32]
2784 layout: { contiguous: required, strided: rejected }
2785 - name: rhs
2786 dtypes: [F32]
2787 layout: { contiguous: required, strided: rejected }
2788 op_params: { variant: None }
2789return:
2790 outputs:
2791 - name: out
2792 dtype_rule: passthrough(lhs)
2793cost:
2794 provenance: declared
2795 class: cheap_elementwise
2796 flops: \"n\"
2797precision:
2798 bit_stable_on_same_hardware: true
2799 audited: true
2800determinism: same_hardware_bitwise
2801```
2802";
2803 let link = DistinctLink::new();
2804 let provider = import_bundle_str(src, &link)
2805 .expect("describe-only + registrable bundle imports (umbrella is valid docs)");
2806
2807 assert_eq!(
2810 provider.primitives.len(),
2811 1,
2812 "exactly one registrable primitive (the umbrella is documentation-only)"
2813 );
2814 assert_eq!(provider.primitives[0].op, OpKind::AddElementwise);
2815
2816 let mut table = KernelBindingTable::new();
2818 let mut fused = FusedKernelRegistry::new();
2819 provider
2820 .register_into(&mut table, &mut fused)
2821 .expect("register_into succeeds (no describe-only section reaches the table)");
2822 assert!(
2823 table
2824 .lookup(
2825 OpKind::AddElementwise,
2826 &[DType::F32, DType::F32, DType::F32],
2827 BackendId::Cpu
2828 )
2829 .is_ok()
2830 );
2831 }
2832
2833 #[test]
2841 fn describe_only_gather_section_does_not_block_bundle_import() {
2842 let src = r#"---
2856fkc_version: 1
2857provider:
2858 name: gather-describe-provider
2859 backend: Cpu
2860 kernel_source: "gather-cpu"
2861---
2862
2863# describe-only gather bundle
2864
2865## add_f32
2866
2867The real F32 addition thunk (registrable).
2868
2869```fkc
2870kernel: add_f32
2871op_kind: AddElementwise
2872blurb: "F32 add"
2873entry_point: "x::add_f32"
2874accept:
2875 inputs:
2876 - name: lhs
2877 dtypes: [F32]
2878 layout: { contiguous: required, strided: rejected }
2879 - name: rhs
2880 dtypes: [F32]
2881 layout: { contiguous: required, strided: rejected }
2882 op_params: { variant: None }
2883return:
2884 outputs:
2885 - name: out
2886 dtype_rule: passthrough(lhs)
2887cost:
2888 provenance: declared
2889 class: cheap_elementwise
2890 flops: "n"
2891precision:
2892 bit_stable_on_same_hardware: true
2893 audited: true
2894determinism: same_hardware_bitwise
2895```
2896
2897## paged_gather
2898
2899Describe-only: a paged KV pool with an FDX gather sidecar (consumer-ahead).
2900
2901```fkc
2902kernel: paged_gather
2903registrable: false
2904op_kind: PagedAttn
2905blurb: "describe-only paged gather"
2906entry_point: "x::paged_gather"
2907accept:
2908 inputs:
2909 - name: q
2910 dtypes: [F32]
2911 layout: { contiguous: required, strided: rejected }
2912 - name: k_cache
2913 dtypes: [F32]
2914 layout: { contiguous: required, strided: rejected }
2915 fdx:
2916 requires_ext: true
2917 symbolic_extent: required
2918 gather: { kind: paged_blocks, block_table: block_table, context_lens: context_lens }
2919 - name: block_table
2920 dtypes: [U32]
2921 layout: { contiguous: required, strided: rejected }
2922 - name: context_lens
2923 dtypes: [U32]
2924 layout: { contiguous: required, strided: rejected }
2925 op_params: { variant: PagedAttn }
2926return:
2927 outputs:
2928 - name: out
2929 dtype_rule: passthrough(q)
2930cost:
2931 provenance: declared
2932 class: attention
2933 flops: "n"
2934precision:
2935 bit_stable_on_same_hardware: true
2936 audited: true
2937determinism: same_hardware_bitwise
2938```
2939"#;
2940 let link = DistinctLink::new();
2941 let provider = import_bundle_str(src, &link).expect(
2942 "a describe-only gather section must NOT block the bundle's importable sections",
2943 );
2944
2945 assert_eq!(
2948 provider.primitives.len(),
2949 1,
2950 "exactly one registrable primitive (the gather section is describe-only)",
2951 );
2952 assert_eq!(provider.primitives[0].op, OpKind::AddElementwise);
2953
2954 let mut table = KernelBindingTable::new();
2956 let mut fused = FusedKernelRegistry::new();
2957 provider
2958 .register_into(&mut table, &mut fused)
2959 .expect("the valid sibling registers end-to-end");
2960 assert!(
2961 table
2962 .lookup(
2963 OpKind::AddElementwise,
2964 &[DType::F32, DType::F32, DType::F32],
2965 BackendId::Cpu
2966 )
2967 .is_ok()
2968 );
2969 }
2970
2971 #[test]
2976 fn hand_built_fused_registers_into_registry() {
2977 let mut dtypes: KernelDTypes = SmallVec::new();
2982 dtypes.push(DType::F32); dtypes.push(DType::F32); let f = ResolvedFused {
2986 id: FusedOps::SOFTMAX_LAST_DIM,
2987 dtypes,
2988 backend: BackendId::Cpu,
2989 caps: KernelCaps::empty(),
2990 layouts: vec![ResolvedLayout {
2991 contiguous: Tri::Required,
2992 strided: Tri::Rejected,
2993 broadcast_stride0: Tri::Rejected,
2994 start_offset: Tri::Rejected,
2995 reverse_strides: Tri::Rejected,
2996 }],
2997 precision: PrecisionGuarantee::UNAUDITED,
2998 cost: CompiledCostExpr::Unknown,
2999 kernel: dummy_a,
3000 kernel_source: "portable-cpu".to_string(),
3001 revision: KernelRevisionHash::UNTRACKED,
3002 variant: None,
3003 bundle_slot_names: Vec::new(),
3004 };
3005
3006 let provider = ImportedProvider {
3007 name: "fuel-fused-registry".to_string(),
3008 backend: BackendId::Cpu,
3009 kernel_source: intern("portable-cpu"),
3010 revision_base: None,
3011 link_registry: None,
3012 primitives: Vec::new(),
3013 fused: vec![f],
3014 warnings: Vec::new(),
3015 };
3016
3017 let mut table = KernelBindingTable::new();
3018 let mut fused = FusedKernelRegistry::new();
3019 provider
3020 .register_into(&mut table, &mut fused)
3021 .expect("fused-only provider registers");
3022
3023 let got = fused.lookup_by_dtypes(
3025 FusedOps::SOFTMAX_LAST_DIM,
3026 BackendId::Cpu,
3027 &[DType::F32, DType::F32],
3028 );
3029 assert!(got.is_some(), "softmax fused impl registered + looked up");
3030 let impl_ = got.unwrap();
3031 assert_eq!(impl_.dtypes, &[DType::F32, DType::F32]);
3033 let sentinel = fused_unknown_cost as *const () as usize;
3035 assert_eq!(
3036 impl_.cost as *const () as usize, sentinel,
3037 "the fused-unknown sentinel CostFn is wired for imported fused ops"
3038 );
3039 assert_eq!(impl_.revision, KernelRevisionHash::UNTRACKED);
3041 }
3042
3043 struct FanStubLink {
3057 seen: Mutex<std::collections::HashMap<String, KernelRef>>,
3058 requested: Mutex<Vec<String>>,
3059 }
3060 impl FanStubLink {
3061 fn new() -> Self {
3062 Self {
3063 seen: Mutex::new(std::collections::HashMap::new()),
3064 requested: Mutex::new(Vec::new()),
3065 }
3066 }
3067 fn resolve(&self, symbol: &str) -> Option<KernelRef> {
3068 self.requested.lock().unwrap().push(symbol.to_string());
3069 let mut g = self.seen.lock().unwrap();
3070 if let Some(k) = g.get(symbol) {
3071 return Some(*k);
3072 }
3073 let k: KernelRef = if g.len().is_multiple_of(2) {
3074 dummy_a
3075 } else {
3076 dummy_b
3077 };
3078 g.insert(symbol.to_string(), k);
3079 Some(k)
3080 }
3081 }
3082 impl LinkRegistry for FanStubLink {
3083 fn resolve_primitive(&self, symbol: &str) -> Option<KernelRef> {
3084 self.resolve(symbol)
3085 }
3086 fn resolve_fused(&self, symbol: &str) -> Option<KernelRef> {
3087 self.resolve(symbol)
3088 }
3089 }
3090
3091 const FANOUT_CONTRACT: &str = r#"---
3097fkc_version: 1
3098provider:
3099 name: fanout-provider
3100 backend: Cpu
3101 kernel_source: "fanout-cpu"
3102---
3103
3104# fanout bundle
3105
3106## relu
3107
3108Uniform multi-dtype unary: one input varying over 4 dtypes.
3109
3110```fkc
3111kernel: relu
3112op_kind: ReluElementwise
3113blurb: "relu fan-out"
3114entry_point: "stub::relu"
3115accept:
3116 inputs:
3117 - name: in
3118 dtypes: [F32, F64, BF16, F16]
3119 layout: { contiguous: required, strided: rejected }
3120 op_params: { variant: None }
3121return:
3122 outputs:
3123 - name: out
3124 dtype_rule: passthrough(in)
3125cost:
3126 provenance: declared
3127 class: cheap_elementwise
3128 flops: "n"
3129precision:
3130 bit_stable_on_same_hardware: true
3131 audited: true
3132determinism: same_hardware_bitwise
3133```
3134
3135## where_op
3136
3137Mixed: a fixed U8 cond + two varying operands; passthrough(a).
3138
3139```fkc
3140kernel: where_op
3141op_kind: Where
3142blurb: "where fan-out with passthrough(a)"
3143entry_point: "stub::where"
3144accept:
3145 inputs:
3146 - name: cond
3147 dtypes: [U8]
3148 layout: { contiguous: required, strided: rejected }
3149 - name: a
3150 dtypes: [F32, F64, BF16, F16]
3151 layout: { contiguous: required, strided: rejected }
3152 - name: b
3153 dtypes: [F32, F64, BF16, F16]
3154 layout: { contiguous: required, strided: rejected }
3155 op_params: { variant: None }
3156return:
3157 outputs:
3158 - name: out
3159 dtype_rule: passthrough(a)
3160cost:
3161 provenance: declared
3162 class: cheap_elementwise
3163 flops: "n"
3164precision:
3165 bit_stable_on_same_hardware: true
3166 audited: true
3167determinism: same_hardware_bitwise
3168```
3169"#;
3170
3171 #[test]
3172 fn multi_dtype_section_fans_out_into_per_dtype_bindings() {
3173 let link = FanStubLink::new();
3174 let provider = import_bundle_str(FANOUT_CONTRACT, &link).expect("fan-out contract imports");
3175
3176 assert_eq!(
3181 provider.primitives.len(),
3182 8,
3183 "relu×4 + where×4 = 8 fanned bindings (pre-change: 2 — first-dtype only)"
3184 );
3185
3186 let mut table = KernelBindingTable::new();
3187 let mut fused = FusedKernelRegistry::new();
3188 provider
3189 .register_into(&mut table, &mut fused)
3190 .expect("fanned bindings register");
3191
3192 let dts = [DType::F32, DType::F64, DType::BF16, DType::F16];
3193
3194 for dt in dts {
3196 assert!(
3197 table
3198 .lookup(OpKind::ReluElementwise, &[dt, dt], BackendId::Cpu)
3199 .is_ok(),
3200 "relu must be bound at [{dt:?}, {dt:?}]",
3201 );
3202 }
3203
3204 for dt in dts {
3208 assert!(
3209 table
3210 .lookup(OpKind::Where, &[DType::U8, dt, dt, dt], BackendId::Cpu)
3211 .is_ok(),
3212 "where must be bound at [U8, {dt:?}, {dt:?}, {dt:?}] (passthrough(a) = a's dtype)",
3213 );
3214 assert!(
3216 table
3217 .lookup(
3218 OpKind::Where,
3219 &[DType::U8, dt, dt, DType::U8],
3220 BackendId::Cpu
3221 )
3222 .is_err(),
3223 "the pre-fix buggy key [U8,{dt:?},{dt:?},U8] must NOT be registered",
3224 );
3225 }
3226
3227 let requested = link.requested.lock().unwrap().clone();
3231 for suffix in ["f32", "f64", "bf16", "f16"] {
3232 assert!(
3233 requested
3234 .iter()
3235 .any(|s| s == &format!("stub::relu_{suffix}")),
3236 "relu variant must resolve stub::relu_{suffix}; requested={requested:?}",
3237 );
3238 assert!(
3239 requested
3240 .iter()
3241 .any(|s| s == &format!("stub::where_{suffix}")),
3242 "where variant must resolve stub::where_{suffix}; requested={requested:?}",
3243 );
3244 }
3245 }
3246
3247 #[test]
3253 fn single_dtype_section_yields_exactly_one_unchanged_binding() {
3254 let src = r#"---
3255fkc_version: 1
3256provider:
3257 name: single-provider
3258 backend: Cpu
3259 kernel_source: "single-cpu"
3260---
3261
3262# single bundle
3263
3264## add_f32
3265
3266```fkc
3267kernel: add_f32
3268op_kind: AddElementwise
3269blurb: "single-dtype add"
3270entry_point: "stub::add_f32"
3271accept:
3272 inputs:
3273 - name: lhs
3274 dtypes: [F32]
3275 layout: { contiguous: required, strided: rejected }
3276 - name: rhs
3277 dtypes: [F32]
3278 layout: { contiguous: required, strided: rejected }
3279 op_params: { variant: None }
3280return:
3281 outputs:
3282 - name: out
3283 dtype_rule: passthrough(lhs)
3284cost:
3285 provenance: declared
3286 class: cheap_elementwise
3287 flops: "n"
3288precision:
3289 bit_stable_on_same_hardware: true
3290 audited: true
3291determinism: same_hardware_bitwise
3292```
3293"#;
3294 let link = FanStubLink::new();
3295 let provider = import_bundle_str(src, &link).expect("single-dtype imports");
3296 assert_eq!(
3297 provider.primitives.len(),
3298 1,
3299 "no varying operand ⇒ exactly one binding"
3300 );
3301 assert_eq!(
3302 provider.primitives[0].dtypes.as_slice(),
3303 &[DType::F32, DType::F32, DType::F32],
3304 );
3305
3306 let requested = link.requested.lock().unwrap().clone();
3309 assert!(
3310 requested.iter().any(|s| s == "stub::add_f32"),
3311 "single-variant resolves the declared symbol as-is; requested={requested:?}",
3312 );
3313 assert!(
3314 !requested.iter().any(|s| s == "stub::add_f32_f32"),
3315 "must NOT append a suffix to a single-variant section",
3316 );
3317 }
3318
3319 const OPTIONAL_LAST_OPERAND_CONTRACT: &str = r#"---
3338fkc_version: 1
3339provider:
3340 name: opt-provider
3341 backend: Cpu
3342 kernel_source: "opt-cpu"
3343---
3344
3345# optional-operand bundle
3346
3347## opt_add
3348
3349One required input + one optional LAST input.
3350
3351```fkc
3352kernel: opt_add
3353op_kind: AddElementwise
3354blurb: "optional last operand"
3355entry_point: "stub::opt_add"
3356accept:
3357 inputs:
3358 - name: x
3359 dtypes: [F32]
3360 layout: { contiguous: required, strided: rejected }
3361 - name: bias
3362 dtypes: [F32]
3363 layout: { contiguous: required, strided: rejected }
3364 optional: true
3365 op_params: { variant: None }
3366return:
3367 outputs:
3368 - name: out
3369 dtype_rule: passthrough(x)
3370cost:
3371 provenance: declared
3372 class: cheap_elementwise
3373 flops: "n"
3374precision:
3375 bit_stable_on_same_hardware: true
3376 audited: true
3377determinism: same_hardware_bitwise
3378```
3379"#;
3380
3381 #[test]
3382 fn optional_last_operand_registers_both_with_and_without_keys() {
3383 let link = FanStubLink::new();
3384 let provider = import_bundle_str(OPTIONAL_LAST_OPERAND_CONTRACT, &link)
3385 .expect("optional-operand contract imports");
3386
3387 assert_eq!(
3391 provider.primitives.len(),
3392 2,
3393 "an optional LAST input fans into 2 keys (with + without the operand); \
3394 pre-change (no `optional` schema field) only the with-operand key builds → 1",
3395 );
3396
3397 let k0 = provider.primitives[0].kernel as usize;
3400 let k1 = provider.primitives[1].kernel as usize;
3401 assert_eq!(
3402 k0, k1,
3403 "both the with- and without-optional keys resolve the SAME kernel (one entry_point)",
3404 );
3405
3406 let mut keys: Vec<Vec<DType>> = provider
3408 .primitives
3409 .iter()
3410 .map(|p| p.dtypes.to_vec())
3411 .collect();
3412 keys.sort_by_key(|k| k.len());
3413 assert_eq!(
3414 keys[0],
3415 vec![DType::F32, DType::F32],
3416 "no-optional key = [x, out]",
3417 );
3418 assert_eq!(
3419 keys[1],
3420 vec![DType::F32, DType::F32, DType::F32],
3421 "with-optional key = [x, bias, out]",
3422 );
3423
3424 let mut table = KernelBindingTable::new();
3426 let mut fused = FusedKernelRegistry::new();
3427 provider
3428 .register_into(&mut table, &mut fused)
3429 .expect("both keys register");
3430 assert!(
3431 table
3432 .lookup(
3433 OpKind::AddElementwise,
3434 &[DType::F32, DType::F32],
3435 BackendId::Cpu
3436 )
3437 .is_ok(),
3438 "no-optional key [F32, F32] is bound",
3439 );
3440 assert!(
3441 table
3442 .lookup(
3443 OpKind::AddElementwise,
3444 &[DType::F32, DType::F32, DType::F32],
3445 BackendId::Cpu,
3446 )
3447 .is_ok(),
3448 "with-optional key [F32, F32, F32] is bound",
3449 );
3450
3451 let requested = link.requested.lock().unwrap().clone();
3453 assert!(
3454 requested.iter().any(|s| s == "stub::opt_add"),
3455 "single-dtype section resolves its declared symbol as-is; requested={requested:?}",
3456 );
3457
3458 let non_optional = OPTIONAL_LAST_OPERAND_CONTRACT.replace(" optional: true\n", "");
3462 let link2 = FanStubLink::new();
3463 let provider2 =
3464 import_bundle_str(&non_optional, &link2).expect("non-optional twin imports");
3465 assert_eq!(
3466 provider2.primitives.len(),
3467 1,
3468 "no optional operand ⇒ exactly one binding (backward-compat)",
3469 );
3470 assert_eq!(
3471 provider2.primitives[0].dtypes.to_vec(),
3472 vec![DType::F32, DType::F32, DType::F32],
3473 "the required-both key [x, bias, out]",
3474 );
3475 }
3476
3477 fn test_pinned_cost(
3491 _s: &[fuel_ir::Shape],
3492 _d: &[DType],
3493 _p: &crate::kernel::OpParams,
3494 _c: &fuel_ir::backend::BackendCapabilities,
3495 ) -> CostEstimate {
3496 CostEstimate {
3497 flops: 999_999,
3498 bytes_moved: 0,
3499 kernel_overhead_ns: 0,
3500 }
3501 }
3502
3503 struct CostPinLink;
3508 impl LinkRegistry for CostPinLink {
3509 fn resolve_primitive(&self, _symbol: &str) -> Option<KernelRef> {
3510 Some(dummy_a)
3511 }
3512 fn resolve_fused(&self, _symbol: &str) -> Option<KernelRef> {
3513 Some(dummy_a)
3514 }
3515 fn resolve_cost_fn(&self, name: &str) -> Option<crate::kernel::CostFn> {
3516 if name == "test_pinned_cost" {
3517 Some(test_pinned_cost)
3518 } else {
3519 None
3520 }
3521 }
3522 }
3523
3524 const COST_PIN_BUNDLE: &str = "\
3527---
3528fkc_version: 1
3529provider:
3530 name: cost-pin-provider
3531 backend: Cpu
3532 kernel_source: \"cost-pin-cpu\"
3533---
3534
3535# cost-pin bundle
3536
3537## add_pinned
3538
3539A.
3540
3541```fkc
3542kernel: add_pinned
3543op_kind: AddElementwise
3544blurb: \"a\"
3545entry_point: \"x::add_pinned\"
3546accept:
3547 inputs:
3548 - name: lhs
3549 dtypes: [F32]
3550 layout: { contiguous: required, strided: rejected }
3551 - name: rhs
3552 dtypes: [F32]
3553 layout: { contiguous: required, strided: rejected }
3554 op_params: { variant: None }
3555return:
3556 outputs:
3557 - name: out
3558 dtype_rule: passthrough(lhs)
3559cost:
3560 provenance: declared
3561 class: cheap_elementwise
3562 flops: \"n\"
3563 cost_fn: \"__COST_FN__\"
3564precision:
3565 bit_stable_on_same_hardware: true
3566 audited: true
3567determinism: same_hardware_bitwise
3568```
3569";
3570
3571 #[test]
3572 fn contract_pinned_cost_fn_survives_fill_unset() {
3573 let src = COST_PIN_BUNDLE.replace("__COST_FN__", "test_pinned_cost");
3580 let provider = import_bundle_str(&src, &CostPinLink)
3581 .expect("a bundle naming a resolvable cost fn imports");
3582
3583 assert_eq!(provider.primitives.len(), 1);
3585 assert!(
3586 provider.primitives[0].cost_fn.is_some(),
3587 "lower_primitive must resolve cost.cost_fn through resolve_cost_fn",
3588 );
3589
3590 let mut table = KernelBindingTable::new();
3591 let mut fused = FusedKernelRegistry::new();
3592 provider
3593 .register_into(&mut table, &mut fused)
3594 .expect("register_into succeeds");
3595
3596 let key = [DType::F32, DType::F32, DType::F32];
3597
3598 let cost_before = table.lookup_cost(OpKind::AddElementwise, &key, BackendId::Cpu);
3600 assert_eq!(
3601 cost_before as usize, test_pinned_cost as *const () as usize,
3602 "register_into must stamp the contract-pinned CostFn (not unknown_cost)",
3603 );
3604 assert_ne!(
3605 cost_before as usize,
3606 crate::kernel::unknown_cost as *const () as usize,
3607 "the pinned CostFn must not be the unknown_cost sentinel",
3608 );
3609
3610 table.fill_unset_cpu_cost(crate::cost::default_cost_for_op_kind);
3612 let cost_after = table.lookup_cost(OpKind::AddElementwise, &key, BackendId::Cpu);
3613 assert_eq!(
3614 cost_after as usize, test_pinned_cost as *const () as usize,
3615 "fill_unset must leave the contract-pinned CostFn untouched",
3616 );
3617 assert_ne!(
3618 cost_after as usize,
3619 crate::cost::cost_elementwise_binary_cpu as *const () as usize,
3620 "the pinned cost must NOT have been clobbered by the op-family default",
3621 );
3622
3623 let alts = table.lookup_alternatives(OpKind::AddElementwise, &key, BackendId::Cpu);
3628 let entry = alts.first().expect("binding present");
3629 assert!(
3630 entry.cost_expr.is_none(),
3631 "a pinned cost_fn wins outright; the declared cost AST must not be stamped alongside it",
3632 );
3633 }
3634
3635 #[test]
3636 fn unknown_cost_fn_name_is_typed_error() {
3637 let src = COST_PIN_BUNDLE.replace("__COST_FN__", "no_such_cost_fn");
3641 let err = import_bundle_str(&src, &CostPinLink)
3642 .expect_err("an unresolved cost_fn name must error");
3643 assert!(
3644 matches!(err, FkcError::UnknownCostFn { ref cost_fn, .. } if cost_fn == "no_such_cost_fn"),
3645 "got {err:?}",
3646 );
3647 }
3648
3649 #[test]
3654 fn imported_provider_exposes_warnings_field_defaulting_empty() {
3655 let p = ImportedProvider {
3659 name: "p".into(),
3660 backend: fuel_ir::probe::BackendId::Cpu,
3661 kernel_source: "ks",
3662 revision_base: None,
3663 link_registry: None,
3664 primitives: Vec::new(),
3665 fused: Vec::new(),
3666 warnings: Vec::new(),
3667 };
3668 assert!(p.warnings.is_empty());
3669 }
3670}