ferrum-interfaces 0.12.2

Core trait contracts for the Ferrum LLM inference engine
Documentation
mod vnext_core_contract;

use vnext_core_contract::*;

#[test]
fn provider_implementation_fingerprint_is_plan_hashed_and_revalidated() {
    let fixture = plan_fixture(0);
    let original_hash = fixture.plan.plan_hash().as_str().to_owned();
    let mut value = serde_json::to_value(&fixture.plan).unwrap();
    assert_eq!(
        value["payload"]["nodes"][0]["provider_implementation_fingerprint"],
        json!(sha('f'))
    );
    value["payload"]["nodes"][0]["provider_implementation_fingerprint"] = json!(sha('0'));
    rehash_plan_json(&mut value);
    assert_ne!(value["plan_hash"], json!(original_hash));
    assert!(ExecutionPlan::from_json_validated(
        &serde_json::to_vec(&value).unwrap(),
        &fixture.family,
        &fixture.catalog,
        &fixture.policy,
        fixture.node_resolutions.clone(),
    )
    .is_err());
}

#[test]
fn provider_execution_semantics_are_plan_hashed_and_revalidated() {
    let fixture = plan_fixture(0);
    let original_hash = fixture.plan.plan_hash().as_str().to_owned();
    let mut value = serde_json::to_value(&fixture.plan).unwrap();
    assert_eq!(
        value["payload"]["nodes"][0]["provider_execution_semantics"],
        serde_json::to_value(ProviderExecutionSemantics::bitwise_eager_and_replay()).unwrap()
    );
    value["payload"]["nodes"][0]["provider_execution_semantics"] =
        serde_json::to_value(ProviderExecutionSemantics::bitwise_eager_only()).unwrap();
    rehash_plan_json(&mut value);
    assert_ne!(value["plan_hash"], json!(original_hash));
    assert!(ExecutionPlan::from_json_validated(
        &serde_json::to_vec(&value).unwrap(),
        &fixture.family,
        &fixture.catalog,
        &fixture.policy,
        fixture.node_resolutions.clone(),
    )
    .is_err());
}

#[test]
fn replay_requirement_rejects_eager_only_provider_with_typed_evidence() {
    let catalog = catalog_with_memory_and_execution_semantics(
        1 << 20,
        ProviderExecutionSemantics::bitwise_eager_only(),
    );
    let operation = catalog.operation(&id("operation.main")).unwrap();
    let report = catalog
        .provider_compatibility(
            ProviderCompatibilityRequest::new(
                operation.id.clone(),
                ContractVersion::new(1, 0),
                BTreeSet::new(),
                BTreeSet::from([id("weight-format.dense")]),
                BTreeSet::new(),
                ExecutionDeterminismRequirement::BitwiseSameRuntimeWithReplay,
            )
            .unwrap(),
        )
        .unwrap();

    assert!(report.compatible_provider_ids().is_empty());
    assert!(matches!(
        report.rejected()[0].reasons.as_slice(),
        [ProviderCompatibilityRejectReason::InsufficientExecutionDeterminism {
            required: ExecutionDeterminismRequirement::BitwiseSameRuntimeWithReplay,
            available,
        }] if *available == ProviderExecutionSemantics::bitwise_eager_only()
    ));
}

#[test]
fn provider_execution_semantics_fingerprint_is_self_validating() {
    let mut value =
        serde_json::to_value(ProviderExecutionSemantics::bitwise_eager_and_replay()).unwrap();
    value["contract_fingerprint"] = json!(sha('0'));
    assert!(serde_json::from_value::<ProviderExecutionSemantics>(value).is_err());
}

#[test]
fn planning_registry_missing_duplicate_and_mismatched_entries_fail_before_plan() {
    let family = TestRegistry::new().prepare();
    let catalog = catalog();
    let policy = policy(4096);

    let mut missing_contract =
        TestPlanningEntries::new(&catalog, 64, 32, EstimateBehavior::Correct);
    let missing_contract_calls = missing_contract.contract_calls.clone();
    let missing_estimator_calls = missing_contract.estimator_calls.clone();
    missing_contract.contracts.clear();
    assert!(missing_contract.build().is_err());
    assert_eq!(missing_contract_calls.load(Ordering::SeqCst), 0);
    assert_eq!(missing_estimator_calls.load(Ordering::SeqCst), 0);

    let mut duplicate_contract =
        TestPlanningEntries::new(&catalog, 64, 32, EstimateBehavior::Correct);
    let duplicate_contract_calls = duplicate_contract.contract_calls.clone();
    let duplicate_estimator_calls = duplicate_contract.estimator_calls.clone();
    duplicate_contract.contracts.push(TestOperationContract {
        descriptor: duplicate_contract.contracts[0].descriptor.clone(),
        calls: duplicate_contract_calls.clone(),
        reject_signature: false,
    });
    assert!(duplicate_contract.build().is_err());
    assert_eq!(duplicate_contract_calls.load(Ordering::SeqCst), 0);
    assert_eq!(duplicate_estimator_calls.load(Ordering::SeqCst), 0);

    let mut mismatched_contract =
        TestPlanningEntries::new(&catalog, 64, 32, EstimateBehavior::Correct);
    let mismatched_contract_calls = mismatched_contract.contract_calls.clone();
    let mismatched_estimator_calls = mismatched_contract.estimator_calls.clone();
    mismatched_contract.contracts[0].descriptor.version = ContractVersion::new(1, 1);
    assert!(mismatched_contract.build().is_err());
    assert_eq!(mismatched_contract_calls.load(Ordering::SeqCst), 0);
    assert_eq!(mismatched_estimator_calls.load(Ordering::SeqCst), 0);

    let mut rejecting_contract =
        TestPlanningEntries::new(&catalog, 64, 32, EstimateBehavior::Correct);
    rejecting_contract.contracts[0].reject_signature = true;
    let rejecting_contract = rejecting_contract.build().unwrap();
    assert!(try_node_resolution_with_registry(
        &family,
        &catalog,
        &policy,
        0,
        &rejecting_contract,
        None,
    )
    .is_err());
    assert_eq!(rejecting_contract.contract_calls.load(Ordering::SeqCst), 1);
    assert_eq!(rejecting_contract.estimator_calls.load(Ordering::SeqCst), 0);

    let mut missing_estimator =
        TestPlanningEntries::new(&catalog, 64, 32, EstimateBehavior::Correct);
    let missing_contract_calls = missing_estimator.contract_calls.clone();
    let missing_estimator_calls = missing_estimator.estimator_calls.clone();
    missing_estimator.estimators.clear();
    assert!(missing_estimator.build().is_err());
    assert_eq!(missing_contract_calls.load(Ordering::SeqCst), 0);
    assert_eq!(missing_estimator_calls.load(Ordering::SeqCst), 0);

    let mut duplicate_estimator =
        TestPlanningEntries::new(&catalog, 64, 32, EstimateBehavior::Correct);
    let duplicate_contract_calls = duplicate_estimator.contract_calls.clone();
    let duplicate_estimator_calls = duplicate_estimator.estimator_calls.clone();
    duplicate_estimator.estimators.push(TestEstimator {
        descriptor: duplicate_estimator.estimators[0].descriptor.clone(),
        calls: duplicate_estimator_calls.clone(),
        scratch_bytes: 64,
        persistent_bytes: 32,
        behavior: EstimateBehavior::Correct,
    });
    assert!(duplicate_estimator.build().is_err());
    assert_eq!(duplicate_contract_calls.load(Ordering::SeqCst), 0);
    assert_eq!(duplicate_estimator_calls.load(Ordering::SeqCst), 0);

    let mut mismatched_estimator =
        TestPlanningEntries::new(&catalog, 64, 32, EstimateBehavior::Correct);
    let descriptor = mismatched_estimator.estimators[0].descriptor.clone();
    mismatched_estimator.estimators[0].descriptor = OperationProviderDescriptor::new(
        descriptor.provider_id().clone(),
        descriptor.operation_id().clone(),
        descriptor.operation_fingerprint(),
        descriptor.provider_implementation_fingerprint(),
        descriptor.execution_semantics(),
        descriptor.version(),
        descriptor.device_id().clone(),
        descriptor.capabilities().clone(),
        descriptor.accepted_weight_formats().clone(),
        descriptor.accepted_quantization_formats().clone(),
        descriptor.dynamic_storage_bindings().to_vec(),
        "resource-estimator.mismatch",
        descriptor.resource_estimator_version(),
        descriptor.resource_estimator_implementation_fingerprint(),
    )
    .unwrap();
    let mismatched_estimator = mismatched_estimator.build().unwrap();
    assert!(try_node_resolution_with_registry(
        &family,
        &catalog,
        &policy,
        0,
        &mismatched_estimator,
        None,
    )
    .is_err());
    assert_eq!(
        mismatched_estimator.contract_calls.load(Ordering::SeqCst),
        1
    );
    assert_eq!(
        mismatched_estimator.estimator_calls.load(Ordering::SeqCst),
        0
    );

    let mut mismatched_provider_implementation =
        TestPlanningEntries::new(&catalog, 64, 32, EstimateBehavior::Correct);
    let descriptor = mismatched_provider_implementation.estimators[0]
        .descriptor
        .clone();
    mismatched_provider_implementation.estimators[0].descriptor = OperationProviderDescriptor::new(
        descriptor.provider_id().clone(),
        descriptor.operation_id().clone(),
        descriptor.operation_fingerprint(),
        sha('0'),
        descriptor.execution_semantics(),
        descriptor.version(),
        descriptor.device_id().clone(),
        descriptor.capabilities().clone(),
        descriptor.accepted_weight_formats().clone(),
        descriptor.accepted_quantization_formats().clone(),
        descriptor.dynamic_storage_bindings().to_vec(),
        descriptor.resource_estimator_id(),
        descriptor.resource_estimator_version(),
        descriptor.resource_estimator_implementation_fingerprint(),
    )
    .unwrap();
    let mismatched_provider_implementation = mismatched_provider_implementation.build().unwrap();
    assert!(try_node_resolution_with_registry(
        &family,
        &catalog,
        &policy,
        0,
        &mismatched_provider_implementation,
        None,
    )
    .is_err());
    assert_eq!(
        mismatched_provider_implementation
            .contract_calls
            .load(Ordering::SeqCst),
        1
    );
    assert_eq!(
        mismatched_provider_implementation
            .estimator_calls
            .load(Ordering::SeqCst),
        0
    );
}

#[test]
fn provider_raw_estimate_identity_input_and_output_are_revalidated_by_core() {
    let family = TestRegistry::new().prepare();
    let catalog = catalog();
    let policy = policy(4096);
    for behavior in [
        EstimateBehavior::WrongEstimatorId,
        EstimateBehavior::WrongEstimatorVersion,
        EstimateBehavior::WrongImplementation,
        EstimateBehavior::WrongInput,
        EstimateBehavior::InvalidAlignment,
        EstimateBehavior::MissingScratch,
    ] {
        let planning = TestPlanningRegistry::new(&catalog, 64, 32, behavior);
        assert!(
            try_node_resolution_with_registry(&family, &catalog, &policy, 0, &planning, None,)
                .is_err()
        );
        assert_eq!(planning.contract_calls.load(Ordering::SeqCst), 1);
        assert_eq!(planning.estimator_calls.load(Ordering::SeqCst), 1);
    }
}

#[test]
fn preferred_provider_is_only_a_core_validated_preference() {
    let family = TestRegistry::new().prepare();
    let catalog = catalog();
    let policy = policy(4096);
    let planning = TestPlanningRegistry::new(&catalog, 64, 32, EstimateBehavior::Correct);
    let resolution = try_node_resolution_with_registry(
        &family,
        &catalog,
        &policy,
        0,
        &planning,
        Some("provider.operation.unregistered"),
    )
    .unwrap();
    assert_eq!(
        resolution.provider_resource_candidates()[0]
            .provider_id()
            .as_str(),
        "provider.operation.reference"
    );
    let plan = ExecutionPlan::build(
        PlanBuildRequest::new(&family, &catalog, &policy, vec![resolution]).unwrap(),
    )
    .unwrap();
    let selection = plan.payload().nodes()[0].selection();
    assert_eq!(
        selection.selected_provider().as_str(),
        "provider.operation.reference"
    );
    assert_eq!(
        selection.selection_reason(),
        ProviderSelectionReason::FallbackFromPreferred
    );
}

#[test]
fn storage_incompatible_preference_falls_back_with_canonical_evidence() {
    let family = TestRegistry::new().prepare();
    let catalog = catalog_with_secondary_provider_storage(
        paged_storage_requirement(4096),
        contiguous_storage_requirement(),
    );
    let policy = policy(4096);
    let planning = TestPlanningRegistry::new(&catalog, 64, 32, EstimateBehavior::Correct);
    let preferred: ProviderId = id("provider.operation.reference");
    let resolution = try_node_resolution_with_registry(
        &family,
        &catalog,
        &policy,
        0,
        &planning,
        Some(preferred.as_str()),
    )
    .unwrap();

    assert_eq!(resolution.provider_resource_candidates().len(), 1);
    assert_eq!(
        resolution.provider_resource_candidates()[0]
            .provider_id()
            .as_str(),
        "provider.operation.secondary"
    );
    let rejected_resource_ids = match resolution
        .provider_resolution_rejections()
        .get(&preferred)
        .unwrap()
    {
        PlanProviderRejectReason::StorageIncompatible { resource_ids } => resource_ids.clone(),
        other => panic!("unexpected storage rejection: {other:?}"),
    };
    assert!(!rejected_resource_ids.is_empty());
    assert!(rejected_resource_ids
        .windows(2)
        .all(|pair| pair[0] < pair[1]));

    let plan = ExecutionPlan::build(
        PlanBuildRequest::new(&family, &catalog, &policy, vec![resolution]).unwrap(),
    )
    .unwrap();
    let selection = plan.payload().nodes()[0].selection();
    assert_eq!(
        selection.selected_provider().as_str(),
        "provider.operation.secondary"
    );
    assert_eq!(
        selection.selection_reason(),
        ProviderSelectionReason::FallbackFromPreferred
    );
    let rejection = selection
        .rejected_providers()
        .iter()
        .find(|rejection| rejection.provider_id() == &preferred)
        .unwrap();
    assert_eq!(
        rejection.reasons(),
        &PlanProviderRejectReason::StorageIncompatible {
            resource_ids: rejected_resource_ids,
        }
    );
}