Skip to content

Let staff undo tracking for a session so it can be tracked again - #1444

Draft
mihow wants to merge 13 commits into
feat/tracking-cost-termsfrom
feat/tracking-reset-session
Draft

mihow wants to merge 13 commits into
feat/tracking-cost-termsfrom
feat/tracking-reset-session

Conversation

@mihow

@mihow mihow commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Tracking only runs on a session that has never been tracked: each detection must still be its own occurrence. That makes it hard to try tracking a night again with different settings, or to see a night as it looked before tracking, because there was no way back. This PR adds a staff command, reset_tracking, that puts a session back into that untracked state so it can be tracked again from scratch. It is meant for tuning work and for comparing settings on the same night, and it is a starting point for a "preview without a destructive change" option later.

The command refuses a session where a person has identified any occurrence, unless --force is given, and --dry-run reports what would change without writing anything.

On a local copy of a partner project, three full nights (about 5,000, 13,000 and 36,600 detections) were reset, tracked through the normal tracking job and reset again. Each reset took under a minute for all three nights, every session passed the tracking task's "fresh session" check afterwards, and a second reset of the same night returned exactly the same occurrence and determination counts as the first (measured).

Stacked on #1442 (which sits on #1439) and merges after it.

Tests on this head (fb2455ef), run locally in the CI compose stack, since GitHub runs the backend tests only on PRs based on main: makemigrations --check reports no changes, and the full backend suite ran 1,102 tests, OK (2 skipped).

List of Changes

Change (user effect) How (implementation)
1. Staff can undo tracking for one or more sessions and track them again. New management command reset_tracking --project P --event E [--event ...] [--dry-run] [--force]. Each session is planned and written in one transaction that locks its occurrence rows, so a tracking run, track edit or new identification on the same session waits for the reset.
2. After a reset every detection is its own occurrence again, and each occurrence shows the species its own detection predicts (or none, if the detection has no scored prediction). The earliest detection of a track keeps the occurrence; the others move to new occurrences (bulk create/update). A track that also holds detections of another session stays with those detections, and is filed under that session if it was filed under the reset one. Determinations of every touched occurrence without an identification are recomputed in batches with the same choice as Occurrence.best_prediction (best_prediction_from_prefetch), and cleared when no scored prediction is left.
3. A reset session has no chain links, no grouping confirmations and no leftover "tracking decided" records. Clears next_detection links between detections of the session (links into other sessions, which regrouping keeps on purpose, are left), clears grouping verification, and deletes the classifications the tracking task recorded on the session's detections.
4. Sessions with human identifications are protected. Refuses unless --force; forced, each identification stays on the occurrence it was made on and that occurrence keeps its determination.
5. Session and station counts stay correct. Refreshes stored track statistics for touched occurrences and calls update_calculated_fields_for_sessions_and_stations.
6. The command reports what it did. Prints the per-session counts it changed plus before/after occurrences, multi-detection occurrences, distinct determinations, links and confirmations.

Detailed Description

The core lives in ami/main/models_future/session_reset.py (reset_session_tracking, session_tracking_counts); the command is a thin wrapper. The query count does not depend on the number of detections except through the determination batches (2,000 occurrences per batch, three queries each); a test pins that doubling a session adds no queries.

How to test

python manage.py reset_tracking --project <id> --event <id> --dry-run
python manage.py reset_tracking --project <id> --event <id>

Tests: ami.ml.post_processing.tests.test_session_reset covers the split with links, verification and tracking records cleared and determinations matching each occurrence's own best prediction (cleared where none is left); the refusal with identifications, and --force keeping the identified determination; dry run writes nothing; an unknown session is rejected; a track reaching into another session stays there and the reset session comes out fresh; a link into another session is kept; and the query count does not grow with the session. ami.main.tests and ami.ml.post_processing pass locally (699 tests), and makemigrations --check reports no changes.

Notes

  • Classifications recorded by the tracking task are deleted rather than kept, because each one describes a merge the reset undoes, and keeping them would let repeated track/reset cycles pile up copies on the same detection.
  • Detections of a split occurrence that lie in another session stay with the original occurrence, and every detection of the reset session leaves it, so the reset session passes the "fresh session" check. Only the reset session's detections move.

🤖 Generated with Claude Code

https://claude.ai/code/session_01C7Xf6VPbwWtTumhjjF15g8

… a session

Splits every multi-detection occurrence of a session back into one occurrence
per detection, recomputes each touched occurrence's determination from its own
detections in batches, clears chain links inside the session, grouping
confirmations and the tracking task's recorded classifications, then refreshes
the session and station cached counts. Refuses sessions with identifications
unless --force; --dry-run reports the plan without writing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7Xf6VPbwWtTumhjjF15g8
@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@netlify

netlify Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for antenna-preview canceled.

Name Link
🔨 Latest commit 33b39e6
🔍 Latest deploy log https://app.netlify.com/projects/antenna-preview/deploys/6abd33c1b38a5c00089bc9e1

mihow and others added 12 commits September 28, 2026 21:23
…hat session on reset

Resetting a session kept the earliest detection of every multi-detection occurrence.
When that detection was in the session being reset and the occurrence also held
detections of a later session, the occurrence still spanned more than one detection
afterwards, so the session did not pass the tracking task's freshness check and could
not be tracked again. The occurrence also stayed filed under the reset session even
when none of its detections remained there.

An occurrence that holds detections of another session now stays whole in that
session: every detection of the reset session leaves it, and if it was filed under the
reset session it moves to the session of its first remaining detection. A new test
covers an occurrence spanning two sessions and checks that the reset session is fresh
and the other session's detections are unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7Xf6VPbwWtTumhjjF15g8
…eft to support it

After a reset, an occurrence whose remaining detection had no scored classification
kept the determination and score it had inherited from the merged track, which
described detections that had moved to other occurrences. Such an occurrence, when it
has no identification, now has its determination and score cleared. The split test
removes the predictions from one kept detection and checks this.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7Xf6VPbwWtTumhjjF15g8
…s it

The reset read the session's counts, checked for identifications and chose which
detections move before opening its transaction, and locked nothing. A tracking run, a
track edit or a new identification landing in between could leave the writes acting on
a stale plan, or split an occurrence a person had just identified.

The reset now locks the session's occurrence rows first, then reads the counts, checks
for identifications and plans the split inside the same transaction as the writes.
Anything that deletes those occurrences, points a detection at them or adds an
identification to them waits until the reset commits. A dry run still plans outside
any transaction and takes no lock.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7Xf6VPbwWtTumhjjF15g8
… another session

The forced reset test now gives the identified occurrence a taxon that differs from its
own prediction, and checks that the occurrence keeps the identified determination while
every occurrence split off from it takes its own best prediction. A new test links the
last detection of one session to the first detection of the next and checks that the
reset keeps that link while clearing the links inside the session.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7Xf6VPbwWtTumhjjF15g8
Brings in the tracking settings branch, which now also carries #1439.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7Xf6VPbwWtTumhjjF15g8
…on is reset

A reset undoes every merge in a session, but the tracking results recorded in
the occurrences' history stayed, so after a new run an occurrence listed merges
from runs that no longer exist. The reset now deletes the tracking results on
the session's occurrences, as it already deletes the tracking task's recorded
classifications. Reviews stay, and an occurrence that reaches into another
session keeps its whole history because a result does not say which session's
run wrote it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7Xf6VPbwWtTumhjjF15g8
… tracking UI branches and main) into feat/tracking-reset-session

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7Xf6VPbwWtTumhjjF15g8
@mihow

mihow commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator Author

Claude says: The merge order and plan for tracking, agreed with the owner today, are on #1412: #1412 (comment)

This PR's place: on hold until tracking (#1469) and its calibration (#1468) have landed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant