Photos misses media written while the server was stopped (startup rebuild runs before the Files scan) #470

Closed
opened 2026-09-29 22:46:08 +00:00 by kayg · 10 comments
Owner

Problem

Photos does not show media that was written into a Home while the server was stopped (for example a restore, an rsync into the Home, or a disk copy). The photos stay missing from the timeline until something else starts a full Photos rebuild (a change to Photos library roots, a broadcast lag, or the next restart).

Found by the #367 perf round on the perf-test VM (release build of dev at 369ab6a2f).

Evidence

apps/web/e2e/photos-perf.mjs --items 5000 --thumbnail-storm --home-only writes 5,000 JPEGs into users/<id>/Photos/… with the server stopped, then starts it:

  • After 9 minutes, files_index held all rows under Photos/, but photos_media had 0 rows and /api/v1/photos/timeline/buckets reported 0 photos. The probe timed out.
  • One PUT /api/v1/photos/library-roots (which calls index::refresh_user) after Files had the rows: all 5,000 photos appeared within about 60 s.

Same result with the large-Home fixture (200 photos, 2,000 files, 500 Notes): 0 photos until the rebuild request.

Cause

  • crates/plugins/photos/src/index.rs start_background_refresh runs one refresh_user per owner at plugin start. At that time the Files startup scan has not adopted the new files, so the refresh sees an empty library.
  • crates/calternal-server/src/wire.rs (startup reconciliation, about line 1395) runs files.reconcile_all() later on its own runtime. It adopts the files into files_index but sends no fs events on the plugin event bus. Only watcher changes (wire.rs about lines 5031 and 5173) send them.
  • So Photos gets no signal after the scan.

Suggested fix (not decided)

Order the Photos startup rebuild after the initial Files reconciliation (for example a startup barrier or a one-shot "Files reconciled" event on the bus), or make reconcile_all announce the paths it adopted. Other plugins that listen for fs events may have the same gap; check them in the same change.

Repro

  1. Stop the server. Copy 100 JPEGs into <user_data>/users/<id>/Photos/2023/.
  2. Start the server and wait until GET /api/v1/files/entries?path=Photos/2023 lists them.
  3. GET /api/v1/photos/timeline/buckets → total: 0. Expected: 100.

The #367 bench works around this in photos-perf.mjs (it alternates the library root to force a rebuild). Remove that workaround when this is fixed.

## Problem Photos does not show media that was written into a Home while the server was stopped (for example a restore, an rsync into the Home, or a disk copy). The photos stay missing from the timeline until something else starts a full Photos rebuild (a change to Photos library roots, a broadcast lag, or the next restart). Found by the #367 perf round on the perf-test VM (release build of `dev` at `369ab6a2f`). ## Evidence `apps/web/e2e/photos-perf.mjs --items 5000 --thumbnail-storm --home-only` writes 5,000 JPEGs into `users/<id>/Photos/…` with the server stopped, then starts it: - After 9 minutes, `files_index` held all rows under `Photos/`, but `photos_media` had **0** rows and `/api/v1/photos/timeline/buckets` reported 0 photos. The probe timed out. - One `PUT /api/v1/photos/library-roots` (which calls `index::refresh_user`) after Files had the rows: all 5,000 photos appeared within about 60 s. Same result with the large-Home fixture (200 photos, 2,000 files, 500 Notes): 0 photos until the rebuild request. ## Cause - `crates/plugins/photos/src/index.rs` `start_background_refresh` runs one `refresh_user` per owner at plugin start. At that time the Files startup scan has not adopted the new files, so the refresh sees an empty library. - `crates/calternal-server/src/wire.rs` (startup reconciliation, about line 1395) runs `files.reconcile_all()` later on its own runtime. It adopts the files into `files_index` but sends no `fs` events on the plugin event bus. Only watcher changes (`wire.rs` about lines 5031 and 5173) send them. - So Photos gets no signal after the scan. ## Suggested fix (not decided) Order the Photos startup rebuild after the initial Files reconciliation (for example a startup barrier or a one-shot "Files reconciled" event on the bus), or make `reconcile_all` announce the paths it adopted. Other plugins that listen for `fs` events may have the same gap; check them in the same change. ## Repro 1. Stop the server. Copy 100 JPEGs into `<user_data>/users/<id>/Photos/2023/`. 2. Start the server and wait until `GET /api/v1/files/entries?path=Photos/2023` lists them. 3. `GET /api/v1/photos/timeline/buckets` → `total: 0`. Expected: 100. The #367 bench works around this in `photos-perf.mjs` (it alternates the library root to force a rebuild). Remove that workaround when this is fixed.
Author
Owner

Starting #470 on job/photos-470, based on origin/dev at 55a2f90feb8a52d91f8bbc1347889b509af02260. I am tracing the shared plugin event bus, startup reconciliation, and every fs event subscriber before implementing the bounded startup notification and regression coverage.

Starting #470 on `job/photos-470`, based on `origin/dev` at `55a2f90feb8a52d91f8bbc1347889b509af02260`. I am tracing the shared plugin event bus, startup reconciliation, and every `fs` event subscriber before implementing the bounded startup notification and regression coverage.
Author
Owner

Subscriber audit from rg -n 'event_bus\\(\\)\\.subscribe|event_bus\\(\\)' crates --glob '*.rs':

  • Photos (plugins/photos/src/index.rs) handles plugin_id == "fs"; it now handles the global Files completion notice by refreshing all timeline viewers.
  • Notes (plugins/notes/src/lib.rs) handles plugin_id == "fs"; it now rebuilds all Notes on the same notice.
  • Search (calternal-search/src/indexer.rs) subscribes to the bus only for search/note-link-health; its startup index scans Home directly, so it is not an fs event consumer.
  • Collaboration (calternal-collab/src/session.rs) and the Notes SSE route consume notes events only. Video and Tags have no bus subscribers.

Files sends one completion notice after a successful full scan. The event has an empty User and path scope, so consumers must detect it before per-User or path validation. It does not emit one event per file.

Subscriber audit from `rg -n 'event_bus\\(\\)\\.subscribe|event_bus\\(\\)' crates --glob '*.rs'`: - Photos (`plugins/photos/src/index.rs`) handles `plugin_id == "fs"`; it now handles the global Files completion notice by refreshing all timeline viewers. - Notes (`plugins/notes/src/lib.rs`) handles `plugin_id == "fs"`; it now rebuilds all Notes on the same notice. - Search (`calternal-search/src/indexer.rs`) subscribes to the bus only for `search/note-link-health`; its startup index scans Home directly, so it is not an `fs` event consumer. - Collaboration (`calternal-collab/src/session.rs`) and the Notes SSE route consume `notes` events only. Video and Tags have no bus subscribers. Files sends one completion notice after a successful full scan. The event has an empty User and path scope, so consumers must detect it before per-User or path validation. It does not emit one event per file.
Author
Owner

Resuming issue #470 on branch job/photos-470 at 55a2f90feb (base SHA: 55a2f90feb). The worktree has uncommitted changes in the event bus, Files reconciliation, Photos, Notes, and server regression coverage. I am auditing those changes and will commit each verified slice before continuing.

Resuming issue #470 on branch job/photos-470 at 55a2f90feb8a52d91f8bbc1347889b509af02260 (base SHA: 55a2f90feb8a52d91f8bbc1347889b509af02260). The worktree has uncommitted changes in the event bus, Files reconciliation, Photos, Notes, and server regression coverage. I am auditing those changes and will commit each verified slice before continuing.
Author
Owner

Subscriber audit: the direct fs invalidation consumers are Photos () and Notes (). Both need the global Files-complete marker because it has no User or path scope. Search subscribes to the same plugin bus only for its own events; its startup integrity scan walks the Home tree directly. The collab Hub handles events, and the Notes SSE route forwards only user-scoped events. I found no separate Video fs subscriber; video media is handled by Photos. Files reconciliation still runs in its existing background thread after the listener gate, and the new notification is one message after the full scan.

Subscriber audit: the direct fs invalidation consumers are Photos () and Notes (). Both need the global Files-complete marker because it has no User or path scope. Search subscribes to the same plugin bus only for its own events; its startup integrity scan walks the Home tree directly. The collab Hub handles events, and the Notes SSE route forwards only user-scoped events. I found no separate Video fs subscriber; video media is handled by Photos. Files reconciliation still runs in its existing background thread after the listener gate, and the new notification is one message after the full scan.
Author
Owner

Correction to my last comment: shell quoting removed the inline code identifiers from that comment. The subscriber audit is: Photos and Notes consume fs events. Search subscribes only to search/note-link-health on this bus and scans Homes directly at startup. The collab Hub and Notes SSE route consume notes events only. No separate Video or Tags bus subscriber exists. The earlier audit comment on this issue has the full paths and findings.

Correction to my last comment: shell quoting removed the inline code identifiers from that comment. The subscriber audit is: Photos and Notes consume `fs` events. Search subscribes only to `search/note-link-health` on this bus and scans Homes directly at startup. The collab Hub and Notes SSE route consume `notes` events only. No separate Video or Tags bus subscriber exists. The earlier audit comment on this issue has the full paths and findings.
Author
Owner

The first server clippy run reached the new regression test and reported E0382: unwrapping app.startup_reconcile partially moved the app before drop(app). The test now uses app.startup_reconcile.take() and retains the app for cleanup. The same run showed that this fresh worktree needs apps/web/build/ for the existing RustEmbed frontend; I am preparing the production build before rerunning clippy.

The first server clippy run reached the new regression test and reported `E0382`: unwrapping `app.startup_reconcile` partially moved the app before `drop(app)`. The test now uses `app.startup_reconcile.take()` and retains the app for cleanup. The same run showed that this fresh worktree needs `apps/web/build/` for the existing `RustEmbed` frontend; I am preparing the production build before rerunning clippy.
Author
Owner

#470 work report

Implemented and committed the startup reconciliation event path. Files emits one global fs/reconciled notice after a successful full scan (also for an empty users/ directory). Notes and Photos subscribe before their listener tasks start and rebuild derived state once on that notice. The server keeps its direct Notes repair only when the Files scan fails. Added a live-app server regression test that writes a WebP before app startup and checks the Photos timeline projection without a manual rebuild.

Subscriber audit

  • Photos and Notes consume fs events and now handle the global completion notice before User/path filtering.
  • Search subscribes to search/note-link-health; its startup integrity scan walks Homes directly.
  • Collab Hub and Notes event streaming consume notes events only.
  • Tags has no bus subscriber; startup tag reconciliation runs after the Files scan.
  • Video has no separate fs bus subscriber; its media is represented by Photos.

Files and commits

Job changes are in crates/calternal-plugin/src/lib.rs, crates/plugins/files/src/index.rs, crates/plugins/notes/src/lib.rs, crates/plugins/photos/src/index.rs, and crates/calternal-server/src/wire.rs.

Commits: ce64e1e72, ac84d280a, 4eb500af7, 26c75f2c2, 159f9fd7f. I fetched and merged origin/dev as required. Final head: 395370602 (Merge remote-tracking branch 'origin/dev' into job/photos-470). The merge also brought upstream changes into the plugin and Notes crates, lockfiles, and web package files.

Gate output captured before the final merge

cargo fmt --check exited 0. The plugin and Files clippy gates passed. Notes clippy passed with:

Finished `dev` profile [unoptimized + debuginfo] target(s) in 11m 09s

Photos clippy passed after collapsing the new nested event-filter condition:

Finished `dev` profile [unoptimized + debuginfo] target(s) in 25.61s

Server clippy passed after building the embedded frontend and fixing the test sender ownership:

Finished `dev` profile [unoptimized + debuginfo] target(s) in 7m 56s

Package tests that completed:

test result: ok. 129 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 259.05s

test result: ok. 123 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 198.55s

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.45s

test result: ok. 44 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 41.61s

These are Files, Notes, Notes apple_replay, and Photos tests, respectively. cargo test -p calternal-plugin also passed 23 tests before the merge. The production web build passed (✓ built in 2m 48s; adapter-static wrote build) with existing bundler warnings about vendor module-level "use client" directives. cargo clean reported Removed 18033 files, 8.5GiB total; generated web build output and the installed node_modules were removed.

Remaining validation gaps

The job reached the owner’s approximately four-hour timebox while cargo test -p calternal-server was still compiling. I stopped that command (exit 130), so the new server regression test did not run. I did not run apps/web/e2e/photos-perf.mjs --items 1 --home-only --home-runs 1.

The required merge brought changes into calternal-plugin, Notes, Cargo.lock, bun.lock, and apps/web/package.json. I did not rerun crate gates or cargo fmt --check on the merged tree. Those post-merge gates, the server test, and the Photos Home-only e2e remain outstanding.

Decision not specified in DESIGN

I used a single global PluginEvent with plugin_id="fs", kind="reconciled", and empty User/path fields. Each fs consumer treats that tuple as a request for one full derived-state reconciliation. Files sends it once only after success, rather than publishing adopted paths or a per-file event storm.

## #470 work report Implemented and committed the startup reconciliation event path. Files emits one global `fs/reconciled` notice after a successful full scan (also for an empty `users/` directory). Notes and Photos subscribe before their listener tasks start and rebuild derived state once on that notice. The server keeps its direct Notes repair only when the Files scan fails. Added a live-app server regression test that writes a WebP before app startup and checks the Photos timeline projection without a manual rebuild. ### Subscriber audit - Photos and Notes consume `fs` events and now handle the global completion notice before User/path filtering. - Search subscribes to `search/note-link-health`; its startup integrity scan walks Homes directly. - Collab Hub and Notes event streaming consume `notes` events only. - Tags has no bus subscriber; startup tag reconciliation runs after the Files scan. - Video has no separate `fs` bus subscriber; its media is represented by Photos. ### Files and commits Job changes are in `crates/calternal-plugin/src/lib.rs`, `crates/plugins/files/src/index.rs`, `crates/plugins/notes/src/lib.rs`, `crates/plugins/photos/src/index.rs`, and `crates/calternal-server/src/wire.rs`. Commits: `ce64e1e72`, `ac84d280a`, `4eb500af7`, `26c75f2c2`, `159f9fd7f`. I fetched and merged `origin/dev` as required. Final head: `395370602` (`Merge remote-tracking branch 'origin/dev' into job/photos-470`). The merge also brought upstream changes into the plugin and Notes crates, lockfiles, and web package files. ### Gate output captured before the final merge `cargo fmt --check` exited 0. The plugin and Files clippy gates passed. Notes clippy passed with: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 11m 09s ``` Photos clippy passed after collapsing the new nested event-filter condition: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 25.61s ``` Server clippy passed after building the embedded frontend and fixing the test sender ownership: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 7m 56s ``` Package tests that completed: ```text test result: ok. 129 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 259.05s test result: ok. 123 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 198.55s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.45s test result: ok. 44 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 41.61s ``` These are Files, Notes, Notes `apple_replay`, and Photos tests, respectively. `cargo test -p calternal-plugin` also passed 23 tests before the merge. The production web build passed (`✓ built in 2m 48s`; adapter-static wrote `build`) with existing bundler warnings about vendor module-level `"use client"` directives. `cargo clean` reported `Removed 18033 files, 8.5GiB total`; generated web build output and the installed `node_modules` were removed. ### Remaining validation gaps The job reached the owner’s approximately four-hour timebox while `cargo test -p calternal-server` was still compiling. I stopped that command (exit 130), so the new server regression test did not run. I did not run `apps/web/e2e/photos-perf.mjs --items 1 --home-only --home-runs 1`. The required merge brought changes into `calternal-plugin`, Notes, `Cargo.lock`, `bun.lock`, and `apps/web/package.json`. I did not rerun crate gates or `cargo fmt --check` on the merged tree. Those post-merge gates, the server test, and the Photos Home-only e2e remain outstanding. ### Decision not specified in DESIGN I used a single global `PluginEvent` with `plugin_id="fs"`, `kind="reconciled"`, and empty User/path fields. Each `fs` consumer treats that tuple as a request for one full derived-state reconciliation. Files sends it once only after success, rather than publishing adopted paths or a per-file event storm.
Author
Owner

All five branches are committed on job/merge-round-2. Validation remains incomplete at the four-hour limit.
Head: 84d4258f130ebebe748a9b3a08f03c8741d01c45. Base: 6c87f5ff9442cd658572139bc536d018fd5222a4.
No push, deploy, or change to dev. No branch was dropped: no included branch produced a Rust code/test failure; unfinished validation is listed below.

Included: job/location (#391), job/webcal-431 (#431), job/small-bugs-4 (#459/#463/#464), job/photos-470 (#470), job/perf-367 (#367). All five heads are ancestors. The required final fetch and origin/dev merge returned Already up to date.

Integration fixes and files:

  • Settings canonical links preserve Maintenance query state and stable Saved place UUID fragments (apps/web/src/routes/settings/[...path]/+page.svelte, registry tests).
  • Authenticated Location routing coexists with public Calendar feeds (crates/calternal-server/src/wire.rs).
  • Mail fixtures retain MIME reader regressions and the full-history profile (crates/plugins/mail/src/sync.rs). Calendar benchmarks use the canonical Daily note first, then search only that User's Home (apps/web/e2e/calendar-perf.mjs).
  • Location uses shared leading and shape tokens (apps/web/src/routes/settings/account/LocationGroup.svelte).
  • Location operations and Saved place identities have explicit fail-closed classifications with regression tests (tests/adversarial/authz_matrix.py, xuser_matrix.py, test_xuser_classification.py).
  • Updated the shared capture harness and its regression tests (apps/web/e2e/harness.mjs, harness.test.mjs, appearance-review.mjs). Earlier failing capture output is preserved; no existing numeric assertion was weakened.
  • Regenerated contracts/openapi.json, packages/api-client/src/generated.ts, and docs/parity-*. No generated files were hand-merged.
  • Reviewed module/function comments were updated with the merge fixes. Imported feature files remain in the five branch histories. The complete changed-file list is artifacts/merge-round-2/files.txt.

Migrations: no duplicate numeric prefixes in any migrations folder. Notes adds 0020 after origin/dev's 0019; Calendar adds 0004 after origin/dev's 0003. Notes bridge is excluded.

Decisions:

  • Keep the existing API adapters' scope. Record the new Location/Calendar adapter gaps in the generated parity inventory rather than invent new CLI/MCP/WebMCP behavior in this merge.
  • Keep both Mail fixture behaviors in one helper. Keep the Calendar fallback scoped to the current User's Home.
  • Preserve dev's existing test expectations. The two web failures were timeouts and were rerun alone. Restore the exact 16-family theme expectation from dev; count dark variant submenu parents as families and use the existing keyboard submenu interaction.
  • In the capture harness, check the saved Auto/System preference separately from its rendered Light/Dark CSS phase. Eight regressions verify both phases and reject wrong persistence or rendering.
  • Seed the review's initial preference through the real API before SPA navigation. Wait for hydration before choosing a mode, and await persistence with bounded API reads on the host. Playwright 1.63 treats the former async predicate as truthy before its Promise resolves.

Known gaps:

  • calternal-server tests were stopped during compilation at the approximately four-hour limit (exit -15). Server clippy passed. No server test assertion result was produced. Run cargo test -p calternal-server before merge.
  • Standalone vendored async-imap clippy/test were initially cancelled while waiting for the build lock and were not completed before the limit. Mail clippy and tests checked/exercised its Tokio dependency path.
  • The ignored large Mail history and worst-case performance profiles were not rerun. The requested local one-item Photos smoke completed; the imported baseline remains unchanged.
  • The live hostile-input and race adversarial round was not run under this session's safety limits. Offline classification and probe-helper tests do not replace it. This branch is not certified ready to merge until that round is completed.
  • Static parity records 188 actions with adapter gaps. New Location operations lack CLI/MCP/WebMCP adapters; Calendar feeds/subscriptions lack MCP adapters. These imported scope gaps remain documented.
  • The official generated-check wrapper returned 143 after its build/generation output. The equivalent OpenAPI generation, client generation, unique-operation check, and clean generated diff were rerun explicitly and all returned 0.
  • The local one-photo debug smoke is not comparable with the 5,000-photo baseline; no regression verdict was made. Its JSON commit field is unknown.

Browser evidence: Calendar feeds passed with 36 screenshots. Location passed with six screenshots, including stable Saved place link restoration and cap-height assertions. The full Appearance review passed with 71 screenshots. Notes, Photos and the Log with its Saved place passed with 18 more screenshots. All required surface matrices cover 390/820/1440 px and light/dark. The additional Unsplash previews use third-party test fixtures; ordinary Notes/Photos/Location/Calendar data comes from the real local API. The production app supplied the screenshots; visual quality review remains with the orchestrator.
Appearance, Notes, Photos and Log matrix. Location full matrix. Calendar full matrix.

Local performance smoke (photos-perf.mjs --items 1 --home-only): server start 1101 ms; all indexed 4060 ms; rebuild requested 2582 ms; mean/peak RSS 350938740/432443392 bytes; mean/peak CPU 25.24/132.98%; CPU 23.74 s. Load after: 33.2/38.3/40.6. Baseline docs/perf/baseline.json, commit 369ab6a2f9fc673e3564b94857fbecfeb04df404, 5000 photos: server start 290 ms; indexed 63230 ms; rebuild 719 ms; mean/peak RSS 360533602/495759360 bytes; mean/peak CPU 63.05/235.82%; CPU 113.24 s. Different dataset and environment: these numbers show the smoke completed, not a regression comparison.

Gate outputs follow. Full logs are under artifacts/merge-round-2/ in the worktree; screenshots and logs are not committed.

Required environment: CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=4 TMPDIR=$PWD/target/tmp; the preset CARGO_TARGET_DIR was retained. Rust gates ran per crate.

cargo fmt --check: exit 0, no output. git diff --check: exit 0, no output.

Per-crate exit statuses, verbatim:

calternal-cli	clippy	0
calternal-cli	test	0
calternal-dav	clippy	0
calternal-dav	test	0
calternal-location	clippy	0
calternal-location	test	0
calternal-notes-core	clippy	0
calternal-notes-core	test	0
calternal-plugin	clippy	0
calternal-plugin	test	0
calternal-plugin-calendar	clippy	0
calternal-plugin-calendar	test	0
calternal-plugin-files	clippy	0
calternal-plugin-files	test	0
calternal-plugin-mail	clippy	0
calternal-plugin-mail	test	0
calternal-plugin-notes	clippy	0
calternal-plugin-notes	test	0
calternal-plugin-photos	clippy	0
calternal-plugin-photos	test	0
calternal-server	clippy	0
calternal-server	test	-15

calternal-cli clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 16m 25s

calternal-cli test:

    Finished `test` profile [unoptimized + debuginfo] target(s) in 57m 13s
test result: ok. 27 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.76s
test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.09s

calternal-dav clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 12m 25s

calternal-dav test:

    Finished `test` profile [unoptimized + debuginfo] target(s) in 6m 06s
test result: ok. 41 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.46s
test result: ok. 33 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

calternal-location clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 05s

calternal-location test:

    Finished `test` profile [unoptimized + debuginfo] target(s) in 57.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.47s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

calternal-notes-core clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 29s

calternal-notes-core test:

    Finished `test` profile [unoptimized + debuginfo] target(s) in 2m 31s
test result: ok. 506 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.74s
test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.47s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.07s
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.53s
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

calternal-plugin clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 9m 55s

calternal-plugin test:

    Finished `test` profile [unoptimized + debuginfo] target(s) in 4m 21s
test result: ok. 23 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.05s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

calternal-plugin-calendar clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 29m 42s

calternal-plugin-calendar test:

    Finished `test` profile [unoptimized + debuginfo] target(s) in 10m 46s
test result: ok. 79 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.33s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.24s
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.23s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

calternal-plugin-files clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 4m 08s

calternal-plugin-files test:

    Finished `test` profile [unoptimized + debuginfo] target(s) in 6m 35s
test result: ok. 129 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 220.28s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

calternal-plugin-mail clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 36s

calternal-plugin-mail test:

    Finished `test` profile [unoptimized + debuginfo] target(s) in 3m 49s
test result: ok. 35 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 1.17s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

calternal-plugin-notes clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 36s

calternal-plugin-notes test:

    Finished `test` profile [unoptimized + debuginfo] target(s) in 7m 40s
test result: ok. 130 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 223.97s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.83s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

calternal-plugin-photos clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 48s

calternal-plugin-photos test:

    Finished `test` profile [unoptimized + debuginfo] target(s) in 6m 06s
test result: ok. 44 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 25.16s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

calternal-server clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 18m 02s

Server test run: cancelled during compilation; no test result. Last compiler output, verbatim:

   Compiling calternal-plugin-money v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/money)
   Compiling rmcp v3.5.0
   Compiling calternal-plugin-files v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/files)
   Compiling calternal-collab v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/calternal-collab)
   Compiling calternal-plugin-calendar v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/calendar)
   Compiling calternal-plugin-ai v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/ai)
   Compiling calternal-plugin-photos v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/photos)
   Compiling calternal-plugin-video v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/video)
   Compiling calternal-plugin-notifications v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/notifications)
   Compiling calternal-plugin-analytics v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/analytics)

Web, contract, classification, parity, offline helper and browser output excerpts follow verbatim. Full output, including earlier failures and isolated reruns, is in the attached log archive.

bun-install.log

Checked 631 installs across 749 packages (no changes) [25.76s]

web-check-final.log

Text sizes and UI shape values use shared role tokens.
svelte-check found 0 errors and 0 warnings

web-test.log

 ❯ |component| src/lib/components/KeyboardShortcutsCard.svelte.test.ts (1 test | 1 failed) 5696ms
 ❯ |unit| src/lib/calendar/zones.test.ts (21 tests | 1 failed) 6881ms
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 2 ⎯⎯⎯⎯⎯⎯⎯
Error: Test timed out in 5000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".
Error: Test timed out in 5000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".
 Test Files  2 failed | 137 passed (139)
      Tests  2 failed | 897 passed (899)
   Duration  416.06s (transform 66%, import 12%, environment 12%, tests 7%, setup 3%)

web-zones-alone.log

 Test Files  1 passed (1)
      Tests  21 passed (21)
   Duration  88.80s (transform 94%, import 6%)

web-shortcuts-alone.log

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Duration  126.01s (transform 79%, environment 11%, import 5%, setup 3%, tests 2%)

settings-alone.log

 Test Files  1 passed (1)
      Tests  8 passed (8)
   Duration  6.85s (transform 85%, import 10%, tests 4%)

api-client-tests.log

(pass) apiFetch > keeps a typed failure body that is not an error envelope [0.23ms]
 9 pass
 0 fail
 31 expect() calls

bench-tests.log

............
----------------------------------------------------------------------
Ran 12 tests in 1.213s

OK

dav-probe-contract-tests.log

.......
----------------------------------------------------------------------
Ran 7 tests in 0.029s

OK

appearance-probe-contract-tests.log

....
----------------------------------------------------------------------
Ran 4 tests in 0.008s

OK

classification-final-tests.log

....
----------------------------------------------------------------------
Ran 4 tests in 0.284s

OK

classify-final.log

Cross-User classification gate: 328 operations classified

parity-final.log

Parity matrix: 206 web API actions, 113 shortcuts, 2 static commands, 131 menu actions, 33 settings groups, 188 actions with adapter gaps

generated-check-confirmed.log

$ /mnt/hdd/targets/jobs/merge-round-2/debug/calternal-server openapi
exit=0
$ bun run --cwd packages/api-client generate
$ bunx --package openapi-typescript@7.13.0 openapi-typescript ../../contracts/openapi.json -o src/generated.ts
✨ openapi-typescript 7.13.0
🚀 ../../contracts/openapi.json → src/generated.ts [3s]
exit=0
$ git diff --exit-code -- contracts/openapi.json packages/api-client/src/generated.ts
exit=0
OpenAPI operation IDs: 328 unique

calendar-feeds.log

Calendar feeds proof passed; screenshots: /home/kayg/Developer/calternal-wt/merge-web/artifacts/merge-round-2/calendar-feeds

location-review.log

PASS appearance review captures: 6 screenshots in /home/kayg/Developer/calternal-wt/merge-web/artifacts/location

photos-home-local.log

  indexed: {
{"items":1,"commit":"unknown","recordedAt":"2026-09-30T10:14:15.246Z","homeOnly":true,"environment":{"host":"calternal-dev","platform":"linux","architecture":"x64"},"homeFixtures":{"photos":1,"photoDays":1,"files":0,"folderItems":0,"notes":0,"logEntries":0,"dailyNotes":0,"largeNoteBytes":0},"homeFixtureWriteMs":10277,"indexing":{"serverUpMs":1101,"allIndexedMs":4060,"photoRebuildRequestedMs":2582,"indexed":{"photos":1,"folderItems":0,"restItems":0,"notes":0,"logEntries":0}},"homeRenders":{"cpuThrottle":4,"runs":3,"order":[["files5k","analyticsYear","note1MiB"],["analyticsYear","note1MiB","files5k"],["note1MiB","files5k","analyticsYear"]],"files5k":{"skipped":true},"analyticsYear":{"skipped":true},"note1MiB":{"skipped":true}},"loadAverageAfter":[33.2,38.3,40.6],"homeResources":{"meanRssBytes":350938740,"peakRssBytes":432443392,"meanCpuPercent":25.24,"peakCpuPercent":132.98,"cpuSeconds":23.74,"samples":186}}

harness-test-final.log:


 8 pass
 0 fail
Ran 8 tests across 1 file. [474.00ms]

appearance-review-awaited.log:

PASS appearance review captures: 71 screenshots in /home/kayg/Developer/calternal-wt/merge-web/artifacts/location

reconcile-review-normal-note.log:

PASS Notes and Photos review: 18 production screenshots, 390/820/1440 px, light/dark

cargo-clean.log:

     Removed 23900 files, 14.0GiB total

migrations.log:

crates/calternal-auth/migrations: 10 numbered migrations; no duplicates
crates/calternal-db/src/migrations: 6 numbered migrations; no duplicates
crates/calternal-plugin/migrations: 1 numbered migrations; no duplicates
crates/calternal-search/migrations: 3 numbered migrations; no duplicates
crates/calternal-tags/migrations: 2 numbered migrations; no duplicates
crates/plugins/ai/migrations: 4 numbered migrations; no duplicates
crates/plugins/analytics/migrations: 2 numbered migrations; no duplicates
crates/plugins/calendar/migrations: 4 numbered migrations; no duplicates
crates/plugins/files/migrations: 15 numbered migrations; no duplicates
crates/plugins/mail/migrations: 8 numbered migrations; no duplicates
crates/plugins/notes/migrations: 20 numbered migrations; no duplicates
crates/plugins/notifications/migrations: 4 numbered migrations; no duplicates
crates/plugins/photos/migrations: 6 numbered migrations; no duplicates
crates/plugins/video/migrations: 1 numbered migrations; no duplicates
PASS: 14 migration folders have unique numeric prefixes

bun run build: exit 0. Output, verbatim:

✓ built in 2m 29s
✓ built in 527ms
✓ built in 4m 52s
> Using @sveltejs/adapter-static

Official generated-check wrapper exit: 143. Confirmed equivalent generation/uniqueness/diff steps: all exit 0, quoted above.
Standalone vendor attempt statuses, verbatim:

async-imap	clippy	-15
async-imap	test	-15

Cleanup: cargo clean exit 0; web build and Svelte build output deleted. Screenshots and logs remain uncommitted. Final git status is clean.

Full gate output, earlier failures, isolated reruns, performance smoke and changed-file manifest.

All five branches are committed on `job/merge-round-2`. Validation remains incomplete at the four-hour limit. Head: `84d4258f130ebebe748a9b3a08f03c8741d01c45`. Base: `6c87f5ff9442cd658572139bc536d018fd5222a4`. No push, deploy, or change to dev. No branch was dropped: no included branch produced a Rust code/test failure; unfinished validation is listed below. Included: `job/location` (#391), `job/webcal-431` (#431), `job/small-bugs-4` (#459/#463/#464), `job/photos-470` (#470), `job/perf-367` (#367). All five heads are ancestors. The required final fetch and origin/dev merge returned `Already up to date.` Integration fixes and files: - Settings canonical links preserve Maintenance query state and stable Saved place UUID fragments (`apps/web/src/routes/settings/[...path]/+page.svelte`, registry tests). - Authenticated Location routing coexists with public Calendar feeds (`crates/calternal-server/src/wire.rs`). - Mail fixtures retain MIME reader regressions and the full-history profile (`crates/plugins/mail/src/sync.rs`). Calendar benchmarks use the canonical Daily note first, then search only that User's Home (`apps/web/e2e/calendar-perf.mjs`). - Location uses shared leading and shape tokens (`apps/web/src/routes/settings/account/LocationGroup.svelte`). - Location operations and Saved place identities have explicit fail-closed classifications with regression tests (`tests/adversarial/authz_matrix.py`, `xuser_matrix.py`, `test_xuser_classification.py`). - Updated the shared capture harness and its regression tests (`apps/web/e2e/harness.mjs`, `harness.test.mjs`, `appearance-review.mjs`). Earlier failing capture output is preserved; no existing numeric assertion was weakened. - Regenerated `contracts/openapi.json`, `packages/api-client/src/generated.ts`, and `docs/parity-*`. No generated files were hand-merged. - Reviewed module/function comments were updated with the merge fixes. Imported feature files remain in the five branch histories. The complete changed-file list is `artifacts/merge-round-2/files.txt`. Migrations: no duplicate numeric prefixes in any migrations folder. Notes adds 0020 after origin/dev's 0019; Calendar adds 0004 after origin/dev's 0003. Notes bridge is excluded. Decisions: - Keep the existing API adapters' scope. Record the new Location/Calendar adapter gaps in the generated parity inventory rather than invent new CLI/MCP/WebMCP behavior in this merge. - Keep both Mail fixture behaviors in one helper. Keep the Calendar fallback scoped to the current User's Home. - Preserve dev's existing test expectations. The two web failures were timeouts and were rerun alone. Restore the exact 16-family theme expectation from dev; count dark variant submenu parents as families and use the existing keyboard submenu interaction. - In the capture harness, check the saved Auto/System preference separately from its rendered Light/Dark CSS phase. Eight regressions verify both phases and reject wrong persistence or rendering. - Seed the review's initial preference through the real API before SPA navigation. Wait for hydration before choosing a mode, and await persistence with bounded API reads on the host. Playwright 1.63 treats the former async predicate as truthy before its Promise resolves. Known gaps: - `calternal-server` tests were stopped during compilation at the approximately four-hour limit (exit -15). Server clippy passed. No server test assertion result was produced. Run `cargo test -p calternal-server` before merge. - Standalone vendored `async-imap` clippy/test were initially cancelled while waiting for the build lock and were not completed before the limit. Mail clippy and tests checked/exercised its Tokio dependency path. - The ignored large Mail history and worst-case performance profiles were not rerun. The requested local one-item Photos smoke completed; the imported baseline remains unchanged. - The live hostile-input and race adversarial round was not run under this session's safety limits. Offline classification and probe-helper tests do not replace it. This branch is not certified ready to merge until that round is completed. - Static parity records 188 actions with adapter gaps. New Location operations lack CLI/MCP/WebMCP adapters; Calendar feeds/subscriptions lack MCP adapters. These imported scope gaps remain documented. - The official generated-check wrapper returned 143 after its build/generation output. The equivalent OpenAPI generation, client generation, unique-operation check, and clean generated diff were rerun explicitly and all returned 0. - The local one-photo debug smoke is not comparable with the 5,000-photo baseline; no regression verdict was made. Its JSON commit field is `unknown`. Browser evidence: Calendar feeds passed with 36 screenshots. Location passed with six screenshots, including stable Saved place link restoration and cap-height assertions. The full Appearance review passed with 71 screenshots. Notes, Photos and the Log with its Saved place passed with 18 more screenshots. All required surface matrices cover 390/820/1440 px and light/dark. The additional Unsplash previews use third-party test fixtures; ordinary Notes/Photos/Location/Calendar data comes from the real local API. The production app supplied the screenshots; visual quality review remains with the orchestrator. [Appearance, Notes, Photos and Log matrix](https://git.kayg.org/attachments/2a0c2168-6199-4d45-9ff2-ad676518e88e). [Location full matrix](https://git.kayg.org/attachments/6078bc47-ceb1-4566-9b5e-63ef5c52b9a1). [Calendar full matrix](https://git.kayg.org/attachments/03f5976a-28a3-4384-9aae-a995bac45409). Local performance smoke (`photos-perf.mjs --items 1 --home-only`): server start 1101 ms; all indexed 4060 ms; rebuild requested 2582 ms; mean/peak RSS 350938740/432443392 bytes; mean/peak CPU 25.24/132.98%; CPU 23.74 s. Load after: 33.2/38.3/40.6. Baseline `docs/perf/baseline.json`, commit `369ab6a2f9fc673e3564b94857fbecfeb04df404`, 5000 photos: server start 290 ms; indexed 63230 ms; rebuild 719 ms; mean/peak RSS 360533602/495759360 bytes; mean/peak CPU 63.05/235.82%; CPU 113.24 s. Different dataset and environment: these numbers show the smoke completed, not a regression comparison. Gate outputs follow. Full logs are under `artifacts/merge-round-2/` in the worktree; screenshots and logs are not committed. Required environment: `CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=4 TMPDIR=$PWD/target/tmp`; the preset CARGO_TARGET_DIR was retained. Rust gates ran per crate. `cargo fmt --check`: exit 0, no output. `git diff --check`: exit 0, no output. Per-crate exit statuses, verbatim: ```text calternal-cli clippy 0 calternal-cli test 0 calternal-dav clippy 0 calternal-dav test 0 calternal-location clippy 0 calternal-location test 0 calternal-notes-core clippy 0 calternal-notes-core test 0 calternal-plugin clippy 0 calternal-plugin test 0 calternal-plugin-calendar clippy 0 calternal-plugin-calendar test 0 calternal-plugin-files clippy 0 calternal-plugin-files test 0 calternal-plugin-mail clippy 0 calternal-plugin-mail test 0 calternal-plugin-notes clippy 0 calternal-plugin-notes test 0 calternal-plugin-photos clippy 0 calternal-plugin-photos test 0 calternal-server clippy 0 calternal-server test -15 ``` calternal-cli clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 16m 25s ``` calternal-cli test: ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 57m 13s test result: ok. 27 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.76s test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.09s ``` calternal-dav clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 12m 25s ``` calternal-dav test: ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 6m 06s test result: ok. 41 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.46s test result: ok. 33 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` calternal-location clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 05s ``` calternal-location test: ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 57.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.47s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` calternal-notes-core clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 29s ``` calternal-notes-core test: ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 2m 31s test result: ok. 506 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.74s test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.47s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.07s test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.53s test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` calternal-plugin clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 9m 55s ``` calternal-plugin test: ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 4m 21s test result: ok. 23 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.05s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` calternal-plugin-calendar clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 29m 42s ``` calternal-plugin-calendar test: ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 10m 46s test result: ok. 79 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.33s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.24s test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.23s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` calternal-plugin-files clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 4m 08s ``` calternal-plugin-files test: ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 6m 35s test result: ok. 129 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 220.28s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` calternal-plugin-mail clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 36s ``` calternal-plugin-mail test: ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 3m 49s test result: ok. 35 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 1.17s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` calternal-plugin-notes clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 36s ``` calternal-plugin-notes test: ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 7m 40s test result: ok. 130 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 223.97s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.83s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` calternal-plugin-photos clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 48s ``` calternal-plugin-photos test: ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 6m 06s test result: ok. 44 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 25.16s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` calternal-server clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 18m 02s ``` Server test run: cancelled during compilation; no test result. Last compiler output, verbatim: ```text Compiling calternal-plugin-money v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/money) Compiling rmcp v3.5.0 Compiling calternal-plugin-files v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/files) Compiling calternal-collab v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/calternal-collab) Compiling calternal-plugin-calendar v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/calendar) Compiling calternal-plugin-ai v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/ai) Compiling calternal-plugin-photos v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/photos) Compiling calternal-plugin-video v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/video) Compiling calternal-plugin-notifications v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/notifications) Compiling calternal-plugin-analytics v0.0.1 (/home/kayg/Developer/calternal-wt/merge-web/crates/plugins/analytics) ``` Web, contract, classification, parity, offline helper and browser output excerpts follow verbatim. Full output, including earlier failures and isolated reruns, is in the attached log archive. ### bun-install.log ```text Checked 631 installs across 749 packages (no changes) [25.76s] ``` ### web-check-final.log ```text Text sizes and UI shape values use shared role tokens. svelte-check found 0 errors and 0 warnings ``` ### web-test.log ```text ❯ |component| src/lib/components/KeyboardShortcutsCard.svelte.test.ts (1 test | 1 failed) 5696ms ❯ |unit| src/lib/calendar/zones.test.ts (21 tests | 1 failed) 6881ms ⎯⎯⎯⎯⎯⎯⎯ Failed Tests 2 ⎯⎯⎯⎯⎯⎯⎯ Error: Test timed out in 5000ms. If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout". Error: Test timed out in 5000ms. If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout". Test Files 2 failed | 137 passed (139) Tests 2 failed | 897 passed (899) Duration 416.06s (transform 66%, import 12%, environment 12%, tests 7%, setup 3%) ``` ### web-zones-alone.log ```text Test Files 1 passed (1) Tests 21 passed (21) Duration 88.80s (transform 94%, import 6%) ``` ### web-shortcuts-alone.log ```text Test Files 1 passed (1) Tests 1 passed (1) Duration 126.01s (transform 79%, environment 11%, import 5%, setup 3%, tests 2%) ``` ### settings-alone.log ```text Test Files 1 passed (1) Tests 8 passed (8) Duration 6.85s (transform 85%, import 10%, tests 4%) ``` ### api-client-tests.log ```text (pass) apiFetch > keeps a typed failure body that is not an error envelope [0.23ms] 9 pass 0 fail 31 expect() calls ``` ### bench-tests.log ```text ............ ---------------------------------------------------------------------- Ran 12 tests in 1.213s OK ``` ### dav-probe-contract-tests.log ```text ....... ---------------------------------------------------------------------- Ran 7 tests in 0.029s OK ``` ### appearance-probe-contract-tests.log ```text .... ---------------------------------------------------------------------- Ran 4 tests in 0.008s OK ``` ### classification-final-tests.log ```text .... ---------------------------------------------------------------------- Ran 4 tests in 0.284s OK ``` ### classify-final.log ```text Cross-User classification gate: 328 operations classified ``` ### parity-final.log ```text Parity matrix: 206 web API actions, 113 shortcuts, 2 static commands, 131 menu actions, 33 settings groups, 188 actions with adapter gaps ``` ### generated-check-confirmed.log ```text $ /mnt/hdd/targets/jobs/merge-round-2/debug/calternal-server openapi exit=0 $ bun run --cwd packages/api-client generate $ bunx --package openapi-typescript@7.13.0 openapi-typescript ../../contracts/openapi.json -o src/generated.ts ✨ openapi-typescript 7.13.0 🚀 ../../contracts/openapi.json → src/generated.ts [3s] exit=0 $ git diff --exit-code -- contracts/openapi.json packages/api-client/src/generated.ts exit=0 OpenAPI operation IDs: 328 unique ``` ### calendar-feeds.log ```text Calendar feeds proof passed; screenshots: /home/kayg/Developer/calternal-wt/merge-web/artifacts/merge-round-2/calendar-feeds ``` ### location-review.log ```text PASS appearance review captures: 6 screenshots in /home/kayg/Developer/calternal-wt/merge-web/artifacts/location ``` ### photos-home-local.log ```text indexed: { {"items":1,"commit":"unknown","recordedAt":"2026-09-30T10:14:15.246Z","homeOnly":true,"environment":{"host":"calternal-dev","platform":"linux","architecture":"x64"},"homeFixtures":{"photos":1,"photoDays":1,"files":0,"folderItems":0,"notes":0,"logEntries":0,"dailyNotes":0,"largeNoteBytes":0},"homeFixtureWriteMs":10277,"indexing":{"serverUpMs":1101,"allIndexedMs":4060,"photoRebuildRequestedMs":2582,"indexed":{"photos":1,"folderItems":0,"restItems":0,"notes":0,"logEntries":0}},"homeRenders":{"cpuThrottle":4,"runs":3,"order":[["files5k","analyticsYear","note1MiB"],["analyticsYear","note1MiB","files5k"],["note1MiB","files5k","analyticsYear"]],"files5k":{"skipped":true},"analyticsYear":{"skipped":true},"note1MiB":{"skipped":true}},"loadAverageAfter":[33.2,38.3,40.6],"homeResources":{"meanRssBytes":350938740,"peakRssBytes":432443392,"meanCpuPercent":25.24,"peakCpuPercent":132.98,"cpuSeconds":23.74,"samples":186}} ``` harness-test-final.log: ```text 8 pass 0 fail Ran 8 tests across 1 file. [474.00ms] ``` appearance-review-awaited.log: ```text PASS appearance review captures: 71 screenshots in /home/kayg/Developer/calternal-wt/merge-web/artifacts/location ``` reconcile-review-normal-note.log: ```text PASS Notes and Photos review: 18 production screenshots, 390/820/1440 px, light/dark ``` cargo-clean.log: ```text Removed 23900 files, 14.0GiB total ``` migrations.log: ```text crates/calternal-auth/migrations: 10 numbered migrations; no duplicates crates/calternal-db/src/migrations: 6 numbered migrations; no duplicates crates/calternal-plugin/migrations: 1 numbered migrations; no duplicates crates/calternal-search/migrations: 3 numbered migrations; no duplicates crates/calternal-tags/migrations: 2 numbered migrations; no duplicates crates/plugins/ai/migrations: 4 numbered migrations; no duplicates crates/plugins/analytics/migrations: 2 numbered migrations; no duplicates crates/plugins/calendar/migrations: 4 numbered migrations; no duplicates crates/plugins/files/migrations: 15 numbered migrations; no duplicates crates/plugins/mail/migrations: 8 numbered migrations; no duplicates crates/plugins/notes/migrations: 20 numbered migrations; no duplicates crates/plugins/notifications/migrations: 4 numbered migrations; no duplicates crates/plugins/photos/migrations: 6 numbered migrations; no duplicates crates/plugins/video/migrations: 1 numbered migrations; no duplicates PASS: 14 migration folders have unique numeric prefixes ``` `bun run build`: exit 0. Output, verbatim: ```text ✓ built in 2m 29s ✓ built in 527ms ✓ built in 4m 52s > Using @sveltejs/adapter-static ``` Official generated-check wrapper exit: 143. Confirmed equivalent generation/uniqueness/diff steps: all exit 0, quoted above. Standalone vendor attempt statuses, verbatim: ```text async-imap clippy -15 async-imap test -15 ``` Cleanup: cargo clean exit 0; web build and Svelte build output deleted. Screenshots and logs remain uncommitted. Final git status is clean. [Full gate output, earlier failures, isolated reruns, performance smoke and changed-file manifest](https://git.kayg.org/attachments/bd32de61-0a7d-4999-b66c-134546087c66).
Author
Owner

Merge round 2 final report

Head: 192ea5457f1fc17735d876e70b41cb506b2a8274 on job/merge-round-2. origin/dev was fetched and merged at 1389119e33831275e6b56b9181ef42838003a4b3; job/bg-422 was already an ancestor (git merge --no-edit job/bg-422 → Already up to date.). No push, deploy, or merge to dev.

Built

Integrated the #391 Location/Appearance, #431 calendar feeds, #459 bug fixes, #470 Photos and #367 performance changes. Follow-up 76d1e71e1 makes Location probes await settled server state. Follow-up 192ea5457 fixes the Photos/Backgrounds SSE ordering race: preserve one event invalidation while the stable folder ID resolves, then refetch once. Updated the production Settings sweep to cover Account → Location and real Photos folder actions.

Files changed by the follow-up:

  • apps/web/src/lib/photos/BackgroundsFolderView.svelte
  • apps/web/e2e/settings-effects.mjs
  • tests/adversarial/appearance_auto_scheme.mjs

Full integration manifest: artifacts/merge-round-2/files.txt.

Gates (output verbatim)

cargo fmt --check: exit 0, no output.

cargo clippy -p calternal-server --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 6m 06s

cargo test -p calternal-server
    Finished `test` profile [unoptimized + debuginfo] target(s) in 9m 02s
test result: ok. 93 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 22.86s

async-imap clippy
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 11.21s

async-imap test
---- client::tests::test_parsing_error stdout ----
thread 'client::tests::test_parsing_error' panicked at crates/plugins/mail/vendor/async-imap/src/client.rs:2724:9:
assertion failed: session.noop().await.unwrap_err().to_string().contains("220 mail.example.org ESMTP Postcow")
test client::tests::test_parsing_error ... FAILED
test result: FAILED. 69 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.40s

bun run check
Text sizes and UI shape values use shared role tokens.
svelte-check found 0 errors and 0 warnings

bun run build
✓ built in 1m 37s
> Using @sveltejs/adapter-static
  Wrote site to "build"
  ✔ done

bun run test (final run)
 ❯ |component| src/lib/themePicker.svelte.test.ts (7 tests | 1 failed) 11924ms
 FAIL |component| src/lib/themePicker.svelte.test.ts > theme menu > reveals the trigger in the sheet scrollport before opening
Error: Test timed out in 5000ms.
 Test Files  1 failed | 138 passed (139)
      Tests  1 failed | 909 passed (910)
   Start at  18:24:29
   Duration  271.28s (transform 61%, environment 16%, import 10%, tests 10%, setup 3%)

generated contract
Finished `dev` profile [unoptimized + debuginfo] target(s) in 13m 26s
Running `/mnt/hdd/targets/jobs/merge-round-2/debug/calternal-server openapi`
$ bunx --package openapi-typescript@7.13.0 openapi-typescript ../../contracts/openapi.json -o src/generated.ts
✨ openapi-typescript 7.13.0
🚀 ../../contracts/openapi.json → src/generated.ts [1.9s]

parity check
Parity matrix: 206 web API actions, 113 shortcuts, 2 static commands, 131 menu actions, 33 settings groups, 188 actions with adapter gaps

Live probes

  • Location: Location API probe: malformed and oversized payloads and file, exact coordinates, Unicode place, concurrent writes, fixture restore, and cross-User isolation passed; Appearance Auto/Fonts/Background burst: 48 concurrent writes, all 200.
  • Webcal: Calendar feeds proof passed; screenshots: /home/kayg/Developer/calternal-wt/merge-web/artifacts/webcal-431.
  • WebDAV race: WebDAV scripted probes passed.
  • Settings and Photos/Backgrounds: PASS settings effects: Appearance, Photos/Backgrounds, Calendar time preview; screenshots in /home/kayg/Developer/calternal-wt/merge-web/artifacts/bg-422.
  • Two-User matrix: 328 operations classified; 157 operations replayed; 565 A-ID vs missing-ID comparisons across B, C, D and anonymous; median absolute timing delta 6.1 ms; ownership: 77 comparisons; 0 denial failures.
  • Media had one SLOW-only finding: the PDF worker list took 5.39 s with HTTP 200 against the probe's 5.0 s threshold. No hostile-input or 5xx finding remained.
  • Local photos-perf.mjs --items 1 --home-only: at load average 38.2/42.8/43, server start 2850 ms, indexed 4790 ms, mean/peak RSS 335424222/425738240 bytes, mean/peak CPU 23.37/95.95%, CPU 22.16 s. This one-photo local smoke is not comparable to the 5,000-photo perf VM baseline.

Known gaps and decisions

  • Standalone IMAP tests retain the existing display expectation and fail client::tests::test_parsing_error; clippy passes. No test expectation was changed.
  • The final web test gate has the single five-second ThemePicker timeout above. The component and test are unchanged from origin/dev; this is reported as a gate failure.
  • Media's 5.39-second response is SLOW-only shared-host load.
  • DESIGN §35 does not specify an SSE event arriving before stable folder identity resolves. Decision: coalesce early events into one list refresh after resolution. DESIGN §47 L1 defines Account as Location consent owner; Auto uses the exact saved location.
  • Settings effects used Node 22 because Bun could not load host Sharp (libstdc++.so.6 missing). No app code changed for the host workaround.

Production screenshots

The new Settings/Photos/Backgrounds matrix covers 390/820/1440 px in light and dark: download review ZIP. Existing full matrices: Location, Appearance/Notes/Photos/Log, Calendar feeds. Screenshots and logs are not committed.

## Merge round 2 final report **Head:** `192ea5457f1fc17735d876e70b41cb506b2a8274` on `job/merge-round-2`. `origin/dev` was fetched and merged at `1389119e33831275e6b56b9181ef42838003a4b3`; `job/bg-422` was already an ancestor (`git merge --no-edit job/bg-422` → `Already up to date.`). No push, deploy, or merge to dev. ### Built Integrated the #391 Location/Appearance, #431 calendar feeds, #459 bug fixes, #470 Photos and #367 performance changes. Follow-up `76d1e71e1` makes Location probes await settled server state. Follow-up `192ea5457` fixes the Photos/Backgrounds SSE ordering race: preserve one event invalidation while the stable folder ID resolves, then refetch once. Updated the production Settings sweep to cover Account → Location and real Photos folder actions. Files changed by the follow-up: - `apps/web/src/lib/photos/BackgroundsFolderView.svelte` - `apps/web/e2e/settings-effects.mjs` - `tests/adversarial/appearance_auto_scheme.mjs` Full integration manifest: `artifacts/merge-round-2/files.txt`. ### Gates (output verbatim) `cargo fmt --check`: exit 0, no output. ```text cargo clippy -p calternal-server --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 6m 06s cargo test -p calternal-server Finished `test` profile [unoptimized + debuginfo] target(s) in 9m 02s test result: ok. 93 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 22.86s async-imap clippy Finished `dev` profile [unoptimized + debuginfo] target(s) in 11.21s async-imap test ---- client::tests::test_parsing_error stdout ---- thread 'client::tests::test_parsing_error' panicked at crates/plugins/mail/vendor/async-imap/src/client.rs:2724:9: assertion failed: session.noop().await.unwrap_err().to_string().contains("220 mail.example.org ESMTP Postcow") test client::tests::test_parsing_error ... FAILED test result: FAILED. 69 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.40s bun run check Text sizes and UI shape values use shared role tokens. svelte-check found 0 errors and 0 warnings bun run build ✓ built in 1m 37s > Using @sveltejs/adapter-static Wrote site to "build" ✔ done bun run test (final run) ❯ |component| src/lib/themePicker.svelte.test.ts (7 tests | 1 failed) 11924ms FAIL |component| src/lib/themePicker.svelte.test.ts > theme menu > reveals the trigger in the sheet scrollport before opening Error: Test timed out in 5000ms. Test Files 1 failed | 138 passed (139) Tests 1 failed | 909 passed (910) Start at 18:24:29 Duration 271.28s (transform 61%, environment 16%, import 10%, tests 10%, setup 3%) generated contract Finished `dev` profile [unoptimized + debuginfo] target(s) in 13m 26s Running `/mnt/hdd/targets/jobs/merge-round-2/debug/calternal-server openapi` $ bunx --package openapi-typescript@7.13.0 openapi-typescript ../../contracts/openapi.json -o src/generated.ts ✨ openapi-typescript 7.13.0 🚀 ../../contracts/openapi.json → src/generated.ts [1.9s] parity check Parity matrix: 206 web API actions, 113 shortcuts, 2 static commands, 131 menu actions, 33 settings groups, 188 actions with adapter gaps ``` ### Live probes - Location: `Location API probe: malformed and oversized payloads and file, exact coordinates, Unicode place, concurrent writes, fixture restore, and cross-User isolation passed`; `Appearance Auto/Fonts/Background burst: 48 concurrent writes, all 200`. - Webcal: `Calendar feeds proof passed; screenshots: /home/kayg/Developer/calternal-wt/merge-web/artifacts/webcal-431`. - WebDAV race: `WebDAV scripted probes passed`. - Settings and Photos/Backgrounds: `PASS settings effects: Appearance, Photos/Backgrounds, Calendar time preview; screenshots in /home/kayg/Developer/calternal-wt/merge-web/artifacts/bg-422`. - Two-User matrix: `328 operations classified; 157 operations replayed; 565 A-ID vs missing-ID comparisons across B, C, D and anonymous; median absolute timing delta 6.1 ms`; ownership: `77 comparisons; 0 denial failures`. - Media had one SLOW-only finding: the PDF worker list took 5.39 s with HTTP 200 against the probe's 5.0 s threshold. No hostile-input or 5xx finding remained. - Local `photos-perf.mjs --items 1 --home-only`: at load average 38.2/42.8/43, server start 2850 ms, indexed 4790 ms, mean/peak RSS 335424222/425738240 bytes, mean/peak CPU 23.37/95.95%, CPU 22.16 s. This one-photo local smoke is not comparable to the 5,000-photo perf VM baseline. ### Known gaps and decisions - Standalone IMAP tests retain the existing display expectation and fail `client::tests::test_parsing_error`; clippy passes. No test expectation was changed. - The final web test gate has the single five-second ThemePicker timeout above. The component and test are unchanged from origin/dev; this is reported as a gate failure. - Media's 5.39-second response is SLOW-only shared-host load. - DESIGN §35 does not specify an SSE event arriving before stable folder identity resolves. Decision: coalesce early events into one list refresh after resolution. DESIGN §47 L1 defines Account as Location consent owner; Auto uses the exact saved location. - Settings effects used Node 22 because Bun could not load host Sharp (`libstdc++.so.6` missing). No app code changed for the host workaround. ### Production screenshots The new Settings/Photos/Backgrounds matrix covers 390/820/1440 px in light and dark: [download review ZIP](https://git.kayg.org/attachments/ef08eb55-75be-4234-a946-b5557db27745). Existing full matrices: [Location](https://git.kayg.org/attachments/6078bc47-ceb1-4566-9b5e-63ef5c52b9a1), [Appearance/Notes/Photos/Log](https://git.kayg.org/attachments/2a0c2168-6199-4d45-9ff2-ad676518e88e), [Calendar feeds](https://git.kayg.org/attachments/03f5976a-28a3-4384-9aae-a995bac45409). Screenshots and logs are not committed.
Author
Owner

Merged into dev and deployed to calternal.cloud at aa372eef6 via merge round 2 (server tests 93 passed, web 914/914, live location/webcal/WebDAV/Settings-Photos/two-User probes passed).

Merged into dev and deployed to calternal.cloud at aa372eef6 via merge round 2 (server tests 93 passed, web 914/914, live location/webcal/WebDAV/Settings-Photos/two-User probes passed).
kayg closed this issue 2026-09-30 17:20:56 +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#470
No description provided.