use crate::history::clock::{ClockProvenance, ClockSource, TamperResistance, TrustGrade};
use crate::history::epoch::{MaterializationSafety, TopologyKind};
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum OrderingBasis {
SequenceOnly,
SaltQualifiedSequence,
WallTimeWithRecordId,
ContentHashDag,
DiscreteSnapshotSet,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SourceTemporalProfile {
pub clock: ClockProvenance,
pub safety: MaterializationSafety,
pub topology: TopologyKind,
pub ordering: OrderingBasis,
}
impl SourceTemporalProfile {
#[must_use]
pub fn sqlite_wal() -> Self {
Self {
clock: sqlite_wal_clock(),
safety: SQLITE_WAL_SAFETY,
topology: TopologyKind::SubJournalCommits,
ordering: OrderingBasis::SaltQualifiedSequence,
}
}
#[must_use]
pub fn evtx() -> Self {
Self {
clock: ClockProvenance {
source: ClockSource::LogRecord,
trust_grade: TrustGrade::LocalSubsystem,
tamper_resistance: TamperResistance::AdminWritable,
ordering_only: false,
skew_known: None,
authenticated: None,
},
safety: MaterializationSafety::ReadOnlySafe,
topology: TopologyKind::LinearJournal,
ordering: OrderingBasis::WallTimeWithRecordId,
}
}
#[must_use]
pub fn usn_journal() -> Self {
Self {
clock: ClockProvenance {
source: ClockSource::LogRecord,
trust_grade: TrustGrade::LocalSubsystem,
tamper_resistance: TamperResistance::AdminWritable,
ordering_only: false,
skew_known: None,
authenticated: None,
},
safety: MaterializationSafety::ReadOnlySafe,
topology: TopologyKind::LinearJournal,
ordering: OrderingBasis::WallTimeWithRecordId,
}
}
#[must_use]
pub fn ese_journal() -> Self {
Self {
clock: ClockProvenance {
source: ClockSource::SequenceOnly,
trust_grade: TrustGrade::OrderingOnly,
tamper_resistance: TamperResistance::AdminWritable,
ordering_only: true,
skew_known: None,
authenticated: None,
},
safety: MaterializationSafety::ReadOnlyRequiresCareful,
topology: TopologyKind::SubJournalCommits,
ordering: OrderingBasis::SequenceOnly,
}
}
#[must_use]
pub fn journald() -> Self {
Self {
clock: ClockProvenance {
source: ClockSource::LogRecord,
trust_grade: TrustGrade::LocalSubsystem,
tamper_resistance: TamperResistance::AdminWritable,
ordering_only: false,
skew_known: None,
authenticated: None,
},
safety: MaterializationSafety::ReadOnlySafe,
topology: TopologyKind::LinearJournal,
ordering: OrderingBasis::WallTimeWithRecordId,
}
}
#[must_use]
pub fn vss() -> Self {
Self {
clock: ClockProvenance {
source: ClockSource::FileMetadata,
trust_grade: TrustGrade::LocalSubsystem,
tamper_resistance: TamperResistance::AdminWritable,
ordering_only: false,
skew_known: None,
authenticated: None,
},
safety: MaterializationSafety::ReadOnlySafe,
topology: TopologyKind::DiscreteSet,
ordering: OrderingBasis::DiscreteSnapshotSet,
}
}
#[must_use]
pub fn git() -> Self {
Self {
clock: ClockProvenance {
source: ClockSource::ApplicationEmbedded,
trust_grade: TrustGrade::LocalApplication,
tamper_resistance: TamperResistance::Trivial,
ordering_only: false,
skew_known: None,
authenticated: None,
},
safety: MaterializationSafety::ReadOnlySafe,
topology: TopologyKind::Dag,
ordering: OrderingBasis::ContentHashDag,
}
}
#[must_use]
pub fn all() -> [Self; 7] {
[
Self::sqlite_wal(),
Self::evtx(),
Self::usn_journal(),
Self::ese_journal(),
Self::journald(),
Self::vss(),
Self::git(),
]
}
}
#[must_use]
pub fn sqlite_wal_clock() -> ClockProvenance {
ClockProvenance {
source: ClockSource::SequenceOnly,
trust_grade: TrustGrade::OrderingOnly,
tamper_resistance: TamperResistance::UserWritable,
ordering_only: true,
skew_known: None,
authenticated: None,
}
}
pub const SQLITE_WAL_SAFETY: MaterializationSafety = MaterializationSafety::ReadOnlyRequiresCareful;
#[cfg(test)]
mod tests {
use super::*;
use crate::history::clock::{ClockSource, TamperResistance, TrustGrade};
use crate::history::epoch::{MaterializationSafety, TopologyKind};
#[test]
fn sqlite_wal_clock_is_ordering_only_and_user_writable() {
let c = sqlite_wal_clock();
assert_eq!(c.source, ClockSource::SequenceOnly);
assert_eq!(c.trust_grade, TrustGrade::OrderingOnly);
assert_eq!(c.tamper_resistance, TamperResistance::UserWritable);
assert!(c.ordering_only);
assert!(c.authenticated.is_none());
assert!(c.skew_known.is_none());
}
#[test]
fn sqlite_wal_safety_requires_careful_reader() {
assert_eq!(
SQLITE_WAL_SAFETY,
MaterializationSafety::ReadOnlyRequiresCareful
);
}
#[test]
fn sqlite_wal_profile_bundles_the_four_axes_plus_ordering_shape() {
let p = SourceTemporalProfile::sqlite_wal();
assert_eq!(p.clock, sqlite_wal_clock());
assert_eq!(p.safety, MaterializationSafety::ReadOnlyRequiresCareful);
assert_eq!(p.topology, TopologyKind::SubJournalCommits);
assert_eq!(p.ordering, OrderingBasis::SaltQualifiedSequence);
}
#[test]
fn evtx_profile_has_wall_time_unlike_wal() {
let p = SourceTemporalProfile::evtx();
assert_eq!(p.clock.source, ClockSource::LogRecord);
assert!(!p.clock.ordering_only);
assert_eq!(p.clock.trust_grade, TrustGrade::LocalSubsystem);
assert_eq!(p.clock.tamper_resistance, TamperResistance::AdminWritable);
assert_eq!(p.safety, MaterializationSafety::ReadOnlySafe);
assert_eq!(p.topology, TopologyKind::LinearJournal);
assert_eq!(p.ordering, OrderingBasis::WallTimeWithRecordId);
assert_ne!(p.ordering, SourceTemporalProfile::sqlite_wal().ordering);
}
#[test]
fn every_source_profile_keeps_ordering_only_in_sync_with_its_clock() {
for p in SourceTemporalProfile::all() {
assert_eq!(
p.clock.ordering_only,
p.clock.source == ClockSource::SequenceOnly,
"ordering_only must track SequenceOnly for {:?}",
p.ordering
);
}
}
#[test]
fn registry_is_not_journal_shaped() {
assert_eq!(
SourceTemporalProfile::vss().topology,
TopologyKind::DiscreteSet
);
assert_eq!(
SourceTemporalProfile::vss().ordering,
OrderingBasis::DiscreteSnapshotSet
);
assert_eq!(SourceTemporalProfile::git().topology, TopologyKind::Dag);
assert_eq!(
SourceTemporalProfile::git().ordering,
OrderingBasis::ContentHashDag
);
assert_eq!(
SourceTemporalProfile::git().clock.tamper_resistance,
TamperResistance::Trivial
);
}
}