docs(privacy): the reading of private studysets (ADR 0019)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
46a47d0975
commit
28372a35e6
1 changed files with 93 additions and 6 deletions
|
|
@ -132,8 +132,10 @@ millisecond), its table and the columns it changed.
|
|||
new rows in its content (whole `asset:` values and a PDF's file, never
|
||||
text) and blanks the old rows nothing else names.
|
||||
- **The marker** (the developer's, 21 Oct): on the library's cards and the
|
||||
studyset's Share alike, a lock for private, an open lock for readable by
|
||||
the instance and not published, a globe for published. The locks open
|
||||
studyset's Share alike, a lock for private (published before or not), a
|
||||
shield with a warning for private but partly readable or unsealed (the
|
||||
reading of 22 Oct), an open lock for readable by the instance and not
|
||||
published, a globe for published. The locks open
|
||||
one dialog saying what that means and changing it (and, while not
|
||||
private, leading to the Publish sheet); the globe opens the Publish
|
||||
sheet.
|
||||
|
|
@ -143,9 +145,8 @@ millisecond), its table and the columns it changed.
|
|||
instance keeps the setting, as D2 asks, but the person's choice is still
|
||||
made where it was.
|
||||
- **Tag names:** the instance refuses a name sent for a tag that isn't the
|
||||
person's and a release whose encrypted tag has none; names of the
|
||||
person's tags the release doesn't carry are ignored rather than refused,
|
||||
as the device sends all its tags' names.
|
||||
person's and a release whose encrypted tag has none; since the reading of
|
||||
22 Oct the device sends only the names of the tags the release carries.
|
||||
- **Locked rows:** a studyset whose key doesn't open shows as locked; its
|
||||
other rows read as blank, which the lists leave out; a tag or settings
|
||||
row that doesn't open is left out entirely, so nothing folds or deletes
|
||||
|
|
@ -154,3 +155,89 @@ millisecond), its table and the columns it changed.
|
|||
column, and signed by the account; the signature goes before the
|
||||
ciphertext in the payload column.
|
||||
|
||||
|
||||
## The reading (22 Oct 2026)
|
||||
|
||||
A second, independent reading found that the device decided what was
|
||||
private, and which key to write with, from columns the instance controls
|
||||
(the top studyset's `keyId`, `parentId`, `card.studysetId`), and trusted
|
||||
every readable row; and that content stayed readable in ordinary use (cards
|
||||
moved, pictures from the full-window editors, a rewrite cut short, a device
|
||||
that hadn't heard yet). The developer decided:
|
||||
|
||||
- **R1** Private studysets hold against an instance that alters data, not
|
||||
only one that reads it.
|
||||
- **R2** Rollback is guarded for the settings alone (a counter inside their
|
||||
sealed payload); other old sealed content handed back is integrity, not
|
||||
confidentiality, and is accepted.
|
||||
|
||||
What changed:
|
||||
|
||||
- **Privacy is a signed fact.** A data key's ID says what it is for
|
||||
(`s1.<studyset>.<ms>.<nonce>` a studyset's key, `p1.<ms>.<nonce>` the
|
||||
person's, `r1.<studyset>.<ms>.<nonce>` a record that the studyset was
|
||||
made readable, which ends its earlier keys); the ID is sealed with the
|
||||
key and signed by the account, so the row's columns are never trusted. A
|
||||
studyset is private while the latest signed record about it says so; the
|
||||
device keeps the latest it saw (`privacy.json` in the person's folder,
|
||||
never synced), so a record withheld or a row replayed changes nothing. A
|
||||
tree's key is the nearest studyset's with such a record, itself or above,
|
||||
so moving a private studyset under a readable one changes nothing.
|
||||
- **Items keep their key.** The device keeps the key each item (a card, a
|
||||
note, a path, a step, a PDF, a step's answers, a studyset, a file) was
|
||||
last seen sealed with, and never writes it with a weaker one unless it
|
||||
moves the item itself or a signed record makes its tree readable.
|
||||
- **Readable rows are signed or distrusted.** A device holding the keys
|
||||
signs every readable row it writes (the account's signature in place of
|
||||
the nonce, for its table, row and column). Where privacy holds (a private
|
||||
tree, an item once sealed, tags and settings once sealed), a readable row
|
||||
nobody signed is locked: never shown, folded or adopted. A signed one,
|
||||
from a device that hadn't heard yet, is shown and sealed anew.
|
||||
- **Rewrites finish.** A rewrite is kept as under way (in the ledger) until
|
||||
done, writes the top studyset last, and holds writes into its tree
|
||||
meanwhile; as the data opens and after every sync that merged, unfinished
|
||||
ones are finished and every private tree is swept for rows not under its
|
||||
key. What stays unsealed (locked rows, files not had) shows on the marker
|
||||
as partly readable, with Finish in its dialog.
|
||||
- **Moves.** Cards moved into a private tree are sealed with their files
|
||||
before they move; cards of a private tree are never moved into a
|
||||
readable one: the app asks to make the target private first. A private
|
||||
topic moved out of its tree (into a readable one, or to the top) keeps its
|
||||
privacy with a key of its own (this changes Decision 1: privacy can now
|
||||
be a topic's own).
|
||||
- **Tags and settings** are sealed once with the personal key, all readable
|
||||
ones then; from then on a readable one nobody signed is left out, so the
|
||||
instance can't confirm a guessed name by having a sealed tag folded into
|
||||
it. Settings carry a counter (`HLKS`, 8 bytes, then the payload, inside
|
||||
the seal); one lower than seen is refused.
|
||||
- **A device without the account's keys,** on an account that has them,
|
||||
writes nothing that would be private (new studysets, tags, settings are
|
||||
refused, and it says so), reports nothing for the learner count, and
|
||||
shows private studysets as needing the password here, not as lost
|
||||
(archiving stays). An anonymous person's keys kept but unreadable are
|
||||
never replaced.
|
||||
- **Files.** The full-window editors carry the studyset they were opened
|
||||
from; where none is known, an account with keys adds no file (a new
|
||||
studyset's description takes pictures once it is made). A file no live
|
||||
row names is never uploaded. A suggestion from a private copy uploads
|
||||
readable copies of its files for the author; accepting swaps whole
|
||||
`asset:` values only. Old file rows are kept while a row this device
|
||||
can't open, or a sent suggestion, might name them.
|
||||
- **The instance:** an upload said to be encrypted must start as a sealed
|
||||
file does (`HLKF`, version 1); a person's room counts the files a live
|
||||
row names and those claimed within the week of grace; copy reports are
|
||||
limited to 60 an hour; publishing gets only the release's tags' names.
|
||||
|
||||
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.
|
||||
- **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)
|
||||
shows as it was: integrity, not confidentiality (R2).
|
||||
- **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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue