oficina / docs Public

Spec: gate the CRDT entropy rule, after it was wrong three times

Second gate to come out of executing plan 1. On wasm the custom getrandom
hook refuses entropy and fastrand masks that with a constant seed, so
anything drawing randomness from yrs is identical across processes -- and
a Yjs client id or document GUID repeating across processes corrupts
documents.

It is a gate rather than a rule because the rule was wrong three times
while being written: the dependency was assumed dead-stripped (naming Doc
pulls it in), an erroring hook was assumed to fail loudly (fastrand
swallows it), and Doc::with_client_id was assumed safe (it draws a GUID
via uuid_v4). Each version was correct about what its author could see,
which is exactly why a comment is not adequate enforcement.

Construction now always uses Options::with_guid_and_client_id with both
values assigned by the instance that owns the document -- which is where
they should come from anyway, so the constraint improved the design
rather than merely constraining it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011F5CivVm4CmL9ByfSSAaXA
Paul Campbell pushed by paul@keymail.dev bc29de7274164c8c1fb3b80ef5eb7f8d5bbe79d3 parent 1cf4941
1 file changed, +18 −0
  • docs/superpowers/specs/2026-08-30-docs-design.md +18 −0

No CI script — run details

diff --git a/docs/superpowers/specs/2026-08-30-docs-design.md b/docs/superpowers/specs/2026-08-30-docs-design.md
index c33efda..79f6eb3 100644
--- a/docs/superpowers/specs/2026-08-30-docs-design.md
+++ b/docs/superpowers/specs/2026-08-30-docs-design.md
@@ -803,6 +803,24 @@ Corrected.
the DOM's actual page-break positions match the engine's computed ones. This
is the gate revision 1 lacked — its conformance test compared wazero to a
browser running *the same module* and never checked what the DOM painted.
+- **No entropy from the CRDT library**, enforced by `clippy.toml`
+ `disallowed-methods` on `yrs::Doc::new`, `yrs::Doc::with_client_id` and
+ `yrs::uuid_v4`, run before every build. *(Added 2026-08-30 from executing
+ plan 1.)* On wasm the custom `getrandom` hook refuses to produce entropy
+ and `fastrand` masks that with a constant seed, so anything drawing
+ randomness from `yrs` is **identical across processes** — and a Yjs client
+ id or document GUID that repeats across processes corrupts documents.
+ Construction therefore always uses
+ `Options::with_guid_and_client_id(guid, client_id)`, with both values
+ assigned by the instance that owns the document, which is where they
+ should come from anyway.
+
+ This is a gate rather than a rule because the rule was wrong three times
+ in three different ways while being written: the dependency was assumed
+ dead-stripped (naming `Doc` pulls it in), an erroring hook was assumed to
+ fail loudly (`fastrand` swallows it), and `Doc::with_client_id` was assumed
+ safe (it draws a GUID). Each version was correct about what its author
+ could see. A rule with that history does not get enforced by a comment.
- **Performance budgets, as gates rather than hopes:** keystroke-to-repaint on
a 120-page fixture, full layout time, and the wazero pool's peak memory
against a 512MB ceiling.