Skip to main content

blockworx_doc/
lib.rs

1//! The commit log: the document's only authoritative representation.
2//!
3//! A document is an append-only history of typed ops. Everything else —
4//! the editor's document state, routed geometry, spatial indexes — is
5//! derived from it and can be thrown away and rebuilt. That inversion is
6//! what makes undo and an audit trail cheap: the log holds every edit
7//! that ever landed, so a step back is another commit rather than an
8//! erasure.
9//!
10//! The layering is strictly one-way:
11//!
12//! ```text
13//! commit log  ──fold──▶  document  ──solve──▶  derived  ──▶  caches
14//! ```
15//!
16//! Order comes from a **process, not a protocol**: the
17//! [`Repo`](repo::Repo) assigns each accepted commit the next
18//! [`Rev`](rev::Rev), so the total order on writes is submission order and
19//! nothing else participates in establishing it. That is why there are no
20//! clocks, no actor ids, no content-addressed history, and no merge pass
21//! here.
22//!
23//! Five rules keep it honest, and every one of them is load-bearing:
24//!
25//! 1. **All state is writes, creates, and deletes.** An op names one
26//!    entity and one field of it, and the last write to land stands, so
27//!    the document is a function of the ops in log order. An op that does
28//!    not reduce to those three breaks it.
29//! 2. **The fold is pure, and it is the only writer.**
30//!    [`try_apply`](document::Document::try_apply) folds into a *new*
31//!    document, so a refused commit cannot leave a partial write behind
32//!    and consumes no rev. No I/O, no clock, no randomness, and no
33//!    re-running of the logic that produced an op — ids are minted before
34//!    an op is recorded, never during replay.
35//! 3. **Nothing derived is ever stored in the log.** Solver output is a
36//!    function of the whole document rather than of any one op, so it has
37//!    no write order to merge under and must be recomputed instead.
38//! 4. **Unknown encodings are refused, never skipped.** Half-loading a log
39//!    written by a newer build forks the document silently. The decode
40//!    boundary is a trust boundary — a log is a file the user's tools can
41//!    reach — so values arriving through it are range-checked and refused,
42//!    never clamped.
43//! 5. **Global invariants are ingress preconditions, not repairs.** One
44//!    apply point means a cycle or a dangling reference can be refused
45//!    before it is sequenced, rather than voided after the fact.
46//!
47//! Per-kind structure is generated, not transcribed: one field list per
48//! entity in [`block_model`] expands through the `entity!` macro to the
49//! struct, its update vocabulary, and the [`Entity`](entity::Entity)
50//! impl — so a field cannot exist without a way to write it, and neither
51//! can drift from the other.
52//!
53//! See `docs/single-author-playbook.md` for the design and
54//! `docs/doc-ng-design-notes.md` for why each piece is shaped as it is.
55
56pub mod block_model;
57pub mod commit;
58pub mod document;
59pub mod entity;
60#[cfg(any(test, feature = "fixtures"))]
61pub mod fixtures;
62pub mod geometry;
63pub mod hash;
64pub mod id;
65pub mod opcode;
66pub mod repo;
67pub mod rev;
68pub mod trail;
69pub mod values;