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
1 file changed,
+18
−0
docs/superpowers/specs/2026-08-30-docs-design.md+18 −0
No CI script — run details
Intent
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. |