oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1# Document body sealing implementation spec
2
3Status: approved for implementation by Claude Fable 5.1
4(`claude-fable-5-1`), session
5`8aa40554-38b1-4597-9cb8-439ab594e268`. The final rollout amendment and
6approval are recorded in Amadan Docs discussion 39. Whole-branch review,
7exact-head CI, release integration, canary and deployment evidence are
8separate gates.
9
10## Scope and encoding
11
12Seal `doc_updates.update_bin` and `doc_snapshots.state`. Titles and other
13metadata are outside this slice. Historical plaintext backups remain
14preserved and are not claimed encrypted by this change.
15
16Use a separate `DOCS_CONTENT_KEY`: strict standard-base64 encoding of 32
17random bytes. Require it in production before opening the database, even
18before activation. Only explicit development mode may use the fixed public
19development key; maintenance always validates as production.
20
21Encoding 1 uses AES-256-GCM with a random 12-byte nonce prepended to the
22ciphertext and tag. Associated data binds the fixed content domain, row
23kind, immutable document UUID, sequence and snapshot ABI version. Allocate
24the sequence inside the writer transaction before sealing the update.
25Never send ciphertext to the CRDT core or sync clients. Decrypt and
26validate all response rows before writing HTTP success headers.
27
28The additive migration creates encoding columns defaulting to 0 and a
29singleton activation marker containing encoding, key fingerprint,
30authenticated keycheck and scrubbed bookkeeping. Keycheck binds a fixed
31sentinel and remains meaningful for an empty database. Wrong-key errors
32are distinct from authentication failures and never include content bytes.
33
34## Runtime states
35
36A database without the marker is in legacy compatibility mode. Refuse
37startup if it already contains nonzero encoding rows. Log an Error on
38every legacy boot with structured encoding and key-fingerprint fields.
39Legacy reads accept only encoding 0. Both update and snapshot inserts
40re-read the marker through the same writer transaction as the insert and
41refuse if activation has occurred. A process never switches modes live.
42
43A database with the marker verifies its keycheck and refuses startup if
44an EXISTS query finds any update or snapshot with encoding other than 1.
45Activated reads reject other encodings and authenticate every body used.
46An unusable snapshot may be abandoned for the retained update log; it is
47an accelerator and is never the only copy of document history.
48
49## Explicit maintenance
50
51Only the `docs-seal` subcommand invokes conversion or scrubbing. It requires
52an existing regular database path and the expected key fingerprint. Read
53the key only from `DOCS_CONTENT_KEY`. Reuse the exact server `BootSchema`.
54Never resolve serving options, bind a listener or start replication.
55There is no deactivate or marker-removal operation.
56
57Conversion is one transaction. Process bounded batches, bind bodies to
58their stored document UUID, verify already-sealed rows and reject unknown
59encodings or orphaned rows. On first conversion write the keycheck marker
60atomically with the converted rows. On explicit repair of an activated
61mixed database, convert remaining encoding-0 rows while leaving the marker,
62fingerprint and keycheck unchanged. Clear only scrubbed bookkeeping when
63new legacy bytes have been converted. Any failure rolls back all changes.
64
65Scrubbing is an explicit operation after conversion. The operator stops
66the server and replication first. Set scrubbed false, use a pinned writer
67connection, check the complete TRUNCATE-checkpoint result, VACUUM, check a
68second TRUNCATE checkpoint, and set scrubbed true only on success. A busy
69checkpoint is failure. Never put conversion or VACUUM on normal startup.
70Every restored copy needs another explicit scrub; its stored scrubbed bit
71is not evidence about the restored file's pages or WAL.
72
73## Rollout constraints
74
75Deploy and smoke-test the compatibility-capable release with the real
76production key before activation. Retain that exact release as the rollback
77target. Verify key fingerprint and backup/key recovery before conversion.
78Stop serving and replication for maintenance, then restart the same
79compatibility-capable release after activation. Never roll back to an older
80plaintext-only binary once sealed rows exist. Preserve historical backups.
81A restored pre-conversion backup is visibly legacy and needs activation;
82it must never be silently presented as encrypted.
83
84## Required evidence
85
86Use actual Yjs fixtures and real SQLite. Cover authenticated row identity,
87wrong keys and tampering; encrypted HTTP read/write and snapshots; stale
88legacy reads and writes; both tables' mixed-state startup checks; explicit
89maintenance inputs; atomic repair and marker preservation; raw database
90and WAL canaries; incomplete checkpoints; process-exit recovery; and an
91independent restored-copy rehearsal. Observe meaningful tests fail when
92their safeguards are removed, then restore the code. Full repository CI
93and an independent complete-diff review remain required before merge.
94