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
//! Errors surfaced by the event log.
/// Failures from opening, appending to, or replaying an [`crate::EventLog`].
///
/// This is a thin wrapper over the underlying
/// [`commonware_storage::journal::Error`]: every fallible event-log operation
/// delegates to the journal primitive, so the storage error is the only failure
/// mode and is preserved verbatim as the [`Self::Journal`] source.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum EventLogError {
/// The underlying commonware-storage journal returned an error while
/// opening, appending, committing, or replaying.
#[error("event log journal error: {0}")]
Journal(#[from] commonware_storage::journal::Error),
/// The durable event-count checkpoint ([`crate::checkpoint`]) failed to
/// open, read, or sync.
#[error("event log checkpoint error: {0}")]
Checkpoint(#[from] commonware_storage::metadata::Error),
/// A partition's tamper-evidence tree could not be rebuilt, or its root
/// could not be signed.
///
/// A rewrite reports this rather than proceeding: every root the partition
/// carried was signed over content the rewrite changes, so a rewrite that
/// cannot sign a fresh one would leave a partition whose signed history
/// does not describe what it holds.
#[error("event log integrity error: {0}")]
Integrity(#[from] crate::IntegrityError),
/// [`crate::EventLog::reclaim`] was asked to remove storage that still
/// holds events.
///
/// Reclaim is Commonware's final-teardown removal, which is not crash
/// safe. It is sound only over a journal a
/// [`crate::EventLog::reset`] already emptied durably, so a caller that
/// skipped the reset is refused rather than served an interrupted removal
/// that could leave a short history.
#[error("event log reclaim refused: the journal still holds {events} event(s); reset it first")]
ReclaimNotEmpty {
/// How many events the journal still held.
events: u64,
},
/// An erasure reported success while durable storage for the partition
/// survived it.
///
/// Commonware's runtime maps EVERY `remove_dir_all` failure to
/// `PartitionMissing`, and both `Partition::remove_all` and
/// `Metadata::destroy` treat that as success. A real I/O failure part-way
/// through a removal is therefore indistinguishable, inside Commonware,
/// from storage that was already gone — so a reclaim can answer `Ok` over
/// a remnant it did not remove.
///
/// The erase path checks the volume afterwards rather than trusting that
/// answer. Without the check the caller receives a completion it can act
/// on, writes its receipt, and leaves a remnant no workflow will come back
/// for — which every later read refuses as damage.
#[error("event log erasure incomplete: durable storage survived the removal")]
EraseIncomplete,
/// A requested repair transformation did not name exactly one survivor.
#[error("event log repair replacement error: {0}")]
RepairReplacement(String),
/// A repair refused a partition whose signed roots contradict the content
/// they cover.
///
/// Repair deletes every root a partition holds and signs one fresh root
/// under the trusted key. So it may run only where the verification
/// failure is a claim about content that is gone. Here the surviving
/// content is not what a trusted key attested, and re-rooting would sign
/// that contradiction rather than report it.
///
/// Distinct from [`Self::Integrity`], which reports a partition that does
/// not verify. This reports a partition this process declines to change.
#[error(
"repair refused: a trusted signed root contradicts the content it covers, so re-rooting \
would sign the contradiction — preserve this partition and investigate (see \
docs/operations/eventlog-disaster-recovery.md)"
)]
RepairRefused,
/// A prior durability call (`append`, `commit`, `sync`, `prune`, `rewind`,
/// or a `snapshot` read) failed and, in doing so, consumed the underlying
/// journal handle. No later call can reach that handle again.
///
/// Commonware 2026.9's journal and qmdb receivers take `self` by value
/// and return it only on success, so a failed mutable call leaves no
/// handle behind. This variant is how the wrapper reports that fact
/// instead of synthesizing an "empty" or "not found" answer that would be
/// indistinguishable from real data loss (see INV-38 in
/// `docs/specifications/invariants.md`). The caller must reopen the log
/// to continue.
#[error("event log handle consumed by an earlier failed durability call; reopen the log")]
HandleConsumed,
/// The durable tail high-water ([`crate::highwater`]) failed to write, or
/// refused what it read.
#[error("event log tail high-water error: {0}")]
HighWater(#[from] crate::HighWaterError),
/// The durable floor checkpoint ([`crate::floor_checkpoint`], U-4b-1)
/// failed to write, or refused what it read.
#[error("event log floor checkpoint error: {0}")]
FloorCheckpoint(#[from] crate::FloorCheckpointError),
/// The durable prune-pass record ([`crate::prune_record`], U-4b-2)
/// failed to write, or refused what it read.
#[error("event log prune pass error: {0}")]
PruneRecord(#[from] crate::prune_record::PruneRecordError),
}