Skip to main content

Crate choir_view

Crate choir_view 

Source
Expand description

L1 view/workspace model: typed operations over the op log and the materialized repo state they fold into (DECISIONS.md jj-style).

The op log (choir_oplog) stores opaque payloads; this crate gives them a versioned schema (ViewOp) and a deterministic fold (View::materialize). Because the fold is pure, the view at any point in history is reconstructible by replaying a prefix (View::at) — that is the whole undo model, no reverse patches.

Commits are content-addressed objects in the chunk store (Commit/TreeEntry). A conflicted merge is a valid commit (TreeEntry::Conflict): work continues on top of it and the resolution is a later commit, never a blocked workspace (DECISIONS.md first-class conflicts, D9).

One-way-door rules (DECISIONS.md): every persisted shape here (ViewOp, Commit) carries format_version, and all identifiers are self-describing ContentHash envelopes.

§Examples

use choir_oplog::{MemLog, OpLog};
use choir_view::{View, ViewOp, OpKind, append_op};
use choir_hash::ContentHash;

let mut log = MemLog::new();
let commit_id = ContentHash::blake3(b"pretend commit");
append_op(&mut log, "agent-1", ViewOp::new(OpKind::SetWorkspaceHead {
    workspace: "agent-1".into(),
    commit: commit_id.clone(),
    prev: None,
})).unwrap();
let view = View::materialize(&log).unwrap();
assert_eq!(view.workspaces.get("agent-1"), Some(&commit_id));

§Where this sits

docs/architecture.md is the map of the whole workspace. This crate is L1, the view that refs, reviews and workspaces are all folded from.

It builds on choir_hash, choir_oplog and choir_store.

The workspace’s architecture, included here because this crate is the version model the rest of it folds into:

§Architecture

Many agents work on one repository; a single-writer sequencer puts every change in one total order; merge conflicts are values, not errors. This page maps the layers and the crate for each.

§The model

A change is a signed operation appended to an append-only log. One writer thread per repository decides the order, stamps a sequence number and appends. Refs, the review queue and workspace ownership are folds over that log, recomputed rather than stored. Undo is a function of position; two agents racing one ref get a compare-and-swap.

§Layers

Layer numbers match code comments and DECISIONS.md.

LayerConcernCrateDecision
L0Content-addressed storage: BLAKE3 + FastCDC chunkingchoir-store, choir-hashD6 (one-way)
L1The op log’s wire format, and the log-backend seamchoir-oplogD1, D16
L1The view: typed operations folded into workspaces, refs, reviewschoir-viewD1, D9
L2Speculative merge queue with a TCP-like windowchoir-queueD5
L3The node daemon: git smart-HTTP plus the platform APIchoir-nodeD12
L5Content-addressed provenancechoir-view (Provenance)D11 (one-way)
L8Identity: one ed25519 key per actor, signatures over log entrieschoir-identityD9 (one-way)
L10Transport: centralized now, peer-to-peer laterchoir-nodeD14 (gated)

Beside the stack:

CrateWhat it is
choir-sequencerThe single writer (D2), decision journal, fairness queue, lag meter
choir-actorA second implementation of the actor-runtime seam, on Rivet (D3); both pass one conformance suite
choir-mergeThe merge-strategy pipeline (D4/D19), cheapest first, Mergiraf as an optional subprocess

Tools: choir-cli (the choir binary and the surface table every generated document renders from), choir-bridge (forge follower, D21), choir-demo (narrated walkthrough), choir-spike (Phase-0 gate binary). choir-fs holds the atomic-write and lock primitives the binaries share. choir-guards holds source-scanning tripwires (D77).

§What one operation does

  agent
    │  choir submit / choir batch          (choir-cli)
    ▼
  POST /api/submit                          (choir-node)
    │  authenticate            --auth-file
    │  authorize               --acl-file            D29
    │  meter                   --rate-limit-api      D33
    │  bound the body          --quota-push-bytes    D37
    ▼
  fairness queue                            (choir-sequencer::fairness)
    │  one bounded window per actor, served round-robin
    ▼
  THE SINGLE WRITER                         (choir-sequencer)
    │  verify the signature                          (choir-identity)  L8
    │  run the admission policy                      (choir-view)
    │  compare-and-swap the ref it touches
    │  stamp seq, append                             (choir-oplog)     L1
    │  record the decision     --journal
    ▼
  the view is refolded                      (choir-view)
    │  refs, workspaces, reviews, provenance
    ▼
  ref landed → webhook        --hooks-file            D32
  • The order is decided in one place. Fairness decides who is asked next; the writer stamps seq alone and appends in that order.
  • Checks before the writer are advisory. The actor key the fairness queue buckets on is a claim; the signature is verified on the writer thread.

[!IMPORTANT] Nothing in front of the writer may become load-bearing for authorization.

§A conflict is a value

TreeEntry::Conflict in choir-view is a valid commit: hashed, signed, appended, and buildable on. The merge queue never blocks; a conflicting change is evicted from the speculative train as a conflict and the queue keeps moving. choir-merge is a pipeline (trivial, line, Mergiraf) where each strategy may decline.

§Replay purity

Replaying the log from zero must produce exactly the served state (D40). So:

  1. Derived data is never a durability barrier. Request log, decision journal and lag log are one-way records.
  2. Some projections are folded, not persisted. The per-user workspace tally behind --quota-workspaces is rebuilt from the log on restart.
  3. Accounts and credentials sit outside the log (D36). Revocation is deletion.

§What the format versions are for

FORMAT_VERSION appears in choir-store, choir-oplog and choir-view.

  • Hashes are self-describing: a codec byte names the function, so a migration adds a codec.
  • Fields needed later exist from day one: OpEntry::witnesses has always been present and empty (D16, D67).
  • Adding an operation variant is one-way for readers.

§Where to go next

You wantRead
To run onedocs/operating/running-a-node.md
To use onedocs/using/cli.md
Why a decision went the way it didDECISIONS.md
To catch up on a log and check a served pageSYNC.md

Structs§

ArchiveAuthorization
Owner-signed authorization carried into a node-authored physical workspace archive operation.
Authorization
Why a OpKind::Submit was allowed to land (D43).
ChangeState
Materialized identity and current revision of one logical change.
CheckState
The latest report for one (subject, check name) pair.
CommentState
One comment on a review, as the fold sees it after replaying OpKind::PostComment (D38).
Commit
A content-addressed commit: parents, a path→entry tree, metadata.
ConflictReport
Conflicts in one commit, split by whether the reader’s cone covers them (D50).
CreateAuthorization
Owner-signed authorization carried into a node-authored physical workspace creation operation.
KeyBinding
One actor key’s durable binding to an operator identity, as the fold sees it after replaying OpKind::BindKey and OpKind::RevokeKey.
OpScope
Where and when an op is admissible: the author’s own statement of which log they are submitting into and which head they observed.
RefSnapshot
A signed attestation that the complete ref-state at log position RefSnapshot::at_seq was exactly RefSnapshot::refs (D25).
ReviewState
Materialized state of one review: what is under review, who was asked, who has answered what, and what was said about it.
Revocation
The append-only record that a binding was withdrawn.
VerdictState
One reviewer’s answer, as the fold recorded it.
View
The materialized repo state: where every workspace and ref points.
ViewOp
A typed operation carried in OpEntry::payload.
VouchState
One standing vouch, as the fold sees it after replaying OpKind::Vouch (D65).
WitnessState
What one witness has attested, as the fold sees it after replaying OpKind::CountersignSnapshot (D67).

Enums§

Basis
The rule that admitted a landing, as the evaluation that admitted it computed it (D43).
CheckStatus
What an automated check found about a commit (D49).
OpKind
The view mutations. Head-moving ops carry prev (compare-and-set against the current view) so a stale writer is rejected instead of silently clobbering a concurrent advance — the same discipline the op log itself applies to its head.
Provenance
Which path authored an op, when it was not the default author-signed submission (D41).
ReviewStatus
Whether a review is still accepting verdicts, or has been settled and had its bulk dropped.
TreeEntry
One entry in a commit’s tree: a path maps to file content or to an unresolved conflict (first-class: committing this is valid, D9).
Verdict
A reviewer’s answer to a review request.
ViewError
Failure modes of view folding and commit storage.

Constants§

FORMAT_VERSION
Current view-op and commit wire-format version. Bump on any incompatible change; additive changes keep the version (DECISIONS.md).
MAX_APPROVAL_WEIGHT_PER_OPERATOR
Maximum approval weight contributed by one operator, regardless of how many agent channels that operator controls.

Functions§

append_op
Validates op against the log’s current view, then appends it as a new OpEntry — the single-writer submit path in miniature. The CAS check happens before the append, so the log never contains an op that fails to replay.
append_op_with_store
append_op, plus the resolution-link check a store makes possible: a head-moving op whose commit the store holds is refused when that commit’s Commit::resolves link is dangling or names a commit with no conflict to resolve.
cone_covers
Whether cone covers path, in git’s cone spelling.
conflicts_for_cone
Splits commit’s conflicts into what cone covers and what it does not.
reviewer_operator
The operator a review channel belongs to: the part before the first / in operator/agent, or the whole name when no prefix is present.