Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@
`Braid::membership_history()` expose accepted `MemberWoven` facts as a
read-only projection over the braid event log, while `frontier()` remains the
current membership projection.
- `warp-core` now exposes historical braid membership views through
`BraidMembershipCursor`, `Braid::current_membership_cursor()`, and
`Braid::membership_at(...)`. The cursor is a half-open event-log interval, so
later woven members do not appear in earlier membership views.
- `warp-core` now exposes `BraidMembershipDiff` through
`Braid::diff_membership(...)`, reporting deterministic added and ended
membership projection facts between historical cursors while reserving
revealed/concealed fact slots for future lawful disclosure evidence.
- `warp-core` now exposes retained braid shell replay/audit facts through
`audit_braid_shell(...)` and `BraidShellAudit`, including member verdicts,
support/frontier digests, posture floor, proof binding, and explicit
self-witness integrity-only posture.
- The braids/strands hardening docs now define the Braid Flight Recorder and
Causal X-Ray lower-mode output target over historical membership, diff, shell
audit, proof-binding, and witness-posture facts.
- `warp-core` now enforces the v1 single-writer-head strand invariant through
both `Strand::new(...)` and `StrandRegistry::insert(...)`, and runtime strand
forking constructs the registered relation through the same constructor
Expand Down
155 changes: 154 additions & 1 deletion crates/warp-core/src/braid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// © James Ross Ω FLYING•ROBOTS <https://github.com/flyingrobots>
//! Evolving coordination log ("Braid") representation.

use std::collections::BTreeSet;
use std::collections::{BTreeMap, BTreeSet};
use thiserror::Error;

use crate::braid_shell::BraidMemberRef;
Expand Down Expand Up @@ -140,6 +140,78 @@ pub struct BraidMembershipEntry {
pub sequence_num: u64,
}

/// Half-open cursor over accepted braid membership events.
///
/// A cursor names the membership interval `[0, next_sequence_num)`.
/// `BraidMembershipCursor::new(0)` is the post-creation interval before any
/// member weave. `BraidMembershipCursor::new(2)` includes accepted member
/// weave sequence numbers `0` and `1`, but excludes sequence `2`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct BraidMembershipCursor {
next_sequence_num: u64,
}

impl BraidMembershipCursor {
/// Creates a membership cursor from the next weave sequence number.
#[must_use]
pub const fn new(next_sequence_num: u64) -> Self {
Self { next_sequence_num }
}

/// Returns the first member weave sequence number excluded by this cursor.
#[must_use]
pub const fn next_sequence_num(self) -> u64 {
self.next_sequence_num
}
}

/// One disclosure-posture change detected between membership projections.
///
/// The current append-only braid event model cannot infer that one sealed
/// reference and one revealed reference identify the same member without
/// external unsealing material. This type reserves the fact vocabulary for
/// future lawful reveal/conceal events; current diffs leave these vectors
/// empty rather than guessing.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BraidMembershipDisclosureChange {
/// Membership fact before the disclosure posture changed.
pub from: BraidMembershipEntry,
/// Membership fact after the disclosure posture changed.
pub to: BraidMembershipEntry,
}

/// Difference between two historical braid membership projections.
///
/// This is a read model over accepted braid events, not an admission token and
/// not a mutation. `ended` means present at `from` and absent at `to`; it does
/// not imply that append-only history was rewritten.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BraidMembershipDiff {
/// Source cursor for the diff.
pub from: BraidMembershipCursor,
/// Target cursor for the diff.
pub to: BraidMembershipCursor,
/// Members present at `to` and absent at `from`.
pub added: Vec<BraidMembershipEntry>,
/// Members present at `from` and absent at `to`.
pub ended: Vec<BraidMembershipEntry>,
/// Members whose reference posture became revealed, when lawfully known.
pub revealed: Vec<BraidMembershipDisclosureChange>,
/// Members whose reference posture became concealed, when lawfully known.
pub concealed: Vec<BraidMembershipDisclosureChange>,
}

impl BraidMembershipDiff {
/// Returns whether the diff carries no membership or disclosure changes.
#[must_use]
pub fn is_empty(&self) -> bool {
self.added.is_empty()
&& self.ended.is_empty()
&& self.revealed.is_empty()
&& self.concealed.is_empty()
}
}

/// Evolving state of a coordination braid reconstructed from its event log.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Braid {
Expand Down Expand Up @@ -341,6 +413,77 @@ impl Braid {
.collect()
}

/// Returns the cursor for the current membership projection.
///
/// Saving this value before later member weaving lets callers request the
/// historical membership view that was current at that event-log interval.
#[must_use]
pub fn current_membership_cursor(&self) -> BraidMembershipCursor {
BraidMembershipCursor::new(self.next_sequence_num)
}

/// Returns accepted membership facts visible at the requested cursor.
///
/// This projection is derived from accepted [`BraidEvent::MemberWoven`]
/// facts. It does not read the current frontier, so later members do not
/// appear in earlier historical views.
#[must_use]
pub fn membership_at(&self, cursor: BraidMembershipCursor) -> Vec<BraidMembershipEntry> {
self.events
.iter()
.filter_map(|event| match event {
BraidEvent::MemberWoven {
member_ref,
sequence_num,
} if *sequence_num < cursor.next_sequence_num() => Some(BraidMembershipEntry {
member_ref: *member_ref,
sequence_num: *sequence_num,
}),
BraidEvent::BraidCreated { .. }
| BraidEvent::MemberWoven { .. }
| BraidEvent::SettlementFinalized { .. }
| BraidEvent::BraidCollapsed { .. } => None,
})
.collect()
}

/// Returns membership change facts between two historical cursors.
///
/// The diff compares projections derived from accepted event-log facts.
/// It does not mutate braid state and does not infer sealed/revealed
/// equivalence without explicit disclosure evidence.
#[must_use]
pub fn diff_membership(
&self,
from: BraidMembershipCursor,
to: BraidMembershipCursor,
) -> BraidMembershipDiff {
let from_membership = self.membership_at(from);
let to_membership = self.membership_at(to);
let from_index = membership_index(&from_membership);
let to_index = membership_index(&to_membership);

let added = to_membership
.iter()
.copied()
.filter(|entry| !from_index.contains_key(&entry.member_ref))
.collect();
let ended = from_membership
.iter()
.copied()
.filter(|entry| !to_index.contains_key(&entry.member_ref))
.collect();

BraidMembershipDiff {
from,
to,
added,
ended,
revealed: Vec::new(),
concealed: Vec::new(),
}
}

/// Returns the current coordination frontier (active woven members).
///
/// This is the current projection over [`Self::membership_history`], not a
Expand All @@ -351,6 +494,16 @@ impl Braid {
}
}

fn membership_index(
entries: &[BraidMembershipEntry],
) -> BTreeMap<BraidMemberRef, BraidMembershipEntry> {
entries
.iter()
.copied()
.map(|entry| (entry.member_ref, entry))
.collect()
}

const fn member_ref_is_sealed(member_ref: &BraidMemberRef) -> bool {
matches!(member_ref, BraidMemberRef::Sealed { .. })
}
Expand Down
Loading
Loading