Skip to main content

View

Struct View 

Source
pub struct View {
    pub workspaces: BTreeMap<String, ContentHash>,
    pub changes: BTreeMap<String, ChangeState>,
    pub refs: BTreeMap<String, ContentHash>,
    pub reviews: BTreeMap<String, ReviewState>,
    pub provenance: BTreeMap<String, BTreeMap<String, String>>,
    pub checks: BTreeMap<String, CheckState>,
    pub bindings: BTreeMap<String, KeyBinding>,
    pub next_seq: u64,
    pub latest_snapshot: Option<RefSnapshot>,
    pub witnessed: BTreeMap<String, WitnessState>,
    pub vouches: BTreeMap<String, BTreeMap<String, VouchState>>,
}
Expand description

The materialized repo state: where every workspace and ref points.

A View is only ever produced by folding ops, so two replicas that replay the same log prefix hold identical views.

Fields§

§workspaces: BTreeMap<String, ContentHash>

Workspace name → head commit id.

§changes: BTreeMap<String, ChangeState>

Stable logical change id → owner, workspace and exact revision.

§refs: BTreeMap<String, ContentHash>

Ref name → target commit id.

§reviews: BTreeMap<String, ReviewState>

Review id → review state (fan-out and verdicts).

§provenance: BTreeMap<String, BTreeMap<String, String>>

Subject → record kind → latest body (D22 provenance records).

§checks: BTreeMap<String, CheckState>

<subject-hex>:<check-name> → the latest report for it (D49).

One flat map rather than subject → name → state, because every consumer of a view section wants the same two things: the ACL narrows section rows one at a time, and the node’s paging bounds them one at a time. A nested map would need both to learn a second shape, and “all checks on commit X” is still a prefix scan. The separator is : for the same reason refs uses it, and it cannot collide: a hex subject contains no :.

§bindings: BTreeMap<String, KeyBinding>

Actor key id → its durable operator binding (D24 T1/T3 substrate).

Keyed by ContentHash::to_hex rather than by the hash itself so it joins directly against the key_id a choir_oplog::Witness carries, which is how an entry names its author.

§next_seq: u64

Number of ops folded so far, which is the log sequence the next applied op will occupy.

It is a fold counter rather than a value read off the log, because View::apply is handed only the op — a signature this crate is deliberately not changing. The counter is correct because every path that builds a view applies exactly the log’s ops, in order, once: View::at replays a prefix, and a node’s live view starts from such a replay and then applies each entry the sequencer admits. A caller holding both can assert view.next_seq == entry.seq before applying; nothing inside the fold can check it on their behalf.

§latest_snapshot: Option<RefSnapshot>

The most recent admitted RefSnapshot, whole rather than by id: readers ask a view “what is the latest attestation?” and the chain check needs its identity, which RefSnapshot::id derives from the value.

§witnessed: BTreeMap<String, WitnessState>

Witness name to its latest attestation (D67). Only the current View::latest_snapshot is attestable, so every row here that names it is a live witness of the state the view is serving, and a row naming anything else is a witness that has fallen behind.

§vouches: BTreeMap<String, BTreeMap<String, VouchState>>

Vouched-for operator -> voucher -> the standing edge (D65).

Keyed by subject first because that is the question a reader brings: “who vouches for this actor”. The other direction is a scan, and it is the rarer one.

Nested rather than the flat a:b key View::checks uses, because that key would have to join two operator names and an operator name is free-form: any separator can occur inside one. checks gets away with : only because a hex subject cannot contain it, and borrowing the shape without the property is how two edges come to share a row.

Implementations§

Source§

impl View

Source

pub fn vouch_stands(&self, voucher: &str, subject: &str) -> bool

Whether voucher’s vouch for subject currently stands (D65).

One lookup for both directions of the question, so admission and withdrawal cannot come to disagree about what “already vouches” means.

Source

pub fn is_bound_operator(&self, operator: &str) -> bool

Whether operator holds at least one key binding that has not been revoked (D65).

Revoked bindings do not count. A vouch from an operator whose every key has been withdrawn would be a statement nobody can be held to, which is the shape the floor exists to refuse.

Source

pub fn validate(&self, op: &ViewOp) -> Result<(), ViewError>

Whether op would apply cleanly, without changing anything.

Every precondition in this model is a read — a CAS comparison, a key lookup, or a non-empty check — so admission can be decided against a shared &View rather than against a private copy of it. That is what lets the single-writer admission path stop cloning the whole view per submission.

View::apply calls this first and mutates only on Ok, so the two can never disagree about what is admissible. Keeping them as one code path is the point: a separate fast-path predicate that drifts from the real one is how “checked in check()” turns into a panic on the writer thread.

§Errors

The same failures View::apply would return for op.

Source

pub fn check_key(subject: &ContentHash, name: &str) -> String

The View::checks key for one (subject, check name) pair.

Source

pub fn checks_for(&self, subject: &ContentHash) -> Vec<(&str, &CheckState)>

Every check reported against subject, as (name, state) in name order.

Source

pub fn checks_verdict(&self, subject: &ContentHash) -> Option<CheckStatus>

The one answer for subject, or None when nothing reported.

Ranked by what the caller must do about it, worst first: Failed, then Errored, then Running, then Passed.

A failure outranks a run still in flight. Both are “not green”, but only one of them can still become green, and a caller deciding whether to wait needs that distinction to point the right way: told Running while a sibling check has already failed, it waits for an outcome that cannot arrive.

Errored outranks Running for exactly that reason and no other. A check that could not run will not become green by being waited on – somebody has to re-run it – so reporting Running beside it sends the caller to wait for an outcome that has already failed to arrive once. It sits below Failed because it is not evidence about the commit, and a summary that hid a real red build behind our own outage would be the D18 conflation again, pointed the other way.

Source

pub fn apply(&mut self, op: &ViewOp) -> Result<(), ViewError>

Applies one op, enforcing its CAS precondition. A rejected op leaves the view unchanged.

§Errors

Returns ViewError::StaleHead when prev does not match.

Source

pub fn snapshot(&self) -> RefSnapshot

The snapshot attesting this view’s current ref-state, chained to the latest admitted one — the value OpKind::RecordRefSnapshot admits as long as nothing lands in between (its at_seq is the CAS: any interleaved op moves the fold position and the emitter re-takes rather than attesting a state it did not read).

Source

pub fn bound_actor_at( &self, channel: &str, at: u64, ) -> Result<ContentHash, String>

The actor key the log binds to reviewer channel channel.

The inverse of KeyBinding::channel, and the join that lets an authorization record name approvers as actor ids when a review can only name channels (see Authorization::approvers).

Resolved as of fold position at (D44), which for an approver is the position of the verdict being credited (VerdictState::at) rather than the position of the landing.

Asking “now” is the bug this replaced. A channel’s key rotates: BindKey tells the holder of a revoked key to bind a fresh one, and the fresh one necessarily claims the same channel, because the channel is the operator’s own name. So resolving at landing time had two failures at once — with the withdrawn row still counted it left the channel permanently ambiguous and refused every later landing citing that reviewer, and with the withdrawn row ignored it would name the fresh key as the approver of a verdict that key never cast. Neither is a record worth keeping. The verdict’s own position has one answer and it is the true one.

Contrast View::operator_of, which answers for a revoked key unconditionally: that is attribution, and attribution must not go blind the moment a key is withdrawn.

The liveness half is exact; the channel half is the latest one. bound_at and Revocation::at are both recorded, so whether a key was live at at replays exactly. Which channel it claimed is read from the current binding, because a re-binding overwrites KeyBinding::channel in place and the fold keeps no history of it. A re-binding cannot change the operator (that is refused) and the channel must read as the operator, so the drift this permits is anaana/laptop within one operator, never across two. An exact answer would need View::at re-folded to at, which this method deliberately does not do: it is called from validate, which has no log.

§Errors

Returns a caller-facing reason when the log binds no key to channel, none that was live at at, or more than one that was. Ambiguity is refused, not resolved. Two keys may legitimately be live on one channel at once, and nothing in a review says which of them cast the verdict, so picking one would put a specific key in a durable record on the strength of a tiebreak. A record that says nothing is recoverable; one that says the wrong thing confidently is not.

“Nothing live at at” is its own message rather than folding into “no binding”: the repairs differ. One needs the operator to bind a key; the other needs a fresh verdict from a fresh key, because the approval on file was cast by a key nobody trusts now.

Source

pub fn operator_of(&self, key: &ContentHash) -> Option<&str>

The operator key is bound to, if the log ever bound it.

Deliberately still answers for a revoked key. Revocation withdraws authority going forward; it does not un-attribute what the key already did, and an audit that lost the operator the moment a key was revoked would go blind exactly when it matters. Authorization must therefore also consult KeyBinding::is_revoked; attribution must not.

Source

pub fn ops_since_binding(&self, key: &ContentHash) -> Option<u64>

Ops sequenced since key was first bound, measured at this view’s fold position.

Named for what it counts. This is an ordering and activity primitive: it says a key has been bound across N sequenced ops, and it is monotonic, replayable and unresettable. It is not a wall clock, and it must not be relabelled as one — ops are not uniformly spaced in time, so a question phrased in days or weeks (D24 T1’s <2 weeks branch) still needs a durable timestamp this crate does not have. A pure fold has no clock, the same reason OpKind::ArchiveReview’s lapse decision is made node-side and merely recorded here.

Source

pub fn operator_keys<'a>( &'a self, operator: &'a str, ) -> impl Iterator<Item = (&'a str, &'a KeyBinding)> + 'a

Every key currently bound to operator, revoked ones included, in key-id order.

Revoked keys stay in the count because the question T3 asks — how concentrated is control — is not answered by a number an operator can lower by revoking keys it no longer needs. Callers wanting only live keys filter on KeyBinding::is_revoked.

Source

pub fn materialize(log: &dyn OpLog) -> Result<Self, ViewError>

Folds the whole log into a view.

§Errors

Propagates decode and CAS failures; a log accepted through append_op always replays cleanly.

Source

pub fn at(log: &dyn OpLog, upto: u64) -> Result<Self, ViewError>

Folds only the first upto entries — the view as it was after op upto - 1. This is undo/time-travel: restore by writing a new op that sets heads back to this view (history itself is append-only).

§Errors

Same failure modes as View::materialize.

Trait Implementations§

Source§

impl Clone for View

Source§

fn clone(&self) -> View

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for View

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for View

Source§

fn default() -> View

Returns the “default value” for a type. Read more
Source§

impl PartialEq for View

Source§

fn eq(&self, other: &View) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for View

Source§

impl StructuralPartialEq for View

Auto Trait Implementations§

§

impl Freeze for View

§

impl RefUnwindSafe for View

§

impl Send for View

§

impl Sync for View

§

impl Unpin for View

§

impl UnsafeUnpin for View

§

impl UnwindSafe for View

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.