From ea4df63128deab30122c8fe31dcdae09c32f00c0 Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:12:02 -0800 Subject: [PATCH 01/20] Add Rust provider workspace --- Cargo.toml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Cargo.toml diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3d76179 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,27 @@ +[workspace] +members = [ + "crates/mnel-provider-api", + "crates/mnel-provider-sdk", + "crates/mnel-provider-host", +] +resolver = "2" + +[workspace.package] +version = "0.1.0-alpha.0" +edition = "2021" +rust-version = "1.79" +license = "Apache-2.0" +repository = "https://github.com/epi13/Machine-Native-Experimental-Learning" + +[workspace.lints.rust] +unsafe_code = "deny" + +[workspace.lints.clippy] +expect_used = "deny" +unwrap_used = "deny" + +[profile.release] +lto = "thin" +codegen-units = 1 +strip = "symbols" +panic = "abort" From 405b71b24a671847df28f9139964afe86b3d2b73 Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:12:07 -0800 Subject: [PATCH 02/20] Pin Rust provider toolchain --- rust-toolchain.toml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 rust-toolchain.toml diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..42be26d --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.79.0" +components = ["clippy", "rustfmt"] +profile = "minimal" From c51432ca74c8a884bf3e404392ed173cb2a5aac0 Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:12:13 -0800 Subject: [PATCH 03/20] Add provider ABI crate manifest --- crates/mnel-provider-api/Cargo.toml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 crates/mnel-provider-api/Cargo.toml diff --git a/crates/mnel-provider-api/Cargo.toml b/crates/mnel-provider-api/Cargo.toml new file mode 100644 index 0000000..b4de3b5 --- /dev/null +++ b/crates/mnel-provider-api/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "mnel-provider-api" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true +description = "Versioned ABI types for MNEL learned micro-providers" + +[lints] +workspace = true From d4e0777e63e28650438c5f008a48b5d1399814c9 Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:12:32 -0800 Subject: [PATCH 04/20] Define versioned provider C ABI --- crates/mnel-provider-api/src/lib.rs | 153 ++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 crates/mnel-provider-api/src/lib.rs diff --git a/crates/mnel-provider-api/src/lib.rs b/crates/mnel-provider-api/src/lib.rs new file mode 100644 index 0000000..0ea298c --- /dev/null +++ b/crates/mnel-provider-api/src/lib.rs @@ -0,0 +1,153 @@ +//! Stable, allocation-neutral ABI vocabulary for diagnostic-only learned providers. +//! +//! The ABI intentionally contains no evaluator verdict, conformance, promotion, or +//! acceptance field. Provider output is diagnostic context only. + +use core::ffi::c_void; + +pub const ABI_VERSION_V1: u32 = 1; +pub const ENTRY_SYMBOL_V1: &str = "mnel_provider_entry_v1"; +pub const AUTHORITY_DIAGNOSTIC_ONLY: u32 = 1; +pub const VERDICT_SEMANTICS_NOT_A_VERDICT: u32 = 1; + +#[repr(C)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct Digest32 { + pub bytes: [u8; 32], +} + +impl Digest32 { + pub const ZERO: Self = Self { bytes: [0; 32] }; +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct ByteView { + pub data: *const u8, + pub len: usize, +} + +impl ByteView { + pub const EMPTY: Self = Self { + data: core::ptr::null(), + len: 0, + }; +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct MutableByteBuffer { + pub data: *mut u8, + pub capacity: usize, + pub len: usize, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ResourceBudgetV1 { + pub wall_time_ns: u64, + pub operation_limit: u64, + pub memory_bytes: u64, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct SnapshotViewV1 { + pub schema_version: u32, + pub reserved: u32, + pub snapshot_identity: Digest32, + pub feature_extractor_identity: Digest32, + pub payload: ByteView, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct ProviderQueryV1 { + pub abi_version: u32, + pub reserved: u32, + pub declaration_identity: Digest32, + pub model_identity: Digest32, + pub calibration_identity: Digest32, + pub query_identity: Digest32, + pub snapshots: *const SnapshotViewV1, + pub snapshot_count: usize, + pub budget: ResourceBudgetV1, +} + +pub type ProviderStatusV1 = u32; +pub const PROVIDER_STATUS_COMPLETED: ProviderStatusV1 = 0; +pub const PROVIDER_STATUS_ABSTAINED: ProviderStatusV1 = 1; +pub const PROVIDER_STATUS_INVALID_INPUT: ProviderStatusV1 = 2; +pub const PROVIDER_STATUS_BUDGET_EXCEEDED: ProviderStatusV1 = 3; +pub const PROVIDER_STATUS_OUT_OF_DISTRIBUTION: ProviderStatusV1 = 4; +pub const PROVIDER_STATUS_RUNTIME_ERROR: ProviderStatusV1 = 5; + +pub type OutputKindV1 = u32; +pub const OUTPUT_LATENT_DISCREPANCY: OutputKindV1 = 1; +pub const OUTPUT_STRUCTURAL_DISCREPANCY: OutputKindV1 = 2; +pub const OUTPUT_ANOMALY_SCORE: OutputKindV1 = 3; +pub const OUTPUT_PAIR_SIMILARITY: OutputKindV1 = 4; +pub const OUTPUT_NEXT_STATE_DISTRIBUTION: OutputKindV1 = 5; +pub const OUTPUT_FEATURE_CONTRIBUTIONS: OutputKindV1 = 6; +pub const OUTPUT_CANDIDATE_RANKING: OutputKindV1 = 7; + +pub const RESULT_FLAG_OUT_OF_DISTRIBUTION: u64 = 1 << 0; +pub const RESULT_FLAG_CALIBRATION_REQUIRED: u64 = 1 << 1; +pub const RESULT_FLAG_TRUNCATED_PAYLOAD: u64 = 1 << 2; + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct ProviderResultV1 { + pub abi_version: u32, + pub status: ProviderStatusV1, + pub output_kind: OutputKindV1, + pub calibration_band: u32, + pub scalar_value: f64, + pub flags: u64, + pub observation_payload: MutableByteBuffer, + pub authority: u32, + pub verdict_semantics: u32, +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct ProviderDescriptorV1 { + pub abi_version: u32, + pub reserved: u32, + pub provider_id: ByteView, + pub provider_version: ByteView, + pub declaration_identity: Digest32, + pub implementation_context: *mut c_void, + pub infer: Option, +} + +pub type ProviderInferV1 = extern "C" fn( + context: *mut c_void, + query: *const ProviderQueryV1, + result: *mut ProviderResultV1, +) -> i32; + +pub type ProviderEntryV1 = extern "C" fn() -> *const ProviderDescriptorV1; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn diagnostic_authority_is_fixed_and_distinct() { + assert_ne!(AUTHORITY_DIAGNOSTIC_ONLY, 0); + assert_ne!(VERDICT_SEMANTICS_NOT_A_VERDICT, 0); + } + + #[test] + fn abi_types_are_c_compatible_and_nonzero_sized() { + assert!(core::mem::size_of::() > 0); + assert!(core::mem::size_of::() > 0); + assert!(core::mem::align_of::() >= core::mem::align_of::()); + } + + #[test] + fn entry_symbol_is_versioned() { + assert_eq!(ENTRY_SYMBOL_V1, "mnel_provider_entry_v1"); + } +} From dcd16fcba6232a654f447a4d7dd974f29c2db266 Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:12:39 -0800 Subject: [PATCH 05/20] Add provider SDK crate manifest --- crates/mnel-provider-sdk/Cargo.toml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 crates/mnel-provider-sdk/Cargo.toml diff --git a/crates/mnel-provider-sdk/Cargo.toml b/crates/mnel-provider-sdk/Cargo.toml new file mode 100644 index 0000000..d7d6b33 --- /dev/null +++ b/crates/mnel-provider-sdk/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "mnel-provider-sdk" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true +description = "Safe Rust authoring surface for MNEL learned micro-providers" + +[dependencies] +mnel-provider-api = { path = "../mnel-provider-api" } + +[lints] +workspace = true From cf2cbc2ed1baff61c923a8d90ecdd40a7c093787 Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:12:59 -0800 Subject: [PATCH 06/20] Add safe Rust provider SDK --- crates/mnel-provider-sdk/src/lib.rs | 196 ++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 crates/mnel-provider-sdk/src/lib.rs diff --git a/crates/mnel-provider-sdk/src/lib.rs b/crates/mnel-provider-sdk/src/lib.rs new file mode 100644 index 0000000..ae0a345 --- /dev/null +++ b/crates/mnel-provider-sdk/src/lib.rs @@ -0,0 +1,196 @@ +//! Safe Rust-facing provider contract layered over the versioned C ABI. + +use mnel_provider_api::{ + Digest32, OutputKindV1, ProviderQueryV1, ResourceBudgetV1, SnapshotViewV1, ABI_VERSION_V1, +}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct InvocationIdentity { + pub declaration: Digest32, + pub model: Digest32, + pub calibration: Digest32, + pub query: Digest32, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ResourceBudget { + pub wall_time_ns: u64, + pub operation_limit: u64, + pub memory_bytes: u64, +} + +impl ResourceBudget { + pub fn validate(self) -> Result { + if self.wall_time_ns == 0 || self.operation_limit == 0 || self.memory_bytes == 0 { + return Err(ProviderError::InvalidBudget); + } + Ok(self) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct SnapshotRef<'a> { + pub schema_version: u32, + pub identity: Digest32, + pub feature_extractor_identity: Digest32, + pub payload: &'a [u8], +} + +#[derive(Debug)] +pub struct Invocation<'a> { + identities: InvocationIdentity, + budget: ResourceBudget, + raw_snapshots: Vec, + snapshot_lifetimes: Vec>, +} + +impl<'a> Invocation<'a> { + pub fn new( + identities: InvocationIdentity, + budget: ResourceBudget, + snapshots: Vec>, + ) -> Result { + let budget = budget.validate()?; + if snapshots.is_empty() { + return Err(ProviderError::MissingSnapshots); + } + if snapshots.iter().any(|snapshot| snapshot.payload.is_empty()) { + return Err(ProviderError::EmptySnapshot); + } + let raw_snapshots = snapshots + .iter() + .map(|snapshot| SnapshotViewV1 { + schema_version: snapshot.schema_version, + reserved: 0, + snapshot_identity: snapshot.identity, + feature_extractor_identity: snapshot.feature_extractor_identity, + payload: mnel_provider_api::ByteView { + data: snapshot.payload.as_ptr(), + len: snapshot.payload.len(), + }, + }) + .collect(); + Ok(Self { + identities, + budget, + raw_snapshots, + snapshot_lifetimes: snapshots, + }) + } + + pub fn as_raw(&self) -> ProviderQueryV1 { + ProviderQueryV1 { + abi_version: ABI_VERSION_V1, + reserved: 0, + declaration_identity: self.identities.declaration, + model_identity: self.identities.model, + calibration_identity: self.identities.calibration, + query_identity: self.identities.query, + snapshots: self.raw_snapshots.as_ptr(), + snapshot_count: self.raw_snapshots.len(), + budget: ResourceBudgetV1 { + wall_time_ns: self.budget.wall_time_ns, + operation_limit: self.budget.operation_limit, + memory_bytes: self.budget.memory_bytes, + }, + } + } + + pub fn snapshots(&self) -> &[SnapshotRef<'a>] { + &self.snapshot_lifetimes + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct DiagnosticResult { + pub output_kind: OutputKindV1, + pub value: f64, + pub calibration_band: u32, + pub out_of_distribution: bool, + pub payload: Vec, +} + +impl DiagnosticResult { + pub fn validate(self) -> Result { + if !self.value.is_finite() { + return Err(ProviderError::NonFiniteResult); + } + Ok(self) + } +} + +pub trait LearnedProvider { + fn infer(&self, invocation: &Invocation<'_>) -> Result; +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ProviderError { + InvalidBudget, + MissingSnapshots, + EmptySnapshot, + NonFiniteResult, + Abstained, + OutOfDistribution, + BudgetExceeded, + RuntimeFailure, +} + +#[cfg(test)] +mod tests { + use super::*; + + fn digest(value: u8) -> Digest32 { + Digest32 { bytes: [value; 32] } + } + + #[test] + fn builds_identity_bound_query_without_copying_payload() { + let payload = [1_u8, 2, 3, 4]; + let invocation = Invocation::new( + InvocationIdentity { + declaration: digest(1), + model: digest(2), + calibration: digest(3), + query: digest(4), + }, + ResourceBudget { + wall_time_ns: 1_000_000, + operation_limit: 10_000, + memory_bytes: 1_048_576, + }, + vec![SnapshotRef { + schema_version: 1, + identity: digest(5), + feature_extractor_identity: digest(6), + payload: &payload, + }], + ); + let invocation = match invocation { + Ok(value) => value, + Err(error) => panic!("expected valid invocation, got {error:?}"), + }; + let raw = invocation.as_raw(); + assert_eq!(raw.abi_version, ABI_VERSION_V1); + assert_eq!(raw.snapshot_count, 1); + assert_eq!(invocation.snapshots()[0].payload.as_ptr(), payload.as_ptr()); + } + + #[test] + fn rejects_unbounded_or_empty_invocations() { + let result = Invocation::new( + InvocationIdentity { + declaration: digest(1), + model: digest(2), + calibration: digest(3), + query: digest(4), + }, + ResourceBudget { + wall_time_ns: 0, + operation_limit: 1, + memory_bytes: 1, + }, + Vec::new(), + ); + assert_eq!(result.err(), Some(ProviderError::InvalidBudget)); + } +} From 673bbf2cf4fc3b8e5d7f558627e039ed568bf0d3 Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:13:04 -0800 Subject: [PATCH 07/20] Add provider host crate manifest --- crates/mnel-provider-host/Cargo.toml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 crates/mnel-provider-host/Cargo.toml diff --git a/crates/mnel-provider-host/Cargo.toml b/crates/mnel-provider-host/Cargo.toml new file mode 100644 index 0000000..2f1db7b --- /dev/null +++ b/crates/mnel-provider-host/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "mnel-provider-host" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true +description = "Persistent policy host for MNEL learned micro-providers" + +[dependencies] +mnel-provider-api = { path = "../mnel-provider-api" } + +[lints] +workspace = true From a3fb64cbb7e3c4eb0b2d2c2bc15db2d0f427db7a Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:13:25 -0800 Subject: [PATCH 08/20] Enforce provider runtime admission policy --- crates/mnel-provider-host/src/lib.rs | 223 +++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 crates/mnel-provider-host/src/lib.rs diff --git a/crates/mnel-provider-host/src/lib.rs b/crates/mnel-provider-host/src/lib.rs new file mode 100644 index 0000000..966978b --- /dev/null +++ b/crates/mnel-provider-host/src/lib.rs @@ -0,0 +1,223 @@ +//! Runtime admission policy and reusable snapshot storage for learned providers. +//! +//! Dynamic loading is deliberately deferred. This crate establishes the policy and +//! in-memory contracts that any loader must obey. + +use std::collections::BTreeMap; +use std::sync::Arc; + +use mnel_provider_api::{Digest32, ABI_VERSION_V1}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ImplementationLanguage { + Rust, + C, + Cpp, + Zig, + Wasm, + Python, + Other, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ExecutionTier { + NativeTrusted, + WasmQuarantined, + ExternalExperimental, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct NativeLanguageException { + pub rationale: String, + pub benchmark_evidence_ids: Vec, + pub threat_review_id: String, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ProviderManifest { + pub provider_id: String, + pub provider_version: String, + pub declaration_identity: Digest32, + pub artifact_identity: Digest32, + pub language: ImplementationLanguage, + pub tier: ExecutionTier, + pub abi_version: u32, + pub persistent_host: bool, + pub language_exception: Option, +} + +impl ProviderManifest { + pub fn validate(&self) -> Result<(), AdmissionError> { + if self.provider_id.trim().is_empty() || self.provider_version.trim().is_empty() { + return Err(AdmissionError::MissingIdentity); + } + if self.abi_version != ABI_VERSION_V1 { + return Err(AdmissionError::UnsupportedAbi); + } + if !self.persistent_host { + return Err(AdmissionError::ProcessPerInvocationForbidden); + } + match self.tier { + ExecutionTier::NativeTrusted => { + if self.language != ImplementationLanguage::Rust { + let exception = self + .language_exception + .as_ref() + .ok_or(AdmissionError::NonRustNativeRequiresException)?; + if exception.rationale.trim().is_empty() + || exception.benchmark_evidence_ids.is_empty() + || exception.threat_review_id.trim().is_empty() + { + return Err(AdmissionError::IncompleteLanguageException); + } + } + } + ExecutionTier::WasmQuarantined => { + if self.language != ImplementationLanguage::Wasm { + return Err(AdmissionError::TierLanguageMismatch); + } + } + ExecutionTier::ExternalExperimental => { + if self.language == ImplementationLanguage::Rust + && self.language_exception.is_some() + { + return Err(AdmissionError::UnnecessaryLanguageException); + } + } + } + Ok(()) + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum AdmissionError { + MissingIdentity, + UnsupportedAbi, + ProcessPerInvocationForbidden, + NonRustNativeRequiresException, + IncompleteLanguageException, + TierLanguageMismatch, + UnnecessaryLanguageException, + DuplicateProvider, +} + +#[derive(Clone, Debug)] +pub struct CachedSnapshot { + pub identity: Digest32, + pub feature_extractor_identity: Digest32, + pub payload: Arc<[u8]>, +} + +#[derive(Default)] +pub struct SnapshotCache { + entries: BTreeMap<[u8; 32], CachedSnapshot>, +} + +impl SnapshotCache { + pub fn insert(&mut self, snapshot: CachedSnapshot) -> Arc<[u8]> { + let key = snapshot.identity.bytes; + let payload = Arc::clone(&snapshot.payload); + self.entries.insert(key, snapshot); + payload + } + + pub fn get(&self, identity: &Digest32) -> Option<&CachedSnapshot> { + self.entries.get(&identity.bytes) + } + + pub fn len(&self) -> usize { + self.entries.len() + } + + pub fn is_empty(&self) -> bool { + self.entries.is_empty() + } +} + +#[derive(Default)] +pub struct ProviderCatalog { + manifests: BTreeMap, +} + +impl ProviderCatalog { + pub fn admit(&mut self, manifest: ProviderManifest) -> Result<(), AdmissionError> { + manifest.validate()?; + if self.manifests.contains_key(&manifest.provider_id) { + return Err(AdmissionError::DuplicateProvider); + } + self.manifests.insert(manifest.provider_id.clone(), manifest); + Ok(()) + } + + pub fn get(&self, provider_id: &str) -> Option<&ProviderManifest> { + self.manifests.get(provider_id) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn digest(value: u8) -> Digest32 { + Digest32 { bytes: [value; 32] } + } + + fn manifest(language: ImplementationLanguage, tier: ExecutionTier) -> ProviderManifest { + ProviderManifest { + provider_id: "state.hidden-markov-model".to_owned(), + provider_version: "0.1.0".to_owned(), + declaration_identity: digest(1), + artifact_identity: digest(2), + language, + tier, + abi_version: ABI_VERSION_V1, + persistent_host: true, + language_exception: None, + } + } + + #[test] + fn rust_is_the_native_default() { + assert_eq!( + manifest(ImplementationLanguage::Rust, ExecutionTier::NativeTrusted).validate(), + Ok(()) + ); + } + + #[test] + fn non_rust_native_requires_evidence_backed_exception() { + let mut candidate = manifest(ImplementationLanguage::Cpp, ExecutionTier::NativeTrusted); + assert_eq!( + candidate.validate(), + Err(AdmissionError::NonRustNativeRequiresException) + ); + candidate.language_exception = Some(NativeLanguageException { + rationale: "Specialized GPU kernel unavailable in Rust toolchain".to_owned(), + benchmark_evidence_ids: vec!["sha256:benchmark".to_owned()], + threat_review_id: "sha256:threat-review".to_owned(), + }); + assert_eq!(candidate.validate(), Ok(())); + } + + #[test] + fn python_cannot_enter_the_native_hot_path() { + let candidate = manifest(ImplementationLanguage::Python, ExecutionTier::NativeTrusted); + assert_eq!( + candidate.validate(), + Err(AdmissionError::NonRustNativeRequiresException) + ); + } + + #[test] + fn snapshot_payload_is_reused_by_arc() { + let payload: Arc<[u8]> = Arc::from([1_u8, 2, 3, 4]); + let mut cache = SnapshotCache::default(); + let returned = cache.insert(CachedSnapshot { + identity: digest(7), + feature_extractor_identity: digest(8), + payload: Arc::clone(&payload), + }); + assert!(Arc::ptr_eq(&payload, &returned)); + assert_eq!(cache.len(), 1); + } +} From a87bd90691a0ec837ad6a99a023c25681f43098f Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:13:41 -0800 Subject: [PATCH 09/20] Publish provider C ABI header --- include/mnel_provider_v1.h | 125 +++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 include/mnel_provider_v1.h diff --git a/include/mnel_provider_v1.h b/include/mnel_provider_v1.h new file mode 100644 index 0000000..acecf29 --- /dev/null +++ b/include/mnel_provider_v1.h @@ -0,0 +1,125 @@ +#ifndef MNEL_PROVIDER_V1_H +#define MNEL_PROVIDER_V1_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MNEL_PROVIDER_ABI_VERSION_V1 1u +#define MNEL_PROVIDER_ENTRY_SYMBOL_V1 "mnel_provider_entry_v1" +#define MNEL_AUTHORITY_DIAGNOSTIC_ONLY 1u +#define MNEL_VERDICT_SEMANTICS_NOT_A_VERDICT 1u + +typedef struct { + uint8_t bytes[32]; +} mnel_digest32; + +typedef struct { + const uint8_t *data; + size_t len; +} mnel_byte_view; + +typedef struct { + uint8_t *data; + size_t capacity; + size_t len; +} mnel_mutable_byte_buffer; + +typedef struct { + uint64_t wall_time_ns; + uint64_t operation_limit; + uint64_t memory_bytes; +} mnel_resource_budget_v1; + +typedef struct { + uint32_t schema_version; + uint32_t reserved; + mnel_digest32 snapshot_identity; + mnel_digest32 feature_extractor_identity; + mnel_byte_view payload; +} mnel_snapshot_view_v1; + +typedef struct { + uint32_t abi_version; + uint32_t reserved; + mnel_digest32 declaration_identity; + mnel_digest32 model_identity; + mnel_digest32 calibration_identity; + mnel_digest32 query_identity; + const mnel_snapshot_view_v1 *snapshots; + size_t snapshot_count; + mnel_resource_budget_v1 budget; +} mnel_provider_query_v1; + +typedef uint32_t mnel_provider_status_v1; +#define MNEL_PROVIDER_COMPLETED 0u +#define MNEL_PROVIDER_ABSTAINED 1u +#define MNEL_PROVIDER_INVALID_INPUT 2u +#define MNEL_PROVIDER_BUDGET_EXCEEDED 3u +#define MNEL_PROVIDER_OUT_OF_DISTRIBUTION 4u +#define MNEL_PROVIDER_RUNTIME_ERROR 5u + +typedef uint32_t mnel_output_kind_v1; +#define MNEL_OUTPUT_LATENT_DISCREPANCY 1u +#define MNEL_OUTPUT_STRUCTURAL_DISCREPANCY 2u +#define MNEL_OUTPUT_ANOMALY_SCORE 3u +#define MNEL_OUTPUT_PAIR_SIMILARITY 4u +#define MNEL_OUTPUT_NEXT_STATE_DISTRIBUTION 5u +#define MNEL_OUTPUT_FEATURE_CONTRIBUTIONS 6u +#define MNEL_OUTPUT_CANDIDATE_RANKING 7u + +#define MNEL_RESULT_OUT_OF_DISTRIBUTION (1ull << 0) +#define MNEL_RESULT_CALIBRATION_REQUIRED (1ull << 1) +#define MNEL_RESULT_TRUNCATED_PAYLOAD (1ull << 2) + +typedef struct { + uint32_t abi_version; + mnel_provider_status_v1 status; + mnel_output_kind_v1 output_kind; + uint32_t calibration_band; + double scalar_value; + uint64_t flags; + mnel_mutable_byte_buffer observation_payload; + uint32_t authority; + uint32_t verdict_semantics; +} mnel_provider_result_v1; + +struct mnel_provider_descriptor_v1; + +typedef int32_t (*mnel_provider_infer_v1)( + void *context, + const mnel_provider_query_v1 *query, + mnel_provider_result_v1 *result +); + +typedef struct mnel_provider_descriptor_v1 { + uint32_t abi_version; + uint32_t reserved; + mnel_byte_view provider_id; + mnel_byte_view provider_version; + mnel_digest32 declaration_identity; + void *implementation_context; + mnel_provider_infer_v1 infer; +} mnel_provider_descriptor_v1; + +typedef const mnel_provider_descriptor_v1 *(*mnel_provider_entry_v1)(void); + +/* + * Every shared provider library exposes: + * + * const mnel_provider_descriptor_v1 *mnel_provider_entry_v1(void); + * + * The descriptor and referenced identifier bytes must remain valid for the lifetime of + * the loaded library. The host owns query memory and the result payload buffer. + * Providers may return diagnostic output only; this ABI intentionally has no evaluator + * verdict, conformance, acceptance, or promotion field. + */ + +#ifdef __cplusplus +} +#endif + +#endif From 219e9f90b3057f828eeb500d1e67fc7c01e46a7d Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:14:02 -0800 Subject: [PATCH 10/20] Add Python runtime admission contract --- src/mnel/provider_runtime.py | 181 +++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 src/mnel/provider_runtime.py diff --git a/src/mnel/provider_runtime.py b/src/mnel/provider_runtime.py new file mode 100644 index 0000000..0533d66 --- /dev/null +++ b/src/mnel/provider_runtime.py @@ -0,0 +1,181 @@ +"""Runtime admission contract for diagnostic-only learned micro-providers. + +Python remains the orchestration, training, and research surface. The admitted native +hot path defaults to the versioned Rust host and C ABI defined by this repository. +""" + +from __future__ import annotations + +import json +from dataclasses import dataclass, field +from enum import Enum +from pathlib import Path +from typing import Any + +from .learned_providers import LearnedProviderDeclaration + +PROVIDER_ABI_V1 = "mnel-provider-c-abi/1" +RUNTIME_MANIFEST_SCHEMA = "mnel-learned-provider-runtime-manifest/0.1" + + +class ImplementationLanguage(str, Enum): + RUST = "rust" + C = "c" + CPP = "cpp" + ZIG = "zig" + WASM = "wasm" + PYTHON = "python" + OTHER = "other" + + +class ExecutionTier(str, Enum): + NATIVE_TRUSTED = "native-trusted" + WASM_QUARANTINED = "wasm-quarantined" + EXTERNAL_EXPERIMENTAL = "external-experimental" + + +@dataclass(frozen=True) +class NativeLanguageException: + rationale: str + benchmark_evidence_ids: tuple[str, ...] + threat_review_id: str + + def __post_init__(self) -> None: + if not self.rationale.strip(): + raise ValueError("language exception rationale must not be empty") + if not self.benchmark_evidence_ids or any( + not item.strip() for item in self.benchmark_evidence_ids + ): + raise ValueError("language exception requires benchmark evidence identities") + if not self.threat_review_id.strip(): + raise ValueError("language exception requires a threat review identity") + + def to_dict(self) -> dict[str, object]: + return { + "rationale": self.rationale, + "benchmark_evidence_ids": list(self.benchmark_evidence_ids), + "threat_review_id": self.threat_review_id, + } + + +@dataclass(frozen=True) +class ProviderRuntimeManifest: + provider_id: str + provider_version: str + declaration_identity: str + artifact_identity: str + implementation_language: ImplementationLanguage + execution_tier: ExecutionTier + abi: str = PROVIDER_ABI_V1 + persistent_host: bool = True + snapshot_transport: str = "identity-bound-compact-binary" + weight_residency: str = "resident-on-admission" + language_exception: NativeLanguageException | None = None + authority: str = field(default="diagnostic-only", init=False) + verdict_semantics: str = field(default="not-a-verdict", init=False) + + def __post_init__(self) -> None: + for name in ( + "provider_id", + "provider_version", + "declaration_identity", + "artifact_identity", + ): + if not getattr(self, name).strip(): + raise ValueError(f"{name} must not be empty") + if self.abi != PROVIDER_ABI_V1: + raise ValueError(f"unsupported provider ABI: {self.abi}") + if not self.persistent_host: + raise ValueError("process-per-invocation providers are forbidden") + if self.snapshot_transport != "identity-bound-compact-binary": + raise ValueError("hot-path snapshots must use identity-bound compact binary transport") + if self.weight_residency != "resident-on-admission": + raise ValueError("admitted provider weights must remain resident") + if self.execution_tier is ExecutionTier.NATIVE_TRUSTED: + if ( + self.implementation_language is not ImplementationLanguage.RUST + and self.language_exception is None + ): + raise ValueError("non-Rust native providers require an evidence-backed exception") + elif self.execution_tier is ExecutionTier.WASM_QUARANTINED: + if self.implementation_language is not ImplementationLanguage.WASM: + raise ValueError("wasm-quarantined tier requires a WASM provider") + elif self.language_exception is not None: + raise ValueError("language exceptions apply only to non-Rust native providers") + + def validate_declaration(self, declaration: LearnedProviderDeclaration) -> None: + if self.provider_id != declaration.provider_id: + raise ValueError("runtime manifest provider_id does not match declaration") + if self.provider_version != declaration.version: + raise ValueError("runtime manifest provider_version does not match declaration") + if self.declaration_identity != declaration.declaration_identity: + raise ValueError("runtime manifest declaration identity does not match declaration") + if declaration.evaluator_eligible or declaration.authority != "diagnostic-only": + raise ValueError("runtime cannot admit an evaluator-eligible learned provider") + + def to_dict(self) -> dict[str, object]: + value: dict[str, object] = { + "schema": RUNTIME_MANIFEST_SCHEMA, + "provider_id": self.provider_id, + "provider_version": self.provider_version, + "declaration_identity": self.declaration_identity, + "artifact_identity": self.artifact_identity, + "runtime": { + "implementation_language": self.implementation_language.value, + "execution_tier": self.execution_tier.value, + "abi": self.abi, + "persistent_host": self.persistent_host, + "snapshot_transport": self.snapshot_transport, + "weight_residency": self.weight_residency, + }, + "authority": self.authority, + "verdict_semantics": self.verdict_semantics, + } + if self.language_exception is not None: + value["language_exception"] = self.language_exception.to_dict() + return value + + @classmethod + def from_dict(cls, value: dict[str, Any]) -> "ProviderRuntimeManifest": + if value.get("schema") != RUNTIME_MANIFEST_SCHEMA: + raise ValueError("unsupported runtime manifest schema") + runtime = value.get("runtime") + if not isinstance(runtime, dict): + raise ValueError("runtime manifest requires a runtime object") + exception_value = value.get("language_exception") + exception = None + if exception_value is not None: + if not isinstance(exception_value, dict): + raise ValueError("language_exception must be an object") + exception = NativeLanguageException( + rationale=str(exception_value.get("rationale", "")), + benchmark_evidence_ids=tuple(exception_value.get("benchmark_evidence_ids", ())), + threat_review_id=str(exception_value.get("threat_review_id", "")), + ) + manifest = cls( + provider_id=str(value.get("provider_id", "")), + provider_version=str(value.get("provider_version", "")), + declaration_identity=str(value.get("declaration_identity", "")), + artifact_identity=str(value.get("artifact_identity", "")), + implementation_language=ImplementationLanguage( + runtime.get("implementation_language") + ), + execution_tier=ExecutionTier(runtime.get("execution_tier")), + abi=str(runtime.get("abi", "")), + persistent_host=bool(runtime.get("persistent_host", False)), + snapshot_transport=str(runtime.get("snapshot_transport", "")), + weight_residency=str(runtime.get("weight_residency", "")), + language_exception=exception, + ) + if value.get("authority") != manifest.authority: + raise ValueError("runtime manifest authority must be diagnostic-only") + if value.get("verdict_semantics") != manifest.verdict_semantics: + raise ValueError("runtime manifest verdict semantics must be not-a-verdict") + return manifest + + +def load_runtime_manifest(path: str | Path) -> ProviderRuntimeManifest: + value = json.loads(Path(path).read_text(encoding="utf-8")) + if not isinstance(value, dict): + raise ValueError("runtime manifest must be a JSON object") + return ProviderRuntimeManifest.from_dict(value) From 1a06f7636ac8d3b4ab175e3af369b3bb16ad7f1a Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:14:10 -0800 Subject: [PATCH 11/20] Export provider runtime policy --- src/mnel/__init__.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/mnel/__init__.py b/src/mnel/__init__.py index d476c54..24d0d22 100644 --- a/src/mnel/__init__.py +++ b/src/mnel/__init__.py @@ -14,18 +14,30 @@ LearnedProviderQuery, LearnedProviderRegistry, ) +from .provider_runtime import ( + ExecutionTier, + ImplementationLanguage, + NativeLanguageException, + ProviderRuntimeManifest, + load_runtime_manifest, +) __all__ = [ "DEFAULT_LEARNED_PROVIDER_REGISTRY", "EvidenceLedger", + "ExecutionTier", "HardGateEvaluator", + "ImplementationLanguage", "LearnedProviderDeclaration", "LearnedProviderObservation", "LearnedProviderQuery", "LearnedProviderRegistry", + "NativeLanguageException", + "ProviderRuntimeManifest", "RecursionGovernor", "VerifiedExperienceDistiller", "canonical_digest", + "load_runtime_manifest", ] __version__ = "0.1.0a0" From 778f91f4b31a93d07a08f18bf73832c6947656cf Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:14:27 -0800 Subject: [PATCH 12/20] Test provider runtime policy --- tests/test_provider_runtime.py | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/test_provider_runtime.py diff --git a/tests/test_provider_runtime.py b/tests/test_provider_runtime.py new file mode 100644 index 0000000..c081260 --- /dev/null +++ b/tests/test_provider_runtime.py @@ -0,0 +1,69 @@ +import json +import unittest +from pathlib import Path + +from mnel.learned_providers import DEFAULT_LEARNED_PROVIDER_REGISTRY +from mnel.provider_runtime import ( + ExecutionTier, + ImplementationLanguage, + NativeLanguageException, + ProviderRuntimeManifest, + load_runtime_manifest, +) + + +class ProviderRuntimePolicyTests(unittest.TestCase): + def setUp(self) -> None: + self.declaration = DEFAULT_LEARNED_PROVIDER_REGISTRY.describe( + "state.hidden-markov-model" + ) + + def manifest(self, **overrides: object) -> ProviderRuntimeManifest: + values: dict[str, object] = { + "provider_id": self.declaration.provider_id, + "provider_version": self.declaration.version, + "declaration_identity": self.declaration.declaration_identity, + "artifact_identity": "sha256:runtime-artifact", + "implementation_language": ImplementationLanguage.RUST, + "execution_tier": ExecutionTier.NATIVE_TRUSTED, + } + values.update(overrides) + return ProviderRuntimeManifest(**values) # type: ignore[arg-type] + + def test_rust_is_native_default(self) -> None: + manifest = self.manifest() + manifest.validate_declaration(self.declaration) + self.assertEqual(manifest.to_dict()["authority"], "diagnostic-only") + self.assertNotIn("verdict", manifest.to_dict()) + + def test_python_is_rejected_from_native_hot_path(self) -> None: + with self.assertRaisesRegex(ValueError, "non-Rust native"): + self.manifest(implementation_language=ImplementationLanguage.PYTHON) + + def test_specialized_native_language_requires_exception_evidence(self) -> None: + manifest = self.manifest( + implementation_language=ImplementationLanguage.CPP, + language_exception=NativeLanguageException( + rationale="Specialized GPU kernel", + benchmark_evidence_ids=("sha256:benchmark",), + threat_review_id="sha256:threat-review", + ), + ) + self.assertEqual(manifest.execution_tier, ExecutionTier.NATIVE_TRUSTED) + + def test_example_manifest_round_trips(self) -> None: + path = Path("examples/learned-providers/runtime-manifest.json") + raw = json.loads(path.read_text(encoding="utf-8")) + raw["declaration_identity"] = self.declaration.declaration_identity + manifest = ProviderRuntimeManifest.from_dict(raw) + manifest.validate_declaration(self.declaration) + + def test_checked_in_manifest_loads(self) -> None: + manifest = load_runtime_manifest( + "examples/learned-providers/runtime-manifest.json" + ) + self.assertEqual(manifest.provider_id, "state.hidden-markov-model") + + +if __name__ == "__main__": + unittest.main() From 80a9bd4eec94f96ec508a79bf58cd81c1cc06cf0 Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:14:45 -0800 Subject: [PATCH 13/20] Add provider runtime manifest schema --- ...rned-provider-runtime-manifest.schema.json | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 schemas/learned-provider-runtime-manifest.schema.json diff --git a/schemas/learned-provider-runtime-manifest.schema.json b/schemas/learned-provider-runtime-manifest.schema.json new file mode 100644 index 0000000..e02521d --- /dev/null +++ b/schemas/learned-provider-runtime-manifest.schema.json @@ -0,0 +1,101 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/epi13/Machine-Native-Experimental-Learning/schemas/learned-provider-runtime-manifest.schema.json", + "title": "MNEL learned-provider runtime manifest", + "type": "object", + "additionalProperties": false, + "required": [ + "schema", + "provider_id", + "provider_version", + "declaration_identity", + "artifact_identity", + "runtime", + "authority", + "verdict_semantics" + ], + "properties": { + "schema": {"const": "mnel-learned-provider-runtime-manifest/0.1"}, + "provider_id": { + "type": "string", + "pattern": "^[a-z0-9]+(?:[.-][a-z0-9]+)*$" + }, + "provider_version": {"type": "string", "minLength": 1}, + "declaration_identity": {"type": "string", "minLength": 1}, + "artifact_identity": {"type": "string", "minLength": 1}, + "runtime": { + "type": "object", + "additionalProperties": false, + "required": [ + "implementation_language", + "execution_tier", + "abi", + "persistent_host", + "snapshot_transport", + "weight_residency" + ], + "properties": { + "implementation_language": { + "enum": ["rust", "c", "cpp", "zig", "wasm", "python", "other"] + }, + "execution_tier": { + "enum": ["native-trusted", "wasm-quarantined", "external-experimental"] + }, + "abi": {"const": "mnel-provider-c-abi/1"}, + "persistent_host": {"const": true}, + "snapshot_transport": {"const": "identity-bound-compact-binary"}, + "weight_residency": {"const": "resident-on-admission"} + } + }, + "language_exception": { + "type": "object", + "additionalProperties": false, + "required": ["rationale", "benchmark_evidence_ids", "threat_review_id"], + "properties": { + "rationale": {"type": "string", "minLength": 1}, + "benchmark_evidence_ids": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": {"type": "string", "minLength": 1} + }, + "threat_review_id": {"type": "string", "minLength": 1} + } + }, + "authority": {"const": "diagnostic-only"}, + "verdict_semantics": {"const": "not-a-verdict"} + }, + "allOf": [ + { + "if": { + "properties": { + "runtime": { + "properties": { + "execution_tier": {"const": "native-trusted"}, + "implementation_language": {"not": {"const": "rust"}} + }, + "required": ["execution_tier", "implementation_language"] + } + } + }, + "then": {"required": ["language_exception"]} + }, + { + "if": { + "properties": { + "runtime": { + "properties": {"execution_tier": {"const": "wasm-quarantined"}}, + "required": ["execution_tier"] + } + } + }, + "then": { + "properties": { + "runtime": { + "properties": {"implementation_language": {"const": "wasm"}} + } + } + } + } + ] +} From a7ac4336c787b010330233f72bfd59f83adcad3b Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:14:53 -0800 Subject: [PATCH 14/20] Add provider runtime manifest example --- .../learned-providers/runtime-manifest.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 examples/learned-providers/runtime-manifest.json diff --git a/examples/learned-providers/runtime-manifest.json b/examples/learned-providers/runtime-manifest.json new file mode 100644 index 0000000..8cb1d85 --- /dev/null +++ b/examples/learned-providers/runtime-manifest.json @@ -0,0 +1,17 @@ +{ + "schema": "mnel-learned-provider-runtime-manifest/0.1", + "provider_id": "state.hidden-markov-model", + "provider_version": "0.1.0", + "declaration_identity": "sha256:bind-to-canonical-declaration-before-admission", + "artifact_identity": "sha256:bind-to-built-provider-artifact-before-admission", + "runtime": { + "implementation_language": "rust", + "execution_tier": "native-trusted", + "abi": "mnel-provider-c-abi/1", + "persistent_host": true, + "snapshot_transport": "identity-bound-compact-binary", + "weight_residency": "resident-on-admission" + }, + "authority": "diagnostic-only", + "verdict_semantics": "not-a-verdict" +} From 426921db10fba7e633d24750aa96f30db2eee2f3 Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:15:09 -0800 Subject: [PATCH 15/20] Record Rust provider runtime decision --- docs/decisions/0001-rust-provider-runtime.md | 119 +++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 docs/decisions/0001-rust-provider-runtime.md diff --git a/docs/decisions/0001-rust-provider-runtime.md b/docs/decisions/0001-rust-provider-runtime.md new file mode 100644 index 0000000..b2fd2cf --- /dev/null +++ b/docs/decisions/0001-rust-provider-runtime.md @@ -0,0 +1,119 @@ +# ADR 0001: Rust-first learned micro-provider runtime + +- **Status:** Accepted +- **Date:** 2026-08-04 +- **Scope:** MNEL learned micro-providers and the MNCS project-family runtime boundary + +## Context + +Learned micro-providers are intended to be small, frequently invoked diagnostic models. +Their usefulness depends on low warm latency, predictable resource use, cheap reuse of +Forge-produced snapshots, and strict preservation of the `diagnostic-only` authority +boundary. A provider invocation also has to bind its declaration, model artifact, +feature extractor, calibration, query, snapshots, and resource budget. + +Python is the correct research and orchestration environment for training, calibration, +data preparation, and architecture experiments. It is not the default per-invocation +hot path because interpreter startup, serialization, garbage collection, process +management, and repeated model loading can dominate the arithmetic of a micro-provider. + +C and C++ can provide maximum control but make memory safety, concurrency, dependency +isolation, and provider lifecycle enforcement more difficult. A Rust-only ABI would tie +the project to compiler-specific Rust ABI details and make specialized kernels or future +third-party providers unnecessarily difficult to integrate. + +## Decision + +MNEL adopts the following implementation policy: + +1. **Rust is the reference and default production language** for the persistent provider + host, provider SDK, runtime policy, snapshot cache, dispatch, budget enforcement, and + CPU-first learned micro-providers. +2. **Python remains the research, training, calibration, export, admission-study, and + high-level MNEL orchestration language.** Python is not admitted into the trusted + native per-invocation hot path. +3. **The stable cross-language boundary is a versioned C ABI**, beginning with + `mnel-provider-c-abi/1` and the symbol `mnel_provider_entry_v1`. +4. **Native providers are persistent and weight-resident.** Starting a process or loading + weights for each invocation is forbidden for admitted providers. +5. **Hot-path snapshots use identity-bound compact binary views.** Canonical JSON remains + appropriate for durable records, manifests, and ledgers, but not as the required + internal inference representation. +6. **Rust is required for the `native-trusted` tier by default.** C, C++, Zig, or another + native language requires an explicit exception containing benchmark evidence and a + threat-review identity. Specialized GPU or vendor kernels may qualify. +7. **WASM is the quarantine and portability tier** for experimental, third-party, or + less-trusted providers when its isolation benefit exceeds its overhead. +8. **Learned provider output remains diagnostic-only.** The ABI and manifest vocabulary + contain no evaluator verdict, conformance, acceptance, or promotion authority. + +The concise policy is: + +> Train and study in Python; host, dispatch, and implement the default hot path in Rust; +> interoperate through a versioned C ABI; admit exceptions only through evidence. + +## Enforcement + +This decision is enforced by repository artifacts rather than prose alone: + +- `Cargo.toml` defines the Rust provider workspace. +- `mnel-provider-api` defines allocation-neutral ABI vocabulary. +- `mnel-provider-sdk` provides a safe Rust authoring surface. +- `mnel-provider-host` encodes native-language admission policy and snapshot reuse. +- `include/mnel_provider_v1.h` is the language-neutral ABI header. +- `ProviderRuntimeManifest` mirrors the admission contract in the Python control plane. +- `learned-provider-runtime-manifest.schema.json` makes the durable manifest testable. +- CI runs Rust formatting, linting, and tests alongside the Python suite. + +A future loader may not weaken these requirements. It must reject unsupported ABI +versions, missing identities, unbounded queries, process-per-invocation providers, +invalid tier/language combinations, or attempts to grant learned output evaluator +semantics. + +## Performance requirements + +Provider studies must report at least: + +- snapshot construction time separately from inference time; +- warm p50, p95, and p99 invocation latency; +- cold admission and weight-load time; +- bytes copied per invocation; +- peak and resident memory; +- batching behavior and queue delay; +- useful confirmed Forge probes per unit of compute; +- abstention and out-of-distribution behavior; and +- comparison against deterministic or classical baselines under equal budgets. + +A faster model that requires materially more snapshot construction or copying is not +presumed to be the faster provider system. + +## Consequences + +### Positive + +- Native performance with stronger memory and concurrency safety than a C/C++ default. +- One provider contract across Rust, specialized native kernels, WASM, and future hosts. +- Lower startup and serialization overhead through a persistent resident runtime. +- A testable exception process rather than informal language drift. +- Alignment with the existing Rust direction in MNCS language and validator projects. + +### Costs + +- The repository becomes a mixed Python/Rust project. +- Training exports and runtime artifacts need explicit compatibility testing. +- FFI versioning and buffer ownership require careful discipline. +- Some model runtimes may still require C++ or vendor libraries behind the ABI. + +## Non-goals + +This decision does not select a neural inference engine, serialization library, GPU +stack, dynamic loader, or model format. It does not claim that every Rust implementation +is faster than every C++ implementation. It establishes the default ownership and +contract boundary so those choices can be measured without changing MNEL authority. + +## Reconsideration + +The decision may be revisited only with repository-recorded evidence showing that a +replacement preserves the ABI and authority guarantees while materially improving +cost-per-useful-probe across representative providers and hardware. Convenience alone +is not sufficient. From 8447e9b27d02c628d9ccb9e8c66287ff3f3103de Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:15:27 -0800 Subject: [PATCH 16/20] Document learned provider runtime contract --- docs/LEARNED_PROVIDER_RUNTIME.md | 144 +++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 docs/LEARNED_PROVIDER_RUNTIME.md diff --git a/docs/LEARNED_PROVIDER_RUNTIME.md b/docs/LEARNED_PROVIDER_RUNTIME.md new file mode 100644 index 0000000..9585044 --- /dev/null +++ b/docs/LEARNED_PROVIDER_RUNTIME.md @@ -0,0 +1,144 @@ +# Learned micro-provider runtime + +This document defines the implementation and execution contract for the learned +micro-provider registry. The architecture decision is recorded in +[ADR 0001](decisions/0001-rust-provider-runtime.md). + +## Runtime planes + +```text +Python research and training + | + | export identified model, calibration, and feature contracts + v +Python MNEL control plane + | + | validate declaration + runtime manifest + budget + v +persistent Rust provider host + | + | identity-bound borrowed snapshot views + v +Rust provider / native kernel / quarantined WASM provider + | + | diagnostic value, calibration, OOD state, bounded payload + v +MNEL diagnostic observation + | + v +investigator proposes a bounded Forge question +``` + +The provider host does not evaluate MNEL gates and cannot promote an observation into a +verdict. Its job is admission, dispatch, bounded execution, normalization, and +measurement. + +## Language and execution tiers + +| Tier | Default language | Purpose | Admission rule | +|---|---|---|---| +| `native-trusted` | Rust | Warm production hot path | Non-Rust requires benchmark and threat-review exception | +| `wasm-quarantined` | WASM | Portable or less-trusted provider | Capability-limited and measured against native overhead | +| `external-experimental` | Python or other | Training, prototyping, admission studies | Never treated as the production latency baseline | + +A provider's training language does not determine its runtime tier. A model may be +trained in Python and exported to a Rust-hosted native runtime. + +## Versioned C ABI + +The v1 contract is defined twice from the same conceptual vocabulary: + +- Rust: `crates/mnel-provider-api/src/lib.rs` +- C: `include/mnel_provider_v1.h` + +The public entry symbol is: + +```c +const mnel_provider_descriptor_v1 *mnel_provider_entry_v1(void); +``` + +The descriptor remains valid for the lifetime of the loaded provider. The host owns +query memory and the result payload buffer. Providers must not retain borrowed snapshot +pointers after returning. + +The ABI binds every invocation to: + +- provider declaration identity; +- model or weight identity; +- calibration identity; +- query identity; +- one or more snapshot identities; +- feature-extractor identities; and +- wall-time, operation, and memory budgets. + +## Result semantics + +A provider may complete, abstain, report invalid input, exceed a budget, identify an +out-of-distribution input, or fail at runtime. Those are runtime statuses, not evaluator +verdicts. + +The normalized result contains: + +- one declared output kind; +- a finite scalar when applicable; +- a calibration-band identifier; +- flags such as out-of-distribution or truncated payload; and +- an optional bounded host-owned payload. + +Every result is stamped with `diagnostic-only` authority and `not-a-verdict` semantics. +No ABI field may represent PASS, FAIL, conformance, causal truth, acceptance, or +promotion. + +## Persistent host requirements + +An admitted host must: + +1. validate the runtime manifest against the canonical provider declaration; +2. verify all material artifact identities before admission; +3. load weights once and keep them resident while admitted; +4. reuse immutable snapshot payloads across compatible providers; +5. avoid JSON parsing and process startup in the normal invocation path; +6. enforce time, operation, memory, and output-payload limits; +7. preserve provider-specific observations rather than voting them into one answer; +8. record warm and cold performance separately; and +9. unload or quarantine a provider after integrity, calibration, or budget failures. + +The initial Rust host crate establishes admission policy and reusable snapshot storage. +Dynamic loading, operating-system sandboxing, and model-runtime selection remain future +implementation work. + +## Snapshot transport + +Forge or another identified producer should construct an AST, graph, trace, transition, +pair, tabular, or composite snapshot once. Compatible providers consume borrowed views +of that immutable payload. + +The durable ledger may describe the snapshot with canonical JSON, but the hot path uses +compact binary bytes with explicit schema and feature-extractor identities. Any material +change to source, dependency, extractor, normalization, toolchain, or environment +invalidates reuse unless the dependency envelope proves the snapshot unaffected. + +## Native-language exceptions + +A non-Rust provider may enter `native-trusted` only when its manifest includes: + +- a concrete technical rationale; +- identities for equal-budget benchmark evidence; and +- an identity for the relevant threat and ownership review. + +Typical candidates are vendor inference engines, CUDA kernels, or specialized libraries +without an adequate Rust implementation. The exception applies to one identified +artifact and does not establish a general language preference. + +## Delivery sequence + +1. Freeze and test the v1 manifest and ABI vocabulary. +2. Implement a process-local Rust reference provider for a classical baseline. +3. Add the persistent loader and host-owned output buffer enforcement. +4. Add Forge snapshot producers and reuse measurements. +5. Export one Python-trained neural provider and compare it with the baseline. +6. Add WASM quarantine only after native measurements establish the overhead budget. +7. Integrate Fabric placement after single-host identity and replay behavior is stable. + +Each stage must preserve the current diagnostic authority boundary and may terminate in +`UNKNOWN` rather than silently widening capability. From 86c8b2ae0c0ff5bc7167faa9ea338deb76e2a63a Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:15:59 -0800 Subject: [PATCH 17/20] Document Rust-first provider runtime --- README.md | 53 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 414a8bb..686621d 100644 --- a/README.md +++ b/README.md @@ -40,10 +40,9 @@ conventional neural-weight training. > **Current status:** functional `0.1.0a0` foundation. The repository implements the > core local lifecycle, deterministic evidence ledger, hard-gate evaluator, recursion > governor, investigator contracts, a diagnostic-only learned micro-provider registry, -> distillation proposal checks, reference adapters, command-line interface, schemas, -> tests, and CI. It does not yet train or execute learned micro-providers, provide -> unattended model execution, distributed scheduling, protected final custody, formal -> MNCS/MNCDS conformance, or automatic RAVEL promotion. +> and a testable Rust-first provider runtime contract. It does not yet train or execute +> learned micro-providers, provide unattended model execution, distributed scheduling, +> protected final custody, formal MNCS/MNCDS conformance, or automatic RAVEL promotion. ## Core rule @@ -84,6 +83,9 @@ copy their authority or silently create substitute implementations. - typed learned micro-provider declarations and diagnostic observations; - deterministic capability matching, cost filtering, and diversity-aware selection; - an initial 12-family architecture catalog with declared advantages and limitations; +- accepted Rust-first runtime architecture decision and versioned C ABI; +- safe Rust provider SDK, host admission policy, reusable snapshot cache, and runtime + manifest validation; - deterministic reference workflow, JSON schemas, mutation-oriented tests, and CI. ## Install @@ -94,8 +96,9 @@ source .venv/bin/activate python -m pip install -e . ``` -MNEL currently requires Python 3.11 or newer and has no runtime dependencies outside -the standard library. +MNEL currently requires Python 3.11 or newer and has no Python runtime dependencies +outside the standard library. Building the provider runtime contracts additionally +requires Rust 1.79 or newer. ## Quick start @@ -181,6 +184,23 @@ investigator decide which bounded Forge question to ask next. See [Learned micro-provider registry](docs/LEARNED_MICRO_PROVIDERS.md). +## Provider runtime implementation policy + +Rust is the reference and default production language for the persistent provider host, +provider SDK, dispatch, budget enforcement, snapshot reuse, and CPU-first provider +implementations. Python remains the training, calibration, experimentation, export, and +high-level orchestration language. + +The stable cross-language boundary is `mnel-provider-c-abi/1`. Native-trusted providers +must be Rust unless an identified benchmark and threat review justify a specialized +non-Rust implementation. WASM is reserved as a quarantine and portability tier. +Admitted providers are persistent, weight-resident, and consume identity-bound compact +binary snapshot views; process startup and JSON parsing are not part of the normal hot +path. + +See [ADR 0001](docs/decisions/0001-rust-provider-runtime.md) and the +[learned-provider runtime contract](docs/LEARNED_PROVIDER_RUNTIME.md). + ## Investigator roles - **Investigator** — proposes falsifiable hypotheses and bounded interventions. @@ -216,13 +236,17 @@ state, and failure modes. ## Repository map ```text -src/mnel/ executable standard-library foundation +src/mnel/ Python control plane and executable foundation +crates/mnel-provider-api/ versioned provider ABI vocabulary +crates/mnel-provider-sdk/ safe Rust provider authoring surface +crates/mnel-provider-host/ admission policy and reusable snapshot storage +include/ language-neutral provider ABI header schemas/ machine-readable record vocabulary -docs/ architecture, method, boundaries, and roadmap +docs/ architecture, decisions, method, boundaries, roadmap examples/reference-study/ deterministic lifecycle example -examples/learned-providers/ initial architecture catalog summary -tests/ lifecycle, integrity, registry, and negative tests -.github/workflows/ continuous verification +examples/learned-providers/ architecture catalog and runtime manifest example +tests/ lifecycle, integrity, registry, runtime, negative tests +.github/workflows/ Python and Rust continuous verification ``` ## Run the checks @@ -233,6 +257,9 @@ python -m unittest discover -s tests -v python -m mnel learned-provider list python -m mnel demo --workspace build/demo python -m mnel ledger verify build/demo/evidence.jsonl +cargo fmt --all --check +cargo clippy --workspace --all-targets -- -D warnings +cargo test --workspace ``` ## Safety and claim boundary @@ -242,6 +269,9 @@ operating-system sandbox. Untrusted experiment execution belongs in a hardened r with network restrictions, resource controls, immutable verifiers, and disposable workspaces. +The provider runtime crates establish contracts and admission policy; they do not yet +implement a hardened dynamic loader or operating-system sandbox. + A local MNEL result or learned-provider observation can describe bounded development context. It cannot by itself establish independent evaluation, protected custody, real-world safety, general recursive self-improvement, formal MNCS/MNCDS status, @@ -249,4 +279,5 @@ certification, or promotion. See [Architecture](docs/ARCHITECTURE.md), [Learning model](docs/LEARNING_MODEL.md), [Learned micro-providers](docs/LEARNED_MICRO_PROVIDERS.md), +[learned-provider runtime](docs/LEARNED_PROVIDER_RUNTIME.md), [Threat model](docs/THREAT_MODEL.md), and [Roadmap](docs/ROADMAP.md). From 690f929b6cb866027378a1710bc2780ee7ec7edf Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:16:17 -0800 Subject: [PATCH 18/20] Roadmap provider runtime delivery --- docs/ROADMAP.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index fa4ccc7..e31ab50 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -11,17 +11,24 @@ - diagnostic-only learned micro-provider declaration registry; - deterministic compatibility matching and diversity selection; - learned-provider schema, architecture catalog, CLI inspection, and negative tests; +- accepted Rust-first provider-runtime architecture decision; +- versioned provider C ABI, safe Rust SDK, host admission policy, manifest schema, and + Python control-plane contract; - schema, reference study, tests, CI, and documentation. -## 0.2 — local investigator harness +## 0.2 — local investigator harness and provider runtime -- native adapter to `epi13-local-harness`; +- native adapter to `MNEL-local-harness`; - eligible-context retrieval and packing; - investigator portfolio scheduling; - explicit read-only and proposal workspaces; - Git worktree or snapshot-isolated candidate transactions; - model, quantization, runtime, prompt, and tool-schema identities; -- deterministic morning reports and quarantine queues. +- deterministic morning reports and quarantine queues; +- process-local persistent Rust provider host; +- host-owned bounded result buffers and ABI loader validation; +- first native Rust classical provider baseline; +- warm/cold latency, copy-byte, resident-memory, and snapshot-reuse benchmarks. ## 0.3 — Forge experiment lifecycle @@ -33,6 +40,7 @@ - skeptic-driven omitted-question discovery; - identity-bound graph, trace, transition, tabular, pair, and composite diagnostic snapshots suitable for both deterministic probes and learned micro-providers; +- compact binary snapshot views shared across compatible providers; - learned observations normalized as diagnostic events without verifier status. ## 0.4 — verified distillation and learned-provider studies @@ -43,10 +51,12 @@ - shuffled-attribution and aggregate-only controls; - strategy retrieval and calibration metrics; - train and calibrate the initial heterogeneous learned-provider portfolio; +- export Python-trained providers into the versioned native runtime boundary; - compare every learned provider against deterministic and classical baselines; - random, heuristic, single-provider, and diversity-routed controls; - correlated-error, disagreement, abstention, and out-of-distribution studies; - useful confirmed probes per operation, latency, memory, energy, and cold-start metrics; +- non-Rust native exception studies with benchmark and threat-review identities; - hidden-transfer admission, quarantine, retirement, and rollback workflows; - optional small proposer-model distillation from verified traces. @@ -58,7 +68,8 @@ - replicated and sharded trial matrices; - node-loss, stale-result, duplicate, and replay handling; - deterministic reconciliation and scaling measurements; -- heterogeneous learned-provider placement by snapshot locality and node capability. +- heterogeneous learned-provider placement by snapshot locality and node capability; +- ABI compatibility and provider-artifact admission across Fabric nodes. ## 0.6 — RAVEL integration study From 7e066e64b55084c3a5b01a1926027377894ee93d Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:16:25 -0800 Subject: [PATCH 19/20] Record provider runtime architecture --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a7cd16..e38b0da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,4 +16,13 @@ boosted-tree, hidden-state, and reservoir architectures. - Add learned-provider CLI inspection, JSON schema, catalog example, architecture and roadmap documentation, and negative tests. +- Establish Rust as the default production language for learned micro-provider hosting, + dispatch, SDKs, and CPU-first provider implementations while retaining Python for + training, calibration, experimentation, and high-level orchestration. +- Add accepted ADR 0001, the learned-provider runtime specification, and an explicit + evidence-backed exception path for specialized non-Rust native implementations. +- Add a versioned allocation-neutral C ABI, matching public header, safe Rust SDK, + persistent-host admission policy, reusable snapshot cache, and runtime manifest schema. +- Add Python runtime-manifest validation, a checked-in example, negative tests, and Rust + formatting, Clippy, and test jobs in CI. - Add schema, deterministic reference workflow, tests, CI, documentation, and roadmap. From d3980d920072943ac40cc90b6d18a0fbb63b5905 Mon Sep 17 00:00:00 2001 From: epi13 Date: Tue, 4 Aug 2026 13:16:33 -0800 Subject: [PATCH 20/20] Test Rust provider runtime in CI --- .github/workflows/ci.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c769587..f8634fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ permissions: contents: read jobs: - test: + python: strategy: matrix: python-version: ["3.11", "3.12", "3.13"] @@ -24,3 +24,15 @@ jobs: - run: python -m mnel demo --workspace build/demo - run: python -m mnel ledger verify build/demo/evidence.jsonl - run: git diff --check + + rust-provider-runtime: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@1.79.0 + with: + components: rustfmt, clippy + - run: cargo fmt --all --check + - run: cargo clippy --workspace --all-targets -- -D warnings + - run: cargo test --workspace + - run: git diff --check