Skip to content

fix: correct preprocessing scale semantics for MiewID and detector path#11

Merged
JasonWildMe merged 3 commits intowildlife-reidfrom
fix/preprocessing-scale-math
Apr 24, 2026
Merged

fix: correct preprocessing scale semantics for MiewID and detector path#11
JasonWildMe merged 3 commits intowildlife-reidfrom
fix/preprocessing-scale-math

Conversation

@JasonWildMe
Copy link
Copy Markdown

Summary

  • DetectorConfig.normalize.scale is documented as a multiplier (e.g. 1/255) in docs/EMBEDDING_PACK_FORMAT.md, but the native ImageTensorModule on both platforms divided by it. A spec-compliant pack would have produced pixel × 255 going into normalization — wildly out of range.
  • The MiewID embedding wrapper hardcoded scale = 1.0, so even if the native math had been right, MiewID got 0–255 values fed into ImageNet mean/std that expects 0–1. Embeddings were silently garbage.
  • Added a cross-platform golden parity fixture (1×1 pure-red pixel through ImageNet norm + scale = 1/255) that asserts identical numerical output — R≈2.249, G≈-2.036, B≈-1.804 — in both Kotlin and Swift. If either native module drifts, both fail loudly with matching messages.
  • Pre-commit hook now skips iOS tests when xcodebuild is unavailable on the host (mirroring the existing SwiftLint-missing pattern). macOS CI still runs them before merge.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Why this matters

This is the foundational fix for the on-device MiewID re-ID pipeline. Without it, every embedding extracted on device would be unusable, every cosine match meaningless, and every downstream stage of the integration plan would be tuning on noise. Catching this before MiewID is wired (rather than after, while debugging zero-rank matches) saves significant downstream work.

Files Changed

File Change
src/services/onnxInferenceService/preprocessing.ts MiewID wrapper: scale: 1.01.0/255.0
__tests__/unit/services/onnxInferenceService.test.ts Updated MiewID expectations to 1.0/255.0
android/.../imagetensor/ImageTensorModule.kt (pixel / scale - mean) / std(pixel * scale - mean) / std
android/.../imagetensor/ImageTensorModuleTest.kt Updated existing tests to multiplier semantics + golden parity fixture
ios/ImageTensorModule.swift Same divide → multiply, mirrored
ios/OffgridMobileTests/OffgridMobileTests.swift Same test update + identical parity fixture
.husky/pre-commit Skip iOS tests when xcodebuild is unavailable (with warning)

Test plan

  • npx tsc --noEmit clean
  • npx jest — 410/410 tests pass
  • ./gradlew :app:testDebugUnitTest --tests ImageTensorModuleTest — 11/11 tests pass on Android
  • iOS tests via macOS CI runner (skipped locally — no xcodebuild on WSL host)
  • Manual verify on Android device that detection + (eventual) MiewID embedding produce sensible values

JasonWildMe and others added 2 commits April 23, 2026 22:30
`scale` in DetectorConfig.normalize is documented as a multiplier
(e.g. 1/255) per docs/EMBEDDING_PACK_FORMAT.md, but native code on
both platforms divided by it instead, and the MiewID TS wrapper
hardcoded scale=1.0 — so a spec-compliant pack would feed
pixel*255 into normalization, and MiewID got 0-255 values fed
into ImageNet mean/std that expects 0-1.

- ImageTensorModule.kt + ImageTensorModule.swift: divide → multiply
- preprocessing.ts: MiewID embedding wrapper passes 1/255 (was 1.0)
- Updated existing native tests to encode the multiplier convention
- Added a cross-platform golden parity fixture (1×1 pure-red pixel
  through ImageNet norm + scale=1/255) asserting identical numerical
  output (R≈2.249, G≈-2.036, B≈-1.804) in Kotlin and Swift
- Pre-commit: skip iOS tests when xcodebuild is unavailable
  (mirrors the existing SwiftLint-missing pattern); macOS CI still
  runs them before merge

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The wildlife re-ID fork lives on the long-lived `wildlife-reid`
integration branch, but CI only fired for main. PRs against
wildlife-reid (including #11) showed no status checks, blocking
the Gemini / Codecov / SonarCloud review loop defined in
CLAUDE.md.

Adding wildlife-reid alongside main in both trigger filters so
the integration branch gets the same quality gates as main.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
JasonWildMe added a commit that referenced this pull request Apr 24, 2026
The wildlife re-ID fork lives on the long-lived `wildlife-reid`
integration branch, but CI only fired for main. PRs against
wildlife-reid (including #11) showed no status checks, blocking
the Gemini / Codecov / SonarCloud review loop defined in
CLAUDE.md.

Adding wildlife-reid alongside main in both trigger filters so
the integration branch gets the same quality gates as main.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JasonWildMe
Copy link
Copy Markdown
Author

Reopening to re-trigger CI once wildlife-reid has the workflow branch filter.

Follow-up to the Stage 0 scale semantics fix — codex 5.5 deep review
and first CI run surfaced two remaining issues:

1. DEFAULT_DETECTOR_CONFIG fallback in useCaptureFlow still had the
   pre-fix `scale: 255` (divisor convention). With the now-corrected
   native multiplier math, the fallback would have produced
   pixel*255, identical to the bug we just fixed for MiewID.
   Updated to `1/255` in both the production default and the
   integration test fixture at pipelineFlow.test.ts.

2. src/screens/MatchReviewScreen.tsx was a 23-line stub superseded
   long ago by the MatchReviewScreen/ directory form, but the stub
   was never removed from git. Node module resolution prefers
   file-over-directory, so Jest in CI resolved the test's import
   to the stub and all 19 MatchReviewScreen tests failed (no
   testIDs on the stub). Works locally because the working tree
   had the file deleted-but-not-committed. Dropping the stub.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JasonWildMe
Copy link
Copy Markdown
Author

/gemini review

@JasonWildMe JasonWildMe merged commit b4517f7 into wildlife-reid Apr 24, 2026
4 checks passed
@JasonWildMe JasonWildMe deleted the fix/preprocessing-scale-math branch April 24, 2026 16:02
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