T09: trip repository, completing Phase 2
All lifecycle transitions inside Drift transactions, each idempotent: start (adopting an active trip rather than duplicating it), pause, resume, complete, discard, rename, delete, merge, and the authoritative aggregate recomputation. Room.withTransaction maps onto Drift's transaction() almost exactly, so this was the most mechanical port so far. 26 tests, green first run. Merge keeps its hard-won properties: segments are never joined, so the boundary between two merged rides stays a segment boundary like a pause, and aggregates are recomputed rather than summed because distance is not additive across the gap. The regression test puts the two rides a degree of latitude apart and asserts the ~111km gap never reaches distanceM. Dropped a mergeTableUpdates helper before committing -- Drift's update() already notifies dependent streams, so it was scaffolding that earned nothing. TripRepositoryTest, MergeTest and SchemaTest were 666 lines of instrumented tests needing a booted emulator. All three now run as unit tests in ~2 seconds. Phase 2 done: 121 tests passing, analyze clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -317,3 +317,54 @@ well under a second with nothing booted. `TripRepositoryTest` and `MergeTest` (4
|
||||
lines) should convert the same way in T09.
|
||||
|
||||
**95 tests passing, analyze clean.**
|
||||
|
||||
---
|
||||
|
||||
## T09 — Trip repository · **complete**
|
||||
|
||||
`lib/src/data/trip_repository.dart`. **26 tests, green on the first run.**
|
||||
|
||||
Every lifecycle transition ported: `startTrip` (adopting, never duplicating), `pauseTrip`,
|
||||
`resumeTrip`, `completeTrip`, `discardTrip`, `renameTrip`, `deleteTrip`, `mergeTrips`,
|
||||
`recomputeAggregates`. Each runs inside `_db.transaction` and each is idempotent, because
|
||||
the platform can restart the recorder from any state.
|
||||
|
||||
`Room.withTransaction` maps onto Drift's `transaction()` almost exactly, so this was the
|
||||
most mechanical port so far.
|
||||
|
||||
### What the tests protect
|
||||
|
||||
- **Adoption over rejection.** `startTrip` on an already-active trip returns the *same*
|
||||
handle rather than opening a second trip — the behaviour that makes a process kill
|
||||
survivable.
|
||||
- **Merge never joins segments.** The boundary between two merged rides stays a segment
|
||||
boundary, exactly like a pause. The regression test puts the two rides a degree of
|
||||
latitude apart and asserts the ~111 km gap never reaches `distanceM`.
|
||||
- **Aggregates are recomputed, not summed** — because distance is not additive across
|
||||
that gap.
|
||||
- **Rename collapses empty and whitespace-only input to null**, so a stored `""` can
|
||||
never diverge from the UI's date-label branch.
|
||||
- **Merge rejects** self-merge, an active trip, and a missing id, and leaves no orphans.
|
||||
|
||||
### One piece of speculative code removed
|
||||
|
||||
A `mergeTableUpdates` helper was written to nudge Drift's stream queries after
|
||||
re-parenting, then deleted before commit: Drift's own `update()` already notifies
|
||||
dependent streams, so it earned nothing and would have been misleading scaffolding.
|
||||
|
||||
### The instrumented-to-unit win, totalled
|
||||
|
||||
`TripRepositoryTest` + `MergeTest` + `SchemaTest` were **666 lines of instrumented tests
|
||||
requiring a booted emulator**. All three are now plain unit tests finishing in about two
|
||||
seconds with nothing running.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 complete
|
||||
|
||||
**121 tests passing, `flutter analyze` clean.** The data layer is done and the domain,
|
||||
statistics and export layers above it are proven equivalent to the Kotlin original.
|
||||
|
||||
Next: **Phase 3, the recording engine** — the risky phase. T10's `LocationSource` seam
|
||||
first, then the pipeline, then the two platform liveness stories. The
|
||||
`flutter_foreground_task` deprecation warnings recorded under T01 become relevant at T12.
|
||||
|
||||
Reference in New Issue
Block a user