Skip to content

Fix 2-digit year timestamp parsing, sync error reporting, and captures columns#1159

Open
mihow wants to merge 4 commits intomainfrom
fix/2digit-year-timestamps-and-sync-improvements
Open

Fix 2-digit year timestamp parsing, sync error reporting, and captures columns#1159
mihow wants to merge 4 commits intomainfrom
fix/2digit-year-timestamps-and-sync-improvements

Conversation

@mihow
Copy link
Collaborator

@mihow mihow commented Feb 27, 2026

Summary

  • 2-digit year timestamp parsing: Some cameras produce filenames with YYMMDDHHMMSS (12-digit) timestamps instead of the expected YYYYMMDDHHMMSS (14-digit). These were silently returning NULL, causing images to show "Dec 31, 1969" in the UI and preventing session grouping. Added a new regex pattern and %y format handling.

  • Skip null-timestamp images and report failures: Images with unparseable timestamps are now skipped during sync rather than imported with NULL. They can't be grouped into events anyway (group_images_into_events already excluded them), so importing them just created orphaned records. Per-image processing is wrapped in try/except, a failed counter is tracked and reported as a "Failed" stage param in the job progress UI. Warns on suspicious pre-2000 timestamps. If timestamp parsing is improved later, a re-sync will pick up previously skipped images.

  • Filename/path columns: Added two new columns to the captures table (hidden by default, toggled via column settings). Exposes the path field in the list serializer and derives filename from it on the frontend.

Related

Screenshots

Before: Null timestamps showing epoch date

Before - null timestamps

After: Correct timestamps parsed from 2-digit year filenames

After - correct timestamps

Filename and Path columns (toggled on via column settings)

Filename and path columns

Sync job error reporting (Failed stage param in job progress)

Sync job error reporting

Test plan

  • Backend unit tests pass for new timestamp patterns
  • Pre-commit hooks pass
  • Verify 2-digit year filenames parse correctly after re-sync
  • Verify sync job shows "Failed" param in job detail view
  • Toggle filename/path columns on in captures table

Copilot AI review requested due to automatic review settings February 27, 2026 07:12
@netlify
Copy link

netlify bot commented Feb 27, 2026

Deploy Preview for antenna-preview ready!

Name Link
🔨 Latest commit dbb28ca
🔍 Latest deploy log https://app.netlify.com/projects/antenna-preview/deploys/69a182abc033f4000858444d
😎 Deploy Preview https://deploy-preview-1159--antenna-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 74 (🟢 up 8 from production)
Accessibility: 89 (🟢 up 9 from production)
Best Practices: 92 (🔴 down 8 from production)
SEO: 100 (🟢 up 8 from production)
PWA: 80 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Feb 27, 2026

Deploy Preview for antenna-ssec ready!

Name Link
🔨 Latest commit dbb28ca
🔍 Latest deploy log https://app.netlify.com/projects/antenna-ssec/deploys/69a182ab484a1900080993b1
😎 Deploy Preview https://deploy-preview-1159--antenna-ssec.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 27, 2026

Warning

Rate limit exceeded

@mihow has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 11 minutes and 19 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between bfb29e2 and dbb28ca.

📒 Files selected for processing (10)
  • ami/jobs/models.py
  • ami/main/api/serializers.py
  • ami/main/api/views.py
  • ami/main/models.py
  • ami/utils/dates.py
  • ami/utils/tests.py
  • ui/src/data-services/models/capture.ts
  • ui/src/pages/captures/capture-columns.tsx
  • ui/src/pages/captures/captures.tsx
  • ui/src/utils/language.ts
📝 Walkthrough

Walkthrough

Adds 2‑digit year timestamp parsing, surfaces path/filename through backend serializers and ordering, strengthens capture sync error handling with per-object failure counts and logging, updates frontend Capture model and table columns to expose path/filename and guard missing timestamps.

Changes

Cohort / File(s) Summary
Sync jobs & progress
ami/jobs/models.py, ami/main/models.py
Initialize per-stage Failed counters; change "Total files" initialization from "" to 0; wrap per-object sync in try/except to increment Failed and log errors; include Failed in in-batch and final progress updates.
Timestamp parsing & tests
ami/utils/dates.py, ami/utils/tests.py
Add short-year (YYMMDDHHMMSS) pattern and parsing branch; normalize matched digits and choose parse format by length; add tests for 2‑digit year filenames.
Backend API: SourceImage path
ami/main/api/serializers.py, ami/main/api/views.py
Expose path in SourceImageListSerializer fields and add path to SourceImageViewSet.ordering_fields.
Frontend model: Capture
ui/src/data-services/models/capture.ts
Change get date() return type to `Date
Frontend UI: capture columns & settings
ui/src/pages/captures/capture-columns.tsx, ui/src/pages/captures/captures.tsx
Add filename and path table columns (sortable by path) and default visibility flags (filename: false, path: false).
Playback: non-null assertions
ui/src/pages/session-details/playback/...capture-navigation.tsx, ui/src/pages/session-details/playback/session-captures-slider/...
Replace activeCapture.date uses with non-null assertions (activeCapture.date!) in places that assume session captures always have dates.
i18n label
ui/src/utils/language.ts
Add FIELD_LABEL_FILENAME enum member and English translation entry Filename.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

backend

Suggested reviewers

  • annavik

Poem

🐰 Two‑digit years hop into view,
Missed files counted, failures too,
Paths and names now proudly shown,
Sync keeps going, seeds are sown,
Little rabbit cheers — anew! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the three main changes: 2-digit year timestamp parsing fix, sync error reporting improvements, and new captures columns.
Description check ✅ Passed The pull request description is comprehensive and well-structured, covering all required template sections with clear, detailed information about changes, testing, and deployment.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/2digit-year-timestamps-and-sync-improvements

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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
ui/src/pages/captures/capture-columns.tsx (1)

137-148: Both columns sort by path — intentional?

The filename column uses sortField: 'path', meaning sorting by filename will actually sort by the full path. This is a reasonable choice (maintains directory grouping), but worth confirming this is the intended UX rather than sorting by the filename segment alone.

If filename-only sorting is desired, a dedicated backend sort field would be needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/src/pages/captures/capture-columns.tsx` around lines 137 - 148, The
filename column currently uses sortField: 'path' (in the column definition with
id: 'filename' and renderCell: (item: Capture) => <BasicTableCell
value={item.filename} />), which sorts by the full path; if you want
filename-only sorting change sortField to 'filename' (and ensure the backend
supports a filename sort field), otherwise explicitly document the intended
behavior (keep sortField: 'path') so it's clear this choice groups by directory;
if the backend lacks a filename sort field, add one server-side before switching
the sortField.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ami/main/models.py`:
- Around line 810-816: The except block around _create_source_image_for_sync
currently only logs errors via job.logger if job exists, so when job is None
exceptions are swallowed and tracebacks lost; update the handler to always
record the error (use the module-level logger or logging.getLogger(__name__))
and include the full traceback (e.g., logger.exception or include
traceback.format_exc()) while still incrementing failed and continuing; keep the
job.logger call when job exists but also emit the same detailed log
unconditionally for visibility in non-job runs.

---

Nitpick comments:
In `@ui/src/pages/captures/capture-columns.tsx`:
- Around line 137-148: The filename column currently uses sortField: 'path' (in
the column definition with id: 'filename' and renderCell: (item: Capture) =>
<BasicTableCell value={item.filename} />), which sorts by the full path; if you
want filename-only sorting change sortField to 'filename' (and ensure the
backend supports a filename sort field), otherwise explicitly document the
intended behavior (keep sortField: 'path') so it's clear this choice groups by
directory; if the backend lacks a filename sort field, add one server-side
before switching the sortField.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8580069 and 7e2e601.

📒 Files selected for processing (9)
  • ami/jobs/models.py
  • ami/main/api/serializers.py
  • ami/main/models.py
  • ami/utils/dates.py
  • ami/utils/tests.py
  • ui/src/data-services/models/capture.ts
  • ui/src/pages/captures/capture-columns.tsx
  • ui/src/pages/captures/captures.tsx
  • ui/src/utils/language.ts

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves capture ingestion and UI display for edge-case timestamps, adds per-image failure reporting to data storage sync jobs, and exposes capture path/filename in the captures table.

Changes:

  • Extend backend filename timestamp parsing to support 12-digit YYMMDDHHMMSS patterns and add unit tests.
  • Add per-file exception handling and a “Failed” counter to data storage sync job progress updates.
  • Update UI capture model to avoid displaying epoch time for null timestamps, and add hidden-by-default Filename/Path table columns (with path added to the capture list serializer).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
ami/utils/dates.py Add regex + %y parsing support for 2-digit year timestamps in filenames.
ami/utils/tests.py Add unit tests covering 2-digit year filename parsing.
ami/main/models.py Track/log sync failures per object and report them via job progress.
ami/jobs/models.py Add “Failed” stage param for the data storage sync job.
ami/main/api/serializers.py Expose path in the capture list serializer.
ui/src/data-services/models/capture.ts Return blank labels for null timestamps; add path/filename getters; make date optional.
ui/src/pages/captures/capture-columns.tsx Add Filename and Path columns (hidden by default), both sortable by path.
ui/src/pages/captures/captures.tsx Add filename and path to persisted column visibility defaults (off).
ui/src/utils/language.ts Add FIELD_LABEL_FILENAME string constant and English label.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
ui/src/pages/session-details/playback/capture-navigation/capture-navigation.tsx (1)

61-68: Consider adding the same explanatory comment here for consistency.

The goToNext function uses the same non-null assertion pattern as goToPrev but lacks the explanatory comment. While the invariant is documented once, duplicating it here would improve readability for anyone reading this function in isolation.

📝 Suggested comment addition
   const goToNext = () => {
     if (!activeCapture) {
       return
     }
 
+    // Session captures always have dates (NULL timestamps excluded from events)
     const nextCaptureId = snapToDetections
       ? findClosestCaptureId({
           minDate: activeCapture.date!,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@ui/src/pages/session-details/playback/capture-navigation/capture-navigation.tsx`
around lines 61 - 68, Duplicate the explanatory non-null invariant comment used
in goToPrev next to the non-null assertion in goToNext: add the same comment
above the nextCaptureId expression (which uses activeCapture.date! and
snapToDetections) to document why the non-null assertion is safe; reference the
goToPrev comment as the source text and place the duplicate immediately before
the nextCaptureId assignment in the capture-navigation.tsx file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@ui/src/pages/session-details/playback/capture-navigation/capture-navigation.tsx`:
- Around line 61-68: Duplicate the explanatory non-null invariant comment used
in goToPrev next to the non-null assertion in goToNext: add the same comment
above the nextCaptureId expression (which uses activeCapture.date! and
snapToDetections) to document why the non-null assertion is safe; reference the
goToPrev comment as the source text and place the duplicate immediately before
the nextCaptureId assignment in the capture-navigation.tsx file.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7e2e601 and bca4478.

📒 Files selected for processing (5)
  • ami/jobs/models.py
  • ami/main/api/views.py
  • ami/main/models.py
  • ui/src/pages/session-details/playback/capture-navigation/capture-navigation.tsx
  • ui/src/pages/session-details/playback/session-captures-slider/session-captures-slider.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • ami/main/models.py
  • ami/jobs/models.py

@mihow mihow requested a review from annavik February 27, 2026 08:24
@mihow
Copy link
Collaborator Author

mihow commented Feb 27, 2026

I'm also unsure why we would ever want to import images with NULL timestamps. That will require a data migration, but seems like a good integrity change.

I went ahead and stopped importing images if the timestamp cannot be parsed.

@mihow mihow force-pushed the fix/2digit-year-timestamps-and-sync-improvements branch from bfb29e2 to 6351030 Compare February 27, 2026 11:33
mihow and others added 3 commits February 27, 2026 03:34
Some cameras (e.g. Farmscape/NSCF) produce filenames with 12-digit
timestamps using a 2-digit year. These were silently returning NULL,
causing images to show epoch dates in the UI and preventing session
grouping.

Add a new regex pattern for 12-digit timestamps and use %y format
for parsing.

Co-Authored-By: Claude <noreply@anthropic.com>
Images with unparseable timestamps can't be grouped into events
(group_images_into_events already excluded them), so importing them
just created orphaned records. Now they are skipped at sync time.

Also wraps per-image processing in try/except, tracks a failed counter,
and reports it as a "Failed" stage param in the job progress UI. Warns
on suspicious pre-2000 timestamps.

Co-Authored-By: Claude <noreply@anthropic.com>
Add two new columns to the captures table (hidden by default, toggled
via column settings). Expose the path field in the list serializer and
add it to sortable fields. Derive filename from path on the frontend.

Co-Authored-By: Claude <noreply@anthropic.com>
@mihow mihow force-pushed the fix/2digit-year-timestamps-and-sync-improvements branch from 6351030 to 1a25c84 Compare February 27, 2026 11:35
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.

2 participants