#![allow(clippy::expect_used, clippy::panic)]
use crate::algebra::{ResourceDimension, ResourceVector, WideResourceVector};
use crate::wire::{
ClosureCapacityReason, ClosureCheckedEnvelope, ClosureRefusalReason, EnrollmentEnvelope,
EnrollmentToken, RepaymentEdge,
};
use super::closure_accounting::{
ClosureAccounting, ClosureAccountingError, RecoveryFenceDecision, RemainingClosureDecision,
RequiredCapacityPlan, RequiredCapacityPlanError, check_recovery_fence, check_remaining_closure,
};
use super::{ClosureDebt, ClosureState, ObserverProjection, StoredEdge};
fn request() -> ClosureCheckedEnvelope {
ClosureCheckedEnvelope::Enrollment(EnrollmentEnvelope {
conversation_id: 91,
enrollment_token: EnrollmentToken::new([0x91; 16]),
})
}
fn accounting(state: ClosureState) -> ClosureAccounting {
let owed = matches!(state, ClosureState::Owed { .. });
ClosureAccounting::try_new(
state,
u64::from(owed),
u64::from(owed),
u64::from(owed) * 4,
u64::from(owed) * 3,
if owed {
ResourceVector::new(2, 20)
} else {
ResourceVector::default()
},
WideResourceVector::new(5, 50),
ResourceVector::new(10, 100),
1,
3,
)
.expect("fixture accounting is valid")
}
fn owed() -> ClosureState {
ClosureState::Owed {
debt: ClosureDebt::new(WideResourceVector::new(1, 7)).expect("fixture debt is nonzero"),
edge: StoredEdge::ObserverProjection(ObserverProjection::new(12)),
}
}
#[test]
fn restore_rejects_mixed_clear_state_and_unencodable_or_impossible_values() {
let mixed = ClosureAccounting::try_new(
ClosureState::Clear,
0,
0,
1,
0,
ResourceVector::default(),
WideResourceVector::new(0, 0),
ResourceVector::new(1, 1),
0,
1,
);
assert_eq!(
mixed,
Err(ClosureAccountingError::ClearStateOwnsEdgeResources)
);
let anchors = ClosureAccounting::try_new(
ClosureState::Clear,
1,
2,
0,
0,
ResourceVector::default(),
WideResourceVector::new(0, 0),
ResourceVector::new(1, 1),
0,
1,
);
assert_eq!(
anchors,
Err(ClosureAccountingError::MarkerAnchorsExceedCredits {
anchors: 2,
credits: 1,
})
);
let huge_debt = ClosureState::Owed {
debt: ClosureDebt::new(WideResourceVector::new(u128::from(u64::MAX) + 1, 0))
.expect("entry debt is nonzero"),
edge: StoredEdge::ObserverProjection(ObserverProjection::new(1)),
};
let result = ClosureAccounting::try_new(
huge_debt,
0,
0,
1,
1,
ResourceVector::default(),
WideResourceVector::new(0, 0),
ResourceVector::new(1, 1),
0,
1,
);
assert_eq!(
result,
Err(ClosureAccountingError::DebtOutsideWireDomain {
dimension: ResourceDimension::Entries,
})
);
}
#[test]
fn recovery_fence_uses_unchanged_state_and_zero_delta_before_numeric_checks() {
let current = accounting(owed());
let decision = check_recovery_fence(&request(), current, true);
let RecoveryFenceDecision::Respond(refusal) = decision else {
panic!("recovery fence must refuse");
};
assert_eq!(refusal.reason, ClosureRefusalReason::RecoveryFence);
assert_eq!(refusal.snapshot.entry_debt, 1);
assert_eq!(refusal.snapshot.byte_debt, 7);
assert_eq!(refusal.snapshot.delta_cycles, 0);
assert_eq!(
refusal.snapshot.repayment_edge,
RepaymentEdge::ObserverProjection { through_seq: 12 }
);
assert_eq!(refusal.snapshot.k_headroom, WideResourceVector::new(5, 50));
assert_eq!(current, accounting(owed()));
}
#[test]
fn remaining_precedence_is_delivered_then_churn_then_entries_then_bytes() {
let current = accounting(ClosureState::Clear);
let required = RequiredCapacityPlan::from_successors(&[
WideResourceVector::new(11, 101),
WideResourceVector::new(12, 102),
])
.expect("two successors are nonempty");
let delivered = check_remaining_closure(&request(), current, true, 9, required);
let RemainingClosureDecision::Respond(delivered) = delivered else {
panic!("delivered marker wins");
};
assert_eq!(
delivered.reason,
ClosureRefusalReason::DeliveredMarkerAwaitingAck
);
assert_eq!(delivered.snapshot.delta_cycles, 0);
let churn = check_remaining_closure(&request(), current, false, 3, required);
let RemainingClosureDecision::Respond(churn) = churn else {
panic!("churn wins before capacity");
};
assert_eq!(churn.reason, ClosureRefusalReason::EpisodeChurnLimit);
assert_eq!(churn.snapshot.delta_cycles, 3);
let entries = check_remaining_closure(&request(), current, false, 2, required);
let RemainingClosureDecision::Respond(entries) = entries else {
panic!("entries fail first");
};
assert_eq!(
entries.reason,
ClosureRefusalReason::Capacity(ClosureCapacityReason {
dimension: ResourceDimension::Entries,
required: 12,
limit: 10,
})
);
let bytes_only = RequiredCapacityPlan::from_successors(&[WideResourceVector::new(10, 101)])
.expect("one successor is nonempty");
let bytes = check_remaining_closure(&request(), current, false, 2, bytes_only);
let RemainingClosureDecision::Respond(bytes) = bytes else {
panic!("bytes fail after entries pass");
};
assert_eq!(
bytes.reason,
ClosureRefusalReason::Capacity(ClosureCapacityReason {
dimension: ResourceDimension::Bytes,
required: 101,
limit: 100,
})
);
}
#[test]
fn equality_passes_with_componentwise_successor_maximum_and_exact_cycle_charge() {
let current = accounting(ClosureState::Clear);
let plan = RequiredCapacityPlan::from_successors(&[
WideResourceVector::new(10, 90),
WideResourceVector::new(8, 100),
])
.expect("two successors are nonempty");
assert_eq!(plan.maximum(), WideResourceVector::new(10, 100));
let decision = check_remaining_closure(&request(), current, false, 2, plan);
let RemainingClosureDecision::Eligible(permit) = decision else {
panic!("capacity and churn equality pass");
};
assert_eq!(permit.accounting(), current);
assert_eq!(permit.required_capacity(), plan);
assert_eq!(permit.delta_cycles(), 2);
}
#[test]
fn ordinary_required_capacity_uses_canonical_widened_addition_order() {
let plan = RequiredCapacityPlan::ordinary(
WideResourceVector::new(4, 40),
ResourceVector::new(2, 20),
ResourceVector::new(1, 10),
)
.expect("fixture additions fit");
assert_eq!(plan.maximum(), WideResourceVector::new(7, 70));
assert_eq!(
RequiredCapacityPlan::from_successors(&[]),
Err(RequiredCapacityPlanError::EmptySuccessorSet)
);
assert_eq!(
RequiredCapacityPlan::ordinary(
WideResourceVector::new(u128::MAX, 0),
ResourceVector::new(1, 0),
ResourceVector::default(),
),
Err(RequiredCapacityPlanError::ArithmeticOverflow {
dimension: ResourceDimension::Entries,
})
);
}
/// The server stores this `Debug` text in durable `RecordAdmission` rows and compares it byte for byte on replay
/// (`liminal-server` `production/ops_frontier.rs:686` and `:1005` at ad2aa69a), so a change to it breaks the replay of
/// every stored row. PROTO-007 changes Debug across the workspace; this golden must hold across all of it.
#[test]
fn the_durable_accounting_debug_text_is_unchanged() {
let clear = alloc::format!("{:?}", accounting(ClosureState::Clear));
assert_eq!(
clear, GOLDEN_CLEAR,
"ClosureAccounting Debug (clear) drifted; durable rows compare it on replay"
);
let owed = alloc::format!(
"{:?}",
accounting(ClosureState::Owed {
debt: ClosureDebt::new(WideResourceVector::new(1, 7)).expect("fixture debt is nonzero"),
edge: StoredEdge::ObserverProjection(ObserverProjection::new(7)),
})
);
assert_eq!(
owed, GOLDEN_OWED,
"ClosureAccounting Debug (owed) drifted; durable rows compare it on replay"
);
}
const GOLDEN_CLEAR: &str = "ClosureAccounting { state: Clear, marker_capacity_credits: 0, marker_anchors: 0, edge_sequence_claims: 0, edge_order_position_claims: 0, edge_k_remaining: ResourceVector { entries: 0, bytes: 0 }, baseline: WideResourceVector { entries: 5, bytes: 50 }, configured_cap: ResourceVector { entries: 10, bytes: 100 }, episode_churn_used: 1, episode_churn_limit: 3 }";
const GOLDEN_OWED: &str = "ClosureAccounting { state: Owed { debt: ClosureDebt(WideResourceVector { entries: 1, bytes: 7 }), edge: ObserverProjection(ObserverProjection { through_seq: 7 }) }, marker_capacity_credits: 1, marker_anchors: 1, edge_sequence_claims: 4, edge_order_position_claims: 3, edge_k_remaining: ResourceVector { entries: 2, bytes: 20 }, baseline: WideResourceVector { entries: 5, bytes: 50 }, configured_cap: ResourceVector { entries: 10, bytes: 100 }, episode_churn_used: 1, episode_churn_limit: 3 }";