diff --git a/.gitea/workflows/build-and-test.yml b/.gitea/workflows/build-and-test.yml index 579663a..ed5d3c9 100644 --- a/.gitea/workflows/build-and-test.yml +++ b/.gitea/workflows/build-and-test.yml @@ -454,7 +454,12 @@ jobs: wine "$SETUP" /S 2>/dev/null INST=$(echo "$HOME"/.wine/drive_c/users/*/AppData/Local/Programs/DarkRoom) ls "$INST" - [ "$(ls "$INST/models" | wc -l)" = 7 ] || { echo "FAIL: expected 7 model files"; exit 1; } + # As many files as package.sh stages: everything but the READMEs in + # the directories it copies. A literal here went stale the first + # time a model was added. + WANT=$(find models/face models/scene models/inpaint -maxdepth 1 -type f ! -name README.md | wc -l) + GOT=$(ls "$INST/models" | wc -l) + [ "$GOT" = "$WANT" ] || { echo "FAIL: expected $WANT model files, installed $GOT"; exit 1; } wine reg query 'HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\DarkRoom' 2>/dev/null \ | grep -q DisplayVersion || { echo "FAIL: no uninstall registry key"; exit 1; } wine "$INST/darkroom.exe" --version 2>/dev/null | grep -q '^darkroom-desktop ' \ diff --git a/README.md b/README.md index 27c28b0..2bfaebc 100644 --- a/README.md +++ b/README.md @@ -76,8 +76,8 @@ controls, its place in the chain and its tests. ## Where it stands -**0.13.5**, nineteen tagged releases in. 184 numbered requirements in -scope, 84% of them claimed by code and [traced to it](docs/dev/traceability.md); +**0.13.6**, twenty tagged releases in. 188 numbered requirements in +scope, 82% of them claimed by code and [traced to it](docs/dev/traceability.md); the rest are written down rather than merely absent. **Not built:** plugins (post-v1, [D12](docs/dev/requirements.md)), compare and diff --git a/core/dr-catalog/src/face_shard.rs b/core/dr-catalog/src/face_shard.rs index 674cfa0..65d50e8 100644 --- a/core/dr-catalog/src/face_shard.rs +++ b/core/dr-catalog/src/face_shard.rs @@ -178,6 +178,67 @@ impl FaceShardStore { .flatten() } + /// The other pipelines this file is held under that share `model_id`'s + /// embedder — the generations a put of `model_id` may supersede. + fn siblings(&self, file_id: u64, model_id: &str) -> Vec { + let mut stmt = match self.index.prepare(&format!( + "SELECT model_id FROM entries + WHERE file_id = ?1 AND model_id != ?2 AND {} = ?3", + crate::faces::embedder_sql("model_id") + )) { + Ok(s) => s, + Err(_) => return Vec::new(), + }; + stmt.query_map( + rusqlite::params![ + file_id as i64, + model_id, + crate::faces::embedder_of(model_id) + ], + |r| r.get::<_, String>(0), + ) + .map(|rows| rows.filter_map(|r| r.ok()).collect()) + .unwrap_or_default() + } + + /// Whether a pass this file is already held under outranks `model_id`, + /// so a put of `model_id` would add a generation nobody would adopt. + pub fn outranked(&self, file_id: u64, model_id: &str) -> bool { + use dr_types::FaceDetector; + let Some(incoming) = FaceDetector::for_model_id(model_id) else { + return false; + }; + self.siblings(file_id, model_id) + .iter() + .filter_map(|m| FaceDetector::for_model_id(m)) + .any(|held| held.outranks(incoming)) + } + + /// Forget the index entries for generations of this file that `model_id` + /// outranks. The bytes stay where they are — a sealed shard is + /// immutable — but the store stops offering them, and a later export or + /// merge writes nothing for them again. + fn supersede(&self, file_id: u64, model_id: &str) -> Result<(), CatalogError> { + use dr_types::FaceDetector; + let Some(incoming) = FaceDetector::for_model_id(model_id) else { + return Ok(()); + }; + for held in self.siblings(file_id, model_id) { + let weaker = FaceDetector::for_model_id(&held).is_some_and(|h| incoming.outranks(h)); + if weaker { + self.index.execute( + "DELETE FROM entries WHERE file_id = ?1 AND model_id = ?2", + rusqlite::params![file_id as i64, held], + )?; + self.index.execute( + "DELETE FROM faces_meta WHERE file_id = ?1 AND model_id = ?2", + rusqlite::params![file_id as i64, held], + )?; + } + } + Ok(()) + } + pub fn contains(&self, file_id: u64, model_id: &str) -> bool { self.index .query_row( @@ -233,6 +294,15 @@ impl FaceShardStore { faces: &[SharedFace], indexed_at: Option, ) -> Result { + // One generation per image per embedder. A store carried every pass + // — 24,123 entries for 19,089 images on the reference library, a + // third of its 293 MB — and only the strongest was ever adopted. + // A weaker pass arriving after a stronger one is not written; a + // stronger one arriving retires the weaker from the index. + if self.outranked(file_id, model_id) { + return Ok(0); + } + self.supersede(file_id, model_id)?; let incoming = faces .iter() .map(|f| BYTES_PER_FACE + if f.crop.is_empty() { 0 } else { BYTES_PER_CROP }) @@ -474,15 +544,28 @@ impl FaceShardStore { rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY | rusqlite::OpenFlags::SQLITE_OPEN_NO_MUTEX, )?; - let mut q = - src.prepare("SELECT file_id, model_id, faces_found, source_edge FROM indexed")?; - let images: Vec<(i64, String, i64, i64)> = q - .query_map([], |r| Ok((r.get(0)?, r.get(1)?, r.get(2)?, r.get(3)?)))? + // The peer's marker travels with the image: it is what lets + // `import_from_shards` record the adoption under the time the peer + // indexed it, and so what keeps `export_to_shards` from reading the + // adoption as a re-index and sending the peer's faces back out under + // this device's name. A shard from before the column has none. + let mut q = src.prepare(&format!( + "SELECT file_id, model_id, faces_found, source_edge, {} FROM indexed", + match has_column(&src, "indexed", "indexed_at") { + Ok(true) => "indexed_at", + _ => "NULL", + } + ))?; + let images: Vec<(i64, String, i64, i64, Option)> = q + .query_map([], |r| { + Ok((r.get(0)?, r.get(1)?, r.get(2)?, r.get(3)?, r.get(4)?)) + })? .collect::>()?; let mut adopted = 0; - for (file_id, model_id, _found, edge) in images { - if self.contains(file_id as u64, &model_id) { + for (file_id, model_id, _found, edge, indexed_at) in images { + if self.contains(file_id as u64, &model_id) || self.outranked(file_id as u64, &model_id) + { continue; } let mut fq = src.prepare(&format!( @@ -501,12 +584,27 @@ impl FaceShardStore { let faces: Vec = fq .query_map(rusqlite::params![file_id, &model_id], read_shared_face)? .collect::>()?; - self.put_image(file_id as u64, &model_id, edge as u32, &faces)?; + self.put_image_at(file_id as u64, &model_id, edge as u32, &faces, indexed_at)?; adopted += 1; } Ok(adopted) } + /// Record when the catalog indexed a held image, for an entry that + /// arrived without a marker — a peer's shard from before the column. + pub fn set_indexed_at( + &self, + file_id: u64, + model_id: &str, + at: i64, + ) -> Result<(), CatalogError> { + self.index.execute( + "UPDATE entries SET indexed_at = ?3 WHERE file_id = ?1 AND model_id = ?2", + rusqlite::params![file_id as i64, model_id, at], + )?; + Ok(()) + } + /// Read back everything held for one image. pub fn get_image( &self, @@ -798,8 +896,21 @@ pub fn import_from_shards( })? .collect::>()?; + /// Images per write transaction. Large enough that fourteen thousand + /// adoptions are a hundred and forty commits rather than fourteen + /// thousand; small enough that a read on the UI thread, queued behind + /// the lock, waits a fraction of a second and not the whole import. + const CHUNK: usize = 100; + let mut adopted = 0; + let mut tx = conn.unchecked_transaction()?; + let mut in_chunk = 0; for (file_id, image_id, local) in candidates { + if in_chunk == CHUNK { + tx.commit()?; + tx = conn.unchecked_transaction()?; + in_chunk = 0; + } let Some(held) = store.held_model(file_id as u64, model_id) else { continue; }; @@ -858,15 +969,42 @@ pub fn import_from_shards( }) .collect(); - crate::faces::record_detections( - conn, + crate::faces::record_detections_within( + &tx, dr_types::ImageId(image_id as u64), &held, edge, &local, )?; + // The peer's marker, not this moment. `record_detections` stamps the + // run as now, and `export_to_shards` reads a marker newer than the + // shard's as a re-index — so every adopted image went straight back + // out as this device's own work: 14,100 adopted, 15,457 "newly + // indexed" on the next pass, and twenty-two shards of a peer's faces + // uploaded again under a second name. Where the peer's shard carried + // no marker, the store takes the catalog's, so the two agree either + // way and the export sees nothing to send. + match store.indexed_at(file_id as u64, &held) { + Some(theirs) => { + tx.execute( + "UPDATE face_index SET indexed_at = ?3 + WHERE image_id = ?1 AND model_id = ?2", + rusqlite::params![image_id, held, theirs], + )?; + } + None => { + let ours: i64 = tx.query_row( + "SELECT indexed_at FROM face_index WHERE image_id = ?1 AND model_id = ?2", + rusqlite::params![image_id, held], + |r| r.get(0), + )?; + store.set_indexed_at(file_id as u64, &held, ours)?; + } + } adopted += 1; + in_chunk += 1; } + tx.commit()?; Ok(adopted) } @@ -1102,6 +1240,32 @@ mod tests { assert!(!s.contains(1, "lvface")); } + /// One generation per image per embedder: a stronger detector's pass + /// retires a weaker one from the index, and a weaker pass arriving after + /// a stronger is not written at all. + #[test] + fn a_stronger_pass_retires_a_weaker_one_and_a_weaker_is_not_added() { + let dir = tempdir(); + let mut s = FaceShardStore::open(&dir).unwrap(); + s.put_image(1, "w600k_mbf", 1024, &[face(1, 1)]).unwrap(); + s.put_image(1, "scrfd_10g+w600k_mbf", 1024, &[face(1, 2)]) + .unwrap(); + assert!(s.contains(1, "scrfd_10g+w600k_mbf")); + assert!(!s.contains(1, "w600k_mbf"), "the fast pass was not retired"); + assert_eq!(s.len(), 1, "faces_meta still counts the retired pass"); + + s.put_image(1, "scrfd_2.5g+w600k_mbf", 1024, &[face(1, 3)]) + .unwrap(); + assert!( + !s.contains(1, "scrfd_2.5g+w600k_mbf"), + "a weaker pass was added" + ); + assert_eq!( + s.held_model(1, "w600k_mbf").as_deref(), + Some("scrfd_10g+w600k_mbf") + ); + } + #[test] fn re_storing_an_image_replaces_rather_than_doubling_it() { let dir = tempdir(); @@ -1322,6 +1486,11 @@ mod catalog_round_trip { assert!((got[0].landmarks[2].0 - 0.15).abs() < 1e-5); let emb = faces::embeddings(&b, "w600k_mbf").unwrap(); assert!(emb.iter().any(|e| e.embedding[0] == 1)); + + // And what B adopted is not B's work: its next export sends nothing. + // Adopting used to stamp the run as now, so every adopted image went + // back out under B's name as a re-index. + assert_eq!(export_to_shards(&b, &mut store_b, "w600k_mbf").unwrap(), 0); } /// The desktop switched to a stronger detector part-way through the diff --git a/core/dr-catalog/src/faces.rs b/core/dr-catalog/src/faces.rs index 93b55ab..b22dc52 100644 --- a/core/dr-catalog/src/faces.rs +++ b/core/dr-catalog/src/faces.rs @@ -279,7 +279,25 @@ pub fn record_detections( faces: &[DetectedFace], ) -> Result, CatalogError> { let tx = conn.unchecked_transaction()?; + let ids = record_detections_within(&tx, image_id, model_id, source_edge, faces)?; + tx.commit()?; + Ok(ids) +} +/// [`record_detections`] inside a transaction the caller owns. +/// +/// For a caller recording many images at once — the shard import adopts +/// fourteen thousand in one pass — where a commit per image is fourteen +/// thousand fsyncs and fourteen thousand turns at the write lock that every +/// read on the UI thread queues behind. `unchecked_transaction` cannot nest, +/// so the batching has to be offered here rather than wrapped from above. +pub fn record_detections_within( + tx: &Connection, + image_id: ImageId, + model_id: &str, + source_edge: u32, + faces: &[DetectedFace], +) -> Result, CatalogError> { // Everything the old faces knew, so it can be carried across the // replacement. Read only when there is something to carry it onto: a // pass that found nothing has nothing to match, and decoding a vector @@ -287,7 +305,7 @@ pub fn record_detections( let prior = if faces.is_empty() { Vec::new() } else { - read_priors(&tx, image_id)? + read_priors(tx, image_id)? }; tx.execute("DELETE FROM faces WHERE image_id = ?1", [image_id.0 as i64])?; @@ -389,7 +407,6 @@ pub fn record_detections( ], )?; - tx.commit()?; Ok(ids) } diff --git a/core/dr-catalog/src/merge.rs b/core/dr-catalog/src/merge.rs index 86b78b5..97cce78 100644 --- a/core/dr-catalog/src/merge.rs +++ b/core/dr-catalog/src/merge.rs @@ -119,6 +119,8 @@ pub struct MergeReport { pub keywords_fused: usize, /// Keyword assignments taken from the remote. pub keywords_assigned: usize, + /// Images whose capture metadata was taken from the remote. + pub metadata_adopted: usize, } impl MergeReport { @@ -133,6 +135,7 @@ impl MergeReport { || self.keywords_deleted > 0 || self.keywords_fused > 0 || self.keywords_assigned > 0 + || self.metadata_adopted > 0 } /// Whether the local catalog holds anything the remote did not, and so @@ -193,10 +196,67 @@ pub fn merge_all(conn: &Connection) -> Result { merge_collections_within(&tx, &mut report)?; merge_keywords_within(&tx, &mut report)?; merge_people_within(&tx, &mut report)?; + merge_metadata_within(&tx, &mut report)?; tx.commit()?; Ok(report) } +/// Adopt capture metadata from an attached catalog, on its own. +pub fn merge_metadata(conn: &Connection) -> Result { + let tx = conn.unchecked_transaction()?; + let mut report = MergeReport::default(); + merge_metadata_within(&tx, &mut report)?; + tx.commit()?; + Ok(report) +} + +/// Capture metadata a peer's sweep already read, for images this device has +/// not dated yet. +/// +/// The `images` table is local state and the merge leaves it alone — except +/// for these columns, which are not: a capture time, an offset, a camera, a +/// lens and an ISO are facts about the file's bytes, identical on every +/// device, and read by fetching a header per image across the whole library +/// (`dr_ui::library::spawn_sweep`). A fresh device inherits its peers' +/// thumbnails and faces from the shards and then spent hours re-reading +/// every header for the timeline; the snapshot it had just merged held +/// every one of those dates. +/// +/// Matched by `oc:fileid`, as collection membership is. Only rows still at +/// `metadata_state < 2` take anything, and only from a remote row at 2: a +/// date this device read for itself is never overwritten, and a peer that +/// has not read one has nothing to give. The sweep's own query +/// (`metadata_state < 2`) then finds nothing left to do for them. +const METADATA_BY_FILE_ID: &str = " + UPDATE main.images + SET captured_at = r.captured_at, + captured_offset = coalesce(main.images.captured_offset, r.captured_offset), + camera = coalesce(main.images.camera, r.camera), + lens = coalesce(main.images.lens, r.lens), + iso = coalesce(main.images.iso, r.iso), + metadata_state = 2 + FROM (SELECT lr.image_id, ri.captured_at, ri.captured_offset, + ri.camera, ri.lens, ri.iso + FROM remote_cat.images ri + JOIN remote_cat.remote rr ON rr.image_id = ri.id + JOIN main.remote lr ON lr.file_id = rr.file_id + WHERE ri.metadata_state >= 2 AND ri.captured_at IS NOT NULL) AS r + WHERE main.images.id = r.image_id + AND main.images.metadata_state < 2"; + +fn merge_metadata_within(tx: &Connection, report: &mut MergeReport) -> Result<(), CatalogError> { + // A snapshot from before these columns, or from a library with no server + // behind it, has nothing to join on. + if !remote_has(tx, "remote")? + || !remote_has_column(tx, "images", "metadata_state")? + || !remote_has_column(tx, "images", "captured_offset")? + { + return Ok(()); + } + report.metadata_adopted = tx.execute(METADATA_BY_FILE_ID, [])?; + Ok(()) +} + /// Merge people and identity judgements from an attached catalog. /// /// The people half of [`merge_all`], on its own, for the same reason the other @@ -1168,6 +1228,57 @@ mod tests { // ---- integration over two real catalogs ------------------------------ + /// A fresh device takes the capture dates a peer's sweep read, matched by + /// `oc:fileid`, and never overwrites a date it read for itself. + #[test] + fn capture_metadata_arrives_for_undated_images_only() { + let c = two_catalogs(); + // Three photographs on both devices: 1 undated here and dated there; + // 2 dated on both, differently; 3 undated on both. + for id in 1..=3 { + add_image_without_hash(&c, "main", id); + add_image_without_hash(&c, "remote_cat", id + 10); + add_remote_id(&c, "main", id, 100 + id); + add_remote_id(&c, "remote_cat", id + 10, 100 + id); + } + c.execute( + "UPDATE remote_cat.images + SET captured_at = 1000, captured_offset = 60, camera = 'X', metadata_state = 2 + WHERE id = 11", + [], + ) + .unwrap(); + c.execute( + "UPDATE remote_cat.images SET captured_at = 2000, metadata_state = 2 WHERE id = 12", + [], + ) + .unwrap(); + c.execute( + "UPDATE main.images SET captured_at = 2222, metadata_state = 2 WHERE id = 2", + [], + ) + .unwrap(); + + let report = merge_metadata(&c).unwrap(); + assert_eq!(report.metadata_adopted, 1); + + let row = |id: i64| -> (Option, Option, Option, i64) { + c.query_row( + "SELECT captured_at, captured_offset, camera, metadata_state + FROM main.images WHERE id = ?1", + [id], + |r| Ok((r.get(0)?, r.get(1)?, r.get(2)?, r.get(3)?)), + ) + .unwrap() + }; + assert_eq!(row(1), (Some(1000), Some(60), Some("X".into()), 2)); + assert_eq!(row(2), (Some(2222), None, None, 2)); + assert_eq!(row(3), (None, None, None, 0)); + + // Idempotent: a second pass finds nothing left to take. + assert_eq!(merge_metadata(&c).unwrap().metadata_adopted, 0); + } + fn two_catalogs() -> Connection { attached_remote(schema::for_attached("remote_cat")) } diff --git a/docker/windows/package.sh b/docker/windows/package.sh index 1ccf833..ebe3766 100755 --- a/docker/windows/package.sh +++ b/docker/windows/package.sh @@ -48,7 +48,13 @@ sed 's/$/\r/' "${REPO}/LICENSE" > "${STAGE}/LICENSE" # tract on the user's machine with a message about a broken graph rather than # a checkout that needed `git lfs pull`. Only the weights are checked; the # scene model's vocabulary and category descriptor are legitimately small. -for dir in face scene; do +# +# The directories are the ones the APK stages (assemble-apk.sh) and the Arch +# package installs: the face pair and its eye-state models, the scene model +# with its two descriptors, and the panorama border filler. The installer +# smoke test counts the same directories, so a model added here is expected +# there without a number to update. +for dir in face scene inpaint; do for f in "${REPO}/models/${dir}"/*; do case "$(basename "${f}")" in README.md) continue ;; diff --git a/docs/dev/catalog.md b/docs/dev/catalog.md index 857ee1f..f999785 100644 --- a/docs/dev/catalog.md +++ b/docs/dev/catalog.md @@ -530,6 +530,15 @@ Three invariants, each tested: | Re-storing an existing id updates in place, never migrates | Migrating would rewrite a sealed shard | | Merging another client's shard is insert-only and idempotent | Both copies derive from the same bytes by the same code, so neither is better; preferring ours avoids dirtying a shard others have synced | +**When the exchange runs.** Corrected 2026-09-20. It fired only after the metadata sweep — hours +on a large library — so a fresh device re-derived every thumbnail it looked at, re-detected faces +and re-read every header before adopting the shards and snapshot that held all of it. It now also +fires the moment the scan completes, which is the first moment the rows the merges key on exist, +and the sweep starts behind it. In steady state that pass is one listing. The catalog merge also +takes **capture metadata** (`captured_at`, offset, camera, lens, ISO) for images still at +`metadata_state < 2`, matched by `oc:fileid` — a date is a fact about the file's bytes, not local +state, and the snapshot already carried it; the sweep's per-chunk query then finds nothing left. + **The transfer**, in `dr-ui`'s `derived_sync`, exchanges shards with `.darkroom-derived/` under the library root. `ThumbStore::shards()` reports which are sealed, so an up-to-date client's whole pass is one listing plus whichever shard is still open. diff --git a/docs/dev/requirements.md b/docs/dev/requirements.md index ce1fac3..116af20 100644 --- a/docs/dev/requirements.md +++ b/docs/dev/requirements.md @@ -1814,6 +1814,28 @@ tool for a hand-held set, and a photograph with real parallax is not a panorama. in one operation until HDR merge exists on its own. No live re-stitch: a different projection or crop after the fact is a new file, not an edit. No video. +### 3.12 Inference runtime + +The face, segmentation and border-fill models run under an inference engine the application +selects per device. [inference.md](inference.md) is the design: its §3 sets the dependency policy +the runtime may reopen, its §10 the milestones (M1–M7) the clauses below cite as acceptance. The +clauses are the register entries inference.md §12 promised; they are stated here so the +traceability gate can count them. + +**FR-INF-1 — Runtime selection.** On launch the application shall determine, per device and +without blocking the first frame, the fastest inference backend that can build and run a session +for the shipped models, by attempting it; shall record and reuse that determination until the +runtime, driver, hardware or models change; and shall display the backend in use in Settings and +on the about screen. *Acceptance:* inference.md §10 M1 and M5. + +**FR-INF-2 — Derived engines.** Backends that require device-specific compilation shall compile in +the background after selection, shall serve requests from the next lower backend until each engine +is ready, and shall not change the backend of a job in progress. *Acceptance:* M5. + +**FR-INF-3 — Model forms.** Quantised model forms are produced at release time from real +calibration data and are shipped only when they meet inference.md §10's accuracy gates against the +canonical form; the application never quantises on the device. *Acceptance:* M2, M7. + --- ## 4. Non-functional requirements @@ -2111,6 +2133,13 @@ it is far cheaper to discover now than after the UI is built. clipping indicators (FR-DSP-7), and the HSL mixer carry a shape or text affordance. This matters more in a colour-grading application than in most software. +### 4.10 Inference + +**NFR-INF-1 — Embedding comparability.** Face embeddings shall be computed at a precision whose +deviation from the f32 reference is within [inference.md](inference.md) §7's gate, on every +backend, so that embeddings from any device are comparable — FR-CULL-9's calibration depends on +it. *Acceptance:* inference.md §10 M3. + --- ## 5. Data model and architecture diff --git a/docs/dev/traceability.md b/docs/dev/traceability.md index dad7d14..f4490e8 100644 --- a/docs/dev/traceability.md +++ b/docs/dev/traceability.md @@ -11,24 +11,24 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n |---|---| | Source files scanned | 434 | | TRACES tags found | 1573 | -| Requirements defined | 184 | +| Requirements defined | 188 | | Requirements deferred (post-v1) | 24 | -| Requirements covered | 154 | -| **Coverage** | **83.7%** (154/184) | +| Requirements covered | 155 | +| **Coverage** | **82.4%** (155/188) | ### By type | Type | Covered | Defined | |---|---|---| -| FR | 116 | 127 | -| NFR | 34 | 50 | +| FR | 117 | 130 | +| NFR | 34 | 51 | | R | 4 | 7 | ## Orphan tags A tag naming an ID `requirements.md` does not define — what renumbering produces, and what a typo produces. -- `FR-INF-1` +_None._ ## Tagged requirements @@ -42,13 +42,13 @@ A tag naming an ID `requirements.md` does not define — what renumbering produc | FR-CAT-15 | [`core/dr-catalog/src/schema.rs:1210`](../../core/dr-catalog/src/schema.rs#L1210), [`core/dr-catalog/src/trash.rs:1`](../../core/dr-catalog/src/trash.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:522`](../../core/dr-sync-nextcloud/src/lib.rs#L522), [`core/dr-sync/src/lib.rs:135`](../../core/dr-sync/src/lib.rs#L135), [`core/dr-sync/src/scan.rs:618`](../../core/dr-sync/src/scan.rs#L618), [`core/dr-sync/src/scan.rs:93`](../../core/dr-sync/src/scan.rs#L93), [`core/dr-thumbs/src/lib.rs:393`](../../core/dr-thumbs/src/lib.rs#L393), [`core/dr-types/src/place.rs:91`](../../core/dr-types/src/place.rs#L91), [`ui/dr-ui/src/collections_ui/trash.rs:84`](../../ui/dr-ui/src/collections_ui/trash.rs#L84), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:819`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L819), [`ui/dr-ui/src/library/cells.rs:158`](../../ui/dr-ui/src/library/cells.rs#L158), [`ui/dr-ui/src/library/cells.rs:192`](../../ui/dr-ui/src/library/cells.rs#L192), [`ui/dr-ui/src/library/filters.rs:12`](../../ui/dr-ui/src/library/filters.rs#L12), [`ui/dr-ui/src/library/filters.rs:29`](../../ui/dr-ui/src/library/filters.rs#L29), [`ui/dr-ui/src/library/filters.rs:59`](../../ui/dr-ui/src/library/filters.rs#L59), [`ui/dr-ui/src/library_ui/controller.rs:232`](../../ui/dr-ui/src/library_ui/controller.rs#L232), [`ui/dr-ui/src/library_ui/controller.rs:909`](../../ui/dr-ui/src/library_ui/controller.rs#L909), [`ui/dr-ui/src/trash.rs:1`](../../ui/dr-ui/src/trash.rs#L1), [`ui/dr-ui/ui/collections.slint:1182`](../../ui/dr-ui/ui/collections.slint#L1182), [`ui/dr-ui/ui/collections.slint:745`](../../ui/dr-ui/ui/collections.slint#L745) | | FR-CAT-1a | [`core/dr-catalog/src/walk.rs:1`](../../core/dr-catalog/src/walk.rs#L1), [`core/dr-types/src/lib.rs:56`](../../core/dr-types/src/lib.rs#L56), [`platform/dr-plat/src/storage.rs:1`](../../platform/dr-plat/src/storage.rs#L1), [`platform/dr-plat/src/storage.rs:216`](../../platform/dr-plat/src/storage.rs#L216), [`platform/dr-plat/src/storage.rs:46`](../../platform/dr-plat/src/storage.rs#L46) | | FR-CAT-2 | [`core/dr-catalog/src/lib.rs:1`](../../core/dr-catalog/src/lib.rs#L1), [`core/dr-catalog/src/schema.rs:1`](../../core/dr-catalog/src/schema.rs#L1) | -| FR-CAT-3 | [`core/dr-catalog/src/jobs.rs:1`](../../core/dr-catalog/src/jobs.rs#L1), [`core/dr-catalog/src/walk.rs:66`](../../core/dr-catalog/src/walk.rs#L66), [`core/dr-sync/src/scan.rs:105`](../../core/dr-sync/src/scan.rs#L105), [`core/dr-thumbs/src/codec.rs:1`](../../core/dr-thumbs/src/codec.rs#L1), [`core/dr-thumbs/src/lib.rs:1`](../../core/dr-thumbs/src/lib.rs#L1), [`ui/dr-ui/src/derived_sync.rs:1`](../../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/import.rs:463`](../../ui/dr-ui/src/import.rs#L463), [`ui/dr-ui/src/import.rs:488`](../../ui/dr-ui/src/import.rs#L488), [`ui/dr-ui/src/library/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/controller.rs:171`](../../ui/dr-ui/src/library_ui/controller.rs#L171), [`ui/dr-ui/src/library_ui/grid.rs:458`](../../ui/dr-ui/src/library_ui/grid.rs#L458), [`ui/dr-ui/src/library_ui/sync.rs:368`](../../ui/dr-ui/src/library_ui/sync.rs#L368), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1), [`ui/dr-ui/src/repairs.rs:687`](../../ui/dr-ui/src/repairs.rs#L687), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482), [`ui/dr-ui/ui/library.slint:730`](../../ui/dr-ui/ui/library.slint#L730), [`ui/dr-ui/ui/settings.slint:435`](../../ui/dr-ui/ui/settings.slint#L435), [`ui/dr-ui/ui/settings.slint:73`](../../ui/dr-ui/ui/settings.slint#L73) | +| FR-CAT-3 | [`core/dr-catalog/src/jobs.rs:1`](../../core/dr-catalog/src/jobs.rs#L1), [`core/dr-catalog/src/walk.rs:66`](../../core/dr-catalog/src/walk.rs#L66), [`core/dr-sync/src/scan.rs:105`](../../core/dr-sync/src/scan.rs#L105), [`core/dr-thumbs/src/codec.rs:1`](../../core/dr-thumbs/src/codec.rs#L1), [`core/dr-thumbs/src/lib.rs:1`](../../core/dr-thumbs/src/lib.rs#L1), [`ui/dr-ui/src/derived_sync.rs:1`](../../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/import.rs:463`](../../ui/dr-ui/src/import.rs#L463), [`ui/dr-ui/src/import.rs:488`](../../ui/dr-ui/src/import.rs#L488), [`ui/dr-ui/src/library/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/controller.rs:171`](../../ui/dr-ui/src/library_ui/controller.rs#L171), [`ui/dr-ui/src/library_ui/grid.rs:458`](../../ui/dr-ui/src/library_ui/grid.rs#L458), [`ui/dr-ui/src/library_ui/sync.rs:385`](../../ui/dr-ui/src/library_ui/sync.rs#L385), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1), [`ui/dr-ui/src/repairs.rs:687`](../../ui/dr-ui/src/repairs.rs#L687), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482), [`ui/dr-ui/ui/library.slint:730`](../../ui/dr-ui/ui/library.slint#L730), [`ui/dr-ui/ui/settings.slint:435`](../../ui/dr-ui/ui/settings.slint#L435), [`ui/dr-ui/ui/settings.slint:73`](../../ui/dr-ui/ui/settings.slint#L73) | | FR-CAT-4 | [`core/dr-catalog/src/lib.rs:1`](../../core/dr-catalog/src/lib.rs#L1), [`core/dr-catalog/src/query.rs:1`](../../core/dr-catalog/src/query.rs#L1), [`core/dr-catalog/src/schema.rs:564`](../../core/dr-catalog/src/schema.rs#L564), [`ui/dr-ui/src/library/filters.rs:39`](../../ui/dr-ui/src/library/filters.rs#L39), [`ui/dr-ui/src/library/mod.rs:1`](../../ui/dr-ui/src/library/mod.rs#L1), [`ui/dr-ui/src/library_ui/mod.rs:1`](../../ui/dr-ui/src/library_ui/mod.rs#L1), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482) | | FR-CAT-5 | [`core/dr-catalog/src/keywords.rs:1`](../../core/dr-catalog/src/keywords.rs#L1), [`core/dr-catalog/src/merge.rs:1`](../../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/rating.rs:1`](../../core/dr-catalog/src/rating.rs#L1), [`core/dr-catalog/src/schema.rs:1125`](../../core/dr-catalog/src/schema.rs#L1125), [`core/dr-catalog/src/schema.rs:1682`](../../core/dr-catalog/src/schema.rs#L1682), [`core/dr-decode/src/lib.rs:301`](../../core/dr-decode/src/lib.rs#L301), [`core/dr-decode/src/lib.rs:307`](../../core/dr-decode/src/lib.rs#L307), [`core/dr-decode/src/lib.rs:317`](../../core/dr-decode/src/lib.rs#L317), [`core/dr-decode/src/lib.rs:444`](../../core/dr-decode/src/lib.rs#L444), [`core/dr-export/src/dng.rs:308`](../../core/dr-export/src/dng.rs#L308), [`core/dr-pipeline/src/sidecar.rs:171`](../../core/dr-pipeline/src/sidecar.rs#L171), [`ui/dr-ui/src/collections_ui/controller.rs:16`](../../ui/dr-ui/src/collections_ui/controller.rs#L16), [`ui/dr-ui/src/collections_ui/controller.rs:204`](../../ui/dr-ui/src/collections_ui/controller.rs#L204), [`ui/dr-ui/src/collections_ui/controller.rs:413`](../../ui/dr-ui/src/collections_ui/controller.rs#L413), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:150`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L150), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:264`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L264), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:323`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L323), [`ui/dr-ui/src/library/cells.rs:206`](../../ui/dr-ui/src/library/cells.rs#L206), [`ui/dr-ui/src/library_ui/controller.rs:784`](../../ui/dr-ui/src/library_ui/controller.rs#L784), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:1012`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L1012), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:1023`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L1023), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:1036`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L1036), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:1051`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L1051), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:1060`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L1060), [`ui/dr-ui/ui/library.slint:1630`](../../ui/dr-ui/ui/library.slint#L1630), [`ui/dr-ui/ui/library.slint:1654`](../../ui/dr-ui/ui/library.slint#L1654), [`ui/dr-ui/ui/library.slint:1707`](../../ui/dr-ui/ui/library.slint#L1707), [`ui/dr-ui/ui/library.slint:19`](../../ui/dr-ui/ui/library.slint#L19), [`ui/dr-ui/ui/library.slint:4523`](../../ui/dr-ui/ui/library.slint#L4523), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482), [`ui/dr-ui/ui/library.slint:504`](../../ui/dr-ui/ui/library.slint#L504), [`ui/dr-ui/ui/library.slint:603`](../../ui/dr-ui/ui/library.slint#L603) | | FR-CAT-6 | [`core/dr-catalog/src/collections.rs:1`](../../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/keywords.rs:1`](../../core/dr-catalog/src/keywords.rs#L1), [`core/dr-catalog/src/lib.rs:1`](../../core/dr-catalog/src/lib.rs#L1), [`core/dr-catalog/src/query.rs:1`](../../core/dr-catalog/src/query.rs#L1), [`core/dr-catalog/src/rating.rs:1`](../../core/dr-catalog/src/rating.rs#L1), [`core/dr-catalog/src/schema.rs:1125`](../../core/dr-catalog/src/schema.rs#L1125), [`core/dr-types/src/place.rs:1`](../../core/dr-types/src/place.rs#L1), [`core/dr-types/src/selector.rs:1`](../../core/dr-types/src/selector.rs#L1), [`core/dr-types/src/settings.rs:64`](../../core/dr-types/src/settings.rs#L64), [`core/dr-types/src/time.rs:67`](../../core/dr-types/src/time.rs#L67), [`core/dr-types/src/time.rs:90`](../../core/dr-types/src/time.rs#L90), [`ui/dr-ui/src/library/filters.rs:64`](../../ui/dr-ui/src/library/filters.rs#L64), [`ui/dr-ui/src/library/spans.rs:253`](../../ui/dr-ui/src/library/spans.rs#L253), [`ui/dr-ui/src/library_ui/controller.rs:391`](../../ui/dr-ui/src/library_ui/controller.rs#L391), [`ui/dr-ui/src/library_ui/controller.rs:500`](../../ui/dr-ui/src/library_ui/controller.rs#L500), [`ui/dr-ui/src/library_ui/filter_bar.rs:295`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L295), [`ui/dr-ui/src/library_ui/filter_bar.rs:350`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L350), [`ui/dr-ui/src/library_ui/filter_bar.rs:718`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L718), [`ui/dr-ui/ui/app.slint:595`](../../ui/dr-ui/ui/app.slint#L595), [`ui/dr-ui/ui/library.slint:111`](../../ui/dr-ui/ui/library.slint#L111), [`ui/dr-ui/ui/library.slint:1822`](../../ui/dr-ui/ui/library.slint#L1822), [`ui/dr-ui/ui/library.slint:4523`](../../ui/dr-ui/ui/library.slint#L4523), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482), [`ui/dr-ui/ui/library.slint:603`](../../ui/dr-ui/ui/library.slint#L603), [`ui/dr-ui/ui/library.slint:652`](../../ui/dr-ui/ui/library.slint#L652), [`ui/dr-ui/ui/settings.slint:191`](../../ui/dr-ui/ui/settings.slint#L191) | -| FR-CAT-7 | [`core/dr-catalog/src/collections.rs:1`](../../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/merge.rs:1`](../../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/sync.rs:1`](../../core/dr-catalog/src/sync.rs#L1), [`core/dr-types/src/selector.rs:1`](../../core/dr-types/src/selector.rs#L1), [`ui/dr-ui/src/collections_ui/controller.rs:258`](../../ui/dr-ui/src/collections_ui/controller.rs#L258), [`ui/dr-ui/src/collections_ui/controller.rs:268`](../../ui/dr-ui/src/collections_ui/controller.rs#L268), [`ui/dr-ui/src/collections_ui/controller.rs:291`](../../ui/dr-ui/src/collections_ui/controller.rs#L291), [`ui/dr-ui/src/collections_ui/controller.rs:312`](../../ui/dr-ui/src/collections_ui/controller.rs#L312), [`ui/dr-ui/src/collections_ui/controller.rs:46`](../../ui/dr-ui/src/collections_ui/controller.rs#L46), [`ui/dr-ui/src/collections_ui/drag.rs:274`](../../ui/dr-ui/src/collections_ui/drag.rs#L274), [`ui/dr-ui/src/collections_ui/mod.rs:1`](../../ui/dr-ui/src/collections_ui/mod.rs#L1), [`ui/dr-ui/src/collections_ui/press.rs:258`](../../ui/dr-ui/src/collections_ui/press.rs#L258), [`ui/dr-ui/src/collections_ui/press.rs:490`](../../ui/dr-ui/src/collections_ui/press.rs#L490), [`ui/dr-ui/src/collections_ui/press.rs:54`](../../ui/dr-ui/src/collections_ui/press.rs#L54), [`ui/dr-ui/src/collections_ui/rename_menu.rs:196`](../../ui/dr-ui/src/collections_ui/rename_menu.rs#L196), [`ui/dr-ui/src/collections_ui/rename_menu.rs:21`](../../ui/dr-ui/src/collections_ui/rename_menu.rs#L21), [`ui/dr-ui/src/collections_ui/tree_sync.rs:246`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L246), [`ui/dr-ui/src/collections_ui/tree_sync.rs:317`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L317), [`ui/dr-ui/src/collections_ui/tree_sync.rs:339`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L339), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:121`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L121), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:171`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L171), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:444`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L444), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:522`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L522), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:586`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L586), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:287`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L287), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:344`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L344), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:394`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L394), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:517`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L517), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:581`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L581), [`ui/dr-ui/src/derived_sync.rs:1`](../../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/library/spans.rs:139`](../../ui/dr-ui/src/library/spans.rs#L139), [`ui/dr-ui/src/library/spans.rs:58`](../../ui/dr-ui/src/library/spans.rs#L58), [`ui/dr-ui/src/library/spans.rs:84`](../../ui/dr-ui/src/library/spans.rs#L84), [`ui/dr-ui/src/library_ui/sync.rs:218`](../../ui/dr-ui/src/library_ui/sync.rs#L218), [`ui/dr-ui/src/library_ui/timeline.rs:513`](../../ui/dr-ui/src/library_ui/timeline.rs#L513), [`ui/dr-ui/src/library_ui/window.rs:273`](../../ui/dr-ui/src/library_ui/window.rs#L273), [`ui/dr-ui/ui/app.slint:2904`](../../ui/dr-ui/ui/app.slint#L2904), [`ui/dr-ui/ui/collections.slint:1182`](../../ui/dr-ui/ui/collections.slint#L1182), [`ui/dr-ui/ui/collections.slint:4`](../../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/collections.slint:587`](../../ui/dr-ui/ui/collections.slint#L587), [`ui/dr-ui/ui/library.slint:1268`](../../ui/dr-ui/ui/library.slint#L1268), [`ui/dr-ui/ui/library.slint:1597`](../../ui/dr-ui/ui/library.slint#L1597), [`ui/dr-ui/ui/library.slint:3219`](../../ui/dr-ui/ui/library.slint#L3219), [`ui/dr-ui/ui/library.slint:4501`](../../ui/dr-ui/ui/library.slint#L4501), [`ui/dr-ui/ui/library.slint:4588`](../../ui/dr-ui/ui/library.slint#L4588), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482), [`ui/dr-ui/ui/library.slint:507`](../../ui/dr-ui/ui/library.slint#L507), [`ui/dr-ui/ui/library.slint:549`](../../ui/dr-ui/ui/library.slint#L549), [`ui/dr-ui/ui/library.slint:559`](../../ui/dr-ui/ui/library.slint#L559) | +| FR-CAT-7 | [`core/dr-catalog/src/collections.rs:1`](../../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/merge.rs:1`](../../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/sync.rs:1`](../../core/dr-catalog/src/sync.rs#L1), [`core/dr-types/src/selector.rs:1`](../../core/dr-types/src/selector.rs#L1), [`ui/dr-ui/src/collections_ui/controller.rs:258`](../../ui/dr-ui/src/collections_ui/controller.rs#L258), [`ui/dr-ui/src/collections_ui/controller.rs:268`](../../ui/dr-ui/src/collections_ui/controller.rs#L268), [`ui/dr-ui/src/collections_ui/controller.rs:291`](../../ui/dr-ui/src/collections_ui/controller.rs#L291), [`ui/dr-ui/src/collections_ui/controller.rs:312`](../../ui/dr-ui/src/collections_ui/controller.rs#L312), [`ui/dr-ui/src/collections_ui/controller.rs:46`](../../ui/dr-ui/src/collections_ui/controller.rs#L46), [`ui/dr-ui/src/collections_ui/drag.rs:274`](../../ui/dr-ui/src/collections_ui/drag.rs#L274), [`ui/dr-ui/src/collections_ui/mod.rs:1`](../../ui/dr-ui/src/collections_ui/mod.rs#L1), [`ui/dr-ui/src/collections_ui/press.rs:258`](../../ui/dr-ui/src/collections_ui/press.rs#L258), [`ui/dr-ui/src/collections_ui/press.rs:490`](../../ui/dr-ui/src/collections_ui/press.rs#L490), [`ui/dr-ui/src/collections_ui/press.rs:54`](../../ui/dr-ui/src/collections_ui/press.rs#L54), [`ui/dr-ui/src/collections_ui/rename_menu.rs:196`](../../ui/dr-ui/src/collections_ui/rename_menu.rs#L196), [`ui/dr-ui/src/collections_ui/rename_menu.rs:21`](../../ui/dr-ui/src/collections_ui/rename_menu.rs#L21), [`ui/dr-ui/src/collections_ui/tree_sync.rs:246`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L246), [`ui/dr-ui/src/collections_ui/tree_sync.rs:317`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L317), [`ui/dr-ui/src/collections_ui/tree_sync.rs:339`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L339), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:121`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L121), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:171`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L171), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:444`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L444), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:522`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L522), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:586`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L586), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:287`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L287), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:344`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L344), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:394`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L394), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:517`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L517), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:581`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L581), [`ui/dr-ui/src/derived_sync.rs:1`](../../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/library/spans.rs:139`](../../ui/dr-ui/src/library/spans.rs#L139), [`ui/dr-ui/src/library/spans.rs:58`](../../ui/dr-ui/src/library/spans.rs#L58), [`ui/dr-ui/src/library/spans.rs:84`](../../ui/dr-ui/src/library/spans.rs#L84), [`ui/dr-ui/src/library_ui/sync.rs:235`](../../ui/dr-ui/src/library_ui/sync.rs#L235), [`ui/dr-ui/src/library_ui/timeline.rs:513`](../../ui/dr-ui/src/library_ui/timeline.rs#L513), [`ui/dr-ui/src/library_ui/window.rs:273`](../../ui/dr-ui/src/library_ui/window.rs#L273), [`ui/dr-ui/ui/app.slint:2904`](../../ui/dr-ui/ui/app.slint#L2904), [`ui/dr-ui/ui/collections.slint:1182`](../../ui/dr-ui/ui/collections.slint#L1182), [`ui/dr-ui/ui/collections.slint:4`](../../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/collections.slint:587`](../../ui/dr-ui/ui/collections.slint#L587), [`ui/dr-ui/ui/library.slint:1268`](../../ui/dr-ui/ui/library.slint#L1268), [`ui/dr-ui/ui/library.slint:1597`](../../ui/dr-ui/ui/library.slint#L1597), [`ui/dr-ui/ui/library.slint:3219`](../../ui/dr-ui/ui/library.slint#L3219), [`ui/dr-ui/ui/library.slint:4501`](../../ui/dr-ui/ui/library.slint#L4501), [`ui/dr-ui/ui/library.slint:4588`](../../ui/dr-ui/ui/library.slint#L4588), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482), [`ui/dr-ui/ui/library.slint:507`](../../ui/dr-ui/ui/library.slint#L507), [`ui/dr-ui/ui/library.slint:549`](../../ui/dr-ui/ui/library.slint#L549), [`ui/dr-ui/ui/library.slint:559`](../../ui/dr-ui/ui/library.slint#L559) | | FR-CAT-8 | [`core/dr-catalog/src/schema.rs:740`](../../core/dr-catalog/src/schema.rs#L740), [`core/dr-pipeline/src/coverage.rs:1`](../../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/graph.rs:587`](../../core/dr-pipeline/src/graph.rs#L587), [`core/dr-pipeline/src/graph.rs:640`](../../core/dr-pipeline/src/graph.rs#L640), [`core/dr-pipeline/src/ops/curve.rs:137`](../../core/dr-pipeline/src/ops/curve.rs#L137), [`core/dr-pipeline/src/ops/curve.rs:656`](../../core/dr-pipeline/src/ops/curve.rs#L656), [`core/dr-pipeline/src/sidecar.rs:1400`](../../core/dr-pipeline/src/sidecar.rs#L1400), [`core/dr-pipeline/src/sidecar.rs:2232`](../../core/dr-pipeline/src/sidecar.rs#L2232), [`core/dr-pipeline/src/sidecar.rs:96`](../../core/dr-pipeline/src/sidecar.rs#L96), [`core/dr-pipeline/src/state.rs:1`](../../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../../core/dr-pipeline/src/state.rs#L75), [`core/dr-pipeline/tests/tone_curve.rs:34`](../../core/dr-pipeline/tests/tone_curve.rs#L34), [`core/dr-sync/src/scan.rs:31`](../../core/dr-sync/src/scan.rs#L31), [`core/dr-sync/src/scan.rs:56`](../../core/dr-sync/src/scan.rs#L56), [`core/dr-sync/src/scan.rs:926`](../../core/dr-sync/src/scan.rs#L926), [`ui/dr-ui/src/develop/mask_ops.rs:1076`](../../ui/dr-ui/src/develop/mask_ops.rs#L1076), [`ui/dr-ui/src/develop/mask_ops.rs:1130`](../../ui/dr-ui/src/develop/mask_ops.rs#L1130), [`ui/dr-ui/src/develop/mask_ops.rs:178`](../../ui/dr-ui/src/develop/mask_ops.rs#L178), [`ui/dr-ui/src/develop/masks.rs:740`](../../ui/dr-ui/src/develop/masks.rs#L740), [`ui/dr-ui/src/develop/session.rs:561`](../../ui/dr-ui/src/develop/session.rs#L561), [`ui/dr-ui/src/develop/session.rs:590`](../../ui/dr-ui/src/develop/session.rs#L590), [`ui/dr-ui/src/export.rs:813`](../../ui/dr-ui/src/export.rs#L813), [`ui/dr-ui/src/lib.rs:1184`](../../ui/dr-ui/src/lib.rs#L1184), [`ui/dr-ui/src/lib.rs:1244`](../../ui/dr-ui/src/lib.rs#L1244), [`ui/dr-ui/src/lib.rs:2692`](../../ui/dr-ui/src/lib.rs#L2692), [`ui/dr-ui/src/lib.rs:2839`](../../ui/dr-ui/src/lib.rs#L2839), [`ui/dr-ui/src/lib.rs:759`](../../ui/dr-ui/src/lib.rs#L759), [`ui/dr-ui/src/library/scan.rs:226`](../../ui/dr-ui/src/library/scan.rs#L226), [`ui/dr-ui/src/library/scan.rs:261`](../../ui/dr-ui/src/library/scan.rs#L261), [`ui/dr-ui/src/library/scan.rs:34`](../../ui/dr-ui/src/library/scan.rs#L34), [`ui/dr-ui/src/library/sidecar.rs:100`](../../ui/dr-ui/src/library/sidecar.rs#L100), [`ui/dr-ui/src/library/sidecar.rs:11`](../../ui/dr-ui/src/library/sidecar.rs#L11), [`ui/dr-ui/src/library/sidecar.rs:373`](../../ui/dr-ui/src/library/sidecar.rs#L373), [`ui/dr-ui/src/library/sidecar.rs:63`](../../ui/dr-ui/src/library/sidecar.rs#L63), [`ui/dr-ui/src/library/thumbnails_fetch.rs:413`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L413), [`ui/dr-ui/src/library_ui/grid.rs:692`](../../ui/dr-ui/src/library_ui/grid.rs#L692), [`ui/dr-ui/src/library_ui/open.rs:455`](../../ui/dr-ui/src/library_ui/open.rs#L455), [`ui/dr-ui/src/sidecar_cache.rs:1`](../../ui/dr-ui/src/sidecar_cache.rs#L1) | -| FR-CAT-9 | [`core/dr-catalog/src/cache.rs:1`](../../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/scan.rs:1`](../../core/dr-catalog/src/scan.rs#L1), [`core/dr-catalog/src/schema.rs:1182`](../../core/dr-catalog/src/schema.rs#L1182), [`core/dr-catalog/src/walk.rs:1022`](../../core/dr-catalog/src/walk.rs#L1022), [`core/dr-catalog/src/walk.rs:162`](../../core/dr-catalog/src/walk.rs#L162), [`core/dr-catalog/src/walk.rs:1`](../../core/dr-catalog/src/walk.rs#L1), [`core/dr-catalog/src/walk.rs:435`](../../core/dr-catalog/src/walk.rs#L435), [`core/dr-catalog/src/walk.rs:728`](../../core/dr-catalog/src/walk.rs#L728), [`core/dr-sync-nextcloud/src/desktop_client.rs:35`](../../core/dr-sync-nextcloud/src/desktop_client.rs#L35), [`core/dr-sync/src/error.rs:113`](../../core/dr-sync/src/error.rs#L113), [`core/dr-sync/src/reachability.rs:1`](../../core/dr-sync/src/reachability.rs#L1), [`core/dr-sync/src/scan.rs:211`](../../core/dr-sync/src/scan.rs#L211), [`core/dr-sync/src/scan.rs:519`](../../core/dr-sync/src/scan.rs#L519), [`core/dr-types/src/lib.rs:122`](../../core/dr-types/src/lib.rs#L122), [`ui/dr-ui/src/develop/render.rs:584`](../../ui/dr-ui/src/develop/render.rs#L584), [`ui/dr-ui/src/develop/render.rs:627`](../../ui/dr-ui/src/develop/render.rs#L627), [`ui/dr-ui/src/library/filters.rs:84`](../../ui/dr-ui/src/library/filters.rs#L84), [`ui/dr-ui/src/library/scan.rs:126`](../../ui/dr-ui/src/library/scan.rs#L126), [`ui/dr-ui/src/library/scan.rs:179`](../../ui/dr-ui/src/library/scan.rs#L179), [`ui/dr-ui/src/library/scan.rs:210`](../../ui/dr-ui/src/library/scan.rs#L210), [`ui/dr-ui/src/library/scan.rs:261`](../../ui/dr-ui/src/library/scan.rs#L261), [`ui/dr-ui/src/library/scan.rs:605`](../../ui/dr-ui/src/library/scan.rs#L605), [`ui/dr-ui/src/library/sidecar.rs:100`](../../ui/dr-ui/src/library/sidecar.rs#L100), [`ui/dr-ui/src/library/sidecar.rs:357`](../../ui/dr-ui/src/library/sidecar.rs#L357), [`ui/dr-ui/src/library/sidecar.rs:373`](../../ui/dr-ui/src/library/sidecar.rs#L373), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/spans.rs:361`](../../ui/dr-ui/src/library/spans.rs#L361), [`ui/dr-ui/src/library/thumbnails_fetch.rs:393`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L393), [`ui/dr-ui/src/library/thumbnails_fetch.rs:449`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L449), [`ui/dr-ui/src/library/thumbnails_gen.rs:74`](../../ui/dr-ui/src/library/thumbnails_gen.rs#L74), [`ui/dr-ui/src/library_ui/controller.rs:279`](../../ui/dr-ui/src/library_ui/controller.rs#L279), [`ui/dr-ui/src/library_ui/controller.rs:315`](../../ui/dr-ui/src/library_ui/controller.rs#L315), [`ui/dr-ui/src/library_ui/controller.rs:323`](../../ui/dr-ui/src/library_ui/controller.rs#L323), [`ui/dr-ui/src/library_ui/controller.rs:568`](../../ui/dr-ui/src/library_ui/controller.rs#L568), [`ui/dr-ui/src/library_ui/controller.rs:657`](../../ui/dr-ui/src/library_ui/controller.rs#L657), [`ui/dr-ui/src/library_ui/filter_bar.rs:405`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L405), [`ui/dr-ui/src/library_ui/filter_bar.rs:491`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L491), [`ui/dr-ui/src/library_ui/offline.rs:561`](../../ui/dr-ui/src/library_ui/offline.rs#L561), [`ui/dr-ui/src/library_ui/offline.rs:607`](../../ui/dr-ui/src/library_ui/offline.rs#L607), [`ui/dr-ui/src/library_ui/offline.rs:623`](../../ui/dr-ui/src/library_ui/offline.rs#L623), [`ui/dr-ui/src/library_ui/open.rs:524`](../../ui/dr-ui/src/library_ui/open.rs#L524), [`ui/dr-ui/src/library_ui/open.rs:604`](../../ui/dr-ui/src/library_ui/open.rs#L604), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:718`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L718), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:71`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L71), [`ui/dr-ui/src/library_ui/sync.rs:270`](../../ui/dr-ui/src/library_ui/sync.rs#L270), [`ui/dr-ui/src/library_ui/sync.rs:397`](../../ui/dr-ui/src/library_ui/sync.rs#L397), [`ui/dr-ui/src/library_ui/sync.rs:80`](../../ui/dr-ui/src/library_ui/sync.rs#L80), [`ui/dr-ui/src/library_ui/window.rs:551`](../../ui/dr-ui/src/library_ui/window.rs#L551), [`ui/dr-ui/src/library_ui/window.rs:831`](../../ui/dr-ui/src/library_ui/window.rs#L831), [`ui/dr-ui/src/presets.rs:486`](../../ui/dr-ui/src/presets.rs#L486), [`ui/dr-ui/src/presets.rs:498`](../../ui/dr-ui/src/presets.rs#L498), [`ui/dr-ui/src/sidecar_cache.rs:1`](../../ui/dr-ui/src/sidecar_cache.rs#L1), [`ui/dr-ui/tests/export_ignores_the_viewport.rs:1`](../../ui/dr-ui/tests/export_ignores_the_viewport.rs#L1) | +| FR-CAT-9 | [`core/dr-catalog/src/cache.rs:1`](../../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/scan.rs:1`](../../core/dr-catalog/src/scan.rs#L1), [`core/dr-catalog/src/schema.rs:1182`](../../core/dr-catalog/src/schema.rs#L1182), [`core/dr-catalog/src/walk.rs:1022`](../../core/dr-catalog/src/walk.rs#L1022), [`core/dr-catalog/src/walk.rs:162`](../../core/dr-catalog/src/walk.rs#L162), [`core/dr-catalog/src/walk.rs:1`](../../core/dr-catalog/src/walk.rs#L1), [`core/dr-catalog/src/walk.rs:435`](../../core/dr-catalog/src/walk.rs#L435), [`core/dr-catalog/src/walk.rs:728`](../../core/dr-catalog/src/walk.rs#L728), [`core/dr-sync-nextcloud/src/desktop_client.rs:35`](../../core/dr-sync-nextcloud/src/desktop_client.rs#L35), [`core/dr-sync/src/error.rs:113`](../../core/dr-sync/src/error.rs#L113), [`core/dr-sync/src/reachability.rs:1`](../../core/dr-sync/src/reachability.rs#L1), [`core/dr-sync/src/scan.rs:211`](../../core/dr-sync/src/scan.rs#L211), [`core/dr-sync/src/scan.rs:519`](../../core/dr-sync/src/scan.rs#L519), [`core/dr-types/src/lib.rs:122`](../../core/dr-types/src/lib.rs#L122), [`ui/dr-ui/src/develop/render.rs:584`](../../ui/dr-ui/src/develop/render.rs#L584), [`ui/dr-ui/src/develop/render.rs:627`](../../ui/dr-ui/src/develop/render.rs#L627), [`ui/dr-ui/src/library/filters.rs:84`](../../ui/dr-ui/src/library/filters.rs#L84), [`ui/dr-ui/src/library/scan.rs:126`](../../ui/dr-ui/src/library/scan.rs#L126), [`ui/dr-ui/src/library/scan.rs:179`](../../ui/dr-ui/src/library/scan.rs#L179), [`ui/dr-ui/src/library/scan.rs:210`](../../ui/dr-ui/src/library/scan.rs#L210), [`ui/dr-ui/src/library/scan.rs:261`](../../ui/dr-ui/src/library/scan.rs#L261), [`ui/dr-ui/src/library/scan.rs:605`](../../ui/dr-ui/src/library/scan.rs#L605), [`ui/dr-ui/src/library/sidecar.rs:100`](../../ui/dr-ui/src/library/sidecar.rs#L100), [`ui/dr-ui/src/library/sidecar.rs:357`](../../ui/dr-ui/src/library/sidecar.rs#L357), [`ui/dr-ui/src/library/sidecar.rs:373`](../../ui/dr-ui/src/library/sidecar.rs#L373), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/spans.rs:361`](../../ui/dr-ui/src/library/spans.rs#L361), [`ui/dr-ui/src/library/thumbnails_fetch.rs:393`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L393), [`ui/dr-ui/src/library/thumbnails_fetch.rs:449`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L449), [`ui/dr-ui/src/library/thumbnails_gen.rs:74`](../../ui/dr-ui/src/library/thumbnails_gen.rs#L74), [`ui/dr-ui/src/library_ui/controller.rs:279`](../../ui/dr-ui/src/library_ui/controller.rs#L279), [`ui/dr-ui/src/library_ui/controller.rs:315`](../../ui/dr-ui/src/library_ui/controller.rs#L315), [`ui/dr-ui/src/library_ui/controller.rs:323`](../../ui/dr-ui/src/library_ui/controller.rs#L323), [`ui/dr-ui/src/library_ui/controller.rs:568`](../../ui/dr-ui/src/library_ui/controller.rs#L568), [`ui/dr-ui/src/library_ui/controller.rs:657`](../../ui/dr-ui/src/library_ui/controller.rs#L657), [`ui/dr-ui/src/library_ui/filter_bar.rs:405`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L405), [`ui/dr-ui/src/library_ui/filter_bar.rs:491`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L491), [`ui/dr-ui/src/library_ui/offline.rs:561`](../../ui/dr-ui/src/library_ui/offline.rs#L561), [`ui/dr-ui/src/library_ui/offline.rs:607`](../../ui/dr-ui/src/library_ui/offline.rs#L607), [`ui/dr-ui/src/library_ui/offline.rs:623`](../../ui/dr-ui/src/library_ui/offline.rs#L623), [`ui/dr-ui/src/library_ui/open.rs:533`](../../ui/dr-ui/src/library_ui/open.rs#L533), [`ui/dr-ui/src/library_ui/open.rs:613`](../../ui/dr-ui/src/library_ui/open.rs#L613), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:718`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L718), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:71`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L71), [`ui/dr-ui/src/library_ui/sync.rs:287`](../../ui/dr-ui/src/library_ui/sync.rs#L287), [`ui/dr-ui/src/library_ui/sync.rs:414`](../../ui/dr-ui/src/library_ui/sync.rs#L414), [`ui/dr-ui/src/library_ui/sync.rs:83`](../../ui/dr-ui/src/library_ui/sync.rs#L83), [`ui/dr-ui/src/library_ui/window.rs:551`](../../ui/dr-ui/src/library_ui/window.rs#L551), [`ui/dr-ui/src/library_ui/window.rs:831`](../../ui/dr-ui/src/library_ui/window.rs#L831), [`ui/dr-ui/src/presets.rs:486`](../../ui/dr-ui/src/presets.rs#L486), [`ui/dr-ui/src/presets.rs:498`](../../ui/dr-ui/src/presets.rs#L498), [`ui/dr-ui/src/sidecar_cache.rs:1`](../../ui/dr-ui/src/sidecar_cache.rs#L1), [`ui/dr-ui/tests/export_ignores_the_viewport.rs:1`](../../ui/dr-ui/tests/export_ignores_the_viewport.rs#L1) | | FR-CULL-1 | [`core/dr-decode/src/preview.rs:121`](../../core/dr-decode/src/preview.rs#L121) | | FR-CULL-10 | [`core/dr-catalog/src/faces.rs:1`](../../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`core/dr-catalog/src/schema.rs:603`](../../core/dr-catalog/src/schema.rs#L603), [`core/dr-catalog/src/schema.rs:781`](../../core/dr-catalog/src/schema.rs#L781), [`core/dr-face/src/assign.rs:1`](../../core/dr-face/src/assign.rs#L1), [`core/dr-face/src/neighbours.rs:1`](../../core/dr-face/src/neighbours.rs#L1), [`core/dr-face/src/references.rs:1`](../../core/dr-face/src/references.rs#L1), [`core/dr-types/src/settings.rs:129`](../../core/dr-types/src/settings.rs#L129), [`ui/dr-ui/src/develop/segmentation.rs:104`](../../ui/dr-ui/src/develop/segmentation.rs#L104), [`ui/dr-ui/src/develop/segmentation.rs:170`](../../ui/dr-ui/src/develop/segmentation.rs#L170), [`ui/dr-ui/src/develop/segmentation.rs:590`](../../ui/dr-ui/src/develop/segmentation.rs#L590), [`ui/dr-ui/src/develop/segmentation.rs:95`](../../ui/dr-ui/src/develop/segmentation.rs#L95), [`ui/dr-ui/src/develop/session.rs:23`](../../ui/dr-ui/src/develop/session.rs#L23), [`ui/dr-ui/src/faces.rs:1`](../../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/identity.rs:1`](../../ui/dr-ui/src/identity.rs#L1), [`ui/dr-ui/src/identity_ui.rs:1434`](../../ui/dr-ui/src/identity_ui.rs#L1434), [`ui/dr-ui/src/identity_ui.rs:1`](../../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/src/lib.rs:2811`](../../ui/dr-ui/src/lib.rs#L2811), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1), [`ui/dr-ui/ui/identity.slint:1`](../../ui/dr-ui/ui/identity.slint#L1), [`ui/dr-ui/ui/settings.slint:529`](../../ui/dr-ui/ui/settings.slint#L529), [`ui/dr-ui/ui/settings.slint:94`](../../ui/dr-ui/ui/settings.slint#L94) | | FR-CULL-11 | [`core/dr-catalog/src/faces.rs:1`](../../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`ui/dr-ui/src/identity.rs:1`](../../ui/dr-ui/src/identity.rs#L1), [`ui/dr-ui/src/identity_ui.rs:1`](../../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/src/library/filters.rs:105`](../../ui/dr-ui/src/library/filters.rs#L105), [`ui/dr-ui/src/library/filters.rs:155`](../../ui/dr-ui/src/library/filters.rs#L155), [`ui/dr-ui/ui/identity.slint:1`](../../ui/dr-ui/ui/identity.slint#L1) | @@ -58,7 +58,7 @@ A tag naming an ID `requirements.md` does not define — what renumbering produc | FR-CULL-3 | [`core/dr-gpu/src/focus.rs:154`](../../core/dr-gpu/src/focus.rs#L154), [`core/dr-gpu/src/focus.rs:186`](../../core/dr-gpu/src/focus.rs#L186), [`core/dr-gpu/src/focus.rs:1`](../../core/dr-gpu/src/focus.rs#L1), [`core/dr-gpu/src/focus.rs:317`](../../core/dr-gpu/src/focus.rs#L317), [`core/dr-gpu/src/raw_histogram.rs:129`](../../core/dr-gpu/src/raw_histogram.rs#L129), [`core/dr-gpu/src/raw_histogram.rs:1`](../../core/dr-gpu/src/raw_histogram.rs#L1), [`core/dr-gpu/src/raw_histogram.rs:272`](../../core/dr-gpu/src/raw_histogram.rs#L272), [`core/dr-gpu/src/raw_histogram.rs:407`](../../core/dr-gpu/src/raw_histogram.rs#L407), [`core/dr-gpu/src/shaders/focus_peak.wgsl:1`](../../core/dr-gpu/src/shaders/focus_peak.wgsl#L1), [`core/dr-gpu/src/shaders/raw_histogram.wgsl:1`](../../core/dr-gpu/src/shaders/raw_histogram.wgsl#L1), [`ui/dr-ui/src/develop/render.rs:1203`](../../ui/dr-ui/src/develop/render.rs#L1203), [`ui/dr-ui/src/develop/render.rs:1267`](../../ui/dr-ui/src/develop/render.rs#L1267), [`ui/dr-ui/src/develop/render.rs:1290`](../../ui/dr-ui/src/develop/render.rs#L1290), [`ui/dr-ui/src/develop/render.rs:256`](../../ui/dr-ui/src/develop/render.rs#L256), [`ui/dr-ui/src/develop/render.rs:269`](../../ui/dr-ui/src/develop/render.rs#L269), [`ui/dr-ui/src/develop/render.rs:314`](../../ui/dr-ui/src/develop/render.rs#L314), [`ui/dr-ui/src/develop/render.rs:325`](../../ui/dr-ui/src/develop/render.rs#L325), [`ui/dr-ui/src/develop/render.rs:331`](../../ui/dr-ui/src/develop/render.rs#L331), [`ui/dr-ui/src/develop/render.rs:348`](../../ui/dr-ui/src/develop/render.rs#L348), [`ui/dr-ui/src/develop/session.rs:118`](../../ui/dr-ui/src/develop/session.rs#L118), [`ui/dr-ui/src/develop/session.rs:138`](../../ui/dr-ui/src/develop/session.rs#L138), [`ui/dr-ui/src/develop/session.rs:144`](../../ui/dr-ui/src/develop/session.rs#L144), [`ui/dr-ui/src/develop_ui.rs:1207`](../../ui/dr-ui/src/develop_ui.rs#L1207), [`ui/dr-ui/src/histogram.rs:1`](../../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/histogram.rs:208`](../../ui/dr-ui/src/histogram.rs#L208), [`ui/dr-ui/src/histogram.rs:228`](../../ui/dr-ui/src/histogram.rs#L228), [`ui/dr-ui/src/histogram.rs:272`](../../ui/dr-ui/src/histogram.rs#L272), [`ui/dr-ui/src/histogram.rs:544`](../../ui/dr-ui/src/histogram.rs#L544), [`ui/dr-ui/src/histogram.rs:565`](../../ui/dr-ui/src/histogram.rs#L565), [`ui/dr-ui/src/histogram.rs:593`](../../ui/dr-ui/src/histogram.rs#L593), [`ui/dr-ui/src/histogram.rs:621`](../../ui/dr-ui/src/histogram.rs#L621), [`ui/dr-ui/src/histogram.rs:658`](../../ui/dr-ui/src/histogram.rs#L658), [`ui/dr-ui/src/lib.rs:1273`](../../ui/dr-ui/src/lib.rs#L1273), [`ui/dr-ui/src/lib.rs:2212`](../../ui/dr-ui/src/lib.rs#L2212), [`ui/dr-ui/src/lib.rs:2325`](../../ui/dr-ui/src/lib.rs#L2325), [`ui/dr-ui/src/lib.rs:2366`](../../ui/dr-ui/src/lib.rs#L2366), [`ui/dr-ui/src/lib.rs:444`](../../ui/dr-ui/src/lib.rs#L444), [`ui/dr-ui/src/peaking.rs:1`](../../ui/dr-ui/src/peaking.rs#L1), [`ui/dr-ui/ui/app.slint:131`](../../ui/dr-ui/ui/app.slint#L131), [`ui/dr-ui/ui/app.slint:1720`](../../ui/dr-ui/ui/app.slint#L1720), [`ui/dr-ui/ui/app.slint:2726`](../../ui/dr-ui/ui/app.slint#L2726), [`ui/dr-ui/ui/peaking.slint:1`](../../ui/dr-ui/ui/peaking.slint#L1), [`ui/dr-ui/ui/peaking.slint:25`](../../ui/dr-ui/ui/peaking.slint#L25), [`ui/dr-ui/ui/peaking.slint:56`](../../ui/dr-ui/ui/peaking.slint#L56), [`ui/dr-ui/ui/peaking.slint:91`](../../ui/dr-ui/ui/peaking.slint#L91) | | FR-CULL-4 | [`core/dr-catalog/src/rating.rs:1`](../../core/dr-catalog/src/rating.rs#L1), [`core/dr-pipeline/src/sidecar.rs:171`](../../core/dr-pipeline/src/sidecar.rs#L171), [`core/dr-xmp/src/lib.rs:442`](../../core/dr-xmp/src/lib.rs#L442), [`ui/dr-ui/src/library/filters.rs:64`](../../ui/dr-ui/src/library/filters.rs#L64), [`ui/dr-ui/src/library/sidecar.rs:11`](../../ui/dr-ui/src/library/sidecar.rs#L11), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482) | | FR-CULL-5 | [`core/dr-catalog/src/bursts.rs:1`](../../core/dr-catalog/src/bursts.rs#L1), [`core/dr-catalog/src/schema.rs:646`](../../core/dr-catalog/src/schema.rs#L646), [`ui/dr-ui/src/bursts.rs:1`](../../ui/dr-ui/src/bursts.rs#L1), [`ui/dr-ui/src/library/cells.rs:19`](../../ui/dr-ui/src/library/cells.rs#L19), [`ui/dr-ui/src/library/cells.rs:769`](../../ui/dr-ui/src/library/cells.rs#L769), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482) | -| FR-CULL-8 | [`core/dr-catalog/src/face_shard.rs:1`](../../core/dr-catalog/src/face_shard.rs#L1), [`core/dr-catalog/src/faces.rs:1`](../../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`core/dr-catalog/src/schema.rs:714`](../../core/dr-catalog/src/schema.rs#L714), [`core/dr-catalog/src/schema.rs:970`](../../core/dr-catalog/src/schema.rs#L970), [`core/dr-face/src/align.rs:296`](../../core/dr-face/src/align.rs#L296), [`core/dr-types/src/settings.rs:176`](../../core/dr-types/src/settings.rs#L176), [`ui/dr-ui/examples/face_detectors.rs:1`](../../ui/dr-ui/examples/face_detectors.rs#L1), [`ui/dr-ui/examples/face_native.rs:1`](../../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/derived_sync.rs:124`](../../ui/dr-ui/src/derived_sync.rs#L124), [`ui/dr-ui/src/faces.rs:1`](../../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/faces.rs:446`](../../ui/dr-ui/src/faces.rs#L446), [`ui/dr-ui/src/faces.rs:462`](../../ui/dr-ui/src/faces.rs#L462), [`ui/dr-ui/src/faces.rs:584`](../../ui/dr-ui/src/faces.rs#L584), [`ui/dr-ui/src/identity_ui.rs:1434`](../../ui/dr-ui/src/identity_ui.rs#L1434), [`ui/dr-ui/src/identity_ui.rs:617`](../../ui/dr-ui/src/identity_ui.rs#L617), [`ui/dr-ui/src/lib.rs:1740`](../../ui/dr-ui/src/lib.rs#L1740), [`ui/dr-ui/src/lib.rs:3099`](../../ui/dr-ui/src/lib.rs#L3099), [`ui/dr-ui/src/library/sweep.rs:241`](../../ui/dr-ui/src/library/sweep.rs#L241), [`ui/dr-ui/src/library/sweep.rs:506`](../../ui/dr-ui/src/library/sweep.rs#L506), [`ui/dr-ui/src/library_ui/controller.rs:401`](../../ui/dr-ui/src/library_ui/controller.rs#L401), [`ui/dr-ui/src/library_ui/controller.rs:488`](../../ui/dr-ui/src/library_ui/controller.rs#L488), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1), [`ui/dr-ui/src/settings_ui.rs:210`](../../ui/dr-ui/src/settings_ui.rs#L210), [`ui/dr-ui/src/settings_ui.rs:571`](../../ui/dr-ui/src/settings_ui.rs#L571), [`ui/dr-ui/ui/app.slint:645`](../../ui/dr-ui/ui/app.slint#L645), [`ui/dr-ui/ui/settings.slint:100`](../../ui/dr-ui/ui/settings.slint#L100), [`ui/dr-ui/ui/settings.slint:467`](../../ui/dr-ui/ui/settings.slint#L467), [`ui/dr-ui/ui/settings.slint:529`](../../ui/dr-ui/ui/settings.slint#L529), [`ui/dr-ui/ui/settings.slint:82`](../../ui/dr-ui/ui/settings.slint#L82), [`ui/dr-ui/ui/settings.slint:94`](../../ui/dr-ui/ui/settings.slint#L94) | +| FR-CULL-8 | [`core/dr-catalog/src/face_shard.rs:1`](../../core/dr-catalog/src/face_shard.rs#L1), [`core/dr-catalog/src/faces.rs:1`](../../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`core/dr-catalog/src/schema.rs:714`](../../core/dr-catalog/src/schema.rs#L714), [`core/dr-catalog/src/schema.rs:970`](../../core/dr-catalog/src/schema.rs#L970), [`core/dr-face/src/align.rs:296`](../../core/dr-face/src/align.rs#L296), [`core/dr-types/src/settings.rs:176`](../../core/dr-types/src/settings.rs#L176), [`ui/dr-ui/examples/face_detectors.rs:1`](../../ui/dr-ui/examples/face_detectors.rs#L1), [`ui/dr-ui/examples/face_native.rs:1`](../../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/derived_sync.rs:127`](../../ui/dr-ui/src/derived_sync.rs#L127), [`ui/dr-ui/src/faces.rs:1`](../../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/faces.rs:446`](../../ui/dr-ui/src/faces.rs#L446), [`ui/dr-ui/src/faces.rs:462`](../../ui/dr-ui/src/faces.rs#L462), [`ui/dr-ui/src/faces.rs:584`](../../ui/dr-ui/src/faces.rs#L584), [`ui/dr-ui/src/identity_ui.rs:1434`](../../ui/dr-ui/src/identity_ui.rs#L1434), [`ui/dr-ui/src/identity_ui.rs:617`](../../ui/dr-ui/src/identity_ui.rs#L617), [`ui/dr-ui/src/lib.rs:1740`](../../ui/dr-ui/src/lib.rs#L1740), [`ui/dr-ui/src/lib.rs:3099`](../../ui/dr-ui/src/lib.rs#L3099), [`ui/dr-ui/src/library/sweep.rs:241`](../../ui/dr-ui/src/library/sweep.rs#L241), [`ui/dr-ui/src/library/sweep.rs:506`](../../ui/dr-ui/src/library/sweep.rs#L506), [`ui/dr-ui/src/library_ui/controller.rs:401`](../../ui/dr-ui/src/library_ui/controller.rs#L401), [`ui/dr-ui/src/library_ui/controller.rs:488`](../../ui/dr-ui/src/library_ui/controller.rs#L488), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1), [`ui/dr-ui/src/settings_ui.rs:210`](../../ui/dr-ui/src/settings_ui.rs#L210), [`ui/dr-ui/src/settings_ui.rs:571`](../../ui/dr-ui/src/settings_ui.rs#L571), [`ui/dr-ui/ui/app.slint:645`](../../ui/dr-ui/ui/app.slint#L645), [`ui/dr-ui/ui/settings.slint:100`](../../ui/dr-ui/ui/settings.slint#L100), [`ui/dr-ui/ui/settings.slint:467`](../../ui/dr-ui/ui/settings.slint#L467), [`ui/dr-ui/ui/settings.slint:529`](../../ui/dr-ui/ui/settings.slint#L529), [`ui/dr-ui/ui/settings.slint:82`](../../ui/dr-ui/ui/settings.slint#L82), [`ui/dr-ui/ui/settings.slint:94`](../../ui/dr-ui/ui/settings.slint#L94) | | FR-CULL-8a | [`core/dr-catalog/src/faces.rs:124`](../../core/dr-catalog/src/faces.rs#L124), [`core/dr-catalog/src/schema.rs:917`](../../core/dr-catalog/src/schema.rs#L917), [`core/dr-face/src/classify.rs:1`](../../core/dr-face/src/classify.rs#L1), [`core/dr-face/src/eyes.rs:1`](../../core/dr-face/src/eyes.rs#L1), [`core/dr-face/src/landmarks.rs:1`](../../core/dr-face/src/landmarks.rs#L1), [`core/dr-types/src/place.rs:129`](../../core/dr-types/src/place.rs#L129), [`ui/dr-ui/src/faces.rs:166`](../../ui/dr-ui/src/faces.rs#L166), [`ui/dr-ui/src/faces.rs:1821`](../../ui/dr-ui/src/faces.rs#L1821), [`ui/dr-ui/src/faces.rs:308`](../../ui/dr-ui/src/faces.rs#L308), [`ui/dr-ui/src/identity.rs:104`](../../ui/dr-ui/src/identity.rs#L104), [`ui/dr-ui/src/library/filters.rs:131`](../../ui/dr-ui/src/library/filters.rs#L131), [`ui/dr-ui/src/library/filters.rs:683`](../../ui/dr-ui/src/library/filters.rs#L683), [`ui/dr-ui/src/library/filters.rs:726`](../../ui/dr-ui/src/library/filters.rs#L726), [`ui/dr-ui/src/library/filters.rs:764`](../../ui/dr-ui/src/library/filters.rs#L764), [`ui/dr-ui/src/repairs.rs:571`](../../ui/dr-ui/src/repairs.rs#L571), [`ui/dr-ui/ui/identity.slint:273`](../../ui/dr-ui/ui/identity.slint#L273), [`ui/dr-ui/ui/identity.slint:63`](../../ui/dr-ui/ui/identity.slint#L63), [`ui/dr-ui/ui/library.slint:1782`](../../ui/dr-ui/ui/library.slint#L1782), [`ui/dr-ui/ui/library.slint:686`](../../ui/dr-ui/ui/library.slint#L686) | | FR-CULL-9 | [`core/dr-catalog/src/faces.rs:1`](../../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`core/dr-catalog/src/schema.rs:781`](../../core/dr-catalog/src/schema.rs#L781), [`core/dr-face/src/assign.rs:1`](../../core/dr-face/src/assign.rs#L1), [`core/dr-face/src/neighbours.rs:1`](../../core/dr-face/src/neighbours.rs#L1), [`core/dr-types/src/settings.rs:129`](../../core/dr-types/src/settings.rs#L129), [`ui/dr-ui/src/faces.rs:1`](../../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/faces.rs:584`](../../ui/dr-ui/src/faces.rs#L584), [`ui/dr-ui/src/identity_ui.rs:1`](../../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/src/repairs.rs:517`](../../ui/dr-ui/src/repairs.rs#L517), [`ui/dr-ui/ui/identity.slint:347`](../../ui/dr-ui/ui/identity.slint#L347) | | FR-DEV-1 | [`core/dr-pipeline/src/graph.rs:1`](../../core/dr-pipeline/src/graph.rs#L1), [`core/dr-pipeline/src/sidecar.rs:1`](../../core/dr-pipeline/src/sidecar.rs#L1) | @@ -97,9 +97,10 @@ A tag naming an ID `requirements.md` does not define — what renumbering produc | FR-EXP-4 | [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/sharpen.rs:1`](../../core/dr-export/src/sharpen.rs#L1), [`core/dr-export/src/size.rs:1`](../../core/dr-export/src/size.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1) | | FR-EXP-5 | [`ui/dr-ui/src/settings_store.rs:1`](../../ui/dr-ui/src/settings_store.rs#L1) | | FR-EXP-6 | [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/name.rs:1`](../../core/dr-export/src/name.rs#L1), [`core/dr-types/src/settings.rs:1`](../../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/export.rs:1`](../../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:609`](../../ui/dr-ui/src/lib.rs#L609), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/src/settings_ui.rs:49`](../../ui/dr-ui/src/settings_ui.rs#L49), [`ui/dr-ui/src/settings_ui.rs:847`](../../ui/dr-ui/src/settings_ui.rs#L847) | -| FR-EXP-7 | [`ui/dr-ui/src/activity.rs:83`](../../ui/dr-ui/src/activity.rs#L83), [`ui/dr-ui/src/develop_ui.rs:309`](../../ui/dr-ui/src/develop_ui.rs#L309), [`ui/dr-ui/src/export.rs:1006`](../../ui/dr-ui/src/export.rs#L1006), [`ui/dr-ui/src/export.rs:1`](../../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:270`](../../ui/dr-ui/src/lib.rs#L270), [`ui/dr-ui/src/lib.rs:609`](../../ui/dr-ui/src/lib.rs#L609), [`ui/dr-ui/src/lib.rs:655`](../../ui/dr-ui/src/lib.rs#L655), [`ui/dr-ui/src/lib.rs:682`](../../ui/dr-ui/src/lib.rs#L682), [`ui/dr-ui/src/library_ui/controller.rs:1004`](../../ui/dr-ui/src/library_ui/controller.rs#L1004), [`ui/dr-ui/src/library_ui/controller.rs:1016`](../../ui/dr-ui/src/library_ui/controller.rs#L1016), [`ui/dr-ui/src/library_ui/controller.rs:1028`](../../ui/dr-ui/src/library_ui/controller.rs#L1028), [`ui/dr-ui/src/library_ui/controller.rs:716`](../../ui/dr-ui/src/library_ui/controller.rs#L716), [`ui/dr-ui/src/library_ui/controller.rs:816`](../../ui/dr-ui/src/library_ui/controller.rs#L816), [`ui/dr-ui/src/library_ui/controller.rs:873`](../../ui/dr-ui/src/library_ui/controller.rs#L873), [`ui/dr-ui/src/library_ui/sync.rs:97`](../../ui/dr-ui/src/library_ui/sync.rs#L97), [`ui/dr-ui/ui/app.slint:1408`](../../ui/dr-ui/ui/app.slint#L1408), [`ui/dr-ui/ui/app.slint:838`](../../ui/dr-ui/ui/app.slint#L838), [`ui/dr-ui/ui/library.slint:1858`](../../ui/dr-ui/ui/library.slint#L1858), [`ui/dr-ui/ui/library.slint:4609`](../../ui/dr-ui/ui/library.slint#L4609) | +| FR-EXP-7 | [`ui/dr-ui/src/activity.rs:83`](../../ui/dr-ui/src/activity.rs#L83), [`ui/dr-ui/src/develop_ui.rs:309`](../../ui/dr-ui/src/develop_ui.rs#L309), [`ui/dr-ui/src/export.rs:1006`](../../ui/dr-ui/src/export.rs#L1006), [`ui/dr-ui/src/export.rs:1`](../../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:270`](../../ui/dr-ui/src/lib.rs#L270), [`ui/dr-ui/src/lib.rs:609`](../../ui/dr-ui/src/lib.rs#L609), [`ui/dr-ui/src/lib.rs:655`](../../ui/dr-ui/src/lib.rs#L655), [`ui/dr-ui/src/lib.rs:682`](../../ui/dr-ui/src/lib.rs#L682), [`ui/dr-ui/src/library_ui/controller.rs:1004`](../../ui/dr-ui/src/library_ui/controller.rs#L1004), [`ui/dr-ui/src/library_ui/controller.rs:1016`](../../ui/dr-ui/src/library_ui/controller.rs#L1016), [`ui/dr-ui/src/library_ui/controller.rs:1028`](../../ui/dr-ui/src/library_ui/controller.rs#L1028), [`ui/dr-ui/src/library_ui/controller.rs:716`](../../ui/dr-ui/src/library_ui/controller.rs#L716), [`ui/dr-ui/src/library_ui/controller.rs:816`](../../ui/dr-ui/src/library_ui/controller.rs#L816), [`ui/dr-ui/src/library_ui/controller.rs:873`](../../ui/dr-ui/src/library_ui/controller.rs#L873), [`ui/dr-ui/src/library_ui/sync.rs:100`](../../ui/dr-ui/src/library_ui/sync.rs#L100), [`ui/dr-ui/ui/app.slint:1408`](../../ui/dr-ui/ui/app.slint#L1408), [`ui/dr-ui/ui/app.slint:838`](../../ui/dr-ui/ui/app.slint#L838), [`ui/dr-ui/ui/library.slint:1858`](../../ui/dr-ui/ui/library.slint#L1858), [`ui/dr-ui/ui/library.slint:4609`](../../ui/dr-ui/ui/library.slint#L4609) | | FR-EXP-8 | [`core/dr-decode/src/lib.rs:366`](../../core/dr-decode/src/lib.rs#L366), [`core/dr-decode/src/lib.rs:390`](../../core/dr-decode/src/lib.rs#L390), [`core/dr-decode/src/lib.rs:404`](../../core/dr-decode/src/lib.rs#L404), [`core/dr-decode/src/lib.rs:71`](../../core/dr-decode/src/lib.rs#L71), [`core/dr-decode/src/lib.rs:79`](../../core/dr-decode/src/lib.rs#L79), [`core/dr-decode/src/lib.rs:82`](../../core/dr-decode/src/lib.rs#L82), [`core/dr-decode/src/locate.rs:1233`](../../core/dr-decode/src/locate.rs#L1233), [`core/dr-decode/src/locate.rs:1292`](../../core/dr-decode/src/locate.rs#L1292), [`core/dr-decode/src/locate.rs:359`](../../core/dr-decode/src/locate.rs#L359), [`core/dr-decode/src/locate.rs:556`](../../core/dr-decode/src/locate.rs#L556), [`core/dr-decode/src/locate.rs:640`](../../core/dr-decode/src/locate.rs#L640), [`core/dr-decode/src/locate.rs:653`](../../core/dr-decode/src/locate.rs#L653), [`core/dr-decode/src/locate.rs:736`](../../core/dr-decode/src/locate.rs#L736), [`core/dr-export/examples/export.rs:99`](../../core/dr-export/examples/export.rs#L99), [`core/dr-export/src/encode.rs:117`](../../core/dr-export/src/encode.rs#L117), [`core/dr-export/src/encode.rs:161`](../../core/dr-export/src/encode.rs#L161), [`core/dr-export/src/encode.rs:1`](../../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/encode.rs:206`](../../core/dr-export/src/encode.rs#L206), [`core/dr-export/src/encode.rs:235`](../../core/dr-export/src/encode.rs#L235), [`core/dr-export/src/encode.rs:311`](../../core/dr-export/src/encode.rs#L311), [`core/dr-export/src/encode.rs:325`](../../core/dr-export/src/encode.rs#L325), [`core/dr-export/src/encode.rs:408`](../../core/dr-export/src/encode.rs#L408), [`core/dr-export/src/encode.rs:456`](../../core/dr-export/src/encode.rs#L456), [`core/dr-export/src/encode.rs:70`](../../core/dr-export/src/encode.rs#L70), [`core/dr-export/src/encode.rs:795`](../../core/dr-export/src/encode.rs#L795), [`core/dr-export/src/encode.rs:809`](../../core/dr-export/src/encode.rs#L809), [`core/dr-export/src/encode.rs:850`](../../core/dr-export/src/encode.rs#L850), [`core/dr-export/src/encode.rs:898`](../../core/dr-export/src/encode.rs#L898), [`core/dr-export/src/exif.rs:1`](../../core/dr-export/src/exif.rs#L1), [`core/dr-export/src/lib.rs:140`](../../core/dr-export/src/lib.rs#L140), [`core/dr-export/src/metadata.rs:1`](../../core/dr-export/src/metadata.rs#L1), [`core/dr-export/src/metadata.rs:41`](../../core/dr-export/src/metadata.rs#L41), [`core/dr-export/src/metadata.rs:74`](../../core/dr-export/src/metadata.rs#L74), [`core/dr-types/src/lib.rs:655`](../../core/dr-types/src/lib.rs#L655), [`core/dr-types/src/settings.rs:671`](../../core/dr-types/src/settings.rs#L671), [`ui/dr-ui/src/develop/session.rs:37`](../../ui/dr-ui/src/develop/session.rs#L37), [`ui/dr-ui/src/develop/session.rs:412`](../../ui/dr-ui/src/develop/session.rs#L412), [`ui/dr-ui/src/develop/session.rs:524`](../../ui/dr-ui/src/develop/session.rs#L524), [`ui/dr-ui/src/export.rs:475`](../../ui/dr-ui/src/export.rs#L475), [`ui/dr-ui/src/export.rs:642`](../../ui/dr-ui/src/export.rs#L642), [`ui/dr-ui/src/export.rs:688`](../../ui/dr-ui/src/export.rs#L688), [`ui/dr-ui/src/export.rs:716`](../../ui/dr-ui/src/export.rs#L716), [`ui/dr-ui/src/export.rs:840`](../../ui/dr-ui/src/export.rs#L840), [`ui/dr-ui/src/export.rs:858`](../../ui/dr-ui/src/export.rs#L858), [`ui/dr-ui/src/lib.rs:270`](../../ui/dr-ui/src/lib.rs#L270), [`ui/dr-ui/src/lib.rs:293`](../../ui/dr-ui/src/lib.rs#L293), [`ui/dr-ui/src/lib.rs:641`](../../ui/dr-ui/src/lib.rs#L641), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1) | | FR-EXP-9 | [`core/dr-decode/src/lib.rs:546`](../../core/dr-decode/src/lib.rs#L546), [`core/dr-export/src/lib.rs:132`](../../core/dr-export/src/lib.rs#L132), [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-gpu/src/adjust.rs:1134`](../../core/dr-gpu/src/adjust.rs#L1134), [`ui/dr-ui/examples/face_native.rs:1`](../../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/develop/mask_ops.rs:1130`](../../ui/dr-ui/src/develop/mask_ops.rs#L1130), [`ui/dr-ui/src/develop/render.rs:546`](../../ui/dr-ui/src/develop/render.rs#L546), [`ui/dr-ui/src/develop/render.rs:584`](../../ui/dr-ui/src/develop/render.rs#L584), [`ui/dr-ui/src/lib.rs:609`](../../ui/dr-ui/src/lib.rs#L609), [`ui/dr-ui/src/library/sweep.rs:506`](../../ui/dr-ui/src/library/sweep.rs#L506), [`ui/dr-ui/tests/export_ignores_the_viewport.rs:1`](../../ui/dr-ui/tests/export_ignores_the_viewport.rs#L1) | +| FR-INF-1 | [`ui/dr-ui/src/lib.rs:1437`](../../ui/dr-ui/src/lib.rs#L1437), [`ui/dr-ui/ui/settings.slint:928`](../../ui/dr-ui/ui/settings.slint#L928) | | FR-MRG-1 | [`core/dr-pano/src/align.rs:1`](../../core/dr-pano/src/align.rs#L1), [`core/dr-pano/src/lib.rs:1`](../../core/dr-pano/src/lib.rs#L1), [`ui/dr-ui/src/lib.rs:1821`](../../ui/dr-ui/src/lib.rs#L1821), [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1), [`ui/dr-ui/src/merge_ui.rs:1`](../../ui/dr-ui/src/merge_ui.rs#L1), [`ui/dr-ui/ui/app.slint:1413`](../../ui/dr-ui/ui/app.slint#L1413), [`ui/dr-ui/ui/app.slint:531`](../../ui/dr-ui/ui/app.slint#L531), [`ui/dr-ui/ui/library.slint:1866`](../../ui/dr-ui/ui/library.slint#L1866), [`ui/dr-ui/ui/library.slint:4554`](../../ui/dr-ui/ui/library.slint#L4554), [`ui/dr-ui/ui/merge.slint:1`](../../ui/dr-ui/ui/merge.slint#L1) | | FR-MRG-10 | [`core/dr-gpu/src/merge.rs:1`](../../core/dr-gpu/src/merge.rs#L1), [`core/dr-gpu/src/shaders/merge.wgsl:1`](../../core/dr-gpu/src/shaders/merge.wgsl#L1), [`core/dr-pano/src/lib.rs:1`](../../core/dr-pano/src/lib.rs#L1) | | FR-MRG-11 | [`core/dr-gpu/src/merge.rs:1`](../../core/dr-gpu/src/merge.rs#L1), [`core/dr-gpu/src/shaders/merge.wgsl:1`](../../core/dr-gpu/src/shaders/merge.wgsl#L1) | @@ -111,24 +112,24 @@ A tag naming an ID `requirements.md` does not define — what renumbering produc | FR-MRG-7 | [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1), [`ui/dr-ui/src/merge_ui.rs:1`](../../ui/dr-ui/src/merge_ui.rs#L1), [`ui/dr-ui/ui/app.slint:531`](../../ui/dr-ui/ui/app.slint#L531), [`ui/dr-ui/ui/merge.slint:1`](../../ui/dr-ui/ui/merge.slint#L1) | | FR-MRG-8 | [`core/dr-pano/src/xfeat.rs:1`](../../core/dr-pano/src/xfeat.rs#L1), [`core/dr-segment/examples/onnx_probe.rs:1`](../../core/dr-segment/examples/onnx_probe.rs#L1) | | FR-NC-1 | [`core/dr-sync-nextcloud/src/auth.rs:132`](../../core/dr-sync-nextcloud/src/auth.rs#L132), [`core/dr-sync-nextcloud/src/auth.rs:44`](../../core/dr-sync-nextcloud/src/auth.rs#L44), [`core/dr-sync-nextcloud/src/provider.rs:1`](../../core/dr-sync-nextcloud/src/provider.rs#L1), [`core/dr-sync/src/account.rs:375`](../../core/dr-sync/src/account.rs#L375), [`ui/dr-ui/src/launch.rs:316`](../../ui/dr-ui/src/launch.rs#L316), [`ui/dr-ui/src/launch.rs:61`](../../ui/dr-ui/src/launch.rs#L61), [`ui/dr-ui/src/launch_ui.rs:446`](../../ui/dr-ui/src/launch_ui.rs#L446) | -| FR-NC-10 | [`core/dr-sync/src/account.rs:240`](../../core/dr-sync/src/account.rs#L240), [`ui/dr-ui/src/export.rs:1`](../../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:682`](../../ui/dr-ui/src/lib.rs#L682), [`ui/dr-ui/src/library/paths.rs:69`](../../ui/dr-ui/src/library/paths.rs#L69), [`ui/dr-ui/src/library/sidecar.rs:100`](../../ui/dr-ui/src/library/sidecar.rs#L100), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/thumbnails_fetch.rs:449`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L449), [`ui/dr-ui/src/library_ui/controller.rs:657`](../../ui/dr-ui/src/library_ui/controller.rs#L657), [`ui/dr-ui/src/library_ui/offline.rs:623`](../../ui/dr-ui/src/library_ui/offline.rs#L623), [`ui/dr-ui/src/library_ui/sync.rs:97`](../../ui/dr-ui/src/library_ui/sync.rs#L97), [`ui/dr-ui/src/sidecar_cache.rs:1`](../../ui/dr-ui/src/sidecar_cache.rs#L1) | +| FR-NC-10 | [`core/dr-sync/src/account.rs:240`](../../core/dr-sync/src/account.rs#L240), [`ui/dr-ui/src/export.rs:1`](../../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:682`](../../ui/dr-ui/src/lib.rs#L682), [`ui/dr-ui/src/library/paths.rs:69`](../../ui/dr-ui/src/library/paths.rs#L69), [`ui/dr-ui/src/library/sidecar.rs:100`](../../ui/dr-ui/src/library/sidecar.rs#L100), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/thumbnails_fetch.rs:449`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L449), [`ui/dr-ui/src/library_ui/controller.rs:657`](../../ui/dr-ui/src/library_ui/controller.rs#L657), [`ui/dr-ui/src/library_ui/offline.rs:623`](../../ui/dr-ui/src/library_ui/offline.rs#L623), [`ui/dr-ui/src/library_ui/sync.rs:100`](../../ui/dr-ui/src/library_ui/sync.rs#L100), [`ui/dr-ui/src/sidecar_cache.rs:1`](../../ui/dr-ui/src/sidecar_cache.rs#L1) | | FR-NC-12 | [`core/dr-sync-folder/src/lib.rs:1`](../../core/dr-sync-folder/src/lib.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:1049`](../../core/dr-sync-nextcloud/src/lib.rs#L1049), [`core/dr-sync-nextcloud/src/lib.rs:40`](../../core/dr-sync-nextcloud/src/lib.rs#L40), [`core/dr-sync-nextcloud/src/provider.rs:1`](../../core/dr-sync-nextcloud/src/provider.rs#L1), [`core/dr-sync/src/account.rs:1`](../../core/dr-sync/src/account.rs#L1), [`core/dr-sync/src/account.rs:87`](../../core/dr-sync/src/account.rs#L87), [`core/dr-sync/src/lib.rs:218`](../../core/dr-sync/src/lib.rs#L218), [`core/dr-sync/src/lib.rs:51`](../../core/dr-sync/src/lib.rs#L51), [`core/dr-sync/src/provider.rs:106`](../../core/dr-sync/src/provider.rs#L106), [`core/dr-sync/src/provider.rs:1`](../../core/dr-sync/src/provider.rs#L1), [`core/dr-sync/src/provider.rs:53`](../../core/dr-sync/src/provider.rs#L53), [`core/dr-sync/src/reachability.rs:1`](../../core/dr-sync/src/reachability.rs#L1), [`ui/dr-ui/src/remote.rs:1`](../../ui/dr-ui/src/remote.rs#L1) | | FR-NC-13 | [`core/dr-sync-folder/src/lib.rs:197`](../../core/dr-sync-folder/src/lib.rs#L197), [`core/dr-sync-folder/src/lib.rs:1`](../../core/dr-sync-folder/src/lib.rs#L1), [`core/dr-sync-folder/src/lib.rs:73`](../../core/dr-sync-folder/src/lib.rs#L73), [`core/dr-sync/src/provider.rs:106`](../../core/dr-sync/src/provider.rs#L106), [`ui/dr-ui/src/launch_ui.rs:345`](../../ui/dr-ui/src/launch_ui.rs#L345), [`ui/dr-ui/src/remote.rs:1`](../../ui/dr-ui/src/remote.rs#L1) | | FR-NC-2 | [`core/dr-sync/src/account.rs:1`](../../core/dr-sync/src/account.rs#L1), [`core/dr-sync/src/account.rs:318`](../../core/dr-sync/src/account.rs#L318), [`core/dr-sync/src/account.rs:375`](../../core/dr-sync/src/account.rs#L375), [`core/dr-sync/src/account.rs:59`](../../core/dr-sync/src/account.rs#L59), [`platform/dr-plat/src/secrets.rs:82`](../../platform/dr-plat/src/secrets.rs#L82) | -| FR-NC-3 | [`core/dr-decode/src/locate.rs:1`](../../core/dr-decode/src/locate.rs#L1), [`core/dr-decode/src/preview.rs:148`](../../core/dr-decode/src/preview.rs#L148), [`core/dr-sync/src/capability.rs:85`](../../core/dr-sync/src/capability.rs#L85), [`core/dr-thumbs/src/lib.rs:1`](../../core/dr-thumbs/src/lib.rs#L1), [`core/dr-types/src/place.rs:1`](../../core/dr-types/src/place.rs#L1), [`ui/dr-ui/src/library/mod.rs:1`](../../ui/dr-ui/src/library/mod.rs#L1), [`ui/dr-ui/src/library/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/grid.rs:458`](../../ui/dr-ui/src/library_ui/grid.rs#L458), [`ui/dr-ui/src/library_ui/mod.rs:1`](../../ui/dr-ui/src/library_ui/mod.rs#L1), [`ui/dr-ui/src/library_ui/sync.rs:368`](../../ui/dr-ui/src/library_ui/sync.rs#L368), [`ui/dr-ui/ui/library.slint:730`](../../ui/dr-ui/ui/library.slint#L730), [`ui/dr-ui/ui/settings.slint:435`](../../ui/dr-ui/ui/settings.slint#L435), [`ui/dr-ui/ui/settings.slint:73`](../../ui/dr-ui/ui/settings.slint#L73) | +| FR-NC-3 | [`core/dr-decode/src/locate.rs:1`](../../core/dr-decode/src/locate.rs#L1), [`core/dr-decode/src/preview.rs:148`](../../core/dr-decode/src/preview.rs#L148), [`core/dr-sync/src/capability.rs:85`](../../core/dr-sync/src/capability.rs#L85), [`core/dr-thumbs/src/lib.rs:1`](../../core/dr-thumbs/src/lib.rs#L1), [`core/dr-types/src/place.rs:1`](../../core/dr-types/src/place.rs#L1), [`ui/dr-ui/src/library/mod.rs:1`](../../ui/dr-ui/src/library/mod.rs#L1), [`ui/dr-ui/src/library/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/grid.rs:458`](../../ui/dr-ui/src/library_ui/grid.rs#L458), [`ui/dr-ui/src/library_ui/mod.rs:1`](../../ui/dr-ui/src/library_ui/mod.rs#L1), [`ui/dr-ui/src/library_ui/sync.rs:385`](../../ui/dr-ui/src/library_ui/sync.rs#L385), [`ui/dr-ui/ui/library.slint:730`](../../ui/dr-ui/ui/library.slint#L730), [`ui/dr-ui/ui/settings.slint:435`](../../ui/dr-ui/ui/settings.slint#L435), [`ui/dr-ui/ui/settings.slint:73`](../../ui/dr-ui/ui/settings.slint#L73) | | FR-NC-4 | [`core/dr-sync-folder/src/lib.rs:197`](../../core/dr-sync-folder/src/lib.rs#L197), [`core/dr-sync-nextcloud/src/propfind.rs:103`](../../core/dr-sync-nextcloud/src/propfind.rs#L103), [`core/dr-sync-nextcloud/src/propfind.rs:51`](../../core/dr-sync-nextcloud/src/propfind.rs#L51), [`core/dr-sync/src/capability.rs:6`](../../core/dr-sync/src/capability.rs#L6), [`core/dr-sync/src/lib.rs:218`](../../core/dr-sync/src/lib.rs#L218), [`core/dr-sync/src/scan.rs:129`](../../core/dr-sync/src/scan.rs#L129), [`ui/dr-ui/src/launch.rs:61`](../../ui/dr-ui/src/launch.rs#L61) | | FR-NC-5 | [`core/dr-sync-nextcloud/src/propfind.rs:51`](../../core/dr-sync-nextcloud/src/propfind.rs#L51), [`ui/dr-ui/src/import.rs:488`](../../ui/dr-ui/src/import.rs#L488) | | FR-NC-6 | [`ui/dr-ui/src/activity.rs:1`](../../ui/dr-ui/src/activity.rs#L1) | | FR-NC-6a | [`core/dr-catalog/src/cache.rs:1`](../../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/cache.rs:225`](../../core/dr-catalog/src/cache.rs#L225), [`core/dr-catalog/src/schema.rs:1182`](../../core/dr-catalog/src/schema.rs#L1182), [`core/dr-catalog/src/schema.rs:1637`](../../core/dr-catalog/src/schema.rs#L1637), [`core/dr-sync-folder/src/borrow.rs:1`](../../core/dr-sync-folder/src/borrow.rs#L1), [`core/dr-types/src/selector.rs:1`](../../core/dr-types/src/selector.rs#L1), [`core/dr-types/src/settings.rs:1`](../../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/collections_ui/rename_menu.rs:75`](../../ui/dr-ui/src/collections_ui/rename_menu.rs#L75), [`ui/dr-ui/src/collections_ui/tree_sync.rs:111`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L111), [`ui/dr-ui/src/collections_ui/tree_sync.rs:387`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L387), [`ui/dr-ui/src/collections_ui/tree_sync.rs:38`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L38), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:560`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L560), [`ui/dr-ui/src/lib.rs:1573`](../../ui/dr-ui/src/lib.rs#L1573), [`ui/dr-ui/src/lib.rs:2722`](../../ui/dr-ui/src/lib.rs#L2722), [`ui/dr-ui/src/lib.rs:2793`](../../ui/dr-ui/src/lib.rs#L2793), [`ui/dr-ui/src/lib.rs:3011`](../../ui/dr-ui/src/lib.rs#L3011), [`ui/dr-ui/src/lib.rs:3012`](../../ui/dr-ui/src/lib.rs#L3012), [`ui/dr-ui/src/lib.rs:3051`](../../ui/dr-ui/src/lib.rs#L3051), [`ui/dr-ui/src/library/thumbnails_fetch.rs:118`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L118), [`ui/dr-ui/src/library/thumbnails_fetch.rs:393`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L393), [`ui/dr-ui/src/library/thumbnails_fetch.rs:574`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L574), [`ui/dr-ui/src/library/thumbnails_fetch.rs:711`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L711), [`ui/dr-ui/src/library/thumbnails_fetch.rs:726`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L726), [`ui/dr-ui/src/library/thumbnails_fetch.rs:95`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L95), [`ui/dr-ui/src/library_ui/controller.rs:339`](../../ui/dr-ui/src/library_ui/controller.rs#L339), [`ui/dr-ui/src/library_ui/controller.rs:350`](../../ui/dr-ui/src/library_ui/controller.rs#L350), [`ui/dr-ui/src/library_ui/controller.rs:365`](../../ui/dr-ui/src/library_ui/controller.rs#L365), [`ui/dr-ui/src/library_ui/controller.rs:374`](../../ui/dr-ui/src/library_ui/controller.rs#L374), [`ui/dr-ui/src/library_ui/controller.rs:382`](../../ui/dr-ui/src/library_ui/controller.rs#L382), [`ui/dr-ui/src/library_ui/controller.rs:512`](../../ui/dr-ui/src/library_ui/controller.rs#L512), [`ui/dr-ui/src/library_ui/controller.rs:522`](../../ui/dr-ui/src/library_ui/controller.rs#L522), [`ui/dr-ui/src/library_ui/controller.rs:537`](../../ui/dr-ui/src/library_ui/controller.rs#L537), [`ui/dr-ui/src/library_ui/controller.rs:584`](../../ui/dr-ui/src/library_ui/controller.rs#L584), [`ui/dr-ui/src/library_ui/controller.rs:599`](../../ui/dr-ui/src/library_ui/controller.rs#L599), [`ui/dr-ui/src/library_ui/controller.rs:673`](../../ui/dr-ui/src/library_ui/controller.rs#L673), [`ui/dr-ui/src/library_ui/controller.rs:704`](../../ui/dr-ui/src/library_ui/controller.rs#L704), [`ui/dr-ui/src/library_ui/controller.rs:716`](../../ui/dr-ui/src/library_ui/controller.rs#L716), [`ui/dr-ui/src/library_ui/filter_bar.rs:424`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L424), [`ui/dr-ui/src/library_ui/filter_bar.rs:444`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L444), [`ui/dr-ui/src/library_ui/offline.rs:196`](../../ui/dr-ui/src/library_ui/offline.rs#L196), [`ui/dr-ui/src/library_ui/offline.rs:20`](../../ui/dr-ui/src/library_ui/offline.rs#L20), [`ui/dr-ui/src/library_ui/offline.rs:261`](../../ui/dr-ui/src/library_ui/offline.rs#L261), [`ui/dr-ui/src/library_ui/offline.rs:407`](../../ui/dr-ui/src/library_ui/offline.rs#L407), [`ui/dr-ui/src/library_ui/offline.rs:528`](../../ui/dr-ui/src/library_ui/offline.rs#L528), [`ui/dr-ui/src/library_ui/offline.rs:93`](../../ui/dr-ui/src/library_ui/offline.rs#L93), [`ui/dr-ui/src/library_ui/window.rs:228`](../../ui/dr-ui/src/library_ui/window.rs#L228), [`ui/dr-ui/src/settings_store.rs:1`](../../ui/dr-ui/src/settings_store.rs#L1), [`ui/dr-ui/src/settings_ui.rs:157`](../../ui/dr-ui/src/settings_ui.rs#L157), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/src/settings_ui.rs:542`](../../ui/dr-ui/src/settings_ui.rs#L542), [`ui/dr-ui/ui/app.slint:1302`](../../ui/dr-ui/ui/app.slint#L1302), [`ui/dr-ui/ui/app.slint:2854`](../../ui/dr-ui/ui/app.slint#L2854), [`ui/dr-ui/ui/app.slint:426`](../../ui/dr-ui/ui/app.slint#L426), [`ui/dr-ui/ui/collections.slint:1037`](../../ui/dr-ui/ui/collections.slint#L1037), [`ui/dr-ui/ui/collections.slint:1048`](../../ui/dr-ui/ui/collections.slint#L1048), [`ui/dr-ui/ui/collections.slint:1127`](../../ui/dr-ui/ui/collections.slint#L1127), [`ui/dr-ui/ui/collections.slint:1228`](../../ui/dr-ui/ui/collections.slint#L1228), [`ui/dr-ui/ui/collections.slint:1236`](../../ui/dr-ui/ui/collections.slint#L1236), [`ui/dr-ui/ui/collections.slint:272`](../../ui/dr-ui/ui/collections.slint#L272), [`ui/dr-ui/ui/collections.slint:424`](../../ui/dr-ui/ui/collections.slint#L424), [`ui/dr-ui/ui/collections.slint:433`](../../ui/dr-ui/ui/collections.slint#L433), [`ui/dr-ui/ui/collections.slint:436`](../../ui/dr-ui/ui/collections.slint#L436), [`ui/dr-ui/ui/collections.slint:482`](../../ui/dr-ui/ui/collections.slint#L482), [`ui/dr-ui/ui/collections.slint:52`](../../ui/dr-ui/ui/collections.slint#L52), [`ui/dr-ui/ui/collections.slint:720`](../../ui/dr-ui/ui/collections.slint#L720), [`ui/dr-ui/ui/collections.slint:877`](../../ui/dr-ui/ui/collections.slint#L877), [`ui/dr-ui/ui/collections.slint:91`](../../ui/dr-ui/ui/collections.slint#L91), [`ui/dr-ui/ui/icons.slint:262`](../../ui/dr-ui/ui/icons.slint#L262), [`ui/dr-ui/ui/settings.slint:114`](../../ui/dr-ui/ui/settings.slint#L114), [`ui/dr-ui/ui/settings.slint:656`](../../ui/dr-ui/ui/settings.slint#L656) | | FR-NC-6b | [`ui/dr-ui/src/library_ui/offline.rs:261`](../../ui/dr-ui/src/library_ui/offline.rs#L261), [`ui/dr-ui/src/memory.rs:1`](../../ui/dr-ui/src/memory.rs#L1) | -| FR-NC-6c | [`core/dr-catalog/src/cache.rs:225`](../../core/dr-catalog/src/cache.rs#L225), [`core/dr-sync-folder/src/borrow.rs:1`](../../core/dr-sync-folder/src/borrow.rs#L1), [`core/dr-sync-folder/src/lib.rs:197`](../../core/dr-sync-folder/src/lib.rs#L197), [`core/dr-sync-folder/src/lib.rs:73`](../../core/dr-sync-folder/src/lib.rs#L73), [`core/dr-sync-folder/src/lib.rs:818`](../../core/dr-sync-folder/src/lib.rs#L818), [`core/dr-sync-folder/src/lib.rs:857`](../../core/dr-sync-folder/src/lib.rs#L857), [`core/dr-sync-folder/src/vfs.rs:1`](../../core/dr-sync-folder/src/vfs.rs#L1), [`core/dr-sync-nextcloud/src/desktop_client.rs:172`](../../core/dr-sync-nextcloud/src/desktop_client.rs#L172), [`core/dr-sync-nextcloud/src/desktop_client.rs:35`](../../core/dr-sync-nextcloud/src/desktop_client.rs#L35), [`core/dr-sync/src/capability.rs:41`](../../core/dr-sync/src/capability.rs#L41), [`core/dr-sync/src/error.rs:39`](../../core/dr-sync/src/error.rs#L39), [`core/dr-sync/src/lib.rs:158`](../../core/dr-sync/src/lib.rs#L158), [`core/dr-sync/src/types.rs:101`](../../core/dr-sync/src/types.rs#L101), [`core/dr-types/src/lib.rs:122`](../../core/dr-types/src/lib.rs#L122), [`core/dr-types/src/lib.rs:204`](../../core/dr-types/src/lib.rs#L204), [`ui/dr-ui/src/activity.rs:1`](../../ui/dr-ui/src/activity.rs#L1), [`ui/dr-ui/src/collections_ui/tree_sync.rs:111`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L111), [`ui/dr-ui/src/collections_ui/tree_sync.rs:387`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L387), [`ui/dr-ui/src/collections_ui/tree_sync.rs:38`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L38), [`ui/dr-ui/src/derived_sync.rs:1042`](../../ui/dr-ui/src/derived_sync.rs#L1042), [`ui/dr-ui/src/derived_sync.rs:642`](../../ui/dr-ui/src/derived_sync.rs#L642), [`ui/dr-ui/src/library/sidecar.rs:531`](../../ui/dr-ui/src/library/sidecar.rs#L531), [`ui/dr-ui/src/library/sweep.rs:677`](../../ui/dr-ui/src/library/sweep.rs#L677), [`ui/dr-ui/src/library/thumbnails_fetch.rs:215`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L215), [`ui/dr-ui/src/library/thumbnails_fetch.rs:305`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L305), [`ui/dr-ui/src/library_ui/offline.rs:20`](../../ui/dr-ui/src/library_ui/offline.rs#L20), [`ui/dr-ui/src/library_ui/offline.rs:310`](../../ui/dr-ui/src/library_ui/offline.rs#L310), [`ui/dr-ui/src/library_ui/offline.rs:93`](../../ui/dr-ui/src/library_ui/offline.rs#L93), [`ui/dr-ui/src/remote.rs:40`](../../ui/dr-ui/src/remote.rs#L40), [`ui/dr-ui/src/repairs.rs:1140`](../../ui/dr-ui/src/repairs.rs#L1140), [`ui/dr-ui/ui/collections.slint:272`](../../ui/dr-ui/ui/collections.slint#L272), [`ui/dr-ui/ui/collections.slint:877`](../../ui/dr-ui/ui/collections.slint#L877), [`ui/dr-ui/ui/icons.slint:262`](../../ui/dr-ui/ui/icons.slint#L262) | +| FR-NC-6c | [`core/dr-catalog/src/cache.rs:225`](../../core/dr-catalog/src/cache.rs#L225), [`core/dr-sync-folder/src/borrow.rs:1`](../../core/dr-sync-folder/src/borrow.rs#L1), [`core/dr-sync-folder/src/lib.rs:197`](../../core/dr-sync-folder/src/lib.rs#L197), [`core/dr-sync-folder/src/lib.rs:73`](../../core/dr-sync-folder/src/lib.rs#L73), [`core/dr-sync-folder/src/lib.rs:818`](../../core/dr-sync-folder/src/lib.rs#L818), [`core/dr-sync-folder/src/lib.rs:857`](../../core/dr-sync-folder/src/lib.rs#L857), [`core/dr-sync-folder/src/vfs.rs:1`](../../core/dr-sync-folder/src/vfs.rs#L1), [`core/dr-sync-nextcloud/src/desktop_client.rs:172`](../../core/dr-sync-nextcloud/src/desktop_client.rs#L172), [`core/dr-sync-nextcloud/src/desktop_client.rs:35`](../../core/dr-sync-nextcloud/src/desktop_client.rs#L35), [`core/dr-sync/src/capability.rs:41`](../../core/dr-sync/src/capability.rs#L41), [`core/dr-sync/src/error.rs:39`](../../core/dr-sync/src/error.rs#L39), [`core/dr-sync/src/lib.rs:158`](../../core/dr-sync/src/lib.rs#L158), [`core/dr-sync/src/types.rs:101`](../../core/dr-sync/src/types.rs#L101), [`core/dr-types/src/lib.rs:122`](../../core/dr-types/src/lib.rs#L122), [`core/dr-types/src/lib.rs:204`](../../core/dr-types/src/lib.rs#L204), [`ui/dr-ui/src/activity.rs:1`](../../ui/dr-ui/src/activity.rs#L1), [`ui/dr-ui/src/collections_ui/tree_sync.rs:111`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L111), [`ui/dr-ui/src/collections_ui/tree_sync.rs:387`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L387), [`ui/dr-ui/src/collections_ui/tree_sync.rs:38`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L38), [`ui/dr-ui/src/derived_sync.rs:1053`](../../ui/dr-ui/src/derived_sync.rs#L1053), [`ui/dr-ui/src/derived_sync.rs:652`](../../ui/dr-ui/src/derived_sync.rs#L652), [`ui/dr-ui/src/library/sidecar.rs:531`](../../ui/dr-ui/src/library/sidecar.rs#L531), [`ui/dr-ui/src/library/sweep.rs:677`](../../ui/dr-ui/src/library/sweep.rs#L677), [`ui/dr-ui/src/library/thumbnails_fetch.rs:215`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L215), [`ui/dr-ui/src/library/thumbnails_fetch.rs:305`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L305), [`ui/dr-ui/src/library_ui/offline.rs:20`](../../ui/dr-ui/src/library_ui/offline.rs#L20), [`ui/dr-ui/src/library_ui/offline.rs:310`](../../ui/dr-ui/src/library_ui/offline.rs#L310), [`ui/dr-ui/src/library_ui/offline.rs:93`](../../ui/dr-ui/src/library_ui/offline.rs#L93), [`ui/dr-ui/src/remote.rs:40`](../../ui/dr-ui/src/remote.rs#L40), [`ui/dr-ui/src/repairs.rs:1140`](../../ui/dr-ui/src/repairs.rs#L1140), [`ui/dr-ui/ui/collections.slint:272`](../../ui/dr-ui/ui/collections.slint#L272), [`ui/dr-ui/ui/collections.slint:877`](../../ui/dr-ui/ui/collections.slint#L877), [`ui/dr-ui/ui/icons.slint:262`](../../ui/dr-ui/ui/icons.slint#L262) | | FR-NC-6d | [`core/dr-sync-folder/src/borrow.rs:1`](../../core/dr-sync-folder/src/borrow.rs#L1), [`core/dr-sync-folder/src/lib.rs:1`](../../core/dr-sync-folder/src/lib.rs#L1), [`core/dr-sync-folder/src/vfs.rs:1`](../../core/dr-sync-folder/src/vfs.rs#L1) | -| FR-NC-7 | [`core/dr-catalog/src/face_shard.rs:1`](../../core/dr-catalog/src/face_shard.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:120`](../../core/dr-sync-nextcloud/src/lib.rs#L120), [`ui/dr-ui/src/derived_sync.rs:1`](../../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/library/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/sync.rs:368`](../../ui/dr-ui/src/library_ui/sync.rs#L368), [`ui/dr-ui/ui/settings.slint:435`](../../ui/dr-ui/ui/settings.slint#L435) | +| FR-NC-7 | [`core/dr-catalog/src/face_shard.rs:1`](../../core/dr-catalog/src/face_shard.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:120`](../../core/dr-sync-nextcloud/src/lib.rs#L120), [`ui/dr-ui/src/derived_sync.rs:1`](../../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/library/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/sync.rs:385`](../../ui/dr-ui/src/library_ui/sync.rs#L385), [`ui/dr-ui/ui/settings.slint:435`](../../ui/dr-ui/ui/settings.slint#L435) | | FR-NC-7a | [`core/dr-ingest/src/layout.rs:1`](../../core/dr-ingest/src/layout.rs#L1), [`core/dr-sync/src/upload.rs:1`](../../core/dr-sync/src/upload.rs#L1), [`core/dr-sync/src/upload.rs:40`](../../core/dr-sync/src/upload.rs#L40), [`core/dr-types/src/settings.rs:377`](../../core/dr-types/src/settings.rs#L377), [`ui/dr-ui/src/import.rs:1`](../../ui/dr-ui/src/import.rs#L1), [`ui/dr-ui/src/import.rs:97`](../../ui/dr-ui/src/import.rs#L97), [`ui/dr-ui/src/import_ui.rs:1`](../../ui/dr-ui/src/import_ui.rs#L1), [`ui/dr-ui/src/lib.rs:1791`](../../ui/dr-ui/src/lib.rs#L1791), [`ui/dr-ui/ui/import.slint:5`](../../ui/dr-ui/ui/import.slint#L5) | | FR-NC-7b | [`core/dr-ingest/src/lib.rs:733`](../../core/dr-ingest/src/lib.rs#L733), [`core/dr-sync/src/upload.rs:1`](../../core/dr-sync/src/upload.rs#L1), [`ui/dr-ui/src/import.rs:122`](../../ui/dr-ui/src/import.rs#L122), [`ui/dr-ui/src/import.rs:336`](../../ui/dr-ui/src/import.rs#L336), [`ui/dr-ui/src/import.rs:584`](../../ui/dr-ui/src/import.rs#L584), [`ui/dr-ui/src/import.rs:97`](../../ui/dr-ui/src/import.rs#L97), [`ui/dr-ui/src/import_ui.rs:1`](../../ui/dr-ui/src/import_ui.rs#L1), [`ui/dr-ui/src/lib.rs:1791`](../../ui/dr-ui/src/lib.rs#L1791) | | FR-NC-8 | [`core/dr-catalog/src/rating.rs:204`](../../core/dr-catalog/src/rating.rs#L204), [`core/dr-catalog/src/rating.rs:66`](../../core/dr-catalog/src/rating.rs#L66), [`core/dr-catalog/src/rating.rs:929`](../../core/dr-catalog/src/rating.rs#L929), [`core/dr-catalog/src/schema.rs:327`](../../core/dr-catalog/src/schema.rs#L327), [`core/dr-pipeline/src/sidecar.rs:137`](../../core/dr-pipeline/src/sidecar.rs#L137), [`core/dr-pipeline/src/sidecar.rs:2991`](../../core/dr-pipeline/src/sidecar.rs#L2991), [`core/dr-pipeline/src/sidecar.rs:660`](../../core/dr-pipeline/src/sidecar.rs#L660), [`core/dr-pipeline/src/sidecar.rs:735`](../../core/dr-pipeline/src/sidecar.rs#L735), [`core/dr-pipeline/src/sidecar.rs:96`](../../core/dr-pipeline/src/sidecar.rs#L96), [`ui/dr-ui/src/lib.rs:2692`](../../ui/dr-ui/src/lib.rs#L2692), [`ui/dr-ui/src/library/sidecar.rs:11`](../../ui/dr-ui/src/library/sidecar.rs#L11), [`ui/dr-ui/src/library/sidecar.rs:271`](../../ui/dr-ui/src/library/sidecar.rs#L271), [`ui/dr-ui/src/library/sidecar.rs:573`](../../ui/dr-ui/src/library/sidecar.rs#L573), [`ui/dr-ui/src/library/thumbnails_fetch.rs:504`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L504), [`ui/dr-ui/src/library_ui/controller.rs:625`](../../ui/dr-ui/src/library_ui/controller.rs#L625), [`ui/dr-ui/src/presets.rs:288`](../../ui/dr-ui/src/presets.rs#L288), [`ui/dr-ui/src/presets.rs:336`](../../ui/dr-ui/src/presets.rs#L336) | -| FR-NC-9 | [`core/dr-catalog/src/merge.rs:1`](../../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/rating.rs:204`](../../core/dr-catalog/src/rating.rs#L204), [`core/dr-catalog/src/rating.rs:66`](../../core/dr-catalog/src/rating.rs#L66), [`core/dr-catalog/src/rating.rs:929`](../../core/dr-catalog/src/rating.rs#L929), [`core/dr-catalog/src/schema.rs:1125`](../../core/dr-catalog/src/schema.rs#L1125), [`core/dr-catalog/src/schema.rs:327`](../../core/dr-catalog/src/schema.rs#L327), [`core/dr-catalog/src/schema.rs:740`](../../core/dr-catalog/src/schema.rs#L740), [`core/dr-catalog/src/sync.rs:1`](../../core/dr-catalog/src/sync.rs#L1), [`core/dr-pipeline/src/sidecar.rs:192`](../../core/dr-pipeline/src/sidecar.rs#L192), [`core/dr-pipeline/src/sidecar.rs:219`](../../core/dr-pipeline/src/sidecar.rs#L219), [`core/dr-pipeline/src/sidecar.rs:2520`](../../core/dr-pipeline/src/sidecar.rs#L2520), [`core/dr-pipeline/src/sidecar.rs:2757`](../../core/dr-pipeline/src/sidecar.rs#L2757), [`core/dr-pipeline/src/sidecar.rs:2991`](../../core/dr-pipeline/src/sidecar.rs#L2991), [`core/dr-pipeline/src/sidecar.rs:395`](../../core/dr-pipeline/src/sidecar.rs#L395), [`core/dr-pipeline/src/sidecar.rs:493`](../../core/dr-pipeline/src/sidecar.rs#L493), [`core/dr-pipeline/src/sidecar.rs:660`](../../core/dr-pipeline/src/sidecar.rs#L660), [`core/dr-pipeline/src/sidecar.rs:710`](../../core/dr-pipeline/src/sidecar.rs#L710), [`core/dr-pipeline/src/sidecar.rs:735`](../../core/dr-pipeline/src/sidecar.rs#L735), [`core/dr-pipeline/src/spot.rs:245`](../../core/dr-pipeline/src/spot.rs#L245), [`core/dr-pipeline/tests/mask_sidecar.rs:1075`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1075), [`core/dr-pipeline/tests/spot_sidecar.rs:1`](../../core/dr-pipeline/tests/spot_sidecar.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:139`](../../core/dr-sync-nextcloud/src/lib.rs#L139), [`core/dr-sync/src/scan.rs:31`](../../core/dr-sync/src/scan.rs#L31), [`core/dr-sync/src/scan.rs:56`](../../core/dr-sync/src/scan.rs#L56), [`core/dr-sync/src/scan.rs:926`](../../core/dr-sync/src/scan.rs#L926), [`core/dr-xmp/src/lib.rs:733`](../../core/dr-xmp/src/lib.rs#L733), [`core/dr-xmp/src/lib.rs:746`](../../core/dr-xmp/src/lib.rs#L746), [`ui/dr-ui/src/derived_sync.rs:1070`](../../ui/dr-ui/src/derived_sync.rs#L1070), [`ui/dr-ui/src/derived_sync.rs:613`](../../ui/dr-ui/src/derived_sync.rs#L613), [`ui/dr-ui/src/derived_sync.rs:642`](../../ui/dr-ui/src/derived_sync.rs#L642), [`ui/dr-ui/src/derived_sync.rs:675`](../../ui/dr-ui/src/derived_sync.rs#L675), [`ui/dr-ui/src/derived_sync.rs:821`](../../ui/dr-ui/src/derived_sync.rs#L821), [`ui/dr-ui/src/library/scan.rs:226`](../../ui/dr-ui/src/library/scan.rs#L226), [`ui/dr-ui/src/library/scan.rs:261`](../../ui/dr-ui/src/library/scan.rs#L261), [`ui/dr-ui/src/library/scan.rs:34`](../../ui/dr-ui/src/library/scan.rs#L34), [`ui/dr-ui/src/library/sidecar.rs:271`](../../ui/dr-ui/src/library/sidecar.rs#L271), [`ui/dr-ui/src/library/sidecar.rs:343`](../../ui/dr-ui/src/library/sidecar.rs#L343), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/sidecar.rs:573`](../../ui/dr-ui/src/library/sidecar.rs#L573), [`ui/dr-ui/src/library/sidecar.rs:593`](../../ui/dr-ui/src/library/sidecar.rs#L593), [`ui/dr-ui/src/library/thumbnails_fetch.rs:504`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L504), [`ui/dr-ui/src/library_ui/open.rs:455`](../../ui/dr-ui/src/library_ui/open.rs#L455), [`ui/dr-ui/src/presets.rs:288`](../../ui/dr-ui/src/presets.rs#L288), [`ui/dr-ui/src/presets.rs:336`](../../ui/dr-ui/src/presets.rs#L336), [`ui/dr-ui/src/xmp_sync.rs:1`](../../ui/dr-ui/src/xmp_sync.rs#L1), [`ui/dr-ui/src/xmp_sync.rs:287`](../../ui/dr-ui/src/xmp_sync.rs#L287) | -| FR-PLAT-AND-2 | [`core/dr-catalog/src/walk.rs:1022`](../../core/dr-catalog/src/walk.rs#L1022), [`core/dr-catalog/src/walk.rs:435`](../../core/dr-catalog/src/walk.rs#L435), [`core/dr-sync-folder/src/lib.rs:242`](../../core/dr-sync-folder/src/lib.rs#L242), [`core/dr-sync-folder/src/tests.rs:51`](../../core/dr-sync-folder/src/tests.rs#L51), [`core/dr-sync/src/error.rs:113`](../../core/dr-sync/src/error.rs#L113), [`core/dr-sync/src/error.rs:195`](../../core/dr-sync/src/error.rs#L195), [`core/dr-sync/src/scan.rs:211`](../../core/dr-sync/src/scan.rs#L211), [`core/dr-sync/src/scan.rs:519`](../../core/dr-sync/src/scan.rs#L519), [`core/dr-sync/src/scan.rs:545`](../../core/dr-sync/src/scan.rs#L545), [`core/dr-sync/src/scan.rs:574`](../../core/dr-sync/src/scan.rs#L574), [`ui/dr-ui/src/library/scan.rs:126`](../../ui/dr-ui/src/library/scan.rs#L126), [`ui/dr-ui/src/library/scan.rs:179`](../../ui/dr-ui/src/library/scan.rs#L179), [`ui/dr-ui/src/library/scan.rs:210`](../../ui/dr-ui/src/library/scan.rs#L210), [`ui/dr-ui/src/library/scan.rs:605`](../../ui/dr-ui/src/library/scan.rs#L605), [`ui/dr-ui/src/library_ui/controller.rs:323`](../../ui/dr-ui/src/library_ui/controller.rs#L323), [`ui/dr-ui/src/library_ui/controller.rs:568`](../../ui/dr-ui/src/library_ui/controller.rs#L568), [`ui/dr-ui/src/library_ui/offline.rs:569`](../../ui/dr-ui/src/library_ui/offline.rs#L569), [`ui/dr-ui/src/library_ui/open.rs:426`](../../ui/dr-ui/src/library_ui/open.rs#L426), [`ui/dr-ui/src/library_ui/open.rs:524`](../../ui/dr-ui/src/library_ui/open.rs#L524) | +| FR-NC-9 | [`core/dr-catalog/src/merge.rs:1`](../../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/rating.rs:204`](../../core/dr-catalog/src/rating.rs#L204), [`core/dr-catalog/src/rating.rs:66`](../../core/dr-catalog/src/rating.rs#L66), [`core/dr-catalog/src/rating.rs:929`](../../core/dr-catalog/src/rating.rs#L929), [`core/dr-catalog/src/schema.rs:1125`](../../core/dr-catalog/src/schema.rs#L1125), [`core/dr-catalog/src/schema.rs:327`](../../core/dr-catalog/src/schema.rs#L327), [`core/dr-catalog/src/schema.rs:740`](../../core/dr-catalog/src/schema.rs#L740), [`core/dr-catalog/src/sync.rs:1`](../../core/dr-catalog/src/sync.rs#L1), [`core/dr-pipeline/src/sidecar.rs:192`](../../core/dr-pipeline/src/sidecar.rs#L192), [`core/dr-pipeline/src/sidecar.rs:219`](../../core/dr-pipeline/src/sidecar.rs#L219), [`core/dr-pipeline/src/sidecar.rs:2520`](../../core/dr-pipeline/src/sidecar.rs#L2520), [`core/dr-pipeline/src/sidecar.rs:2757`](../../core/dr-pipeline/src/sidecar.rs#L2757), [`core/dr-pipeline/src/sidecar.rs:2991`](../../core/dr-pipeline/src/sidecar.rs#L2991), [`core/dr-pipeline/src/sidecar.rs:395`](../../core/dr-pipeline/src/sidecar.rs#L395), [`core/dr-pipeline/src/sidecar.rs:493`](../../core/dr-pipeline/src/sidecar.rs#L493), [`core/dr-pipeline/src/sidecar.rs:660`](../../core/dr-pipeline/src/sidecar.rs#L660), [`core/dr-pipeline/src/sidecar.rs:710`](../../core/dr-pipeline/src/sidecar.rs#L710), [`core/dr-pipeline/src/sidecar.rs:735`](../../core/dr-pipeline/src/sidecar.rs#L735), [`core/dr-pipeline/src/spot.rs:245`](../../core/dr-pipeline/src/spot.rs#L245), [`core/dr-pipeline/tests/mask_sidecar.rs:1075`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1075), [`core/dr-pipeline/tests/spot_sidecar.rs:1`](../../core/dr-pipeline/tests/spot_sidecar.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:139`](../../core/dr-sync-nextcloud/src/lib.rs#L139), [`core/dr-sync/src/scan.rs:31`](../../core/dr-sync/src/scan.rs#L31), [`core/dr-sync/src/scan.rs:56`](../../core/dr-sync/src/scan.rs#L56), [`core/dr-sync/src/scan.rs:926`](../../core/dr-sync/src/scan.rs#L926), [`core/dr-xmp/src/lib.rs:733`](../../core/dr-xmp/src/lib.rs#L733), [`core/dr-xmp/src/lib.rs:746`](../../core/dr-xmp/src/lib.rs#L746), [`ui/dr-ui/src/derived_sync.rs:1081`](../../ui/dr-ui/src/derived_sync.rs#L1081), [`ui/dr-ui/src/derived_sync.rs:623`](../../ui/dr-ui/src/derived_sync.rs#L623), [`ui/dr-ui/src/derived_sync.rs:652`](../../ui/dr-ui/src/derived_sync.rs#L652), [`ui/dr-ui/src/derived_sync.rs:685`](../../ui/dr-ui/src/derived_sync.rs#L685), [`ui/dr-ui/src/derived_sync.rs:832`](../../ui/dr-ui/src/derived_sync.rs#L832), [`ui/dr-ui/src/library/scan.rs:226`](../../ui/dr-ui/src/library/scan.rs#L226), [`ui/dr-ui/src/library/scan.rs:261`](../../ui/dr-ui/src/library/scan.rs#L261), [`ui/dr-ui/src/library/scan.rs:34`](../../ui/dr-ui/src/library/scan.rs#L34), [`ui/dr-ui/src/library/sidecar.rs:271`](../../ui/dr-ui/src/library/sidecar.rs#L271), [`ui/dr-ui/src/library/sidecar.rs:343`](../../ui/dr-ui/src/library/sidecar.rs#L343), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/sidecar.rs:573`](../../ui/dr-ui/src/library/sidecar.rs#L573), [`ui/dr-ui/src/library/sidecar.rs:593`](../../ui/dr-ui/src/library/sidecar.rs#L593), [`ui/dr-ui/src/library/thumbnails_fetch.rs:504`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L504), [`ui/dr-ui/src/library_ui/open.rs:455`](../../ui/dr-ui/src/library_ui/open.rs#L455), [`ui/dr-ui/src/presets.rs:288`](../../ui/dr-ui/src/presets.rs#L288), [`ui/dr-ui/src/presets.rs:336`](../../ui/dr-ui/src/presets.rs#L336), [`ui/dr-ui/src/xmp_sync.rs:1`](../../ui/dr-ui/src/xmp_sync.rs#L1), [`ui/dr-ui/src/xmp_sync.rs:287`](../../ui/dr-ui/src/xmp_sync.rs#L287) | +| FR-PLAT-AND-2 | [`core/dr-catalog/src/walk.rs:1022`](../../core/dr-catalog/src/walk.rs#L1022), [`core/dr-catalog/src/walk.rs:435`](../../core/dr-catalog/src/walk.rs#L435), [`core/dr-sync-folder/src/lib.rs:242`](../../core/dr-sync-folder/src/lib.rs#L242), [`core/dr-sync-folder/src/tests.rs:51`](../../core/dr-sync-folder/src/tests.rs#L51), [`core/dr-sync/src/error.rs:113`](../../core/dr-sync/src/error.rs#L113), [`core/dr-sync/src/error.rs:195`](../../core/dr-sync/src/error.rs#L195), [`core/dr-sync/src/scan.rs:211`](../../core/dr-sync/src/scan.rs#L211), [`core/dr-sync/src/scan.rs:519`](../../core/dr-sync/src/scan.rs#L519), [`core/dr-sync/src/scan.rs:545`](../../core/dr-sync/src/scan.rs#L545), [`core/dr-sync/src/scan.rs:574`](../../core/dr-sync/src/scan.rs#L574), [`ui/dr-ui/src/library/scan.rs:126`](../../ui/dr-ui/src/library/scan.rs#L126), [`ui/dr-ui/src/library/scan.rs:179`](../../ui/dr-ui/src/library/scan.rs#L179), [`ui/dr-ui/src/library/scan.rs:210`](../../ui/dr-ui/src/library/scan.rs#L210), [`ui/dr-ui/src/library/scan.rs:605`](../../ui/dr-ui/src/library/scan.rs#L605), [`ui/dr-ui/src/library_ui/controller.rs:323`](../../ui/dr-ui/src/library_ui/controller.rs#L323), [`ui/dr-ui/src/library_ui/controller.rs:568`](../../ui/dr-ui/src/library_ui/controller.rs#L568), [`ui/dr-ui/src/library_ui/offline.rs:569`](../../ui/dr-ui/src/library_ui/offline.rs#L569), [`ui/dr-ui/src/library_ui/open.rs:426`](../../ui/dr-ui/src/library_ui/open.rs#L426), [`ui/dr-ui/src/library_ui/open.rs:533`](../../ui/dr-ui/src/library_ui/open.rs#L533) | | FR-PLAT-AND-3 | [`core/dr-catalog/src/jobs.rs:1`](../../core/dr-catalog/src/jobs.rs#L1), [`core/dr-catalog/src/runner.rs:1`](../../core/dr-catalog/src/runner.rs#L1) | | FR-PLAT-AND-4 | [`core/dr-catalog/src/runner.rs:1`](../../core/dr-catalog/src/runner.rs#L1) | | FR-PLAT-AND-5 | [`apps/darkroom-android/src/lib.rs:166`](../../apps/darkroom-android/src/lib.rs#L166), [`core/dr-gpu/src/adjust.rs:1057`](../../core/dr-gpu/src/adjust.rs#L1057), [`core/dr-gpu/src/detail.rs:161`](../../core/dr-gpu/src/detail.rs#L161), [`core/dr-gpu/src/detail.rs:547`](../../core/dr-gpu/src/detail.rs#L547), [`core/dr-gpu/tests/detail_stage.rs:417`](../../core/dr-gpu/tests/detail_stage.rs#L417), [`ui/dr-ui/src/develop/render.rs:519`](../../ui/dr-ui/src/develop/render.rs#L519), [`ui/dr-ui/src/identity_ui.rs:125`](../../ui/dr-ui/src/identity_ui.rs#L125), [`ui/dr-ui/src/lib.rs:1218`](../../ui/dr-ui/src/lib.rs#L1218), [`ui/dr-ui/src/lib.rs:1600`](../../ui/dr-ui/src/lib.rs#L1600), [`ui/dr-ui/src/memory.rs:163`](../../ui/dr-ui/src/memory.rs#L163), [`ui/dr-ui/src/memory.rs:1`](../../ui/dr-ui/src/memory.rs#L1) | @@ -149,7 +150,7 @@ A tag naming an ID `requirements.md` does not define — what renumbering produc | FR-UI-5 | [`ui/dr-ui/src/collections_ui/mod.rs:1`](../../ui/dr-ui/src/collections_ui/mod.rs#L1), [`ui/dr-ui/src/develop_ui.rs:857`](../../ui/dr-ui/src/develop_ui.rs#L857), [`ui/dr-ui/src/lib.rs:3396`](../../ui/dr-ui/src/lib.rs#L3396), [`ui/dr-ui/src/lib.rs:3603`](../../ui/dr-ui/src/lib.rs#L3603), [`ui/dr-ui/src/masks_ui.rs:1584`](../../ui/dr-ui/src/masks_ui.rs#L1584), [`ui/dr-ui/ui/app.slint:2260`](../../ui/dr-ui/ui/app.slint#L2260), [`ui/dr-ui/ui/app.slint:2300`](../../ui/dr-ui/ui/app.slint#L2300), [`ui/dr-ui/ui/collections.slint:4`](../../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/session.slint:75`](../../ui/dr-ui/ui/session.slint#L75) | | FR-UI-6 | [`ui/dr-ui/ui/widgets.slint:1`](../../ui/dr-ui/ui/widgets.slint#L1) | | FR-UI-7 | [`core/dr-pipeline/src/descriptor.rs:195`](../../core/dr-pipeline/src/descriptor.rs#L195), [`core/dr-pipeline/src/framing.rs:395`](../../core/dr-pipeline/src/framing.rs#L395), [`core/dr-types/src/settings.rs:492`](../../core/dr-types/src/settings.rs#L492), [`ui/dr-ui/src/develop/rows.rs:118`](../../ui/dr-ui/src/develop/rows.rs#L118), [`ui/dr-ui/src/lib.rs:3221`](../../ui/dr-ui/src/lib.rs#L3221), [`ui/dr-ui/ui/adjust.slint:974`](../../ui/dr-ui/ui/adjust.slint#L974), [`ui/dr-ui/ui/app.slint:2017`](../../ui/dr-ui/ui/app.slint#L2017), [`ui/dr-ui/ui/settings.slint:681`](../../ui/dr-ui/ui/settings.slint#L681), [`ui/dr-ui/ui/toolrail.slint:89`](../../ui/dr-ui/ui/toolrail.slint#L89) | -| FR-UI-8 | [`core/dr-catalog/src/collections.rs:654`](../../core/dr-catalog/src/collections.rs#L654), [`core/dr-catalog/src/collections.rs:675`](../../core/dr-catalog/src/collections.rs#L675), [`core/dr-types/src/place.rs:1`](../../core/dr-types/src/place.rs#L1), [`ui/dr-ui/src/derived_sync.rs:216`](../../ui/dr-ui/src/derived_sync.rs#L216), [`ui/dr-ui/src/derived_sync.rs:81`](../../ui/dr-ui/src/derived_sync.rs#L81), [`ui/dr-ui/src/derived_sync.rs:894`](../../ui/dr-ui/src/derived_sync.rs#L894), [`ui/dr-ui/src/derived_sync.rs:904`](../../ui/dr-ui/src/derived_sync.rs#L904), [`ui/dr-ui/src/derived_sync.rs:986`](../../ui/dr-ui/src/derived_sync.rs#L986), [`ui/dr-ui/src/library/cells.rs:274`](../../ui/dr-ui/src/library/cells.rs#L274), [`ui/dr-ui/src/library/cells.rs:553`](../../ui/dr-ui/src/library/cells.rs#L553), [`ui/dr-ui/src/library/cells.rs:619`](../../ui/dr-ui/src/library/cells.rs#L619), [`ui/dr-ui/src/library/paths.rs:22`](../../ui/dr-ui/src/library/paths.rs#L22), [`ui/dr-ui/src/library_ui/controller.rs:189`](../../ui/dr-ui/src/library_ui/controller.rs#L189), [`ui/dr-ui/src/library_ui/controller.rs:924`](../../ui/dr-ui/src/library_ui/controller.rs#L924), [`ui/dr-ui/src/library_ui/filter_bar.rs:671`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L671), [`ui/dr-ui/src/library_ui/grid.rs:205`](../../ui/dr-ui/src/library_ui/grid.rs#L205), [`ui/dr-ui/src/library_ui/grid.rs:247`](../../ui/dr-ui/src/library_ui/grid.rs#L247), [`ui/dr-ui/src/library_ui/grid.rs:276`](../../ui/dr-ui/src/library_ui/grid.rs#L276), [`ui/dr-ui/src/library_ui/grid.rs:582`](../../ui/dr-ui/src/library_ui/grid.rs#L582), [`ui/dr-ui/src/library_ui/grid.rs:708`](../../ui/dr-ui/src/library_ui/grid.rs#L708), [`ui/dr-ui/src/library_ui/open.rs:118`](../../ui/dr-ui/src/library_ui/open.rs#L118), [`ui/dr-ui/src/library_ui/open.rs:36`](../../ui/dr-ui/src/library_ui/open.rs#L36), [`ui/dr-ui/src/library_ui/open.rs:71`](../../ui/dr-ui/src/library_ui/open.rs#L71), [`ui/dr-ui/src/library_ui/open.rs:827`](../../ui/dr-ui/src/library_ui/open.rs#L827), [`ui/dr-ui/src/library_ui/open.rs:844`](../../ui/dr-ui/src/library_ui/open.rs#L844), [`ui/dr-ui/src/library_ui/open.rs:942`](../../ui/dr-ui/src/library_ui/open.rs#L942), [`ui/dr-ui/src/place.rs:1`](../../ui/dr-ui/src/place.rs#L1) | +| FR-UI-8 | [`core/dr-catalog/src/collections.rs:654`](../../core/dr-catalog/src/collections.rs#L654), [`core/dr-catalog/src/collections.rs:675`](../../core/dr-catalog/src/collections.rs#L675), [`core/dr-types/src/place.rs:1`](../../core/dr-types/src/place.rs#L1), [`ui/dr-ui/src/derived_sync.rs:226`](../../ui/dr-ui/src/derived_sync.rs#L226), [`ui/dr-ui/src/derived_sync.rs:84`](../../ui/dr-ui/src/derived_sync.rs#L84), [`ui/dr-ui/src/derived_sync.rs:905`](../../ui/dr-ui/src/derived_sync.rs#L905), [`ui/dr-ui/src/derived_sync.rs:915`](../../ui/dr-ui/src/derived_sync.rs#L915), [`ui/dr-ui/src/derived_sync.rs:997`](../../ui/dr-ui/src/derived_sync.rs#L997), [`ui/dr-ui/src/library/cells.rs:274`](../../ui/dr-ui/src/library/cells.rs#L274), [`ui/dr-ui/src/library/cells.rs:553`](../../ui/dr-ui/src/library/cells.rs#L553), [`ui/dr-ui/src/library/cells.rs:619`](../../ui/dr-ui/src/library/cells.rs#L619), [`ui/dr-ui/src/library/paths.rs:22`](../../ui/dr-ui/src/library/paths.rs#L22), [`ui/dr-ui/src/library_ui/controller.rs:189`](../../ui/dr-ui/src/library_ui/controller.rs#L189), [`ui/dr-ui/src/library_ui/controller.rs:924`](../../ui/dr-ui/src/library_ui/controller.rs#L924), [`ui/dr-ui/src/library_ui/filter_bar.rs:671`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L671), [`ui/dr-ui/src/library_ui/grid.rs:205`](../../ui/dr-ui/src/library_ui/grid.rs#L205), [`ui/dr-ui/src/library_ui/grid.rs:247`](../../ui/dr-ui/src/library_ui/grid.rs#L247), [`ui/dr-ui/src/library_ui/grid.rs:276`](../../ui/dr-ui/src/library_ui/grid.rs#L276), [`ui/dr-ui/src/library_ui/grid.rs:582`](../../ui/dr-ui/src/library_ui/grid.rs#L582), [`ui/dr-ui/src/library_ui/grid.rs:708`](../../ui/dr-ui/src/library_ui/grid.rs#L708), [`ui/dr-ui/src/library_ui/open.rs:118`](../../ui/dr-ui/src/library_ui/open.rs#L118), [`ui/dr-ui/src/library_ui/open.rs:36`](../../ui/dr-ui/src/library_ui/open.rs#L36), [`ui/dr-ui/src/library_ui/open.rs:71`](../../ui/dr-ui/src/library_ui/open.rs#L71), [`ui/dr-ui/src/library_ui/open.rs:836`](../../ui/dr-ui/src/library_ui/open.rs#L836), [`ui/dr-ui/src/library_ui/open.rs:853`](../../ui/dr-ui/src/library_ui/open.rs#L853), [`ui/dr-ui/src/library_ui/open.rs:951`](../../ui/dr-ui/src/library_ui/open.rs#L951), [`ui/dr-ui/src/place.rs:1`](../../ui/dr-ui/src/place.rs#L1) | | NFR-A11Y-2 | [`ui/dr-ui/tests/ui_controls_are_accessible.rs:1`](../../ui/dr-ui/tests/ui_controls_are_accessible.rs#L1), [`ui/dr-ui/ui/adjust.slint:171`](../../ui/dr-ui/ui/adjust.slint#L171), [`ui/dr-ui/ui/app.slint:2433`](../../ui/dr-ui/ui/app.slint#L2433), [`ui/dr-ui/ui/app.slint:2471`](../../ui/dr-ui/ui/app.slint#L2471) | | NFR-A11Y-3 | [`ui/dr-ui/src/histogram.rs:356`](../../ui/dr-ui/src/histogram.rs#L356), [`ui/dr-ui/ui/histogram.slint:137`](../../ui/dr-ui/ui/histogram.slint#L137), [`ui/dr-ui/ui/library.slint:1031`](../../ui/dr-ui/ui/library.slint#L1031), [`ui/dr-ui/ui/library.slint:1179`](../../ui/dr-ui/ui/library.slint#L1179), [`ui/dr-ui/ui/peaking.slint:1`](../../ui/dr-ui/ui/peaking.slint#L1) | | NFR-ARCH-2 | [`core/dr-catalog/src/jobs.rs:1`](../../core/dr-catalog/src/jobs.rs#L1), [`ui/dr-ui/src/faces.rs:1`](../../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1) | @@ -169,7 +170,7 @@ A tag naming an ID `requirements.md` does not define — what renumbering produc | NFR-PORT-2 | [`core/dr-gpu/src/lib.rs:1`](../../core/dr-gpu/src/lib.rs#L1) | | NFR-PORT-3 | [`platform/dr-plat/src/storage.rs:1`](../../platform/dr-plat/src/storage.rs#L1) | | NFR-R1 | [`core/dr-catalog/src/schema.rs:361`](../../core/dr-catalog/src/schema.rs#L361), [`core/dr-catalog/src/sync.rs:1`](../../core/dr-catalog/src/sync.rs#L1), [`core/dr-gpu/src/lib.rs:194`](../../core/dr-gpu/src/lib.rs#L194), [`core/dr-sync/src/account.rs:240`](../../core/dr-sync/src/account.rs#L240), [`ui/dr-ui/src/library/paths.rs:69`](../../ui/dr-ui/src/library/paths.rs#L69) | -| NFR-R2 | [`core/dr-catalog/src/recovery.rs:1`](../../core/dr-catalog/src/recovery.rs#L1), [`core/dr-catalog/src/recovery.rs:222`](../../core/dr-catalog/src/recovery.rs#L222), [`core/dr-catalog/src/sync.rs:61`](../../core/dr-catalog/src/sync.rs#L61), [`core/dr-catalog/src/trash.rs:1`](../../core/dr-catalog/src/trash.rs#L1), [`ui/dr-ui/src/derived_sync.rs:613`](../../ui/dr-ui/src/derived_sync.rs#L613), [`ui/dr-ui/src/derived_sync.rs:736`](../../ui/dr-ui/src/derived_sync.rs#L736), [`ui/dr-ui/src/library_ui/sync.rs:22`](../../ui/dr-ui/src/library_ui/sync.rs#L22), [`ui/dr-ui/src/library_ui/sync.rs:345`](../../ui/dr-ui/src/library_ui/sync.rs#L345) | +| NFR-R2 | [`core/dr-catalog/src/recovery.rs:1`](../../core/dr-catalog/src/recovery.rs#L1), [`core/dr-catalog/src/recovery.rs:222`](../../core/dr-catalog/src/recovery.rs#L222), [`core/dr-catalog/src/sync.rs:61`](../../core/dr-catalog/src/sync.rs#L61), [`core/dr-catalog/src/trash.rs:1`](../../core/dr-catalog/src/trash.rs#L1), [`ui/dr-ui/src/derived_sync.rs:623`](../../ui/dr-ui/src/derived_sync.rs#L623), [`ui/dr-ui/src/derived_sync.rs:746`](../../ui/dr-ui/src/derived_sync.rs#L746), [`ui/dr-ui/src/library_ui/sync.rs:22`](../../ui/dr-ui/src/library_ui/sync.rs#L22), [`ui/dr-ui/src/library_ui/sync.rs:362`](../../ui/dr-ui/src/library_ui/sync.rs#L362) | | NFR-R3 | [`core/dr-decode/src/error.rs:30`](../../core/dr-decode/src/error.rs#L30) | | NFR-R4 | [`core/dr-types/src/settings.rs:92`](../../core/dr-types/src/settings.rs#L92), [`ui/dr-ui/src/library/xmp.rs:25`](../../ui/dr-ui/src/library/xmp.rs#L25), [`ui/dr-ui/src/library/xmp.rs:9`](../../ui/dr-ui/src/library/xmp.rs#L9), [`ui/dr-ui/src/library_ui/controller.rs:387`](../../ui/dr-ui/src/library_ui/controller.rs#L387), [`ui/dr-ui/src/library_ui/controller.rs:532`](../../ui/dr-ui/src/library_ui/controller.rs#L532), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:529`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L529), [`ui/dr-ui/src/settings_ui.rs:558`](../../ui/dr-ui/src/settings_ui.rs#L558), [`ui/dr-ui/src/xmp_sync.rs:1`](../../ui/dr-ui/src/xmp_sync.rs#L1), [`ui/dr-ui/ui/settings.slint:1093`](../../ui/dr-ui/ui/settings.slint#L1093), [`ui/dr-ui/ui/settings.slint:199`](../../ui/dr-ui/ui/settings.slint#L199) | | NFR-R5 | [`core/dr-catalog/src/collections.rs:1`](../../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/error.rs:1`](../../core/dr-catalog/src/error.rs#L1), [`core/dr-catalog/src/keywords.rs:1`](../../core/dr-catalog/src/keywords.rs#L1), [`core/dr-catalog/src/schema.rs:1`](../../core/dr-catalog/src/schema.rs#L1) | @@ -220,7 +221,7 @@ Defined in `requirements.md` and marked `(post-v1)` on the defining line. Not in ## Not yet tagged -30 of 184 requirements have no implementation tag. Expected while the codebase is young; each should gain one as it is built. +33 of 188 requirements have no implementation tag. Expected while the codebase is young; each should gain one as it is built.
Show untagged requirements @@ -230,6 +231,8 @@ Defined in `requirements.md` and marked `(post-v1)` on the defining line. Not in - FR-DEV-3g - FR-DSP-2 - FR-DSP-4 +- FR-INF-2 +- FR-INF-3 - FR-MRG-9 - FR-NC-11 - FR-PLAT-AND-1 @@ -238,6 +241,7 @@ Defined in `requirements.md` and marked `(post-v1)` on the defining line. Not in - NFR-A11Y-1 - NFR-ARCH-1 - NFR-COMPAT-2 +- NFR-INF-1 - NFR-MRG-1 - NFR-MRG-2 - NFR-OPS-4 diff --git a/docs/dev/windows.md b/docs/dev/windows.md index a2c9cff..e25604d 100644 --- a/docs/dev/windows.md +++ b/docs/dev/windows.md @@ -282,7 +282,9 @@ $LOCALAPPDATA\Programs\DarkRoom\ models\ scrfd_500m_640.onnx scrfd_2.5g_640.onnx scrfd_10g_640.onnx arcface_mbf_b1.onnx 2d106det_b1.onnx ocec_s_b1.onnx sgc_l_48_b1.onnx + scrfd_500m_640.int8.onnx scrfd_2.5g_640.int8.onnx scrfd_10g_640.int8.onnx yolo26s-sem-ade20k.onnx yolo26s-sem-ade20k.classes.json categories.txt + migan-512.onnx LICENSE uninstall.exe ``` diff --git a/ui/dr-ui/src/derived_sync.rs b/ui/dr-ui/src/derived_sync.rs index 078769c..ff0c99c 100644 --- a/ui/dr-ui/src/derived_sync.rs +++ b/ui/dr-ui/src/derived_sync.rs @@ -67,6 +67,9 @@ pub struct SyncReport { /// devices already had gains *no* collection, and reporting only the /// former left the sidebar showing no count beside a full collection. pub members_gained: usize, + /// Images dated from the remote's snapshot rather than by this device's + /// own sweep — what makes the timeline whole on a fresh device. + pub dates_gained: usize, // Face data is counted apart from thumbnails for the same reason keywords // are counted apart from collections: "adopted 4,812 faces" is a sentence @@ -195,9 +198,13 @@ async fn run( // cheaper than probing, and an existing folder is not an error. let _ = backend.create_dir(&base).await; - let _ = tx.send(SyncMessage::Status("checking thumbnails…".into())); - sync_shards(backend, &base, thumbs_dir, scratch, &mut report).await?; - + // Small before large, and what the user is waiting for before what + // fills in behind them. Faces first because the catalog merge assigns + // identities to faces this device holds, so they must be here by then; + // the catalog next for collections, people and dates; thumbnails last, + // because a fresh device's thumbnail stage is hundreds of megabytes and + // everything queued behind it — the sidebar, the timeline, the names — + // was invisible for as long as it ran. let _ = tx.send(SyncMessage::Status("checking faces…".into())); sync_face_shards( backend, @@ -213,6 +220,9 @@ async fn run( let _ = tx.send(SyncMessage::Status("checking collections…".into())); sync_catalog(backend, &base, catalog_path, scratch, &mut report).await?; + let _ = tx.send(SyncMessage::Status("checking thumbnails…".into())); + sync_shards(backend, &base, thumbs_dir, scratch, &mut report).await?; + // TRACES: FR-UI-8 // Last, and it costs one small GET plus at most one small PUT. Last because // it is the only thing here that is not derived state and so the only thing @@ -815,6 +825,7 @@ fn merge_downloaded( report.catalog_merged = true; report.collections_gained += merge.inserted + merge.updated; report.members_gained += merge.members_added; + report.dates_gained += merge.metadata_adopted; Ok(()) } diff --git a/ui/dr-ui/src/library_ui/open.rs b/ui/dr-ui/src/library_ui/open.rs index 4070b69..01d1583 100644 --- a/ui/dr-ui/src/library_ui/open.rs +++ b/ui/dr-ui/src/library_ui/open.rs @@ -23,7 +23,7 @@ use crate::{AppWindow, Library, View}; use super::controller::{stop, LibraryController}; use super::offline::refresh_offline; use super::ratings_keywords::refresh_xmp_conflicts; -use super::sync::start_sweep; +use super::sync::{start_derived_sync, start_sweep}; use super::timeline::{apply_place, note_place}; use super::window::{load_window, window_start}; @@ -494,6 +494,15 @@ fn drain_scan( } } load_window(&w, ctl); + // Take the server's shards and catalog *now*, + // before the sweep: the rows they key on exist + // from this moment, and on a fresh device + // every thumbnail, face and collection a peer + // has already made is on the server. Waiting + // for the sweep — hours on a large library — + // meant re-deriving all of it here first. In + // steady state this is one listing. + start_derived_sync(&w, ctl); // Everything the grid did not touch: the rest // of the library gets a thumbnail and a date, // so the timeline describes all of it rather diff --git a/ui/dr-ui/src/library_ui/sync.rs b/ui/dr-ui/src/library_ui/sync.rs index c640019..349dfc7 100644 --- a/ui/dr-ui/src/library_ui/sync.rs +++ b/ui/dr-ui/src/library_ui/sync.rs @@ -49,8 +49,11 @@ fn spawn_scheduled_backup(ctl: &Rc) { /// Push shards and the catalog to the server, and take what it has. /// -/// Fired after the sweep completes, when there is a finished index worth -/// sharing, and from the Sync button for an explicit exchange. +/// Fired when the scan completes, so a fresh device inherits its peers' +/// work before deriving any of its own; after the sweep completes, when +/// there is a finished index worth sharing; and from the Sync button for an +/// explicit exchange. A pass still running when the next trigger fires is +/// left to finish — the guard below. pub(super) fn start_derived_sync(window: &AppWindow, ctl: &Rc) { // An escape hatch for running the app against a *copied* library without // touching the account's real server. @@ -174,7 +177,7 @@ pub(super) fn start_derived_sync(window: &AppWindow, ctl: &Rc crate::derived_sync::SyncMessage::Finished(report) => { log::info!( "sync: {} shard(s) up, {} down ({} thumbnails), \ - catalog {}{}", + catalog {}{}{}", report.shards_uploaded, report.shards_downloaded, report.thumbnails_adopted, @@ -191,6 +194,11 @@ pub(super) fn start_derived_sync(window: &AppWindow, ctl: &Rc format!(", {} collection(s) gained", report.collections_gained) } else { String::new() + }, + if report.dates_gained > 0 { + format!(", {} date(s) gained", report.dates_gained) + } else { + String::new() } ); w.global::().set_library_syncing(false); @@ -208,13 +216,22 @@ pub(super) fn start_derived_sync(window: &AppWindow, ctl: &Rc .set_library_status(format!("synced · {summary}").into()); } // Adopted thumbnails and merged collections both change - // what the grid should show. + // what the grid should show; adopted dates change its + // order, and the timeline beside it. if report.thumbnails_adopted > 0 || report.collections_gained > 0 || report.members_gained > 0 + || report.dates_gained > 0 { load_window(&w, &ctl_cb); } + if report.dates_gained > 0 { + let borrow = ctl_cb.catalog(); + let borrow = borrow.borrow(); + if let Some(cat) = borrow.as_ref() { + refresh_timeline(&w, cat, &ctl_cb); + } + } // TRACES: FR-CAT-7 // And the sidebar, which the grid reload does not // touch. Membership counts as a change: a sync that