fix(privacy): publishing and suggestions after the short reading (ADR 0019)

Publishing is refused on the device where anything in the tree is sealed,
before any tag's name goes out: the tree and the tags' links are the
instance's to change. A suggestion leaves sealed files out, as the
instance could name another private tree's file through a planted row.
Docs: ADR 0019's "The short reading (22 Oct 2026)", and the general
residual risk that any device can be held at an earlier genuine record;
Learn's AGENTS.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-22 10:09:50 +02:00
commit 2d772a17e2
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -230,10 +230,12 @@ What changed:
Residual risks, written down:
- **A fresh device** that never saw a studyset private, while the instance
withholds its records and hands back an old readable row, can be made to
write readable there. Nothing on such a device says otherwise; the
person's other devices still see the signed records once they come.
- **Any device can be held at any earlier genuine record:** the instance
can withhold the records made since a device last synced, so it acts on
the latest it saw. A fresh device, which saw none, is the case that
matters: shown a studyset never made private as far as it knows, and an
old readable row, it can be made to write readable there. The person's
other devices still see the signed records once they come.
- **First sealing of tags and settings** on each device trusts what is
readable then: rows the instance planted before become the person's.
- **Old sealed content handed back** (a title, a card's earlier revision)
@ -241,3 +243,41 @@ Residual risks, written down:
- **Structure and rhythm** stay readable as before (D7); a card's place in
a tree is the instance's to change, which the item's own key keeps from
mattering for what is written, not for where it shows.
## The short reading (22 Oct 2026)
A short reading of the reading's fixes, its findings confirmed by probes on
the real gateways; each probe is a test now.
- **Rewrites stay in their own keys.** A rewrite or sweep changes only rows
under no key, under the target key, or under a key whose signed ID names
the studyset rewritten; rows under another studyset's key (which the
instance could have moved in) are left as they are. Only the person's
own moves re-key rows of other keys.
- **Item keys can't be led astray.** An item's key is never replaced by a
key a record ended, nor by another studyset's while the one kept holds,
and an item is written with its own key before its tree's.
- **Pending rewrites** the latest record no longer asks for are dropped,
so a make-readable cut short never runs over a later private record.
- **Failures stay small.** A file that won't move is counted and owed (the
tree partly readable meanwhile); each step of the upkeep fails alone.
- **Settings carry a version vector** (each device's count of writes,
`HLKV`): a row is a rollback only when it brings news from no device, so
two devices' changes at once both count.
- **Cheaper upkeep:** sweeps look rows up by their key, skip those known
unmovable, and ask for a sync only when they wrote.
- **One rewrite at a time,** each writing back only rows unchanged since it
read them.
- **Records outrun the clock:** a new record is made later than the latest
known about its studyset.
- **Fail-closed:** an unreadable `privacy.json` is kept aside and nothing
private is written until the keys are opened again; whether the account
has keys is the register's to say (`signInWays().password`), not the key
rows'.
- **Publishing** is refused on the device where anything in the tree is
sealed, before any tag's name goes out; a suggestion leaves sealed files
out.
Left open: the Publish sheet doesn't yet list the tag names it sends; Finish
doesn't offer to adopt unsigned edits after asking; a suggestion from a
private copy carries no files.