effect-runtime 0.1.0

Typed side-effect intent, execution receipt, and policy primitives for RecursiveIntell runtime gates
Documentation
#![allow(clippy::expect_used)]

use effect_runtime::{
    BlastRadiusCeilingV1, BudgetSufficiencyResultV1, CheckResultV1, ClosureRecommendationV1,
    CommitAtomicityV1, CompensationClassV1, CompensationExecutionReceiptV1, CompensationPlanV1,
    EffectClassV1, EffectCommitDecisionV1, EffectCommitDispositionV1, EffectExecutionReceiptV1,
    EffectIntentV1, EffectObservationBundleV1, EffectPreflightDispositionV1,
    EffectPreflightReportV1, EffectWindowV1, ExecutionStateV1, ExternalEffectLedgerEntryV1,
    ExternalObservationStateV1, ObservationStateV1, PublicationStatusV1, RetryOwnerV1,
    ReversibilityClassV1, RunModeV1, V25ConstitutionCitation, V25ObligationRefs,
};
use stack_ids::{
    ApplicabilityContextId, ApprovalGrantId, CompiledObligationSetId, CompositionConflictSetId,
    CompositionReceiptId, EffectCommitDecisionId, EffectExecutionReceiptId, EffectIntentId,
    EffectObservationBundleId, EffectPreflightReportId, EffectWindowId, ExecutionPermitId,
    ExternalEffectLedgerEntryId, ProfileExceptionBundleId, ProfileSetId,
};

fn sample_citation() -> V25ConstitutionCitation {
    V25ConstitutionCitation {
        applicability_context_id: ApplicabilityContextId::new("ac_001"),
        profile_set_id: ProfileSetId::new("ps_001"),
        composition_receipt_id: CompositionReceiptId::new("cr_001"),
        effective_constitution_id: stack_ids::EffectiveConstitutionId::new("ec_001"),
        compiled_obligation_set_id: CompiledObligationSetId::new("cos_001"),
        composition_conflict_set_id: Some(CompositionConflictSetId::new("ccs_001")),
        profile_exception_bundle_ids: vec![ProfileExceptionBundleId::new("peb_001")],
    }
}

fn sample_obligation_refs() -> V25ObligationRefs {
    V25ObligationRefs {
        required_obligation_refs: vec!["obs:admission-check-ok".into()],
        blocking_obligation_refs: Vec::new(),
        monitoring_obligation_refs: vec!["obs:latency".into()],
        decision_basis_obligation_refs: vec!["obs:policy-compliance".into()],
    }
}

#[test]
fn serde_roundtrip_example() {
    let citation = sample_citation();
    let obligation_refs = sample_obligation_refs();

    let window = EffectWindowV1::builder(
        EffectWindowId::new("fxw_001"),
        "2026-03-15T12:00:00Z",
        "2026-03-15T12:10:00Z",
        "2026-03-15T12:30:00Z",
        CommitAtomicityV1::ExactlyOnce,
        RetryOwnerV1::ForgeOrchestration,
        effect_runtime::CloseMidflightBehaviorV1::FailClosed,
    )
    .build()
    .expect("build window");

    let intent = EffectIntentV1::builder(
        EffectIntentId::new("fxi_001"),
        EffectClassV1::ExternalWrite,
        "ticketing/api",
        "apply approved configuration change",
        vec!["episode:ep_100".to_string(), "plan:pl_200".to_string()],
        "cap_change_window",
        "project:alpha",
        BlastRadiusCeilingV1::SingleTenant,
        ReversibilityClassV1::Compensatable,
        "idem_001",
        window.effect_window_id.clone(),
        vec!["obs:latency".to_string(), "obs:error_budget".to_string()],
        vec!["approval:chg_881".to_string()],
        RunModeV1::Live,
        PublicationStatusV1::Required,
    )
    .build()
    .expect("build intent");

    let preflight = EffectPreflightReportV1::builder(
        EffectPreflightReportId::new("fxp_001"),
        intent.effect_intent_id.clone(),
        citation.clone(),
        obligation_refs.clone(),
        CheckResultV1::Pass,
        CheckResultV1::Pass,
        CheckResultV1::Pass,
        BudgetSufficiencyResultV1::Sufficient,
        EffectPreflightDispositionV1::CommitEligible,
        "2026-03-15T12:00:00Z",
        vec!["all preconditions satisfied".to_string()],
    )
    .build()
    .expect("build preflight");

    let commit = EffectCommitDecisionV1::builder(
        EffectCommitDecisionId::new("fxc_001"),
        intent.effect_intent_id.clone(),
        preflight.effect_preflight_report_id.clone(),
        citation.clone(),
        obligation_refs.clone(),
        vec!["approval:chaperone".to_string()],
        EffectCommitDispositionV1::Authorized,
        vec!["person:alice".to_string(), "person:bob".to_string()],
        Some(ExecutionPermitId::new("permit_001")),
        Some(ApprovalGrantId::new("grant_001")),
        "",
        "2026-03-15T12:02:00Z",
    )
    .build()
    .expect("build commit");

    let execution_receipt = EffectExecutionReceiptV1::builder(
        EffectExecutionReceiptId::new("fxr_001"),
        commit.effect_commit_decision_id.clone(),
        citation.clone(),
        vec![
            "forge-pilot".to_string(),
            "llm-tool-runtime".to_string(),
            "ticketing/api".to_string(),
        ],
        ExecutionStateV1::Completed,
        false,
        "",
        false,
        vec!["ticket:chg-881".to_string()],
        "ext_8821",
        "2026-03-15T12:08:00Z",
    )
    .build()
    .expect("build execution receipt");

    let observation_bundle = EffectObservationBundleV1::builder(
        EffectObservationBundleId::new("fxo_001"),
        execution_receipt.effect_execution_receipt_id.clone(),
        citation.clone(),
        "2026-03-15T12:08:00Z/2026-03-15T13:08:00Z",
        ObservationStateV1::Complete,
        "change applied without rollback",
        "no material drift observed",
        vec!["metric:latency_1h".to_string(), "log:event_991".to_string()],
        ClosureRecommendationV1::CloseSuccessfully,
        "2026-03-15T13:09:00Z",
    )
    .build()
    .expect("build observation bundle");

    let compensation_plan = CompensationPlanV1::builder(
        stack_ids::CompensationPlanId::new("fxcp_001"),
        intent.effect_intent_id.clone(),
        citation.clone(),
        true,
        CompensationClassV1::StateRestore,
        vec![
            "reapply prior config".to_string(),
            "notify operator".to_string(),
        ],
        vec![
            "prior state restored".to_string(),
            "post-check green".to_string(),
        ],
        "team:ops",
        "2026-03-15T12:40:00Z",
        false,
    )
    .build()
    .expect("build compensation plan");

    let compensation_receipt = CompensationExecutionReceiptV1::builder(
        stack_ids::CompensationExecutionReceiptId::new("fxcr_001"),
        compensation_plan.compensation_plan_id.clone(),
        citation.clone(),
        ExecutionStateV1::Completed,
        vec![
            "reapply prior config".to_string(),
            "notify operator".to_string(),
        ],
        Vec::new(),
        "none",
        "2026-03-15T12:28:00Z",
    )
    .build()
    .expect("build compensation receipt");

    let ledger = ExternalEffectLedgerEntryV1::builder(
        ExternalEffectLedgerEntryId::new("fxl_001"),
        execution_receipt.effect_execution_receipt_id.clone(),
        citation,
        "ticketing",
        "ext_8821",
        ExternalObservationStateV1::Committed,
        "2026-03-15T12:08:30Z",
        true,
    )
    .build()
    .expect("build ledger");

    let value = serde_json::to_string(&intent).expect("serialize intent");
    let intent_rt: EffectIntentV1 = serde_json::from_str(&value).expect("deserialize intent");
    intent_rt.validate().expect("validate intent");

    let value = serde_json::to_string(&preflight).expect("serialize preflight");
    let preflight_rt: EffectPreflightReportV1 =
        serde_json::from_str(&value).expect("deserialize preflight");
    preflight_rt.validate().expect("validate preflight");

    let value = serde_json::to_string(&commit).expect("serialize commit");
    let commit_rt: EffectCommitDecisionV1 =
        serde_json::from_str(&value).expect("deserialize commit");
    commit_rt.validate().expect("validate commit");

    let value = serde_json::to_string(&execution_receipt).expect("serialize execution");
    let execution_rt: EffectExecutionReceiptV1 =
        serde_json::from_str(&value).expect("deserialize execution");
    execution_rt.validate().expect("validate execution");

    let value = serde_json::to_string(&observation_bundle).expect("serialize observation");
    let observation_rt: EffectObservationBundleV1 =
        serde_json::from_str(&value).expect("deserialize observation");
    observation_rt.validate().expect("validate observation");

    let value = serde_json::to_string(&compensation_plan).expect("serialize plan");
    let compensation_plan_rt: CompensationPlanV1 =
        serde_json::from_str(&value).expect("deserialize plan");
    compensation_plan_rt.validate().expect("validate plan");

    let value =
        serde_json::to_string(&compensation_receipt).expect("serialize compensation receipt");
    let compensation_receipt_rt: CompensationExecutionReceiptV1 =
        serde_json::from_str(&value).expect("deserialize compensation receipt");
    compensation_receipt_rt
        .validate()
        .expect("validate compensation receipt");

    let value = serde_json::to_string(&window).expect("serialize window");
    let window_rt: EffectWindowV1 = serde_json::from_str(&value).expect("deserialize window");
    window_rt.validate().expect("validate window");

    let value = serde_json::to_string(&ledger).expect("serialize ledger");
    let ledger_rt: ExternalEffectLedgerEntryV1 =
        serde_json::from_str(&value).expect("deserialize ledger");
    ledger_rt.validate().expect("validate ledger");
}