Spec: the ABI needs state export before a real document uses it
Found by executing plan 1. ABI v1 has no state-export, so the host can only recover a trapped instance by replaying every update it has seen -- which makes the retained log load-bearing, and a bound on the log becomes a bound on the document. The sharp consequence, which a review found and I had not anticipated: rehydrating a document from persisted updates replays them through the same path, so a document with more history than the cap would be UNLOADABLE rather than merely slow. And 4096 sounds generous until you notice Yjs emits an update per keystroke burst, so ordinary editing crosses it, not just abuse. Recovery must restore a snapshot and replay only what follows -- which is what §4.1's snapshot cadence already exists for and what ABI v1 cannot express. Until then the host is falsification-grade, not production-grade, and that is now written down rather than implied.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011F5CivVm4CmL9ByfSSAaXA
1 file changed,
+18
−1
docs/superpowers/specs/2026-08-30-docs-design.md+18 −1
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 8733e0d..9019305 100644 |
| --- a/docs/superpowers/specs/2026-08-30-docs-design.md |
| +++ b/docs/superpowers/specs/2026-08-30-docs-design.md |
| @@ -279,6 +279,18 @@ cycle is bursty and coarse. |
| and stops when page geometry reconverges, returning a box-tree delta |
| rather than the whole tree. Without this a keystroke on page 3 of 120 |
| relays out everything and marshals the result across the boundary. |
| +- **The ABI must export state encode/decode before any real document uses |
| + it.** *(Found by executing plan 1, 2026-08-30.)* ABI v1 has no |
| + state-export, so the host can only recover a trapped instance by replaying |
| + every update it has seen. That is not merely slow — it makes the retained |
| + log load-bearing, and a bound on it becomes a bound on the document. A cap |
| + of 4096 updates sounds generous until you notice Yjs emits an update per |
| + keystroke burst, and that **rehydrating a document from persisted updates |
| + replays them through the same path**, so a document with more history than |
| + the cap would be unloadable rather than merely slow. Recovery must |
| + therefore restore a snapshot (§4.1) and replay only what follows it, which |
| + is what §4.1's snapshot cadence exists for and what ABI v1 cannot express. |
| + Until then the host is falsification-grade, not production-grade. |
| --- |
| @@ -926,7 +938,12 @@ thumbnails all fall out of it. |
| both can hand-roll verification and would rather not do it twice, |
| differently. |
| 5. **`.amadan/ci.d/10-gate`** arrives with the first code branch. |
| -6. **The three-language cost.** Revisit once the crate is real. Revision 2 |
| +6. **ABI v2 state export**, before `internal/core` has a real caller. The |
| + in-memory replay log is capped at 4096 updates with a clean failure, which |
| + bounds the count but not the bytes, has no recovery path, and would make a |
| + long-lived document unloadable. Acceptable only while nothing imports the |
| + package — verified by grep, not assumed. |
| +7. **The three-language cost.** Revisit once the crate is real. Revision 2 |
| already spent this clause once — the "same artifact both sides" claim did |
| not survive contact — so the next honest answer may be that the crate |
| shrinks to layout alone. |