bijux-dag-runtime 0.4.0

Execution engine, replay semantics, and runtime policy layer for Bijux DAG graphs.
Documentation
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PluginBoundaryKind {
    TaskAdapter,
    ExecutorBackend,
    ArtifactStore,
    ObservabilitySink,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CapabilityRange {
    pub min_contract_version: String,
    pub max_contract_version: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PluginMetadata {
    pub name: String,
    pub version: String,
    pub boundary: PluginBoundaryKind,
    pub capabilities: Vec<String>,
    pub policy_requirements: Vec<String>,
    pub compatibility: CapabilityRange,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PluginLoadingMode {
    StaticLinking,
    DynamicLoadingDeferred,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ExtensionRegistration {
    pub plugin_name: String,
    pub plugin_version: String,
    pub boundary: PluginBoundaryKind,
    pub registered_unix_ms: u128,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ExtensionDescriptor {
    pub plugin_name: String,
    pub plugin_version: String,
    pub boundary: PluginBoundaryKind,
    pub contract_version: String,
    pub capabilities: Vec<String>,
    pub trust_model: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ExtensionCompatibilityIssue {
    pub plugin_name: String,
    pub reason: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ExtensionStabilityLevel {
    InternalHook,
    Experimental,
    Stable,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ExtensionPointStatus {
    pub extension_point: String,
    pub stability: ExtensionStabilityLevel,
    pub owner: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct InternalHookPromotionChecklist {
    pub hook_name: String,
    pub has_contract_doc: bool,
    pub has_versioning_policy: bool,
    pub has_negative_tests: bool,
    pub has_failure_isolation: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PluginTrustPolicy {
    pub require_signature: bool,
    pub allowlisted_publishers: Vec<String>,
    pub allowed_environments: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PluginIsolationPolicy {
    pub deny_undeclared_effects: bool,
    pub require_deterministic_mode: bool,
    pub enforce_resource_caps: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PluginConformanceSuiteResult {
    pub plugin_name: String,
    pub boundary: PluginBoundaryKind,
    pub passed: bool,
    pub failures: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PluginLifecycleState {
    Develop,
    Register,
    Validate,
    Release,
    Deprecate,
    Remove,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct OfficialPluginPolicy {
    pub requires_core_team_review: bool,
    pub requires_security_assessment: bool,
    pub release_channel: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ExtensionDiscoveryRecord {
    pub plugin_name: String,
    pub boundary: PluginBoundaryKind,
    pub capabilities: Vec<String>,
    pub active: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DslExtensionPoint {
    pub node_family: String,
    pub contract_name: String,
    pub compile_time_validated: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CodeGenerationHook {
    pub hook_name: String,
    pub produces: Vec<String>,
    pub consumes: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ExtensionRoadmap {
    pub core_surface: Vec<String>,
    pub pluggable_surface: Vec<String>,
    pub intentionally_unsupported: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PlatformMaturityScorecard {
    pub engine_ready: u8,
    pub scheduler_ready: u8,
    pub artifacts_ready: u8,
    pub observability_ready: u8,
    pub api_ready: u8,
    pub infrastructure_ready: u8,
    pub extension_ready: u8,
}

pub fn negotiate_plugin_version(range: &CapabilityRange, requested_contract_version: &str) -> bool {
    requested_contract_version >= range.min_contract_version.as_str()
        && requested_contract_version <= range.max_contract_version.as_str()
}

pub fn validate_plugin_conformance(
    metadata: &PluginMetadata,
    trust: &PluginTrustPolicy,
    isolation: &PluginIsolationPolicy,
) -> PluginConformanceSuiteResult {
    let mut failures = Vec::new();
    if metadata.name.trim().is_empty() {
        failures.push("plugin name must not be empty".to_string());
    }
    if metadata.version.trim().is_empty() {
        failures.push("plugin version must not be empty".to_string());
    }
    if metadata.capabilities.is_empty() {
        failures.push("plugin must declare at least one capability".to_string());
    }
    if trust.require_signature && trust.allowlisted_publishers.is_empty() {
        failures.push("signature-required plugins need allowlisted publishers".to_string());
    }
    if isolation.require_deterministic_mode
        && !metadata.policy_requirements.iter().any(|r| r == "deterministic")
    {
        failures.push("plugin must require deterministic policy".to_string());
    }
    PluginConformanceSuiteResult {
        plugin_name: metadata.name.clone(),
        boundary: metadata.boundary.clone(),
        passed: failures.is_empty(),
        failures,
    }
}

pub fn extension_discovery_inventory(
    registrations: &[ExtensionRegistration],
) -> Vec<ExtensionDiscoveryRecord> {
    let mut out = registrations
        .iter()
        .map(|r| ExtensionDiscoveryRecord {
            plugin_name: r.plugin_name.clone(),
            boundary: r.boundary.clone(),
            capabilities: Vec::new(),
            active: true,
        })
        .collect::<Vec<_>>();
    out.sort_by(|a, b| a.plugin_name.cmp(&b.plugin_name));
    out
}

pub fn compute_platform_maturity(scores: &[u8]) -> u8 {
    if scores.is_empty() {
        return 0;
    }
    let total: u32 = scores.iter().map(|v| *v as u32).sum();
    (total / scores.len() as u32) as u8
}

pub fn validate_extension_descriptor(descriptor: &ExtensionDescriptor) -> Result<(), String> {
    if descriptor.plugin_name.trim().is_empty() {
        return Err("plugin_name must not be empty".to_string());
    }
    if descriptor.plugin_version.trim().is_empty() {
        return Err("plugin_version must not be empty".to_string());
    }
    if !descriptor.contract_version.starts_with('v') {
        return Err("contract_version must use v-prefixed format".to_string());
    }
    if descriptor.capabilities.is_empty() {
        return Err("descriptor must declare capabilities".to_string());
    }
    Ok(())
}

pub fn register_extension(
    registry: &mut BTreeMap<String, ExtensionDescriptor>,
    descriptor: ExtensionDescriptor,
) -> Result<(), String> {
    validate_extension_descriptor(&descriptor)?;
    if registry.contains_key(&descriptor.plugin_name) {
        return Err(format!("extension registration conflict for {}", descriptor.plugin_name));
    }
    registry.insert(descriptor.plugin_name.clone(), descriptor);
    Ok(())
}

pub fn detect_extension_compatibility_issues(
    descriptors: &[ExtensionDescriptor],
    supported_contract_versions: &BTreeSet<String>,
    required_capabilities: &BTreeSet<String>,
) -> Vec<ExtensionCompatibilityIssue> {
    let mut issues = Vec::new();
    for descriptor in descriptors {
        if !supported_contract_versions.contains(&descriptor.contract_version) {
            issues.push(ExtensionCompatibilityIssue {
                plugin_name: descriptor.plugin_name.clone(),
                reason: format!("unsupported contract version {}", descriptor.contract_version),
            });
        }
        for capability in required_capabilities {
            if !descriptor.capabilities.iter().any(|c| c == capability) {
                issues.push(ExtensionCompatibilityIssue {
                    plugin_name: descriptor.plugin_name.clone(),
                    reason: format!("missing required capability {}", capability),
                });
            }
        }
    }
    issues
}

pub fn extension_point_status_report() -> Vec<ExtensionPointStatus> {
    vec![
        ExtensionPointStatus {
            extension_point: "task_adapter".to_string(),
            stability: ExtensionStabilityLevel::Stable,
            owner: "runtime".to_string(),
        },
        ExtensionPointStatus {
            extension_point: "executor_backend".to_string(),
            stability: ExtensionStabilityLevel::Experimental,
            owner: "runtime".to_string(),
        },
        ExtensionPointStatus {
            extension_point: "validation_hook".to_string(),
            stability: ExtensionStabilityLevel::InternalHook,
            owner: "core".to_string(),
        },
    ]
}

pub fn internal_hook_ready_for_promotion(check: &InternalHookPromotionChecklist) -> bool {
    check.has_contract_doc
        && check.has_versioning_policy
        && check.has_negative_tests
        && check.has_failure_isolation
}

pub fn extension_failure_isolated(failure_scope: &str, engine_crashed: bool) -> bool {
    failure_scope == "extension_only" && !engine_crashed
}