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.
| Layer | Concern | Crate | Decision |
|---|---|---|---|
| L0 | Content-addressed storage: BLAKE3 + FastCDC chunking | choir-store, choir-hash | D6 (one-way) |
| L1 | The op log’s wire format, and the log-backend seam | choir-oplog | D1, D16 |
| L1 | The view: typed operations folded into workspaces, refs, reviews | choir-view | D1, D9 |
| L2 | Speculative merge queue with a TCP-like window | choir-queue | D5 |
| L3 | The node daemon: git smart-HTTP plus the platform API | choir-node | D12 |
| L5 | Content-addressed provenance | choir-view (Provenance) | D11 (one-way) |
| L8 | Identity: one ed25519 key per actor, signatures over log entries | choir-identity | D9 (one-way) |
| L10 | Transport: centralized now, peer-to-peer later | choir-node | D14 (gated) |
Beside the stack:
| Crate | What it is |
|---|---|
choir-sequencer | The single writer (D2), decision journal, fairness queue, lag meter |
choir-actor | A second implementation of the actor-runtime seam, on Rivet (D3); both pass one conformance suite |
choir-merge | The 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
seqalone 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:
- Derived data is never a durability barrier. Request log, decision journal and lag log are one-way records.
- Some projections are folded, not persisted. The per-user workspace
tally behind
--quota-workspacesis rebuilt from the log on restart. - 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::witnesseshas always been present and empty (D16, D67). - Adding an operation variant is one-way for readers.
§Where to go next
| You want | Read |
|---|---|
| To run one | docs/operating/running-a-node.md |
| To use one | docs/using/cli.md |
| Why a decision went the way it did | DECISIONS.md |
| To catch up on a log and check a served page | SYNC.md |
Structs§
- Archive
Authorization - Owner-signed authorization carried into a node-authored physical workspace archive operation.
- Authorization
- Why a
OpKind::Submitwas allowed to land (D43). - Change
State - Materialized identity and current revision of one logical change.
- Check
State - The latest report for one
(subject, check name)pair. - Comment
State - 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.
- Conflict
Report - Conflicts in one commit, split by whether the reader’s cone covers them (D50).
- Create
Authorization - 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::BindKeyandOpKind::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_seqwas exactlyRefSnapshot::refs(D25). - Review
State - 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.
- Verdict
State - 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. - Vouch
State - One standing vouch, as the fold sees it after replaying
OpKind::Vouch(D65). - Witness
State - 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).
- Check
Status - 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).
- Review
Status - Whether a review is still accepting verdicts, or has been settled and had its bulk dropped.
- Tree
Entry - 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.
- View
Error - 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
opagainst the log’s current view, then appends it as a newOpEntry— 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’sCommit::resolveslink is dangling or names a commit with no conflict to resolve.- cone_
covers - Whether
conecoverspath, in git’s cone spelling. - conflicts_
for_ cone - Splits
commit’s conflicts into whatconecovers and what it does not. - reviewer_
operator - The operator a review channel belongs to: the part before the first
/inoperator/agent, or the whole name when no prefix is present.