///|
/// Runs repeated expiry, takeover, and stale-writer scenarios.
pub fn run_failover_simulation(
cycles : Int,
ttl? : Int = 5,
) -> SimulationReport {
if cycles <= 0 || ttl <= 0 {
return {
cycles: 0,
leases_acquired: 0,
writes_accepted: 0,
stale_writes_rejected: 0,
final_token: 0,
audit_valid: true,
evidence: 0,
}
}
let mut table = LeaseTable::new()
let mut fence = FenceGuard::new()
let mut leases_acquired = 0
let mut writes_accepted = 0
let mut stale_rejected = 0
let mut previous_holder = ""
let mut previous_token = 0
let mut final_token = 0
let mut evidence = 17
for cycle = 0; cycle < cycles; cycle = cycle + 1 {
let now = cycle * (ttl + 1)
let holder = "worker-\{cycle % 7}"
let acquisition = table.apply(
"cluster/leader",
Acquire(holder, ttl, None),
now,
)
table = acquisition.table
if acquisition.decision.accepted {
leases_acquired = leases_acquired + 1
guard acquisition.decision.lease is Some(lease) else { continue }
final_token = lease.token
let current = fence.check({
resource: lease.resource,
holder,
token: lease.token,
operation: "commit",
})
fence = current.next_guard
if current.accepted {
writes_accepted = writes_accepted + 1
}
if previous_token > 0 {
let stale = fence.check({
resource: lease.resource,
holder: previous_holder,
token: previous_token,
operation: "late-commit",
})
fence = stale.next_guard
if !stale.accepted {
stale_rejected = stale_rejected + 1
}
}
previous_holder = holder
previous_token = lease.token
evidence = (
evidence * 31 +
lease.token * 17 +
writes_accepted * 7 +
stale_rejected
) %
1000003
}
}
let audit = audit_events(table.events)
{
cycles,
leases_acquired,
writes_accepted,
stale_writes_rejected: stale_rejected,
final_token,
audit_valid: audit.valid,
evidence,
}
}
///|
/// Encodes reproducible simulation evidence as stable JSON.
pub fn SimulationReport::to_json(self : SimulationReport) -> String {
"{\"cycles\":\{self.cycles},\"leases_acquired\":\{self.leases_acquired},\"writes_accepted\":\{self.writes_accepted},\"stale_writes_rejected\":\{self.stale_writes_rejected},\"final_token\":\{self.final_token},\"audit_valid\":\{self.audit_valid},\"evidence\":\{self.evidence}}"
}