lenso-service 0.1.21

Public contracts for Lenso Providers and Autonomous Services.
Documentation
use std::collections::BTreeMap;

use lenso_service::{
    ComponentKind, ContractConsumerEvidence, ContractRetirementInput, EvidenceReceiptTrust,
    FailureCondition, FailureObservation, FailureOutcome, FailureScenarioInput, GaComponent,
    GaSupportManifestInput, ManifestFormat, ManifestKind, ManifestMigrationInput,
    RetirementApproval, ServiceUpgradeInput, ServiceUpgradeRuntimeObservation,
    SupportCombinationInput, SupportDecision, SupportStatus, UpgradeEdgeInput, UpgradeWorkload,
    apply_contract_retirement, apply_manifest_migration, assemble_ga_support_manifest,
    assemble_ga_support_manifest_with_trust, contract_retirement_receipt_integrity_is_valid,
    evaluate_failure_scenario, evaluate_ga_support, evaluate_service_upgrade_admission,
    ga_support_manifest_integrity_valid, plan_contract_retirement, plan_manifest_migration,
    plan_service_upgrade,
};
use serde_json::json;

fn digest(value: char) -> String {
    format!("sha256:{}", value.to_string().repeat(64))
}

fn support_manifest() -> lenso_service::GaSupportManifest {
    assemble_ga_support_manifest_with_trust(
        GaSupportManifestInput {
            status: SupportStatus::GeneralAvailability,
            components: vec![
                GaComponent {
                    kind: ComponentKind::Runtime,
                    component_id: "lenso-service".into(),
                    version: "1.0.0".into(),
                    digest: digest('a'),
                },
                GaComponent {
                    kind: ComponentKind::Cli,
                    component_id: "lenso-cli".into(),
                    version: "1.0.0".into(),
                    digest: digest('b'),
                },
            ],
            manifest_formats: vec![
                ManifestFormat {
                    kind: ManifestKind::Provider,
                    version: "lenso.service.v1".into(),
                },
                ManifestFormat {
                    kind: ManifestKind::System,
                    version: "lenso.system.v1".into(),
                },
                ManifestFormat {
                    kind: ManifestKind::System,
                    version: "lenso.system.v2".into(),
                },
                ManifestFormat {
                    kind: ManifestKind::Service,
                    version: "lenso.service.v2".into(),
                },
            ],
            state_versions: vec!["service-store.v1".into(), "service-store.v2".into()],
            adapter_versions: BTreeMap::from([
                ("nats-jetstream".into(), "2.11".into()),
                ("spiffe-spire".into(), "1.12".into()),
            ]),
            documentation: lenso_service::DocumentationIdentity {
                version: "m6-ga".into(),
                digest: digest('d'),
            },
            combinations: vec![SupportCombinationInput {
                combination_id: "ga-1".into(),
                component_references: vec![
                    "cli:lenso-cli@1.0.0".into(),
                    "runtime:lenso-service@1.0.0".into(),
                ],
                state_version: "service-store.v2".into(),
                status: SupportStatus::GeneralAvailability,
            }],
            upgrade_edges: vec![UpgradeEdgeInput {
                edge_id: "state-v1-v2".into(),
                source_format: "service-store.v1".into(),
                target_format: "service-store.v2".into(),
                mixed_version_references: vec![
                    "runtime:lenso-service@1.0.0".into(),
                    "runtime:lenso-service@0.9.0".into(),
                ],
                rollback_safe: false,
            }],
        },
        EvidenceReceiptTrust {
            authorities: BTreeMap::from([
                (
                    "lenso.performance-profile.v1".into(),
                    "test-authority".into(),
                ),
                (
                    "lenso.service-restore-evidence.v1".into(),
                    "test-authority".into(),
                ),
            ]),
            public_keys: BTreeMap::from([(
                "test-authority".into(),
                "-----BEGIN PUBLIC KEY-----\ntest\n-----END PUBLIC KEY-----".into(),
            )]),
        },
    )
    .expect("valid support manifest")
}

#[test]
fn support_manifest_is_canonical_and_unknown_combinations_fail_explicitly() {
    let manifest = support_manifest();
    let mut reordered = manifest.clone();
    reordered.components.reverse();
    let rebuilt = assemble_ga_support_manifest_with_trust(
        reordered.clone().into_input(),
        EvidenceReceiptTrust {
            authorities: reordered.evidence_receipt_authorities,
            public_keys: reordered.receipt_authority_public_keys,
        },
    )
    .unwrap();
    assert_eq!(manifest.manifest_id, rebuilt.manifest_id);
    assert_eq!(manifest.manifest_digest, rebuilt.manifest_digest);

    let supported = evaluate_ga_support(
        &manifest,
        &["runtime:lenso-service@1.0.0", "cli:lenso-cli@1.0.0"],
        "service-store.v2",
    );
    assert_eq!(supported.decision, SupportDecision::Supported);

    let unknown = evaluate_ga_support(
        &manifest,
        &["runtime:lenso-service@1.1.0", "cli:lenso-cli@1.0.0"],
        "service-store.v2",
    );
    assert_eq!(unknown.decision, SupportDecision::Unknown);
    assert_eq!(unknown.issues[0].code.as_str(), "ga_combination_unknown");
    assert!(
        unknown
            .next_actions
            .iter()
            .any(|action| action.contains("manifest"))
    );

    let mut tampered = manifest;
    tampered.components[0].version = "9.9.9".into();
    let rejected = evaluate_ga_support(
        &tampered,
        &["runtime:lenso-service@1.0.0", "cli:lenso-cli@1.0.0"],
        "service-store.v2",
    );
    assert_eq!(rejected.decision, SupportDecision::Blocked);
    assert_eq!(rejected.issues[0].code.as_str(), "ga_manifest_invalid");
}

#[test]
fn legacy_v1_support_manifest_without_receipt_trust_keeps_its_digest() {
    let current = support_manifest();
    let legacy = assemble_ga_support_manifest(current.into_input()).unwrap();
    let mut encoded = serde_json::to_value(&legacy).unwrap();
    encoded
        .as_object_mut()
        .unwrap()
        .remove("evidenceReceiptAuthorities");
    encoded
        .as_object_mut()
        .unwrap()
        .remove("receiptAuthorityPublicKeys");
    let decoded: lenso_service::GaSupportManifest = serde_json::from_value(encoded).unwrap();
    assert!(ga_support_manifest_integrity_valid(&decoded));
    assert_eq!(decoded.manifest_digest, legacy.manifest_digest);
}

#[test]
fn manifest_migration_is_deterministic_stale_safe_and_preserves_identity() {
    let source = json!({
        "protocol": "lenso.system.v1",
        "systemId": "support-system",
        "services": [{"serviceId": "support", "moduleId": "support-ticket"}]
    });
    let input = ManifestMigrationInput {
        kind: ManifestKind::System,
        source_format: "lenso.system.v1".into(),
        target_format: "lenso.system.v2".into(),
        source: source.clone(),
        identity_pointers: vec![
            "/systemId".into(),
            "/services/0/serviceId".into(),
            "/services/0/moduleId".into(),
        ],
    };
    let plan = plan_manifest_migration(&input, &support_manifest()).unwrap();
    assert!(!plan.effects.mutates_source);
    let receipt = apply_manifest_migration(&plan, &source, false).unwrap();
    assert_eq!(receipt.migrated["protocol"], "lenso.system.v2");
    assert_eq!(receipt.migrated["systemId"], "support-system");

    let mut changed = source;
    changed["systemId"] = json!("changed");
    let error = apply_manifest_migration(&plan, &changed, false).unwrap_err();
    assert_eq!(error.code.as_str(), "manifest_source_stale");

    let mut tampered = plan;
    tampered.migrated["systemId"] = json!("forged");
    let error = apply_manifest_migration(&tampered, &input.source, false).unwrap_err();
    assert_eq!(error.code.as_str(), "ga_plan_integrity_invalid");
}

#[test]
fn service_upgrade_orders_migration_before_api_and_worker_and_reports_rollback_constraint() {
    let plan = plan_service_upgrade(
        &support_manifest(),
        ServiceUpgradeInput {
            service_id: "support".into(),
            from_release_id: "release-old".into(),
            from_release_digest: digest('1'),
            to_release_id: "release-new".into(),
            to_release_digest: digest('2'),
            config_revision_id: "config-1".into(),
            config_revision_digest: digest('3'),
            source_state_version: "service-store.v1".into(),
            target_state_version: "service-store.v2".into(),
            workflow_artifact_digests: vec![digest('4')],
        },
    )
    .unwrap();

    assert_eq!(
        plan.steps
            .iter()
            .map(|step| step.workload.as_str())
            .collect::<Vec<_>>(),
        ["migration", "api", "worker"]
    );
    assert!(!plan.rollback.automatic_allowed);
    assert!(plan.rollback.approval_boundary.is_some());
    assert!(plan.preserved_identities.contains(&"inbox".into()));
    assert!(plan.preserved_identities.contains(&"story_segment".into()));

    let blocked = evaluate_service_upgrade_admission(
        &plan,
        &ServiceUpgradeRuntimeObservation {
            workload: UpgradeWorkload::Worker,
            current_release_id: "release-old".into(),
            current_state_version: "service-store.v1".into(),
            migration_completed: false,
            workflow_artifact_digests: vec![digest('4')],
        },
    );
    assert_eq!(blocked.decision, SupportDecision::Blocked);
    assert!(!blocked.claims_work);
    assert!(!blocked.mutates_state);

    let admitted = evaluate_service_upgrade_admission(
        &plan,
        &ServiceUpgradeRuntimeObservation {
            workload: UpgradeWorkload::Worker,
            current_release_id: "release-new".into(),
            current_state_version: "service-store.v2".into(),
            migration_completed: true,
            workflow_artifact_digests: vec![digest('4')],
        },
    );
    assert_eq!(admitted.decision, SupportDecision::Supported);
    assert!(admitted.claims_work);

    let mut tampered = plan;
    tampered.input.to_release_id = "forged-release".into();
    let blocked = evaluate_service_upgrade_admission(
        &tampered,
        &ServiceUpgradeRuntimeObservation {
            workload: UpgradeWorkload::Worker,
            current_release_id: "forged-release".into(),
            current_state_version: "service-store.v2".into(),
            migration_completed: true,
            workflow_artifact_digests: vec![digest('4')],
        },
    );
    assert_eq!(blocked.decision, SupportDecision::Blocked);
    assert_eq!(blocked.issues[0].code.as_str(), "ga_plan_integrity_invalid");
}

#[test]
fn contract_retirement_blocks_active_consumers_and_requires_exact_approval() {
    let blocked_input = ContractRetirementInput {
        system_graph_digest: digest('5'),
        environment_evidence_digest: digest('6'),
        evidence_fresh: true,
        contract_id: "support-http".into(),
        retiring_version: "v1".into(),
        replacement_version: "v2".into(),
        deprecation_window_complete: true,
        consumers: vec![ContractConsumerEvidence {
            consumer_id: "console".into(),
            active_version: Some("v1".into()),
            replacement_verified: false,
        }],
    };
    let blocked = plan_contract_retirement(&blocked_input);
    assert_eq!(blocked.decision, SupportDecision::Unsupported);
    assert!(!blocked.effects.retires_contract);

    let mut ready_input = blocked_input;
    ready_input.consumers[0].active_version = Some("v2".into());
    ready_input.consumers[0].replacement_verified = true;
    let ready = plan_contract_retirement(&ready_input);
    let wrong = RetirementApproval {
        plan_digest: digest('7'),
        approver: "release-owner".into(),
        reason: "approved local fixture retirement".into(),
    };
    assert_eq!(
        apply_contract_retirement(&ready, &ready_input, &wrong)
            .unwrap_err()
            .code
            .as_str(),
        "retirement_approval_invalid"
    );
    let approval = RetirementApproval {
        plan_digest: ready.plan_digest.clone(),
        ..wrong
    };
    let receipt = apply_contract_retirement(&ready, &ready_input, &approval).unwrap();
    assert!(receipt.retired);
    assert_eq!(receipt.contract_id, "support-http");
    assert!(contract_retirement_receipt_integrity_is_valid(&receipt));
    let mut tampered_receipt = receipt;
    tampered_receipt.replacement_version = "v3".into();
    assert!(!contract_retirement_receipt_integrity_is_valid(
        &tampered_receipt
    ));

    let mut tampered = ready;
    tampered.replacement_version = "v3".into();
    assert_eq!(
        apply_contract_retirement(&tampered, &ready_input, &approval)
            .unwrap_err()
            .code
            .as_str(),
        "ga_plan_integrity_invalid"
    );
}

#[test]
fn recovery_evidence_rejects_unexpected_continuation_and_requires_cleanup() {
    let evidence = evaluate_failure_scenario(FailureScenarioInput {
        scenario_id: "store-outage".into(),
        condition: FailureCondition::PostgresStoreUnavailable,
        expected: FailureOutcome::RejectWork,
        observations: vec![FailureObservation {
            subject: "support-api".into(),
            expected: None,
            outcome: FailureOutcome::Continue,
            evidence_digest: digest('8'),
        }],
        effects: vec!["request accepted while authority unavailable".into()],
        cleanup_complete: false,
        adapter_version: Some("postgres-18".into()),
        controlled_time_unix_ms: Some(1_721_600_000_000),
    });
    assert_eq!(evidence.decision, SupportDecision::Unsupported);
    assert!(
        evidence
            .issues
            .iter()
            .any(|issue| { issue.code.as_str() == "failure_unexpected_outcome" })
    );
    assert!(
        evidence
            .issues
            .iter()
            .any(|issue| { issue.code.as_str() == "failure_cleanup_incomplete" })
    );
}

#[test]
fn system_plane_outage_allows_established_data_plane_and_pauses_new_mutation() {
    let evidence = evaluate_failure_scenario(FailureScenarioInput {
        scenario_id: "system-plane-outage".into(),
        condition: FailureCondition::SystemPlaneUnavailable,
        expected: FailureOutcome::PauseCoordinatedMutation,
        observations: vec![
            FailureObservation {
                subject: "established-direct-request".into(),
                expected: Some(FailureOutcome::Continue),
                outcome: FailureOutcome::Continue,
                evidence_digest: digest('9'),
            },
            FailureObservation {
                subject: "new-promotion".into(),
                expected: Some(FailureOutcome::PauseCoordinatedMutation),
                outcome: FailureOutcome::PauseCoordinatedMutation,
                evidence_digest: digest('a'),
            },
        ],
        effects: vec!["one established business effect committed once".into()],
        cleanup_complete: true,
        adapter_version: None,
        controlled_time_unix_ms: Some(1_721_600_000_000),
    });
    assert_eq!(evidence.decision, SupportDecision::Supported);
}