Observed
While verifying #212 on a fresh local stack (2026-07-28): after classifying several sequences through the UI (PATCH /api/v1/annotations/sequences/{id} moving them ready_to_annotate -> seq_annotation_done), every row still had updated_at IS NULL:
sequence_id | updated_at | created_at
-------------+------------+-------------------------------
29 | | 2026-07-28 12:13:42.583139+00
23 | | 2026-07-28 12:13:41.856097+00
Cause
SequenceAnnotationUpdate exposes updated_at as an optional client-supplied field, and the update path only writes what the payload contains — the server never stamps it. The frontend's save mutations don't send it, so it stays NULL forever. (Pre-existing behavior; not introduced by #212. DetectionAnnotation.updated_at is worth auditing for the same pattern.)
Why it matters
Any future sort/filter/reporting on "last modified" (dashboards, contribution stats, debugging who-changed-what-when) silently gets NULLs. It also makes incident forensics harder — during the #212 verification session it cost a debugging detour because save times couldn't be established from the data.
Proposed fix
Stamp updated_at = datetime.now(UTC) server-side in the CRUD update path(s) whenever a mutation occurs, and drop (or ignore) the client-supplied field from the update schemas — clients shouldn't own server timestamps. Backfill is optional: existing NULLs can be left as "unknown" or set to created_at.
Observed
While verifying #212 on a fresh local stack (2026-07-28): after classifying several sequences through the UI (
PATCH /api/v1/annotations/sequences/{id}moving themready_to_annotate -> seq_annotation_done), every row still hadupdated_at IS NULL:Cause
SequenceAnnotationUpdateexposesupdated_atas an optional client-supplied field, and the update path only writes what the payload contains — the server never stamps it. The frontend's save mutations don't send it, so it stays NULL forever. (Pre-existing behavior; not introduced by #212.DetectionAnnotation.updated_atis worth auditing for the same pattern.)Why it matters
Any future sort/filter/reporting on "last modified" (dashboards, contribution stats, debugging who-changed-what-when) silently gets NULLs. It also makes incident forensics harder — during the #212 verification session it cost a debugging detour because save times couldn't be established from the data.
Proposed fix
Stamp
updated_at = datetime.now(UTC)server-side in the CRUD update path(s) whenever a mutation occurs, and drop (or ignore) the client-supplied field from the update schemas — clients shouldn't own server timestamps. Backfill is optional: existing NULLs can be left as "unknown" or set tocreated_at.