Skip to content

Fix over-eager dive matching (time gate) + Consolidate for file imports#494

Merged
ericgriffin merged 5 commits into
mainfrom
worktree-dive-match-consolidate
Jul 6, 2026
Merged

Fix over-eager dive matching (time gate) + Consolidate for file imports#494
ericgriffin merged 5 commits into
mainfrom
worktree-dive-match-consolidate

Conversation

@ericgriffin

@ericgriffin ericgriffin commented Jul 6, 2026

Copy link
Copy Markdown
Member

Addresses a tester report on ScubaBoard (user stiebs): a Subsurface import was flagged as a 50% "possible duplicate" of an existing dive that was months apart, ~4.5 km away, at a different time of day — sharing only its 47-minute duration. The same report noted that Combine/Consolidate only worked for direct dive-computer downloads, not file imports.

Part 1 — Time is now a necessary gate in the matcher

File imports score candidates with DiveMatcher.calculateMatchScore, a weighted sum: time*0.50 + depth*0.30 + duration*0.20. With timeScore = 0 (starts >= 15 min apart), depth (0.30) + duration (0.20) alone summed to exactly 0.50 — the isPossibleDuplicate threshold — so two unrelated dives with a similar profile got flagged.

A dive is a single event in time; two recordings that do not line up in time cannot be the same dive. The fix makes time a necessary condition: once time evidence is zero, the pair is not a match, before the weighted sum runs. The dive-computer download path already gated on time via SQL, so it is unchanged.

stiebs's pair now scores 0.0 instead of 0.50.

Part 2 — Manual Consolidate for file imports

The consolidation capability already existed but was only wired into the dive-computer download adapter; the live file-import adapter (UniversalAdapter) offered only skip / import-as-new and hard-coded consolidatedCount: 0. This ports the proven wiring (performConsolidations + DiveConsolidationService) into UniversalAdapter:

  • consolidate added to supportedDuplicateActions → the review UI renders the button automatically (one declarative set drives every layer of the UI).
  • Exact source_uuid re-imports are flagged matchedExistingSource so they default to skip (never consolidated).
  • performImport folds consolidate-flagged dives after import and reports an accurate count — folded dives are subtracted from the "imported as new" count instead of being double-counted.

File imports are manual-consolidate only: a file has no single "current computer" to prove a cross-computer match, so the user chooses. Consolidating onto a same-computer target fails gracefully (the fold is rejected, the standalone import is tombstoned via the existing compensating-delete path, and it is reported as skipped).

Testing

  • DiveMatcher: gate tests incl. the exact ScubaBoard regression (months apart, identical depth + duration → 0.0), same-day-hours-apart, the 15-minute boundary, and a within-window guard.
  • ImportDuplicateChecker: matchedExistingSource true for source_uuid / false for content matches; far-apart dives no longer matched.
  • UniversalAdapter: supports consolidate; performImport folds a consolidate-flagged dive and adjusts counts (wiring test).
  • Full suite green: 10449 passed / 12 skipped; flutter analyze clean (whole project); macOS build succeeds.

Design spec and implementation plan are included under docs/superpowers/.

@codecov

codecov Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 tightens duplicate-dive detection for file imports by making time proximity a hard prerequisite in DiveMatcher, and it wires manual “Consolidate” support into the routed file-import adapter (UniversalAdapter) so file imports can fold duplicates the same way dive-computer downloads can.

Changes:

  • Make time a necessary gate in DiveMatcher.calculateMatchScore so far-apart dives can’t reach duplicate thresholds via depth+duration alone.
  • Flag exact source_uuid re-import matches as matchedExistingSource and enable manual DuplicateAction.consolidate for file imports, including post-import folding and corrected summary counts.
  • Add targeted regression and wiring tests, plus design/spec documentation under docs/superpowers/.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/features/universal_import/data/services/import_duplicate_checker_test.dart Adds tests for matchedExistingSource semantics and far-apart dives no longer matching.
test/features/import_wizard/data/adapters/universal_adapter_test.dart Verifies consolidate is supported and performImport delegates fold + adjusts counts.
test/features/dive_import/domain/services/dive_matcher_test.dart Adds time-gate regression/boundary tests for matcher scoring.
lib/features/universal_import/data/services/import_duplicate_checker.dart Sets matchedExistingSource: true for exact source_uuid matches.
lib/features/import_wizard/data/adapters/universal_adapter.dart Enables consolidate for file imports and performs post-import consolidation with updated result accounting.
lib/features/dive_import/domain/services/dive_matcher.dart Implements the time-as-gate short-circuit in calculateMatchScore.
docs/superpowers/specs/2026-07-06-dive-matching-time-gate-and-file-import-consolidation-design.md Design spec documenting the two fixes and rationale.
docs/superpowers/plans/2026-07-06-dive-matching-time-gate-and-file-import-consolidation.md Implementation plan for the work (for traceability/process).

Comment thread lib/features/import_wizard/data/adapters/universal_adapter.dart Outdated
@ericgriffin ericgriffin merged commit f4b7749 into main Jul 6, 2026
19 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in Submersion Release Tracker Jul 6, 2026
@ericgriffin ericgriffin deleted the worktree-dive-match-consolidate branch July 6, 2026 15:44
ericgriffin added a commit that referenced this pull request Jul 6, 2026
…anup

Cleanup: shared MatchScorer + remove dead import code (follow-up to #494)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants