Repository navigation
Conversation
…ction is re-scored `update_occurrence_determination` only recomputed `determination_score` inside the branch where the winning identification's or prediction's taxon differed from the current determination. Class masking creates a new terminal classification that often keeps the same taxon with a different score, so the occurrence kept its old, lower score. Under the project's default score threshold such occurrences disappear from occurrence lists and their project-scoped detail URL returns 404. The function now picks the winning identification or prediction first and compares each cached field to it separately, so the score follows the winner even when the taxon is unchanged. A human identification still wins over any prediction and keeps its own score. The no-op path still returns False without saving. Tests pin the same-taxon re-score, the taxon change, the no-op path, the human identification rule, and an end-to-end class masking run whose unchanged winner rises above the score threshold. Found while reviewing #1461. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L52AN9tabp76yjhjyCZkSJ
✅ Deploy Preview for antenna-preview canceled.
|
✅ Deploy Preview for antenna-ssec canceled.
|
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This was referenced Oct 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Projects that ran class masking (#999) can have occurrences that are hidden even though their best prediction now scores well. Class masking re-scores a classification under a new algorithm, and in most cases the winning taxon stays the same while the score goes up. The occurrence kept its old, lower score, because the determination refresh only recomputed the score when the taxon changed. With a project score threshold of 0.5, an occurrence whose masked winner scored 0.55 but whose stored score was still 0.38 vanished from the occurrence lists, and its project-scoped detail page returned 404. Occurrences whose taxon did change were fine.
This PR makes the occurrence's score follow its best identification or prediction whenever the score differs, not only when the taxon differs. After a class masking run, re-scored occurrences now stay visible under the default filters. It was found while reviewing #1461.
List of Changes
update_occurrence_determinationpicks the winning identification or prediction first and then compares the taxon and the score to the stored values separately, instead of computing both only inside the "taxon changed" branch. A score of exactly0.0is now also written (is not Noneinstead of truthiness).Falseand does not save.updated_atis untouched.TestOccurrenceDeterminationRefreshinami/main/tests.py(five cases) and one end-to-end class masking case inami/ml/post_processing/tests/test_class_masking.py. The stale@TODO Add testsnote in the docstring is removed.Related Issues
Relates to #999 (class masking) and #1461 (where the stale score was noticed during review).
Detailed Description
update_occurrence_determinationinami/main/models.pyis called fromOccurrence.save(), fromIdentification.save()andIdentification.delete(), and from the pipeline results path. Before this change it looked like this:new_scorewas only set when the taxon differed, so a re-scored winner with the same taxon leftdetermination_scoreuntouched. The fix drops the!= current_determinationguard from the winner selection and keeps the per-field comparisons that already followed it. TheOccurrencemodel onmaincaches onlydeterminationanddetermination_score, so no other field is affected.Side effect worth knowing: an occurrence that a human confirms with the same taxon the machine already chose now gets the identification's score (1.0) instead of keeping the machine score. That matches what already happened when the human chose a different taxon, and matches
Occurrence.get_determination_score().How to Test the Changes
Automated:
docker compose run --rm django python manage.py test --noinput \ ami.main.tests.TestOccurrenceDeterminationRefresh \ ami.ml.post_processing.tests.test_class_maskingBefore the fix,
test_score_follows_a_rescored_prediction_with_the_same_taxonfails withFalse is not true(no update), andtest_rescored_unchanged_winner_keeps_the_occurrence_visiblefails with the stored score (about 0.44) not matching the masked score (about 0.73). Both pass with the fix. The full backend suite was run in a CI-style compose stack; 748 tests passed with 2 skipped.Manual: on a project with a score threshold of 0.5, run class masking with a taxa list that excludes a class carrying real probability for some occurrences. Open an occurrence whose winner did not change: its score now equals the masked classification's score, and it stays listed when the threshold would otherwise hide the old score.
Deployment Notes
No migration. Existing occurrences that were masked before this fix still carry their old score until they are re-saved. There is no management command on
mainthat recomputes determinations, and re-running the class masking job does not help because already-masked classifications are skipped. Until a command exists, an operator can refresh a project's occurrences from the Django shell. Re-saving an occurrence recomputes its determination and score in place:Each save is a few queries, so expect it to take a while on a large project; run it from a worker host, not a web request. Adding a
refresh_occurrence_determinationsmanagement command (project scoped, with a dry run) is a sensible follow-up.Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_01L52AN9tabp76yjhjyCZkSJ