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;