Multi-species awareness: remaining pages & backend surfaces
Follow-up to #1294 (multi-subject burst review) and the Compare subject-aware work. A photo can now legitimately carry two different species (multiple MegaDetector boxes, predictions keyed to detection_id, photo.subjects[], multi-valued species keywords). Burst review and Compare were updated; the rest of the app still collapses a photo to one species or one "primary" detection.
Shared root cause
Three legacy reducers, still consumed everywhere despite subjects[] now existing:
confirmed_species = alphabetically-first keyword per photo (vireo/pipeline.py:395).
species_top5 flattens all detections' predictions into one per-photo list (vireo/pipeline.py:329), feeding a single-winner encounter vote (vireo/encounters.py:800).
ROW_NUMBER() OVER (PARTITION BY photo_id ORDER BY confidence DESC) ... rn=1 — keeps only the single most-confident species. Powers highlights, browse summary, readiness pills, iNat prepare.
Actively wrong (data loss / core feature broken)
Silently incomplete (second species disappears, no wrong claim)
Already correct (no change)
life_list, stats top-species, keywords, best_batch, audit, location_review, lightroom, XMP sidecar sync, and the prediction-resolution layer (update_prediction_status, accept_prediction sibling-rejection are detection-scoped). misses / photo_editor fine for species.
Suggested sequencing
accept_prediction replace-scoping + /api/encounters/species (data loss / core feature).
- rapid review + cull + highlights (review workflows).
- map, pipeline pills, browse summary, export naming (reporting/cosmetic).
Multi-species awareness: remaining pages & backend surfaces
Follow-up to #1294 (multi-subject burst review) and the Compare subject-aware work. A photo can now legitimately carry two different species (multiple MegaDetector boxes, predictions keyed to
detection_id,photo.subjects[], multi-valued species keywords). Burst review and Compare were updated; the rest of the app still collapses a photo to one species or one "primary" detection.Shared root cause
Three legacy reducers, still consumed everywhere despite
subjects[]now existing:confirmed_species= alphabetically-first keyword per photo (vireo/pipeline.py:395).species_top5flattens all detections' predictions into one per-photo list (vireo/pipeline.py:329), feeding a single-winner encounter vote (vireo/encounters.py:800).ROW_NUMBER() OVER (PARTITION BY photo_id ORDER BY confidence DESC) ... rn=1— keeps only the single most-confident species. Powers highlights, browse summary, readiness pills, iNat prepare.Actively wrong (data loss / core feature broken)
accept_prediction(replace_species=True)(db.py:14099) — replace doesDELETE ... photo_keywords WHERE photo_id=? AND keyword_id IN (all species), not detection-scoped. Accepting the teal with "replace" erases a wigeon keyword confirmed on the other detection. Data loss./api/encounters/species(app.py:23527) — one species slot per burst. Confirming a second real species tripsis_replacementand untags the first;_auto_detach_burst_for_speciestreats two species as a grouping error. A burst genuinely holding two species can't hold both.pipeline_rapid_review.html—photoSpecies()= singleconfirmed_species; one keyword applied to whole burst; photo drops out of "Needs species" after any one tag. Can't tag a second species.cull.html—topSpeciesForPhoto=species_top5[0];speciesForEncountercollapses encounter to one species; keep/reject tallies attribute the photo wholly to one species.highlights.html//api/highlights—get_highlights_candidatescollapses each photo to one species (accepted-keywordrn=1+ top-1 prediction); confirm endpoint skips photos with any species keyword as "already confirmed."_navbar.html→api_inat_prepare→get_top_prediction_for_photo) — prefills only one taxon for a two-species photo.Silently incomplete (second species disappears, no wrong claim)
map.html/get_geolocated_photos(db.py:7675) — SQL collapses each photo to one species; marker/legend/popup show one.review.html— cards are per-detection (good), but disagreement/conflict badges compare each prediction against the photo's whole keyword set ignoringdetection_id; consensus grouping by timestamp can merge co-occurring subjects.pipeline.htmlreadiness pills —count_primary_detections_in_scope/count_primary_classify_staleuseWHERE rn=1; under-count multi-subject classify work. (Partially addressed by ae8faca — verify.)browse.html"Top Species" summary (get_browse_summary,db.py:7522) —rn=1top-1 collapse. Grid cards themselves are fine.encounter_species_label(encounters.py:800) — single winner per encounter; second species invisible at encounter level.{species}token (export.py:248,browse.html:8484) — usesspecies_list[0]. Naming/routing only; embedded keywords complete.Already correct (no change)
life_list, stats top-species, keywords, best_batch, audit, location_review, lightroom, XMP sidecar sync, and the prediction-resolution layer (
update_prediction_status,accept_predictionsibling-rejection are detection-scoped). misses / photo_editor fine for species.Suggested sequencing
accept_predictionreplace-scoping +/api/encounters/species(data loss / core feature).