Describe albums, the folder pickers and download progress in the designs

storage.md's trait listing stopped at get; it now has get_reporting,
what the default and the Nextcloud override do, and where develop reads
the figures. A new §5.3 says how folders are chosen — the portal or
Windows dialogue, the server browser whose New folder is create_dir,
SAF on Android — and where an album's files go: a server folder relative
to the account root, with the outbox's third .dest line, or a device
folder that never syncs.

catalog.md §8.2 said only collections merge, which had not been true
since keywords, people and capture metadata joined them, and is less
true with albums; it now lists what merges and why album_folders does
not. §2 records that the album tables, like dedup_probes, are made on
first use rather than by a migration.

outstanding.md said there was no SAF code on Android. There is now,
for album folders only, and it carries TRACES: FR-PLAT-AND-1, which
the entry says overstates a requirement about the library; FR-PLAT-AND-2
and S10's row follow from that.
This commit is contained in:
2026-09-26 14:54:46 -04:00
parent caaae11d98
commit dee509c6ef
3 changed files with 118 additions and 24 deletions
+35 -7
View File
@@ -129,6 +129,17 @@ CREATE INDEX members_image ON collection_members(image_id);
partial index over the non-NULL subset is both smaller and what FR-CAT-9's reconnection-by-hash
and FR-CAT-11's duplicate detection actually query.
**Made on first use, not by a migration.** A new `user_version` makes every older build refuse this
catalog's snapshot at sync (`sync::remote_is_mergeable` compares it and nothing else), and a tablet
a release behind would stop merging collections, keywords and people for a feature it does not
have. So what later releases added without needing old rows rewritten is created with `IF NOT
EXISTS` where it is first used, and an older build that meets it ignores it:
- `dedup_probes` (FR-CAT-11a, §3.5);
- the albums (FR-EXP-10, `core/dr-catalog/src/albums.rs`): `albums`, `album_exports` — one row per
file written into an album, keyed on the file name, since two crops of one photograph are two
files — and `album_folders`, this device's folder for each (§8.2).
---
## 3. Incremental scan
@@ -686,13 +697,29 @@ mechanism.
### 8.2 What the file sync does and does not carry
Only **collections and their membership** merge. The rest of a catalog describes *local* state —
folder mtimes, cache file paths, job rows, `tier_actual` — and importing another device's version
of those would be actively wrong. The downloaded remote is read for its collections and discarded.
Collections were the first thing merged, and the rules in §8.4 were written for them. What else
merges reuses those rules or keys on the same identities, and each has no other home:
This is what keeps §6.12 substantially intact: nothing here makes the local database authoritative
for anything a rebuild could not recover. The catalog is still deletable. What syncs is one table
pair that had no other home.
- **Collections and their membership** — by uuid and revision, membership as a set union.
- **Keywords** — the vocabulary by the same verdict, the assignments as a union.
- **People and identity judgements** — people by uuid and revision, and the confirmed and rejected
face assignments matched to local faces by box (`merge::match_faces`).
- **Albums** (FR-EXP-10, 0.17.0) — by uuid and revision with tombstones, and what went into each as
a set union keyed on the server's file id (a content hash on a folder library). An album's
server folder is a column of its row and travels with it; a folder on *this device* is in
`album_folders`, which the merge never reads and the upload snapshot drops (§8.3), because a
path or a SAF grant on one device means nothing on another.
- **Capture metadata** — the one exception inside `images`: a date, a camera, a lens and an ISO are
facts about the file's bytes, so a row this device has not yet read takes them from a peer that
has (`merge_metadata`), matched by `oc:fileid`.
The rest of a catalog describes *local* state — folder mtimes, cache file paths, job rows,
`tier_actual` — and importing another device's version of those would be actively wrong; the
downloaded remote is read for the tables above and discarded.
This is what keeps §6.12 substantially intact. The catalog is still deletable; what a rebuild from
sidecars cannot recover — collections and albums, which nothing in the filesystem records — is what
the sync exists to carry.
### 8.3 Two hazards the implementation must handle
@@ -714,7 +741,8 @@ crop. They were first stripped (2026-08) by copying the whole file with the back
`crop` to NULL and `VACUUM`ing. That wrote the file about three times to upload 50 MB. Since #71
the snapshot is built without them. Its header is kept as it was (`user_version`, page size and
the WAL flag), so every earlier build merges it unchanged. NFR-R2 backups still use the backup API
and keep the crops, because a backup is a file the user may have to live on.
and keep the crops, because a backup is a file the user may have to live on. `album_folders` is
dropped from the built file for the reason §8.2 gives.
**Integer primary keys are not identities.** Two devices each allocate `collections.id = 1` for
different collections, so a row-level merge keyed on the integer id would collide them. Collections