Dive planner Phase 2: persisted plans, sync, and the PlanEngine#485
Merged
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Contributor
There was a problem hiding this comment.
Pull request overview
Implements Phase 2 of the dive-planner redesign by introducing a persisted/synced dive-plan aggregate plus a new PlanEngine that computes schedules, consumption, and issues using the Phase 1 deco-engine seams. This keeps the legacy planner UI largely intact while making “Save”/deep-link “Load” operate against real stored plans.
Changes:
- Adds schema v100 plan tables (
dive_plans,dive_plan_tanks,dive_plan_segments) with migration/backstop and full sync registration + FK-on round-trip coverage. - Introduces the
planner/feature module:domain.DivePlan+DivePlanRepository+PlanEngine+ Riverpod providers. - Wires legacy planner save/load to persisted plans via a state↔aggregate mapper and adds end-to-end tests for save/reset/load.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/features/planner/plan_engine_schedule_test.dart | Validates PlanEngine schedule generation and parity with legacy planner results. |
| test/features/planner/plan_engine_issues_test.dart | Covers PlanEngine issue detection, sorting, and consumption math. |
| test/features/planner/dive_plan_state_mapper_test.dart | Ensures legacy UI state round-trips through the persisted aggregate. |
| test/features/planner/dive_plan_repository_test.dart | Exercises plan persistence, summaries, tombstones, duplication, and pending sync markers. |
| test/features/planner/dive_plan_entity_test.dart | Verifies DivePlan derived defaults, max-depth logic, and copyWith clear-flags. |
| test/features/dive_planner/save_load_round_trip_test.dart | End-to-end test for save → reset → load through Riverpod + repository. |
| test/core/services/sync/dive_plan_sync_round_trip_test.dart | Sync export/JSON/apply round-trip validation with FK ON. |
| test/core/deco/gas_density_test.dart | Pins density computation vectors and thresholds. |
| test/core/database/migration_v100_dive_plans_test.dart | Asserts v100 tables/indexes exist and beforeOpen backstop heals collisions. |
| lib/features/planner/presentation/providers/plan_repository_providers.dart | Provides repository + live-updating summaries list providers. |
| lib/features/planner/domain/services/plan_engine.dart | New PlanEngine orchestration: schedule, segments, consumption, and issue computation. |
| lib/features/planner/domain/services/dive_plan_state_mapper.dart | Maps between legacy planner state and the new persisted domain.DivePlan. |
| lib/features/planner/domain/entities/plan_outcome.dart | Defines PlanEngine output model (stops, tank usage, issues, tissue timeline). |
| lib/features/planner/domain/entities/dive_plan.dart | Defines persisted dive-plan aggregate + summary row type. |
| lib/features/planner/data/repositories/dive_plan_repository.dart | Implements persistence, child tombstones, sync pending markers, and duplication. |
| lib/features/dive_planner/presentation/providers/dive_planner_providers.dart | Wires notifier to repository-backed save/load while preserving legacy flows. |
| lib/features/dive_planner/presentation/pages/dive_planner_page.dart | Loads persisted plan by route id and replaces save TODO with real persistence. |
| lib/features/dive_log/data/services/profile_analysis_service.dart | Deduplicates density math via shared helper. |
| lib/core/services/sync/sync_service.dart | Registers plan entities in merge order, updatedAt map, and parent refs. |
| lib/core/services/sync/sync_data_serializer.dart | Adds plan entities to SyncData + export/upsert/delete/record-id plumbing. |
| lib/core/deco/gas_density.dart | New shared gas-density helper + thresholds. |
| lib/core/database/database.dart | Adds Drift table definitions, schema bump to v100, migration + beforeOpen re-assert. |
| lib/core/data/repositories/sync_repository.dart | Registers plan tables as HLC targets for pending marking. |
| docs/superpowers/plans/2026-07-05-dive-planner-phase2-domain.md | Implementation plan/spec for Phase 2 work items and constraints. |
This was referenced Jul 5, 2026
- PlanEngine: reject non-Buhlmann start states up front; accumulate CNS/OTU over decompression stops (primary + air-break gas) - DivePlanRepository: preserve child tank/segment createdAt across edits - Add entity, engine, repository, and sync round-trip coverage
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 2 of the dive planner redesign (spec, plan). Builds directly on #484 (Phase 1 engine, now merged).
Persistence + sync
dive_plans/dive_plan_tanks/dive_plan_segmentswith HLC columns, idempotent migration, and abeforeOpenre-assert backstop against parallel-branch version collisions. The plan row carries CCR/contingency/repetitive config columns now (Phases 4-6 fill them) plus denormalized summary columns so the saved-plans list never runs the engine per row.entityHasUpdatedAt,parentRefs,_hlcTargets) — verified by the structural safety-net tests plus a new FK-ON export/JSON/upsert round-trip test.DivePlanRepository: save/get/list/delete/duplicate withmarkRecordPending+ fresh HLC on every write and per-row tombstones for removed children (the parent-surviving-child-delete lesson from multi-computer consolidation).Domain + engine
domain.DivePlanaggregate: the persisted superset of the legacy planner state — mode (OC/CCR), water type, descent/ascent rates, last stop, air breaks, three SAC rates (bottom / deco / stressed with 0.8x / 2.5x derived defaults), deviation deltas, turn-pressure rule, setpoints, tissue-seeding and plan-vs-actual dive links.PlanEngine:DivePlan -> PlanOutcomebuilt entirely on the Phase 1 seams (BuhlmannGf/SchedulePolicy/BreathingConfig/DiveEnvironment). Produces the stop schedule with per-stop gas/tank/arrival, per-segment NDL/ceiling/TTS/CNS/OTU, a tissue timeline for the Phase 3 canvas, environment-aware three-SAC consumption with compressibility-corrected remaining pressure, and a severity-sortedPlanIssuelist: ppO2, hypoxic gas, END, gas density 5.2/6.2 g/L (new sharedgas_density.darthelper, also deduplicating the dive-details density curve), CNS/OTU, reserve/gas-out, and deco-without-deco-gas.PlanEngineagainst the legacyPlanCalculatorService: identical stops, TTS, and NDL on the default path.User-visible
/planning/dive-planner/:planIdloads a saved plan back into the editor. Everything else about the old planner is unchanged — the new UI is Phase 3.Verification
790 tests green across the sweep (4 migration, 304 deco, 82 planner, 400 sync);
flutter analyzeclean.