Photos: library scope — Photos/ plus opted-in folders #27

Closed
opened 2026-09-24 14:45:04 +00:00 by kayg · 5 comments
Owner

Owner decision (round 13, P1): the photos timeline shows media under Photos/ plus any folders the user opts in (e.g. Files/Camera exports). Media elsewhere in the home is not in the timeline.

Why: managed app folders were dropped (DESIGN §4); users keep full control of their tree, and the timeline must not be cluttered by stray images in unrelated folders.

Acceptance:

  • Per-user setting listing library roots (stored in <home>/.calternal/settings.json, file over app); default ["Photos"]; add/remove in Photos settings.
  • The photos index (derived data) covers exactly those roots; adding a root indexes it in the background; removing one drops it from the timeline without touching files.
  • Shared folders (Shared//…) can be opted in too, read-only.
  • Media outside the roots stays reachable through Files as usual.

Design: DESIGN §12, §28.

Context for the owning job

  • Repo: kayg/calternal (~/Developer/calternal). Read CLAUDE.md, CONTEXT.md and docs/DESIGN.md first; this issue's section is cited below.
  • Owner rules that always apply: file over app (plain files are the truth, the DB is an index); the server is the single writer; data loss is unacceptable; performance first, never at the cost of finesse; UI is the calternal.js design system (copy components verbatim, compare side by side with calternal.js reference screenshots; Claude does visual review); never ship sample/mock data; atomic commits; adversarial testing after API work; good enough, not perfect (merge blockers: crash/DoS, data loss, security, sync collisions).
  • Comment on this issue when you start (branch, base SHA), on each finding, when blocked, and when finished (head SHA + gate output). Never close it.
Owner decision (round 13, P1): the photos timeline shows media under `Photos/` **plus any folders the user opts in** (e.g. `Files/Camera exports`). Media elsewhere in the home is not in the timeline. Why: managed app folders were dropped (DESIGN §4); users keep full control of their tree, and the timeline must not be cluttered by stray images in unrelated folders. Acceptance: - Per-user setting listing library roots (stored in `<home>/.calternal/settings.json`, file over app); default `["Photos"]`; add/remove in Photos settings. - The photos index (derived data) covers exactly those roots; adding a root indexes it in the background; removing one drops it from the timeline without touching files. - Shared folders (Shared/<owner>/…) can be opted in too, read-only. - Media outside the roots stays reachable through Files as usual. Design: DESIGN §12, §28. ## Context for the owning job - Repo: kayg/calternal (~/Developer/calternal). Read CLAUDE.md, CONTEXT.md and docs/DESIGN.md first; this issue's section is cited below. - Owner rules that always apply: file over app (plain files are the truth, the DB is an index); the server is the single writer; data loss is unacceptable; performance first, never at the cost of finesse; UI is the calternal.js design system (copy components verbatim, compare side by side with calternal.js reference screenshots; Claude does visual review); never ship sample/mock data; atomic commits; adversarial testing after API work; good enough, not perfect (merge blockers: crash/DoS, data loss, security, sync collisions). - Comment on this issue when you start (branch, base SHA), on each finding, when blocked, and when finished (head SHA + gate output). Never close it.
Author
Owner

Starting server-side implementation for #27, #28, #29, and #33.

Branch: job/photos-core
Base SHA: 57118d9648582e682f0a0e1997fc8ad9f84bab35

I have read the issue bodies and repository design/context. I am mapping the existing Files upload, thumbnail, identity, and plugin registration APIs before defining the photos plugin boundary.

Starting server-side implementation for #27, #28, #29, and #33. Branch: `job/photos-core` Base SHA: `57118d9648582e682f0a0e1997fc8ad9f84bab35` I have read the issue bodies and repository design/context. I am mapping the existing Files upload, thumbnail, identity, and plugin registration APIs before defining the photos plugin boundary.
Author
Owner

Finding: the repository has no per-user settings.json read/modify/write service in the plugins. The design requires <home>/.calternal/settings.json, so Photos needs an atomic update that preserves unrelated and future settings keys. I plan to use calternal-fs and keep that file as the source of truth.

Finding: the repository has no per-user `settings.json` read/modify/write service in the plugins. The design requires `<home>/.calternal/settings.json`, so Photos needs an atomic update that preserves unrelated and future settings keys. I plan to use `calternal-fs` and keep that file as the source of truth.
Author
Owner

Starting server-side implementation for #27, #28, #29, and #33.

Branch: job/photos-core
Base SHA: 41aa77499e0a090371ff252458722fd80b4e6a44

I read each issue body and comment thread, plus CLAUDE.md, docs/DESIGN.md, and CONTEXT.md. The approved scope includes a rebuildable Photos index keyed by Files item IDs, opt-in library roots in .calternal/settings.json, date-routed Photos uploads using the existing tus staging/install pipeline, pairing and compact paginated timeline APIs with ThumbHash placeholders, and source-mtime metadata from calternald through server installation.

Starting server-side implementation for #27, #28, #29, and #33. Branch: `job/photos-core` Base SHA: `41aa77499e0a090371ff252458722fd80b4e6a44` I read each issue body and comment thread, plus CLAUDE.md, docs/DESIGN.md, and CONTEXT.md. The approved scope includes a rebuildable Photos index keyed by Files item IDs, opt-in library roots in `.calternal/settings.json`, date-routed Photos uploads using the existing tus staging/install pipeline, pairing and compact paginated timeline APIs with ThumbHash placeholders, and source-mtime metadata from `calternald` through server installation.
Author
Owner

Completed Photos library indexing and the compact timeline/day-bucket API, including live file-ID checks and the 150k-item benchmark fixture. Latest recorded benchmark: p50 141,085 µs, p95 262,645 µs. Timeline unit tests passed; the 150k benchmark remains an ignored manual test.

Head SHA: f77c8d135e.

Gate output (commands use CARGO_PROFILE_DEV_DEBUG=line-tables-only and CARGO_INCREMENTAL=0):

  • cargo fmt --all --check: exit 0, no output.
  • cargo clippy --all-targets -- -D warnings (exit 0):
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 14.64s
  • cargo test (workspace, exit 0):
    Finished `test` profile [unoptimized + debuginfo] target(s) in 3m 25s
test result: ok. 13 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.04s
  • bash packages/api-client/check-generated.sh (exit 0, no generated diff):
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 40s
     Running `target/debug/calternal-server openapi`
$ bunx --package openapi-typescript@7.13.0 openapi-typescript ../../contracts/openapi.json -o src/generated.ts
Resolving dependencies
Resolved, downloaded and extracted [24]
Saved lockfile
✨ openapi-typescript 7.13.0
🚀 ../../contracts/openapi.json → src/generated.ts [1.4s]
  • bash tests/adversarial/run.sh (exit 1 because Round 1 reported Calendar task latency; Round 2 reported zero findings):
==== FINDINGS 21
 - Task storm 3 :: SLOW 7.4s status 201
 - Task storm 4 :: SLOW 5.1s status 201
 - Task storm 5 :: SLOW 6.9s status 201
 - Task storm 6 :: SLOW 9.6s status 201
 - Task storm 7 :: SLOW 8.3s status 201
 - Task storm 8 :: SLOW 7.9s status 201
 - Task storm 9 :: SLOW 12.9s status 201
 - Task storm 10 :: SLOW 12.1s status 201
 - Task storm 11 :: SLOW 13.4s status 201
 - Task storm 12 :: SLOW 14.3s status 201
 - Task storm 13 :: SLOW 14.3s status 201
 - Task storm 14 :: SLOW 12.9s status 201
 - Task storm 15 :: SLOW 12.4s status 201
 - Task storm 16 :: SLOW 11.9s status 201
 - Task storm 17 :: SLOW 13.7s status 201
 - Task storm 18 :: SLOW 14.3s status 201
 - Task storm 19 :: SLOW 17.4s status 201
 - Task storm 20 :: SLOW 16.7s status 201
 - Task storm 21 :: SLOW 14.8s status 201
 - Task storm 22 :: SLOW 17.2s status 201
 - Task storm 23 :: SLOW 17.3s status 201
==== ROUND 2 FINDINGS 0
Completed Photos library indexing and the compact timeline/day-bucket API, including live file-ID checks and the 150k-item benchmark fixture. Latest recorded benchmark: p50 141,085 µs, p95 262,645 µs. Timeline unit tests passed; the 150k benchmark remains an ignored manual test. Head SHA: f77c8d135eeec4f1a30da6034e61217df5b9a04b. Gate output (commands use CARGO_PROFILE_DEV_DEBUG=line-tables-only and CARGO_INCREMENTAL=0): - cargo fmt --all --check: exit 0, no output. - cargo clippy --all-targets -- -D warnings (exit 0): ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 14.64s ``` - cargo test (workspace, exit 0): ``` Finished `test` profile [unoptimized + debuginfo] target(s) in 3m 25s test result: ok. 13 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.04s ``` - bash packages/api-client/check-generated.sh (exit 0, no generated diff): ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 40s Running `target/debug/calternal-server openapi` $ bunx --package openapi-typescript@7.13.0 openapi-typescript ../../contracts/openapi.json -o src/generated.ts Resolving dependencies Resolved, downloaded and extracted [24] Saved lockfile ✨ openapi-typescript 7.13.0 🚀 ../../contracts/openapi.json → src/generated.ts [1.4s] ``` - bash tests/adversarial/run.sh (exit 1 because Round 1 reported Calendar task latency; Round 2 reported zero findings): ``` ==== FINDINGS 21 - Task storm 3 :: SLOW 7.4s status 201 - Task storm 4 :: SLOW 5.1s status 201 - Task storm 5 :: SLOW 6.9s status 201 - Task storm 6 :: SLOW 9.6s status 201 - Task storm 7 :: SLOW 8.3s status 201 - Task storm 8 :: SLOW 7.9s status 201 - Task storm 9 :: SLOW 12.9s status 201 - Task storm 10 :: SLOW 12.1s status 201 - Task storm 11 :: SLOW 13.4s status 201 - Task storm 12 :: SLOW 14.3s status 201 - Task storm 13 :: SLOW 14.3s status 201 - Task storm 14 :: SLOW 12.9s status 201 - Task storm 15 :: SLOW 12.4s status 201 - Task storm 16 :: SLOW 11.9s status 201 - Task storm 17 :: SLOW 13.7s status 201 - Task storm 18 :: SLOW 14.3s status 201 - Task storm 19 :: SLOW 17.4s status 201 - Task storm 20 :: SLOW 16.7s status 201 - Task storm 21 :: SLOW 14.8s status 201 - Task storm 22 :: SLOW 17.2s status 201 - Task storm 23 :: SLOW 17.3s status 201 ==== ROUND 2 FINDINGS 0 ```
Author
Owner

Completed on dev in e0b3da9a54 (Merge job/photos-core: Photos backend: library, pairing, stacks, timeline, upload ingest (#27, #28, #29, #33)).

Completed on dev in e0b3da9a54bb1eb77f7501a4eb2928fe9cd1b19a (Merge job/photos-core: Photos backend: library, pairing, stacks, timeline, upload ingest (#27, #28, #29, #33)).
kayg closed this issue 2026-10-01 05:08:38 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#27
No description provided.