Expand description
The commit log: the document’s only authoritative representation.
A document is an append-only history of typed ops. Everything else — the editor’s document state, routed geometry, spatial indexes — is derived from it and can be thrown away and rebuilt. That inversion is what makes undo and an audit trail cheap: the log holds every edit that ever landed, so a step back is another commit rather than an erasure.
The layering is strictly one-way:
commit log ──fold──▶ document ──solve──▶ derived ──▶ cachesOrder comes from a process, not a protocol: the
Repo assigns each accepted commit the next
Rev, so the total order on writes is submission order and
nothing else participates in establishing it. That is why there are no
clocks, no actor ids, no content-addressed history, and no merge pass
here.
Five rules keep it honest, and every one of them is load-bearing:
- All state is writes, creates, and deletes. An op names one entity and one field of it, and the last write to land stands, so the document is a function of the ops in log order. An op that does not reduce to those three breaks it.
- The fold is pure, and it is the only writer.
try_applyfolds into a new document, so a refused commit cannot leave a partial write behind and consumes no rev. No I/O, no clock, no randomness, and no re-running of the logic that produced an op — ids are minted before an op is recorded, never during replay. - Nothing derived is ever stored in the log. Solver output is a function of the whole document rather than of any one op, so it has no write order to merge under and must be recomputed instead.
- Unknown encodings are refused, never skipped. Half-loading a log written by a newer build forks the document silently. The decode boundary is a trust boundary — a log is a file the user’s tools can reach — so values arriving through it are range-checked and refused, never clamped.
- Global invariants are ingress preconditions, not repairs. One apply point means a cycle or a dangling reference can be refused before it is sequenced, rather than voided after the fact.
Per-kind structure is generated, not transcribed: one field list per
entity in block_model expands through the entity! macro to the
struct, its update vocabulary, and the Entity
impl — so a field cannot exist without a way to write it, and neither
can drift from the other.
See docs/single-author-playbook.md for the design and
docs/doc-ng-design-notes.md for why each piece is shaped as it is.
Modules§
- block_
model - The block model: entities and namespaces of the document.
Rationale:
docs/doc-ng-design-notes.md. - commit
- The commit — the sealed unit of edit, undo, and review: a labeled
batch of ops. The
Revand wall time are assigned as the commit is applied and live outside the payload. Rationale:docs/doc-ng-design-notes.md. - document
- The document root and the index derived from it.
Rationale:
docs/doc-ng-design-notes.md. - entity
- The
Entitytrait and theentity!macro that implements it: one field list per kind (block_model.rs) expands to the struct, its update vocabulary, and the trait impl — the mirror guard is generation, not transcription. - fixtures
- Test builders shared across the module’s suites.
- geometry
- Geometry value types for the document model.
- hash
- A simple wrapper for the blake3 hasher
- id
- opcode
- The opcode: one primitive edit, its target id bundled in. A commit’s
payload is a
Vec<OpCodes>; an op’s index in it is itsSeqin the total write order. Rationale:docs/doc-ng-design-notes.md. - repo
- The document, in one type: the folded
Documentand the commit log it folds. Rationale:docs/single-author-playbook.md. - rev
- The commit sequence number — the first component of the total write
order. Totality is structural: the head rev lives in the document and
is minted only by a successful
try_apply, so a refused commit consumes nothing and the log cannot gap. ARevoutside the fold is inert (try_applytakes no rev), sonextstays public while minting stays module-private. - trail
- The undo trail: which revs a session can step back to, and which forward.
- values
- Shared value enums: the closed vocabularies entity registers draw from.
Serde variant names are wire tags — never rename or repurpose a variant;
deprecate and add instead. Rationale:
docs/doc-ng-design-notes.md.