Files: hide sidecars (.xmp/.aae) by default, Settings → Files → Hidden files, sidecars travel with their file #420

Closed
opened 2026-09-29 09:14:09 +00:00 by kayg · 37 comments
Owner

Decision (owner, 2026-09-29, #341 Q11 = a)

Sidecars keep their standard names (Lease.pdf.xmp, IMG_1234.CR3.xmp, Apple IMG_1234.AAE), so Lightroom, digiKam and exiftool find them. calternal Files hides them by default and keeps each one with its parent file. The owner said: "which then means we need a Hidden Files section in Settings → Files".

Build

  1. Settings → Files → Hidden files (a new Files settings section if none exists; reuse the shared Settings card and row block from #402, with the deep link /settings/files/hidden). Per-User switches:
    • Show sidecar files (.xmp, .aae next to a file with the same base name): off by default.
    • Show dot files (names that start with .): off by default. This replaces today's per-request show_hidden query. Keep the query for API and CLI callers, and make the setting its default for the web.
    • A short explanation of what sidecars hold and why other apps need them.
  2. Sidecar detection belongs in one shared function, in calternal-fs or the Files plugin, and Photos, Tags and Documents reuse it. A sidecar is <full name>.xmp, <stem>.xmp (Lightroom form) or <stem>.AAE/.aae, and only when the parent file exists. An orphaned .xmp with no parent is shown like any other file.
  3. Sidecars travel with the parent file. Move, rename, copy, delete, Trash, restore and share all carry the sidecar, in both the API and WebDAV. Over WebDAV, only operations that calternal performs can be carried; a client that renames only the parent file leaves the sidecar behind. In that case, re-pair it on the next index pass when exactly one candidate matches.
  4. Search, counts and storage totals: sidecars do not appear as separate results. Storage totals still include their bytes.
  5. Parity (#395): the setting is exposed through the API, the CLI and MCP.

Proof

  • Tests for detection (all three name forms, orphans, case), for each travel operation, and for the setting's default.
  • The adversarial round: a cursed sidecar name, a sidecar that is a symlink or a directory, a parent and sidecar pair in two different folders, and a concurrent rename of the parent and its sidecar.
  • Screenshots of the settings section at 390, 820 and 1440 px, light and dark.
## Decision (owner, 2026-09-29, #341 Q11 = a) Sidecars keep their standard names (`Lease.pdf.xmp`, `IMG_1234.CR3.xmp`, Apple `IMG_1234.AAE`), so Lightroom, digiKam and exiftool find them. calternal Files hides them by default and keeps each one with its parent file. The owner said: "which then means we need a Hidden Files section in Settings → Files". ## Build 1. **Settings → Files → Hidden files** (a new Files settings section if none exists; reuse the shared Settings card and row block from #402, with the deep link `/settings/files/hidden`). Per-User switches: - **Show sidecar files** (`.xmp`, `.aae` next to a file with the same base name): off by default. - **Show dot files** (names that start with `.`): off by default. This replaces today's per-request `show_hidden` query. Keep the query for API and CLI callers, and make the setting its default for the web. - A short explanation of what sidecars hold and why other apps need them. 2. **Sidecar detection** belongs in one shared function, in `calternal-fs` or the Files plugin, and Photos, Tags and Documents reuse it. A sidecar is `<full name>.xmp`, `<stem>.xmp` (Lightroom form) or `<stem>.AAE`/`.aae`, and only when the parent file exists. An orphaned `.xmp` with no parent is shown like any other file. 3. **Sidecars travel with the parent file.** Move, rename, copy, delete, Trash, restore and share all carry the sidecar, in both the API and WebDAV. Over WebDAV, only operations that calternal performs can be carried; a client that renames only the parent file leaves the sidecar behind. In that case, re-pair it on the next index pass when exactly one candidate matches. 4. **Search, counts and storage totals:** sidecars do not appear as separate results. Storage totals still include their bytes. 5. **Parity (#395):** the setting is exposed through the API, the CLI and MCP. ## Proof - Tests for detection (all three name forms, orphans, case), for each travel operation, and for the setting's default. - The adversarial round: a cursed sidecar name, a sidecar that is a symlink or a directory, a parent and sidecar pair in two different folders, and a concurrent rename of the parent and its sidecar. - Screenshots of the settings section at 390, 820 and 1440 px, light and dark.
Author
Owner

Starting #420 on branch job/hidden-420, based on dev at 191b179baac3ef4f5bebfe07ce91c4b7a887ace2. I am tracing the existing Files lifecycle, user settings API and UI before implementing shared sidecar behavior.

Starting #420 on branch `job/hidden-420`, based on `dev` at `191b179baac3ef4f5bebfe07ce91c4b7a887ace2`. I am tracing the existing Files lifecycle, user settings API and UI before implementing shared sidecar behavior.
Author
Owner

Finding: the existing transfer helper in crates/calternal-tags/src/source.rs carries only XMP for photo/video files. It does not carry Apple .AAE files or sidecars for other file types. prepare_trash also deletes XMP sidecars and stores their bytes in Tags metadata before Files moves the parent. I will move sidecar lifecycle ownership into the shared Files filesystem path and keep Tags responsible for XMP content only.

Finding: the existing transfer helper in `crates/calternal-tags/src/source.rs` carries only XMP for photo/video files. It does not carry Apple `.AAE` files or sidecars for other file types. `prepare_trash` also deletes XMP sidecars and stores their bytes in Tags metadata before Files moves the parent. I will move sidecar lifecycle ownership into the shared Files filesystem path and keep Tags responsible for XMP content only.
Author
Owner

Progress update on job/hidden-420, based on dev at 191b179baac3ef4f5bebfe07ce91c4b7a887ace2.

Committed shared filename pairing in 1b5454f12138e3a86cdaac26aac181d6e0c6577d. cargo test -p calternal-fs passed (44 unit tests and 42 storage tests); cargo clippy -p calternal-fs --all-targets -- -D warnings passed. The detector pairs only unique regular siblings and covers full-name XMP, Lightroom XMP, Apple AAE, orphans, ambiguous names, links, directories, cross-folder isolation and hostile names.

Review finding: a stale Files Index relation could survive if another client replaced a sidecar path with a link or directory. Pair refresh now clears non-regular relations, and move/copy paths reject unrelated sidecar-name collisions before touching the parent.

Progress update on `job/hidden-420`, based on `dev` at `191b179baac3ef4f5bebfe07ce91c4b7a887ace2`. Committed shared filename pairing in `1b5454f12138e3a86cdaac26aac181d6e0c6577d`. `cargo test -p calternal-fs` passed (44 unit tests and 42 storage tests); `cargo clippy -p calternal-fs --all-targets -- -D warnings` passed. The detector pairs only unique regular siblings and covers full-name XMP, Lightroom XMP, Apple AAE, orphans, ambiguous names, links, directories, cross-folder isolation and hostile names. Review finding: a stale Files Index relation could survive if another client replaced a sidecar path with a link or directory. Pair refresh now clears non-regular relations, and move/copy paths reject unrelated sidecar-name collisions before touching the parent.
Author
Owner

Finding during the requested symlink adversarial probe: folder reconciliation attempted to hash a symlink through the no-follow filesystem API, which could fail the scan. I changed reconciliation to remove symlinks and special files from the Files Index, and sidecar pairing now validates the current regular-file objects before acting. Regression coverage includes a symlink and a directory named like sidecars. The live-server adversarial pass is pending.

Finding during the requested symlink adversarial probe: folder reconciliation attempted to hash a symlink through the no-follow filesystem API, which could fail the scan. I changed reconciliation to remove symlinks and special files from the Files Index, and sidecar pairing now validates the current regular-file objects before acting. Regression coverage includes a symlink and a directory named like sidecars. The live-server adversarial pass is pending.
Author
Owner

Contract note: I added a small public sidecar filename pairing helper and sidecar-kind type in calternal-fs. Files, Photos and Tags use the same held-folder pairing rules, so a filename is not paired differently by each plugin. The helper accepts names plus regular-file status; the Files Index persists the resulting parent relation for access and listing operations.

Contract note: I added a small public sidecar filename pairing helper and sidecar-kind type in `calternal-fs`. Files, Photos and Tags use the same held-folder pairing rules, so a filename is not paired differently by each plugin. The helper accepts names plus regular-file status; the Files Index persists the resulting parent relation for access and listing operations.
Author
Owner

Finding during review of the Search path: calternal-search builds results directly from regular files under each User Home, so a paired .xmp could still appear by filename after the Files search provider filtered it. I am using the shared same-folder pairing helper during Search directory scans and adding a regression test for a paired sidecar and an orphan.

Finding during review of the Search path: `calternal-search` builds results directly from regular files under each User Home, so a paired `.xmp` could still appear by filename after the Files search provider filtered it. I am using the shared same-folder pairing helper during Search directory scans and adding a regression test for a paired sidecar and an orphan.
Author
Owner

Finding from cargo test -p calternal-plugin-files: compilation reported unused import: path::Path in crates/calternal-tags/src/source.rs after its sidecar rename path moved to the shared helper. I removed the import; the Tags crate gate will verify the correction.

Finding from `cargo test -p calternal-plugin-files`: compilation reported `unused import: path::Path` in `crates/calternal-tags/src/source.rs` after its sidecar rename path moved to the shared helper. I removed the import; the Tags crate gate will verify the correction.
Author
Owner

Finding from the first Files crate compile: Rust rejected moving sidecar source/destination RelPath values while borrowed relative names were still in use, and rejected mutating a shared-entry vector while a HashSet<&str> borrowed from it. I changed the move plan and shared listing filter to own those relative/name strings before moving or retaining entries. The queued Files clippy and the next test run will verify the fix.

Finding from the first Files crate compile: Rust rejected moving sidecar source/destination `RelPath` values while borrowed relative names were still in use, and rejected mutating a shared-entry vector while a `HashSet<&str>` borrowed from it. I changed the move plan and shared listing filter to own those relative/name strings before moving or retaining entries. The queued Files clippy and the next test run will verify the fix.
Author
Owner

Finding from the Files suite: 87 tests returned HTTP 500 or files Index update failed after new sidecar calls began querying sidecar_parent_id and sidecar_kind. The migrations directory had 0016_sidecar_pairs.sql, but FilesPlugin::migrations() stopped at version 15, so test and server databases never added the columns. I registered migration 16 in the Plugin migration set; I am rerunning the Files suite to verify the repair.

Finding from the Files suite: 87 tests returned HTTP 500 or `files Index update failed` after new sidecar calls began querying `sidecar_parent_id` and `sidecar_kind`. The migrations directory had `0016_sidecar_pairs.sql`, but `FilesPlugin::migrations()` stopped at version 15, so test and server databases never added the columns. I registered migration 16 in the Plugin migration set; I am rerunning the Files suite to verify the repair.
Author
Owner

Sidecar matcher finding: photo.AAE matched both photo.cr3 and the sibling photo.xmp, because the Lightroom sidecar was also considered a possible parent. That left AAE unpaired. The shared matcher now excludes recognized sidecar filenames as parents. cargo test -p calternal-plugin-files passed with the regression covering all three naming forms and move/copy/trash/restore.

The move path also exceeded the standard test thread stack while retaining the nested Files move/index futures. Boxing those async boundaries and skipping folder-metadata rewrites for photo/video tags brought the full travel test back under the default stack. No product stack-size increase was made.

Sidecar matcher finding: `photo.AAE` matched both `photo.cr3` and the sibling `photo.xmp`, because the Lightroom sidecar was also considered a possible parent. That left AAE unpaired. The shared matcher now excludes recognized sidecar filenames as parents. `cargo test -p calternal-plugin-files` passed with the regression covering all three naming forms and move/copy/trash/restore. The move path also exceeded the standard test thread stack while retaining the nested Files move/index futures. Boxing those async boundaries and skipping folder-metadata rewrites for photo/video tags brought the full travel test back under the default stack. No product stack-size increase was made.
Author
Owner

Stopped at the job's four-hour time box.

Implemented and committed through 0b6a065dfed6e2ba1091e47666a2002f78da6a56:

  • Shared sidecar detection and pairing for full-name .xmp, stem .xmp, and .AAE/.aae files, including orphan handling and collision avoidance.
  • Files-side sidecar indexing, default hiding, search/count filtering, storage accounting, and sidecar travel through Files and DAV operations, including post-index re-pairing after a DAV parent-only rename.
  • Files adversarial probe and a screenshot capture hook.

The working tree also contains uncommitted follow-on integration in Photos, Search, CLI, MCP, and the Web Files/settings UI. The Settings → Files → Hidden files section and preference API are present in that working tree, but the API schema/client generation is incomplete.

Gate results:

  • cargo fmt --all && cargo fmt --check: exit 0, no output.
  • cargo test -p calternal-plugin-files:
    test result: ok. 134 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 193.67s
    
       Doc-tests calternal_plugin_files
    
    running 0 tests
    
    test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
    
  • bun run test:
     Test Files  125 passed (125)
          Tests  804 passed (804)
    
  • cargo clippy -p calternal-plugin-files --all-targets -- -D warnings: interrupted at the time limit (exit 130); it did not produce a gate result.
  • bun run check failed because the generated API types do not yet include the new schema/path:
    Error: Property 'FilesPreferences' does not exist on type ...
    Error: Argument of type '"/api/v1/files/preferences"' is not assignable to parameter of type 'ApiPath'.
    error: script "check" exited with code 1
    

Not completed: merge dev once before final gates; remaining Rust crate/server/CLI/MCP gates; regenerate API schema/client and rerun Web check; production screenshots for 390/820/1440 px in light/dark; run and attach the adversarial probe results. No issue close, push, deploy, or merge was done. cargo clean completed: Removed 8707 files, 3.3GiB total; Web .svelte-kit and build output were removed.

Decision note: Search indexing applies the sidecar filter to Documents because this checkout has no separate Documents plugin. Sidecar candidates exclude files that are themselves recognized sidecars so paired .xmp/.AAE metadata cannot become an ambiguous parent candidate.

Stopped at the job's four-hour time box. Implemented and committed through `0b6a065dfed6e2ba1091e47666a2002f78da6a56`: - Shared sidecar detection and pairing for full-name `.xmp`, stem `.xmp`, and `.AAE`/`.aae` files, including orphan handling and collision avoidance. - Files-side sidecar indexing, default hiding, search/count filtering, storage accounting, and sidecar travel through Files and DAV operations, including post-index re-pairing after a DAV parent-only rename. - Files adversarial probe and a screenshot capture hook. The working tree also contains uncommitted follow-on integration in Photos, Search, CLI, MCP, and the Web Files/settings UI. The Settings → Files → Hidden files section and preference API are present in that working tree, but the API schema/client generation is incomplete. Gate results: - `cargo fmt --all && cargo fmt --check`: exit 0, no output. - `cargo test -p calternal-plugin-files`: ``` test result: ok. 134 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 193.67s Doc-tests calternal_plugin_files running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` - `bun run test`: ``` Test Files 125 passed (125) Tests 804 passed (804) ``` - `cargo clippy -p calternal-plugin-files --all-targets -- -D warnings`: interrupted at the time limit (exit 130); it did not produce a gate result. - `bun run check` failed because the generated API types do not yet include the new schema/path: ``` Error: Property 'FilesPreferences' does not exist on type ... Error: Argument of type '"/api/v1/files/preferences"' is not assignable to parameter of type 'ApiPath'. error: script "check" exited with code 1 ``` Not completed: merge `dev` once before final gates; remaining Rust crate/server/CLI/MCP gates; regenerate API schema/client and rerun Web check; production screenshots for 390/820/1440 px in light/dark; run and attach the adversarial probe results. No issue close, push, deploy, or merge was done. `cargo clean` completed: `Removed 8707 files, 3.3GiB total`; Web `.svelte-kit` and build output were removed. Decision note: Search indexing applies the sidecar filter to Documents because this checkout has no separate Documents plugin. Sidecar candidates exclude files that are themselves recognized sidecars so paired `.xmp`/`.AAE` metadata cannot become an ambiguous parent candidate.
Author
Owner

Starting resumed work on job/hidden-420. Current HEAD: 0b6a065dfed6e2ba1091e47666a2002f78da6a56; branch base (merge-base with dev): 191b179baac3ef4f5bebfe07ce91c4b7a887ace2. I am reviewing the existing uncommitted Files/Settings, CLI, Search, MCP, Photos and docs changes before committing them in logical steps.

Starting resumed work on `job/hidden-420`. Current HEAD: `0b6a065dfed6e2ba1091e47666a2002f78da6a56`; branch base (merge-base with `dev`): `191b179baac3ef4f5bebfe07ce91c4b7a887ace2`. I am reviewing the existing uncommitted Files/Settings, CLI, Search, MCP, Photos and docs changes before committing them in logical steps.
Author
Owner

Review finding: FilesBrowser.toggleHiddenFiles() builds a full Files preferences update from filesVisibility.show_sidecar_files without waiting for loadFilesVisibility(). If the toolbar action runs before the GET completes (or the GET fails), changing dot-file visibility can write the default false value over an existing show_sidecar_files: true setting. I will make the toggle load the canonical preference snapshot before saving and cover the ordering with a web regression test.

Review finding: `FilesBrowser.toggleHiddenFiles()` builds a full Files preferences update from `filesVisibility.show_sidecar_files` without waiting for `loadFilesVisibility()`. If the toolbar action runs before the GET completes (or the GET fails), changing dot-file visibility can write the default `false` value over an existing `show_sidecar_files: true` setting. I will make the toggle load the canonical preference snapshot before saving and cover the ordering with a web regression test.
Author
Owner

Review finding: Photos initially fetched paired XMP paths with one extra SQLite query for every photo whose metadata changed. That made a large library reconciliation issue N+1 Index queries. The Photos query now returns the selected Sidecar path and hash together, using the Files Index pairing relation, and a focused test covers Lightroom-form XMP parsing.

Review finding: Photos initially fetched paired XMP paths with one extra SQLite query for every photo whose metadata changed. That made a large library reconciliation issue N+1 Index queries. The Photos query now returns the selected Sidecar path and hash together, using the Files Index pairing relation, and a focused test covers Lightroom-form XMP parsing.
Author
Owner

Review finding: the existing MCP adversarial probe asserted an exact set of eight tools. Adding the Files preference read/write tools made that contract stale. The probe now expects ten tools, checks the listing filter and per-User preference read/write, and can run with the sidecar API probe in the same API-only server round.

Review finding: the existing MCP adversarial probe asserted an exact set of eight tools. Adding the Files preference read/write tools made that contract stale. The probe now expects ten tools, checks the listing filter and per-User preference read/write, and can run with the sidecar API probe in the same API-only server round.
Author
Owner

The first OpenAPI generator build failed while compiling calternal-search: RelPath::split() was pub(crate) in calternal-fs, so Search could not inspect the parent directory and final component for a sidecar watcher event. I made this existing helper public with a documented invariant and a focused split test. This is the small cross-crate API addition needed for #420; it does not change filesystem behavior.

The first OpenAPI generator build failed while compiling `calternal-search`: `RelPath::split()` was `pub(crate)` in `calternal-fs`, so Search could not inspect the parent directory and final component for a sidecar watcher event. I made this existing helper public with a documented invariant and a focused split test. This is the small cross-crate API addition needed for #420; it does not change filesystem behavior.
Author
Owner

The first cargo test -p calternal-search run found that the new global sidecar-filter test created only search_manifest, while the query path also reads search_frecency; SQLite returned no such table: search_frecency. The test now applies the existing Search migrations, and the full Search crate test command passes (34 unit tests plus all integration suites; 3 expected ignored benchmarks).

The first `cargo test -p calternal-search` run found that the new global sidecar-filter test created only `search_manifest`, while the query path also reads `search_frecency`; SQLite returned `no such table: search_frecency`. The test now applies the existing Search migrations, and the full Search crate test command passes (34 unit tests plus all integration suites; 3 expected ignored benchmarks).
Author
Owner

cargo clippy -p calternal-plugin-photos --all-targets -- -D warnings first stopped in its calternal-plugin-files dependency with 9 lints (nested conditions, or_insert_with(Vec::new), two explicit counters, needless borrows, and an 8-argument Shared memory-page function). I fixed the mechanical lints and grouped the grant-derived cursor fields in MemoryPageScope; cargo clippy -p calternal-plugin-files --all-targets -- -D warnings now passes, as do all 134 Files tests (one performance probe ignored). Photos Clippy and tests pass too.

`cargo clippy -p calternal-plugin-photos --all-targets -- -D warnings` first stopped in its `calternal-plugin-files` dependency with 9 lints (nested conditions, `or_insert_with(Vec::new)`, two explicit counters, needless borrows, and an 8-argument Shared memory-page function). I fixed the mechanical lints and grouped the grant-derived cursor fields in `MemoryPageScope`; `cargo clippy -p calternal-plugin-files --all-targets -- -D warnings` now passes, as do all 134 Files tests (one performance probe ignored). Photos Clippy and tests pass too.
Author
Owner

Resuming hidden-420 on branch job/hidden-420. The branch base is 191b179baa. The API, Files, Photos, Search, and adversarial-probe slices are committed; I am reviewing and finishing the remaining CLI/MCP parity changes before the final merge and gates.

Resuming hidden-420 on branch job/hidden-420. The branch base is 191b179baac3ef4f5bebfe07ce91c4b7a887ace2. The API, Files, Photos, Search, and adversarial-probe slices are committed; I am reviewing and finishing the remaining CLI/MCP parity changes before the final merge and gates.
Author
Owner

Finding during the resumed CLI gate: cargo test -p calternal-cli reports E0308 at main.rs:915 because the new ls argument test compares Option<String> directly with "Photos". I am changing the guard to compare path.as_deref() with Some("Photos"), then rerunning the CLI test and Clippy gates.

Finding during the resumed CLI gate: `cargo test -p calternal-cli` reports E0308 at `main.rs:915` because the new `ls` argument test compares `Option<String>` directly with `"Photos"`. I am changing the guard to compare `path.as_deref()` with `Some("Photos")`, then rerunning the CLI test and Clippy gates.
Author
Owner

Finding during the CLI test rerun: Clap accepts files preferences but rejects set-preferences as its child (UnknownArgument), while the walkthrough and regression test document files preferences set-preferences. I am nesting the update action under the preferences command so the implemented CLI matches the documented command path.

Finding during the CLI test rerun: Clap accepts `files preferences` but rejects `set-preferences` as its child (`UnknownArgument`), while the walkthrough and regression test document `files preferences set-preferences`. I am nesting the update action under the preferences command so the implemented CLI matches the documented command path.
Author
Owner

Finding after the origin/dev merge: cargo test -p calternal-tags failed because rebuilds_all_tag_sources_after_index_loss_and_renames_nested_tags expected Tags::prepare_trash to remove XMP Sidecars from Home. Issue #420 moves Sidecar lifecycle to Files, where Files moves each Sidecar with its parent during Trash and restore; Tags records tag state and leaves the Sidecar in place until that Files operation. The Files integration test sidecar_files_travel_with_the_parent_through_move_copy_trash_and_restore covers the actual lifecycle and passed. I updated the Tags unit test to assert that preparation preserves both packet bytes, then reran cargo test -p calternal-tags: 11 passed, 0 failed. This changes an expectation only to match the explicit #420 Sidecar travel behavior.

Finding after the origin/dev merge: `cargo test -p calternal-tags` failed because `rebuilds_all_tag_sources_after_index_loss_and_renames_nested_tags` expected `Tags::prepare_trash` to remove XMP Sidecars from Home. Issue #420 moves Sidecar lifecycle to Files, where Files moves each Sidecar with its parent during Trash and restore; Tags records tag state and leaves the Sidecar in place until that Files operation. The Files integration test `sidecar_files_travel_with_the_parent_through_move_copy_trash_and_restore` covers the actual lifecycle and passed. I updated the Tags unit test to assert that preparation preserves both packet bytes, then reran `cargo test -p calternal-tags`: 11 passed, 0 failed. This changes an expectation only to match the explicit #420 Sidecar travel behavior.
Author
Owner

Finding from the requested full Web gate: bun run test completed in 798.89s with 875 passed and 7 failed. All 7 failures were Test timed out in 5000ms in themePicker, TimeGrid, KeyboardShortcutsCard, OverlaySurface, two Composer cases and RangeBar; none reported an assertion mismatch. During the run, several other worktrees were also running Vitest and Svelte checks, and this run reported 2457.44s of repeated module transforms. I am treating these as shared-host load timeouts and will not rerun the full suite, per the one-run rule.

Finding from the requested full Web gate: `bun run test` completed in 798.89s with 875 passed and 7 failed. All 7 failures were `Test timed out in 5000ms` in themePicker, TimeGrid, KeyboardShortcutsCard, OverlaySurface, two Composer cases and RangeBar; none reported an assertion mismatch. During the run, several other worktrees were also running Vitest and Svelte checks, and this run reported 2457.44s of repeated module transforms. I am treating these as shared-host load timeouts and will not rerun the full suite, per the one-run rule.
Author
Owner

Probe preparation finding: the first timeout 20m invocation passed the Cross-User classification gate and production Web build (✓ built in 3m 4s), then reached the local Server binary build. Shared-host Server codegen did not finish within the 20-minute bound, so fixture setup, screenshots and the API probes did not start. The production Web output and /mnt/hdd/targets/jobs/hidden-420/debug/calternal-server binary are now present; I am continuing the requested single probe pass with those completed artifacts and will skip duplicate builds.

Probe preparation finding: the first `timeout 20m` invocation passed the Cross-User classification gate and production Web build (`✓ built in 3m 4s`), then reached the local Server binary build. Shared-host Server codegen did not finish within the 20-minute bound, so fixture setup, screenshots and the API probes did not start. The production Web output and `/mnt/hdd/targets/jobs/hidden-420/debug/calternal-server` binary are now present; I am continuing the requested single probe pass with those completed artifacts and will skip duplicate builds.
Author
Owner

The live #420 probe sent an extra unexpected key to PUT /api/v1/files/preferences. The route rejected it, but Axum returned HTTP 422 while the OpenAPI route documents a 400 ErrorEnvelope. The Files Pins handler already maps Axum JSON rejections to the shared Files 400 envelope and preserves 413 for oversized bodies. I am applying the same behavior to Files preferences and adding a regression test before rerunning the focused live probes.

The live #420 probe sent an extra `unexpected` key to `PUT /api/v1/files/preferences`. The route rejected it, but Axum returned HTTP 422 while the OpenAPI route documents a 400 ErrorEnvelope. The Files Pins handler already maps Axum JSON rejections to the shared Files 400 envelope and preserves 413 for oversized bodies. I am applying the same behavior to Files preferences and adding a regression test before rerunning the focused live probes.
Author
Owner

The focused production screenshot matrix completed with all 18 requested captures. The combined adversarial runner then stopped in the existing later multi-User setup step: POST /api/v1/auth/invites returned HTTP 403 ({"code":"forbidden","message":"Access denied"}), before the requested Sidecar probe ran. I retained the local fixture and am running the Sidecar and MCP probes directly so this unrelated invite setup does not hide their results.

The focused production screenshot matrix completed with all 18 requested captures. The combined adversarial runner then stopped in the existing later multi-User setup step: `POST /api/v1/auth/invites` returned HTTP 403 (`{"code":"forbidden","message":"Access denied"}`), before the requested Sidecar probe ran. I retained the local fixture and am running the Sidecar and MCP probes directly so this unrelated invite setup does not hide their results.
Author
Owner

The live Sidecar probe reached its final path cases. Two actual .. segments are rejected, but the literal path component %2e%2e returns an empty 200 listing: urllib.parse.urlencode encodes the percent sign, so the API decodes once and correctly sees a literal filename rather than a traversal segment. This matches the Files path rule and the probe's cursed-name case. I am changing the probe to assert 400/404 for decoded dot segments and an empty result for the literal percent-encoded name.

The live Sidecar probe reached its final path cases. Two actual `..` segments are rejected, but the literal path component `%2e%2e` returns an empty 200 listing: `urllib.parse.urlencode` encodes the percent sign, so the API decodes once and correctly sees a literal filename rather than a traversal segment. This matches the Files path rule and the probe's cursed-name case. I am changing the probe to assert 400/404 for decoded dot segments and an empty result for the literal percent-encoded name.
Author
Owner

The focused live-server Sidecar probe now passes. It exercised default and changed Files preferences, unknown and oversized bodies, a cursed literal filename with its Sidecar moved together, a parent and XMP in different folders, symlink and directory Sidecars staying independent, two concurrent parent renames preserving one parent/XMP pair, decoded .. rejection, and a literal %2e%2e path returning an empty in-folder listing. The probe assertions were corrected to count the XMP-named directory as its own Files entry and to reflect the API's single query decode.

The focused live-server Sidecar probe now passes. It exercised default and changed Files preferences, unknown and oversized bodies, a cursed literal filename with its Sidecar moved together, a parent and XMP in different folders, symlink and directory Sidecars staying independent, two concurrent parent renames preserving one parent/XMP pair, decoded `..` rejection, and a literal `%2e%2e` path returning an empty in-folder listing. The probe assertions were corrected to count the XMP-named directory as its own Files entry and to reflect the API's single query decode.
Author
Owner

The post-fix cargo test -p calternal-plugin-files run completed in 375.81s: 134 passed, 1 ignored, and only internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm failed. Its five-minute completion timeout elapsed; during teardown the write worker reported atomic write 892 failed: entry not found. All Files preference, Sidecar, DAV, and other tests passed. I am running that stress test once by itself to determine whether the NotFound is reproducible or only follows the shared-host timeout.

The post-fix `cargo test -p calternal-plugin-files` run completed in 375.81s: 134 passed, 1 ignored, and only `internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm` failed. Its five-minute completion timeout elapsed; during teardown the write worker reported `atomic write 892 failed: entry not found`. All Files preference, Sidecar, DAV, and other tests passed. I am running that stress test once by itself to determine whether the `NotFound` is reproducible or only follows the shared-host timeout.
Author
Owner

The isolated rerun confirms the stress-test failure is its SLOW-only five-minute limit under shared-host load. It again ended at Elapsed(()) after 301.31s, after 881 of 1,000 writes; the entry not found panic was from the writer during timeout abort. The full Files run had no other failures, and the earlier Files suite passed this same stress test. No production failure reproduced in the focused Sidecar probe.

The isolated rerun confirms the stress-test failure is its SLOW-only five-minute limit under shared-host load. It again ended at `Elapsed(())` after 301.31s, after 881 of 1,000 writes; the `entry not found` panic was from the writer during timeout abort. The full Files run had no other failures, and the earlier Files suite passed this same stress test. No production failure reproduced in the focused Sidecar probe.
Author
Owner

Completed Forgejo #420.

Branch: job/hidden-420
Head: 81f2bc2f7e0512bf952ecc8e0063301a0f106ba4
Base incorporated: origin/dev via merge commit e16f6a51f.

Built

  • Added shared Sidecar pairing for full-name and stem .xmp, plus .AAE and .aae. Only unambiguous regular files in the same folder pair. Files listing, Search, Tags and Photos use the shared rule.
  • Kept paired Sidecars with their parent through Files rename, move, Trash and restore. Added Index support for DAV parent-only rename recovery and preserved storage accounting.
  • Added per-User Files visibility preferences, the Files preferences API, Settings → Files → Hidden files, listing filters, CLI flags/preferences, and MCP visibility preferences. Regenerated OpenAPI and API client outputs.
  • Added the live-server Sidecar probe and the production screenshot capture path.

Files

Changed files span:

  • crates/calternal-fs/src/{lib.rs,path.rs,sidecar.rs}
  • crates/plugins/files/src/{dav.rs,index.rs,lib.rs,listing.rs,lookup.rs,preferences.rs,shares.rs} and migration 0016_sidecar_pairs.sql
  • crates/calternal-search/src/indexer.rs, crates/calternal-tags/src/{index.rs,lib.rs,rename.rs,source.rs}, crates/plugins/photos/src/{index.rs,routes.rs}
  • crates/calternal-server/src/mcp.rs, crates/calternal-cli/src/{main.rs,remote_commands.rs}
  • Files and Settings modules/tests under apps/web/src
  • contracts/openapi.json, packages/api-client/src/generated.ts, docs/cli-walkthrough.md, docs/mcp.md
  • tests/adversarial/{mcp_probe.py,run.sh,setup.mjs,sidecar_probe.py}

All 18 requested screenshots are in ignored artifacts/hidden-420/: Settings → Files → Hidden files, and Files lists with Sidecars hidden/shown, at 390/820/1440 px in light/dark. They are not committed. scripts/fj issue has no attachment command, so I could not upload them to this issue.

Gates and probes

  • cargo fmt --check: exit 0, no output.
  • cargo clippy -p calternal-fs -p calternal-plugin-files -p calternal-tags -p calternal-search -p calternal-server -p calternal-cli -p calternal-plugin-photos --all-targets -- -D warnings: each per-crate clippy run exited 0. Files output: Finished dev profile [unoptimized + debuginfo] target(s) in 10m 02s. Server output: Finished dev profile [unoptimized + debuginfo] target(s) in 10m 55s.
  • Other Rust tests passed: calternal-fs (47 unit + 42 storage), calternal-tags (11), calternal-search, calternal-cli (28 unit + 15 output-contract), Photos (45 passed, 2 ignored).
  • Server tests: test result: ok. 85 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 19.58s.
  • Files tests had one SLOW-only timeout in internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm: test result: FAILED. 134 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out; finished in 375.81s. The isolated retry hit its five-minute cap at 881/1000 writes; the teardown then logged atomic write 881 failed: entry not found. All other Files tests passed. No test expectation was changed.
  • bun run check: svelte-check found 0 errors and 0 warnings.
  • bun run test: Tests 7 failed | 875 passed (882); all seven failures were 5000 ms timeouts in themePicker, TimeGrid, KeyboardShortcutsCard, OverlaySurface, two Composer cases and RangeBar. No assertion mismatch. The host was running other Vitest/Svelte jobs; I did not rerun the full suite.
  • bash packages/api-client/check-generated.sh regenerated the expected OpenAPI/client diff and exited 1 while reporting that diff; both generated files are committed.
  • Sidecar live-server probe: sidecar live-server probe passed: preferences, hostile names, cross-folder orphan, links, directories and concurrent rename.
  • The combined adversarial runner later stopped at its existing multi-User invite setup: POST /api/v1/auth/invites returned 403 Access denied. The direct Sidecar probe passed.
  • Cleanup: Removed 23242 files, 17.3GiB total.

Decisions not specified in DESIGN

  • Search applies Sidecar filtering to Documents because this checkout has no separate Documents Plugin.
  • Photos prefers full-name XMP over the Lightroom stem form if both are paired.
  • Files preferences live with per-User settings in .calternal/settings.json; dot-file visibility remains a per-request option, with Web/CLI/MCP using the saved preference.
  • Tags prepares Trash metadata but Files owns movement of paired bytes and their lifecycle.
  • Malformed or unknown Files preference JSON maps to the documented 400 ErrorEnvelope; oversized request bodies keep 413.
  • A literal %2e%2e path component is decoded once and stays a harmless filename string; decoded .. segments are rejected.
Completed Forgejo #420. Branch: `job/hidden-420` Head: `81f2bc2f7e0512bf952ecc8e0063301a0f106ba4` Base incorporated: `origin/dev` via merge commit `e16f6a51f`. ## Built - Added shared Sidecar pairing for full-name and stem `.xmp`, plus `.AAE` and `.aae`. Only unambiguous regular files in the same folder pair. Files listing, Search, Tags and Photos use the shared rule. - Kept paired Sidecars with their parent through Files rename, move, Trash and restore. Added Index support for DAV parent-only rename recovery and preserved storage accounting. - Added per-User Files visibility preferences, the Files preferences API, Settings → Files → Hidden files, listing filters, CLI flags/preferences, and MCP visibility preferences. Regenerated OpenAPI and API client outputs. - Added the live-server Sidecar probe and the production screenshot capture path. ## Files Changed files span: - `crates/calternal-fs/src/{lib.rs,path.rs,sidecar.rs}` - `crates/plugins/files/src/{dav.rs,index.rs,lib.rs,listing.rs,lookup.rs,preferences.rs,shares.rs}` and migration `0016_sidecar_pairs.sql` - `crates/calternal-search/src/indexer.rs`, `crates/calternal-tags/src/{index.rs,lib.rs,rename.rs,source.rs}`, `crates/plugins/photos/src/{index.rs,routes.rs}` - `crates/calternal-server/src/mcp.rs`, `crates/calternal-cli/src/{main.rs,remote_commands.rs}` - Files and Settings modules/tests under `apps/web/src` - `contracts/openapi.json`, `packages/api-client/src/generated.ts`, `docs/cli-walkthrough.md`, `docs/mcp.md` - `tests/adversarial/{mcp_probe.py,run.sh,setup.mjs,sidecar_probe.py}` All 18 requested screenshots are in ignored `artifacts/hidden-420/`: Settings → Files → Hidden files, and Files lists with Sidecars hidden/shown, at 390/820/1440 px in light/dark. They are not committed. `scripts/fj issue` has no attachment command, so I could not upload them to this issue. ## Gates and probes - `cargo fmt --check`: exit 0, no output. - `cargo clippy -p calternal-fs -p calternal-plugin-files -p calternal-tags -p calternal-search -p calternal-server -p calternal-cli -p calternal-plugin-photos --all-targets -- -D warnings`: each per-crate clippy run exited 0. Files output: `Finished `dev` profile [unoptimized + debuginfo] target(s) in 10m 02s`. Server output: `Finished `dev` profile [unoptimized + debuginfo] target(s) in 10m 55s`. - Other Rust tests passed: calternal-fs (47 unit + 42 storage), calternal-tags (11), calternal-search, calternal-cli (28 unit + 15 output-contract), Photos (45 passed, 2 ignored). - Server tests: `test result: ok. 85 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 19.58s`. - Files tests had one SLOW-only timeout in `internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm`: `test result: FAILED. 134 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out; finished in 375.81s`. The isolated retry hit its five-minute cap at 881/1000 writes; the teardown then logged `atomic write 881 failed: entry not found`. All other Files tests passed. No test expectation was changed. - `bun run check`: `svelte-check found 0 errors and 0 warnings`. - `bun run test`: `Tests 7 failed | 875 passed (882)`; all seven failures were 5000 ms timeouts in themePicker, TimeGrid, KeyboardShortcutsCard, OverlaySurface, two Composer cases and RangeBar. No assertion mismatch. The host was running other Vitest/Svelte jobs; I did not rerun the full suite. - `bash packages/api-client/check-generated.sh` regenerated the expected OpenAPI/client diff and exited 1 while reporting that diff; both generated files are committed. - Sidecar live-server probe: `sidecar live-server probe passed: preferences, hostile names, cross-folder orphan, links, directories and concurrent rename`. - The combined adversarial runner later stopped at its existing multi-User invite setup: `POST /api/v1/auth/invites` returned 403 Access denied. The direct Sidecar probe passed. - Cleanup: `Removed 23242 files, 17.3GiB total`. ## Decisions not specified in DESIGN - Search applies Sidecar filtering to Documents because this checkout has no separate Documents Plugin. - Photos prefers full-name XMP over the Lightroom stem form if both are paired. - Files preferences live with per-User settings in `.calternal/settings.json`; dot-file visibility remains a per-request option, with Web/CLI/MCP using the saved preference. - Tags prepares Trash metadata but Files owns movement of paired bytes and their lifecycle. - Malformed or unknown Files preference JSON maps to the documented 400 ErrorEnvelope; oversized request bodies keep 413. - A literal `%2e%2e` path component is decoded once and stays a harmless filename string; decoded `..` segments are rejected.
Author
Owner

Correction to the gate command wording in my final report: clippy ran separately for each listed crate as cargo clippy -p <crate> --all-targets -- -D warnings; it was not one combined multi-package invocation. The per-crate exit results are unchanged.

Correction to the gate command wording in my final report: clippy ran separately for each listed crate as `cargo clippy -p <crate> --all-targets -- -D warnings`; it was not one combined multi-package invocation. The per-crate exit results are unchanged.
Author
Owner

Finding during final merge gates: Files Clippy rejected an orphaned Trash cleanup doc comment at crates/plugins/files/src/index.rs:1574 (clippy::empty_line_after_doc_comments). I moved it onto empty_trash and documented both sidecar query helpers. Commit df6b07a5a. Verification: cargo clippy -p calternal-plugin-files --all-targets -- -D warnings finished successfully; cargo test -p calternal-plugin-files reported 144 passed, 0 failed, 1 ignored.

Finding during final merge gates: Files Clippy rejected an orphaned Trash cleanup doc comment at crates/plugins/files/src/index.rs:1574 (`clippy::empty_line_after_doc_comments`). I moved it onto empty_trash and documented both sidecar query helpers. Commit df6b07a5a. Verification: `cargo clippy -p calternal-plugin-files --all-targets -- -D warnings` finished successfully; `cargo test -p calternal-plugin-files` reported 144 passed, 0 failed, 1 ignored.
Author
Owner

Merge round 3 integration report

State: incomplete; do not fast-forward this snapshot to dev yet. The four-hour job limit ended while CLI Clippy was compiling. No completed final-tree gate failed. No source branch was dropped because the completed gates showed no failing branch.

  • Branch: job/merge-round-3
  • Head: 3e5056d485e9021d2d1f708613e783b0b901b447
  • Included in order: job/multiget-500, job/dav-delete-471, job/iso-435, job/admin-deny-483, job/attach-427, job/hidden-420, job/files-sel-keys, job/small-bugs-3, job/sweep-478.
  • Additional commits: 92f5803f3, 3ea69e317, 26b986bc4, 0948cffa1, 99c088193, df6b07a5a, 3e5056d48.

Completed gate output (verbatim excerpts)

cargo fmt --check exited 0 with no output.

  • DAV clippy: Finished \dev` profile [unoptimized + debuginfo] target(s) in 56.92s`
  • DAV tests:
    test result: ok. 40 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.37s
    test result: ok. 36 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s
    test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.31s
  • Notes Core clippy: Finished \dev` profile [unoptimized + debuginfo] target(s) in 14.97s`
  • Notes Core tests:
    test result: ok. 512 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.21s
    test result: ok. 19 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.21s
    test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s
    test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.35s
    test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
  • Notes plugin clippy: Finished \dev` profile [unoptimized + debuginfo] target(s) in 2m 55s`
  • Notes plugin tests: test result: ok. 127 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 151.26s
  • Files clippy (after comment fix): Finished \dev` profile [unoptimized + debuginfo] target(s) in 48.77s`
  • Files tests: test result: ok. 144 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 178.62s
    The dev-version migration test passed: test tests::dev_files_schema_upgrades_through_share_log_and_sidecar_migrations ... ok
  • Calendar clippy: Finished \dev` profile [unoptimized + debuginfo] target(s) in 1m 53s`
  • Calendar tests:
    test result: ok. 52 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.01s
    test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.12s
    test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.22s
  • Photos clippy: Finished \dev` profile [unoptimized + debuginfo] target(s) in 1m 13s`
  • Photos tests: test result: ok. 45 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 11.10s
  • Search clippy: Finished \dev` profile [unoptimized + debuginfo] target(s) in 55.79s`
  • Search tests:
    test result: ok. 36 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 46.71s
    test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.38s
    test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s
    test result: ok. 21 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 10.44s
    test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s
    test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
    test result: ok. 1 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 5.66s
    test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
  • Embed clippy: Finished \dev` profile [unoptimized + debuginfo] target(s) in 27.32s`
  • Embed tests: test result: ok. 31 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 1.93s
  • Filesystem clippy: Finished \dev` profile [unoptimized + debuginfo] target(s) in 10.78s`
  • Filesystem tests:
    test result: ok. 50 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.04s
    test result: ok. 42 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.56s
  • Server clippy: Finished \dev` profile [unoptimized + debuginfo] target(s) in 1m 48s`
  • Server tests: test result: ok. 85 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 19.67s

Other completed checks:

  • Parity matrix: 190 web API actions, 122 shortcuts, 2 static commands, 136 menu actions, 31 settings groups, 172 actions with adapter gaps
  • Cross-User classification gate: 311 operations classified; its test suite printed Ran 5 tests in 0.246s and OK.
  • Admin coverage: 39 reviewed operations; contract and Rust guards agree; its test suite printed Ran 14 tests in 2.404s and OK.
  • Migration audit: ai: 4 migrations, no duplicate numbers; analytics: 2 migrations, no duplicate numbers; calendar: 3 migrations, no duplicate numbers; files: 18 migrations, no duplicate numbers; mail: 8 migrations, no duplicate numbers; notes: 19 migrations, no duplicate numbers; notifications: 4 migrations, no duplicate numbers; photos: 6 migrations, no duplicate numbers; video: 1 migrations, no duplicate numbers.

Remaining work

  • CLI Clippy was interrupted at the four-hour limit while checking dependencies; CLI tests and both Auth gates did not run.
  • The generated contract check, web bun run check, bun run test, and bun run build are pending.
  • The live two-User matrix, authz matrix, DAV round (including Apple’s 100-href and DELETE re-parent replays), sidecar probe, and attachment e2e are pending.
  • Production-browser screenshots for each affected screen at 390/820/1440 px in light/dark mode are pending. No visual review artifacts were produced.
  • The new benchmark profile was added, but its local run and comparison with docs/perf/baseline.json are pending.
  • cargo clean is running but has not returned yet; apps/web/build was removed.

Decisions

  • Files migration IDs follow merge order after dev’s 0015: 0016 share_search_invalidations, 0017 log_attachment_trash, 0018 sidecar_pairs. The populated dev-schema upgrade test passed.
  • Hidden-file Settings copy leads with the User-visible result and uses “Photo edit files (.xmp, .aae)”.
  • The parity exception snapshot was regenerated and reviewed for the newly merged API and Files UI actions.

The branch contains the merged code and commits, but the listed pending gates mean this is not a green merge candidate yet.

## Merge round 3 integration report **State: incomplete; do not fast-forward this snapshot to `dev` yet.** The four-hour job limit ended while CLI Clippy was compiling. No completed final-tree gate failed. No source branch was dropped because the completed gates showed no failing branch. - Branch: `job/merge-round-3` - Head: `3e5056d485e9021d2d1f708613e783b0b901b447` - Included in order: `job/multiget-500`, `job/dav-delete-471`, `job/iso-435`, `job/admin-deny-483`, `job/attach-427`, `job/hidden-420`, `job/files-sel-keys`, `job/small-bugs-3`, `job/sweep-478`. - Additional commits: `92f5803f3`, `3ea69e317`, `26b986bc4`, `0948cffa1`, `99c088193`, `df6b07a5a`, `3e5056d48`. ### Completed gate output (verbatim excerpts) `cargo fmt --check` exited 0 with no output. - DAV clippy: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 56.92s` - DAV tests: `test result: ok. 40 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.37s` `test result: ok. 36 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s` `test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.31s` - Notes Core clippy: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 14.97s` - Notes Core tests: `test result: ok. 512 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.21s` `test result: ok. 19 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.21s` `test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s` `test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.35s` `test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s` - Notes plugin clippy: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 2m 55s` - Notes plugin tests: `test result: ok. 127 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 151.26s` - Files clippy (after comment fix): `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 48.77s` - Files tests: `test result: ok. 144 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 178.62s` The dev-version migration test passed: `test tests::dev_files_schema_upgrades_through_share_log_and_sidecar_migrations ... ok` - Calendar clippy: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 1m 53s` - Calendar tests: `test result: ok. 52 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.01s` `test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.12s` `test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.22s` - Photos clippy: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 1m 13s` - Photos tests: `test result: ok. 45 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 11.10s` - Search clippy: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 55.79s` - Search tests: `test result: ok. 36 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 46.71s` `test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.38s` `test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s` `test result: ok. 21 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 10.44s` `test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s` `test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s` `test result: ok. 1 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 5.66s` `test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s` - Embed clippy: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 27.32s` - Embed tests: `test result: ok. 31 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 1.93s` - Filesystem clippy: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 10.78s` - Filesystem tests: `test result: ok. 50 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.04s` `test result: ok. 42 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.56s` - Server clippy: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 1m 48s` - Server tests: `test result: ok. 85 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 19.67s` Other completed checks: - `Parity matrix: 190 web API actions, 122 shortcuts, 2 static commands, 136 menu actions, 31 settings groups, 172 actions with adapter gaps` - `Cross-User classification gate: 311 operations classified`; its test suite printed `Ran 5 tests in 0.246s` and `OK`. - `Admin coverage: 39 reviewed operations; contract and Rust guards agree`; its test suite printed `Ran 14 tests in 2.404s` and `OK`. - Migration audit: `ai: 4 migrations, no duplicate numbers`; `analytics: 2 migrations, no duplicate numbers`; `calendar: 3 migrations, no duplicate numbers`; `files: 18 migrations, no duplicate numbers`; `mail: 8 migrations, no duplicate numbers`; `notes: 19 migrations, no duplicate numbers`; `notifications: 4 migrations, no duplicate numbers`; `photos: 6 migrations, no duplicate numbers`; `video: 1 migrations, no duplicate numbers`. ### Remaining work - CLI Clippy was interrupted at the four-hour limit while checking dependencies; CLI tests and both Auth gates did not run. - The generated contract check, web `bun run check`, `bun run test`, and `bun run build` are pending. - The live two-User matrix, authz matrix, DAV round (including Apple’s 100-href and DELETE re-parent replays), sidecar probe, and attachment e2e are pending. - Production-browser screenshots for each affected screen at 390/820/1440 px in light/dark mode are pending. No visual review artifacts were produced. - The new benchmark profile was added, but its local run and comparison with `docs/perf/baseline.json` are pending. - `cargo clean` is running but has not returned yet; `apps/web/build` was removed. ### Decisions - Files migration IDs follow merge order after dev’s 0015: 0016 `share_search_invalidations`, 0017 `log_attachment_trash`, 0018 `sidecar_pairs`. The populated dev-schema upgrade test passed. - Hidden-file Settings copy leads with the User-visible result and uses “Photo edit files (.xmp, .aae)”. - The parity exception snapshot was regenerated and reviewed for the newly merged API and Files UI actions. The branch contains the merged code and commits, but the listed pending gates mean this is not a green merge candidate yet.
Author
Owner

Merge round 3 report addendum

Branch job/merge-round-3, HEAD 3e5056d485e9021d2d1f708613e783b0b901b447.

  • Cleanup completed after the main report: Removed 25367 files, 17.5GiB total.
  • apps/web/build removal check: web build output removed: True.
  • git diff --check exited 0 with no output; the worktree has no modified or untracked files.
  • The 4-hour cutoff also prevented a full re-read of documentation comments across all 234 changed files. This remains an audit gap alongside the pending gates listed in the main report.

The branch is still not a green merge candidate.

## Merge round 3 report addendum Branch `job/merge-round-3`, HEAD `3e5056d485e9021d2d1f708613e783b0b901b447`. - Cleanup completed after the main report: `Removed 25367 files, 17.5GiB total`. - `apps/web/build` removal check: `web build output removed: True`. - `git diff --check` exited 0 with no output; the worktree has no modified or untracked files. - The 4-hour cutoff also prevented a full re-read of documentation comments across all 234 changed files. This remains an audit gap alongside the pending gates listed in the main report. The branch is still not a green merge candidate.
Author
Owner

Merged in merge round 3 and deployed to calternal.cloud in cc25c441b (healthy).

Merged in merge round 3 and deployed to calternal.cloud in cc25c441b (healthy).
kayg closed this issue 2026-09-30 23:22:43 +00:00
Author
Owner

#427 additional check: the unchanged Files hidden-files E2E stops before preference changes because it uploads hidden-proof.png.aae and expects it to be a paired Apple edit. calternal-fs/src/sidecar.rs is identical on cc25c441b and a6fd7f704; Apple edits use <stem>.aae, so this photo pairs with hidden-proof.aae. XMP permits the full filename suffix but Apple AAE does not.

I kept the committed fixture and expectation unchanged for owner review. A temporary diagnostic with only that filename corrected passed the complete existing preference and visibility flow: FILES HIDDEN-FILES E2E PASSED; CSP REPORTS files: 0 across 1 pages. This verifies that #427's redundant-GET guard still refreshes real visibility changes. The temporary script was removed. This is a pre-existing fixture mismatch, not a changed sidecar contract.

#427 additional check: the unchanged Files hidden-files E2E stops before preference changes because it uploads `hidden-proof.png.aae` and expects it to be a paired Apple edit. `calternal-fs/src/sidecar.rs` is identical on cc25c441b and a6fd7f704; Apple edits use `<stem>.aae`, so this photo pairs with `hidden-proof.aae`. XMP permits the full filename suffix but Apple AAE does not. I kept the committed fixture and expectation unchanged for owner review. A temporary diagnostic with only that filename corrected passed the complete existing preference and visibility flow: `FILES HIDDEN-FILES E2E PASSED`; `CSP REPORTS files: 0 across 1 pages`. This verifies that #427's redundant-GET guard still refreshes real visibility changes. The temporary script was removed. This is a pre-existing fixture mismatch, not a changed sidecar contract.
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#420
No description provided.