1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//! Deterministic crash injection for simulation crash-recovery tests
//! (sim-testing W5.c item 7, issue #1797).
//!
//! This is the **crash lane** of the sim harness: a seed-derived, reproducible
//! *crash schedule* that models a process dying mid-flight so a
//! [`#[sim_test]`](crate::sim_test) can prove its **durable** work survives a
//! crash and is recovered on restart — without a flaky, timing-dependent kill.
//!
//! # Kill / restart primitive
//!
//! The crash itself is driven through the [`Sim`](crate::sim::Sim) handle:
//! [`Sim::kill`](crate::sim::Sim::kill) drops the mounted app (cancelling the
//! in-process job runtime's in-flight work **without** completing it), and
//! [`Sim::restart`](crate::sim::Sim::restart) mounts a fresh app on the **same
//! durable database** (the caller re-passes `substrate.pool()`), modelling a
//! process restart on the same on-disk/in-memory store.
//! [`Sim::crash_and_restart`](crate::sim::Sim::crash_and_restart) is the
//! kill-then-restart convenience.
//!
//! # The seeded crash schedule (determinism contract)
//!
//! Every crash decision is drawn from a **dedicated seeded stream**, seeded from
//! `seed ^ CRASH_STREAM_SALT` so it is independent of both the app-facing
//! entropy source and the [`chaos`](crate::sim::chaos) decision stream. Two
//! same-seed runs therefore derive an **identical crash schedule byte-for-byte**
//! (the schedule is a pure function of the seed), which is what the W5.c
//! Definition-of-Done asserts; different seeds (overwhelmingly likely) diverge.
//! Read the schedule through
//! [`Sim::crash_schedule`](crate::sim::Sim::crash_schedule) /
//! [`Sim::crash_point`](crate::sim::Sim::crash_point).
//!
//! # Representative crash point (scope, stated plainly)
//!
//! This wave injects a **single representative deterministic crash point** — the
//! `await` boundary **after** a repository write has enqueued its durable
//! commit-hook row but **before** that hook drains — rather than a fully-general
//! "between ANY two `await`s" injector. That representative boundary is the
//! sharpest test of durable recovery: the durable row is committed, the in-flight
//! work is not, so a correct recovery re-runs it exactly-once/idempotently on
//! restart. The schedule API is shaped generally (an ordered sequence of
//! [`CrashPoint`]s, each carrying a seed-derived `await_index`), so a later wave
//! can realize more of the enumerated boundaries without a breaking change; today
//! the harness realizes the first one. This is documented representativeness, not
//! faked generality.
use crateSeededEntropy;
/// Salt `XOR`ed into the sim seed to derive the crash **decision** stream, keeping
/// it independent of the app-facing entropy source and the
/// [`chaos`](crate::sim::chaos) decision stream (both seeded from other values).
/// An arbitrary fixed non-zero constant.
pub const CRASH_STREAM_SALT: u64 = 0xC7A5_4EAD_C7A5_4EAD;
/// The number of enumerated `await` boundaries in the representative durable
/// write → enqueue → drain path a crash can target. A seed-derived draw is taken
/// `% CRASH_AWAIT_BOUNDARIES` to pick one. The realized representative crash
/// always fires at the "commit-hook enqueued, pre-drain" boundary; this modulus
/// only shapes the (general) recorded schedule so it stays a small, stable index
/// space across runs.
pub const CRASH_AWAIT_BOUNDARIES: u64 = 4;
/// Default number of crash decisions the derived schedule records for a sim.
/// Generous relative to the single representative crash the harness realizes; the
/// extra entries exist only so the recorded schedule is a non-trivial seeded
/// sequence the Definition-of-Done can compare across two same-seed runs.
pub const DEFAULT_CRASH_SCHEDULE_LEN: usize = 8;
/// One seed-derived crash decision in a [`CrashSchedule`].
///
/// `#[non_exhaustive]` so fields can be added without breaking readers; the
/// derived [`PartialEq`] is what the W5.c Definition-of-Done compares two
/// same-seed runs on.
/// A reproducible crash schedule for one simulation, derived purely from
/// `seed ^ CRASH_STREAM_SALT`.
///
/// Constructed by [`Sim::from_seed`](crate::sim::Sim::from_seed)'s seed and read
/// through [`Sim::crash_schedule`](crate::sim::Sim::crash_schedule). Two
/// same-seed sims produce an equal schedule; that equality is the W5.c
/// determinism Definition-of-Done.