Skip to content

Fix bounding box not appearing on /react/encounter after detection#1559

Merged
JasonWildMe merged 4 commits intomainfrom
flakebook-10.10-encounter-bbox-fixes
May 1, 2026
Merged

Fix bounding box not appearing on /react/encounter after detection#1559
JasonWildMe merged 4 commits intomainfrom
flakebook-10.10-encounter-bbox-fixes

Conversation

@JasonWildMe
Copy link
Copy Markdown
Collaborator

@JasonWildMe JasonWildMe commented Apr 26, 2026

Summary

Three independent bugs combined to prevent bounding boxes from rendering on /react/encounter after detection completed. Each is fixed in its own commit on this branch.

  1. Feature.parameters returned null on cross-PM reads — the JDO mapping used <property> with no backing String field, so DataNucleus' bytecode enhancement persisted the value without invoking the user-defined setParametersAsString on load. The in-memory parameters JSONObject stayed null, getBbox() returned null, and the encounter API serializer emitted boundingBox: [] even though the DB row had correct width/height/x/y JSON.
  2. Service worker cached /api/ polling responses — the catchall registerRoute(() => true, new NetworkFirst()) caches every fetch. NetworkFirst falls back to cache on slow/erroring network, so a brief empty-bbox response could be replayed to subsequent polls and even hard refreshes.
  3. React polling stopped too early on bulk imports — the polling predicate treated null detectionStatus as terminal, but bulk-imported encounters arrive with detectionStatus = null plus a trivial placeholder annotation while detection is queued in WBIA. Polling stopped on the first poll, never noticed when detection actually completed, and the in-place setMediaAssets mutation prevented useEffects from re-running anyway.

After all three fixes: backend correctly persists and serves bbox data, SW does not cache it, polling stays alive through the WBIA wait, React UI updates without a refresh.

Verified end-to-end by uploading bulk-import encounters on flakebook.wildme.org during this session: bounding boxes now appear automatically once WBIA returns, no manual refresh needed.

Test plan

  • Run mvn clean install — build succeeds with new JDO mapping. (Verified locally.)
  • Run npm run build in frontend/ — bundle compiles. (Verified locally — eslint clean on changed files.)
  • Single-encounter submission: upload an image, observe yellow "Detection in progress" bar, observe red bbox appear automatically when detection completes (no refresh required).
  • Bulk-import submission: same as above for each encounter in the import.
  • Existing encounters' annotations still render correctly (no regression on already-detected data).
  • Legacy/manual encounters without importTaskId and trivial-only annotations don't poll forever (max-poll cap of ~5 minutes serves as a safety net regardless).

Out of scope (separate tickets recommended)

  • MediaAsset.derivationMethod uses the same broken <property> pattern as old Feature.parameters. Likely silently broken; nothing user-visible currently depends on it.
  • IndexingManager.addIndexingQueueEntry has a dedup race where late updates during a bg index runnable's lifetime are silently dropped.
  • BulkImport.doDelete violates MATCHRESULT_FK1 when deleting an import whose annotations are referenced from MATCHRESULT.
  • QueueUtil.background halts the entire queue consumer on the first exception in getNext() — recommend catch-and-continue instead.
  • Cleaner architectural fix for issue 3 above: have the bulk-import IA dispatch set detectionStatus = "queued"/"sent" server-side instead of leaving it null. Would let us drop the isAwaitingBulkImportDetection workaround.

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 26, 2026

Codecov Report

❌ Patch coverage is 82.35294% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 51.54%. Comparing base (d6bee0d) to head (d876b05).

Files with missing lines Patch % Lines
frontend/src/pages/Encounter/pollingHelpers.js 83.33% 1 Missing and 3 partials ⚠️
...ntend/src/pages/Encounter/stores/EncounterStore.js 0.00% 1 Missing ⚠️
frontend/src/service-worker.js 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1559   +/-   ##
=======================================
  Coverage   51.54%   51.54%           
=======================================
  Files         307      308    +1     
  Lines       11942    11952   +10     
  Branches     3836     3842    +6     
=======================================
+ Hits         6155     6161    +6     
- Misses       5502     5503    +1     
- Partials      285      288    +3     
Flag Coverage Δ
backend 51.54% <82.35%> (+<0.01%) ⬆️
frontend 51.54% <82.35%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

JasonWildMe and others added 3 commits April 26, 2026 13:22
Feature.parametersAsString was mapped via <property> with no backing
String field, so DataNucleus' bytecode enhancement persisted the value
without invoking the user-defined setParametersAsString on load. The
in-memory JSONObject parameters field stayed null, and getBbox()
returned null on any PM that wasn't the one that created the Feature
in memory. The encounter API serializer then emitted boundingBox: []
even though the DB row had correct width/height/x/y JSON.

Fix mirrors the working MediaAsset.parameters pattern:
  - Add String parametersAsString field to Feature.java
  - Change package.jdo from <property> to <field name="parametersAsString">
  - getParameters() lazy-parses from parametersAsString when null
  - setParameters() keeps both fields in sync
  - get/setParametersAsString operate on the new field

DB column unchanged. Existing rows load correctly with no migration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The catchall registerRoute(() => true, new NetworkFirst()) was caching
every fetch including the /api/v3/encounters/<id> polling responses.
NetworkFirst falls back to cache on slow network or transient errors,
so a poll that briefly returned an empty annotations array got cached
and replayed to subsequent polls and even hard refreshes, masking
correct backend state.

API responses are not idempotent (encounter state changes during
detection) and should never go through SW caching. Static assets and
navigations still benefit from the strategy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three issues prevented the bounding box from rendering after detection
completes for bulk-imported encounters:

1. setMediaAssets mutated _encounterData.mediaAssets in place. React
   useEffects keyed on store.encounterData saw the same reference and
   never re-ran, so rects/imageReady never updated when polling
   returned new annotations. Switched to immutable update: replace
   _encounterData with a new object.

2. The polling predicate treated null detectionStatus as terminal.
   Bulk imports create encounters with a trivial placeholder annotation
   and detectionStatus=null while detection is queued to WBIA. The
   first poll saw null, stopped polling, and never noticed when
   detection actually completed. Added isAwaitingBulkImportDetection
   helper that keeps polling alive when detectionStatus is null,
   importTaskId is set, and only trivial annotations exist.

3. ImageCard's "Detection in progress" indicator used the same broken
   predicate. Now uses the shared helper so the spinner shows during
   the WBIA wait.

Centralized the predicates in pollingHelpers.js so Encounter.jsx and
ImageCard.jsx can't drift. Added MAX_POLL_CYCLES=100 (~5 min at 3s
interval) safety cap so encounters that never get detection don't
poll forever.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JasonWildMe JasonWildMe force-pushed the flakebook-10.10-encounter-bbox-fixes branch from fef5ffe to adeb87e Compare April 26, 2026 20:23
Copy link
Copy Markdown
Member

@naknomum naknomum left a comment

Choose a reason for hiding this comment

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

code looks good, problem fixed in testing.

@JasonWildMe JasonWildMe merged commit af0abd3 into main May 1, 2026
2 checks passed
@JasonWildMe JasonWildMe deleted the flakebook-10.10-encounter-bbox-fixes branch May 1, 2026 17:46
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.

3 participants