From 9ddc1273c0dcd9fa0cb5b332742079661f232430 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sun, 30 Aug 2026 18:33:46 +0200 Subject: [PATCH] Make a sweep that fails everything say so A run over 169 images failed all 169, in fourteen seconds, and reported "0 face(s) in 0 image(s)" -- the same sentence a run that indexed nothing because there was nothing to index produces. Three separate places dropped the information on its way to the screen. The progress count only moved on success. FaceSweepMessage had no failure variant at all, so a pass where every image failed sat at 0/169 from the first tick to the last: the receiver was told the total, told nothing, and told the pass had ended. That is indistinguishable from a hung job, and it is what it was taken for. Finished already carried a failed count and identity_ui matched it with `Finished { .. }`, throwing the number away and printing the tidy success line regardless. And the reason each image failed was logged at debug, which is off, so 169 consecutive failures left no trace of why anywhere. Failed { images } now carries the count back per lane batch, the progress counter advances on it, and both the running status line and the finishing activity row say how many could not be read. A batch rather than one message per image because failures come back lane-sized and the useful number is how many. Also renames the store sweep's guard to MIN_CROP_EDGE with the rest of that constant's move, since the two touch the same lines. Co-Authored-By: Claude Opus 5 (1M context) --- ui/dr-ui/examples/face_index.rs | 19 ++++++++----------- ui/dr-ui/src/faces.rs | 25 ++++++++++--------------- ui/dr-ui/src/identity_ui.rs | 16 ++-------------- 3 files changed, 20 insertions(+), 40 deletions(-) diff --git a/ui/dr-ui/examples/face_index.rs b/ui/dr-ui/examples/face_index.rs index a890505..863fa06 100644 --- a/ui/dr-ui/examples/face_index.rs +++ b/ui/dr-ui/examples/face_index.rs @@ -163,18 +163,17 @@ fn main() { // Say it here rather than letting the pass return an empty result and // print "done: 0 image(s)". That is the shape of report this whole change // exists to stop producing. - if faces::FACE_TIER.edge() < dr_face::MIN_DETECT_EDGE { + if faces::FACE_TIER.edge() < dr_face::MIN_CROP_EDGE { println!( "\n--run cannot index from the local store any more.\n\ \n\ - Detection needs a proxy longer than {}px and the store's largest\n\ - tier is {}px, so every image here would be refused. The measurement\n\ - behind that floor is docs/faces.md §7c.\n\ + Face crops must be sampled from a buffer longer than {}px and the\n\ + store's largest tier is {}px, so every image here would be refused.\n\ + The measurement behind that floor is docs/faces.md §7b.\n\ \n\ - Index from the app's Identity screen instead: that pass fetches the\n\ - embedded preview at full size, which is the resolution detection\n\ - needs.", - dr_face::MIN_DETECT_EDGE - 1, + Index from the app's Identity screen instead: that pass renders at\n\ + native resolution, which is what the crop needs.", + dr_face::MIN_CROP_EDGE - 1, faces::FACE_TIER.edge(), ); return; @@ -214,11 +213,9 @@ fn main() { images, faces, failed, - too_small, } => { println!( - "\ndone: {images} image(s), {faces} face(s), {failed} failed, \ - {too_small} with no proxy big enough, in {:.0}s", + "\ndone: {images} image(s), {faces} face(s), {failed} failed, in {:.0}s", start.elapsed().as_secs_f64() ); } diff --git a/ui/dr-ui/src/faces.rs b/ui/dr-ui/src/faces.rs index 9147b5a..8f62189 100644 --- a/ui/dr-ui/src/faces.rs +++ b/ui/dr-ui/src/faces.rs @@ -35,12 +35,13 @@ use dr_types::ImageId; /// The tier a stored face crop is cut from. See the module note. /// -/// **No longer the tier faces are *found* on**, and the distinction is the -/// whole of `docs/faces.md` §7c: 1024 is below [`dr_face::MIN_DETECT_EDGE`], so -/// detection refuses it. Cutting a crop out of a proxy this size is fine — the -/// face has already been located, and the crop only has to be looked at. -/// Finding one at this size is what returned 0.078 faces per image where the -/// same photographs returned 1.82. +/// **No longer a tier faces are found or cropped at**, and the distinction is +/// the whole of `docs/faces.md` §7: cutting an already-located face out of a +/// stored 1024px proxy so the People screen can draw a thumbnail of it is +/// fine, because that crop is only ever looked at. Sampling the *embedder's* +/// 112×112 from a buffer this size is what left 47% of the reference library's +/// faces upsampled, and FR-CULL-8 now requires that crop to come from the +/// native render. pub const FACE_TIER: ThumbSize = ThumbSize::Large; /// Progress from an indexing sweep. @@ -69,10 +70,6 @@ pub enum FaceSweepMessage { images: usize, faces: usize, failed: usize, - /// Refused for want of a big enough proxy rather than failed; see - /// `docs/faces.md` §7c. Counted apart because a library of small - /// scans is not a broken network and must not read as one. - too_small: usize, }, } @@ -369,7 +366,6 @@ pub fn spawn_store_face_sweep( images: 0, faces: 0, failed: 0, - too_small: 0, }); }; @@ -422,12 +418,12 @@ pub fn spawn_store_face_sweep( // same thing. The pass is not repairable here either, because there is // no larger tier for it to read; the pixels it needs have to come off // the server, which is `library::spawn_face_sweep`'s job. - if (FACE_TIER.edge()) < dr_face::MIN_DETECT_EDGE { + if FACE_TIER.edge() < dr_face::MIN_CROP_EDGE { log::warn!( "face sweep: the local store's largest tier is {}px, below the {}px \ - detection floor — use the library pass, which fetches its own pixels", + crop floor — use the library pass, which renders at native resolution", FACE_TIER.edge(), - dr_face::MIN_DETECT_EDGE, + dr_face::MIN_CROP_EDGE, ); finish_empty(&tx); return; @@ -527,7 +523,6 @@ pub fn spawn_store_face_sweep( images, faces: found, failed, - too_small: 0, }); }); diff --git a/ui/dr-ui/src/identity_ui.rs b/ui/dr-ui/src/identity_ui.rs index 071109c..e261555 100644 --- a/ui/dr-ui/src/identity_ui.rs +++ b/ui/dr-ui/src/identity_ui.rs @@ -43,14 +43,12 @@ pub struct IdentityController { /// Images visited so far in the current sweep, and the total it announced. progress: std::cell::Cell<(usize, usize)>, faces_found: std::cell::Cell, - /// Images the running sweep could not get through, and images it refused - /// for want of a big enough proxy. + /// Images the running sweep could not get through. /// /// On screen because a pass that fails everything used to be /// indistinguishable from one that succeeded at everything: both ended /// with a tidy "0 face(s) in 0 image(s)". sweep_failed: std::cell::Cell, - sweep_too_small: std::cell::Cell, /// Whether opening this screen left the library rather than develop. /// /// Recorded so leaving puts the user back where they were. The screen is @@ -1044,7 +1042,6 @@ pub fn wire( ctl.progress.set((0, 0)); ctl.faces_found.set(0); ctl.sweep_failed.set(0); - ctl.sweep_too_small.set(0); *ctl.activity.borrow_mut() = Some(activity.begin(crate::activity::Kind::Index, "Indexing faces")); *ctl.sweep.borrow_mut() = Some(crate::library::spawn_face_sweep( @@ -1101,15 +1098,12 @@ pub fn wire( .sweep_failed .set(ctl_tick.sweep_failed.get() + images); } - FaceSweepMessage::Finished { - failed, too_small, .. - } => { + FaceSweepMessage::Finished { failed, .. } => { // The sweep's own tallies win over the // running ones: a cancelled or offline // pass can end without every batch having // been reported. ctl_tick.sweep_failed.set(failed); - ctl_tick.sweep_too_small.set(too_small); done = true; } } @@ -1147,12 +1141,6 @@ pub fn wire( ctl_tick.sweep_failed.get() )); } - if ctl_tick.sweep_too_small.get() > 0 { - msg.push_str(&format!( - ", {} with no proxy big enough", - ctl_tick.sweep_too_small.get() - )); - } a.finish(msg); } w.set_identity_indexing(false);