You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Planning Flensburg → Marstal at the default safety depth (3.0 m) fails outright with error.noRoute.unreachable ("No route found — the destination cannot be reached without crossing land or too-shallow water."). In reality the passage is fine for a 2.1 m-draft boat: Marstal's dredged approach channel is deep enough, but EMODnet bathymetry can't resolve it at 46 m cells, so in the shipped mask Marstal's snap cell sits in a 119-cell pocket that only 4-connects to open water at gate depths ≤ 2.3 m (documented in app/src/routing/realmask.repro.test.ts:114-122, CONNECTIVITY_EXCEPTIONS_M in pipeline/verify_mask.py, PR #8, #9).
A hard failure is the wrong UX for this class of data limitation. The user gets a dead end with no way forward except manually guessing a lower safety depth in settings.
Expected behavior
When no route exists at the requested safety depth, the router should degrade gracefully instead of failing completely:
Retry with a relaxed depth gate (bounded below — never below boat draft 2.1 m; e.g. step down 3.0 → 2.7 → 2.4 → 2.1, or binary-search the highest depth that routes).
If a relaxed route is found, return it with explicit shallow-water warnings instead of no-route:
a plan-level warning ("route requires passing water charted shallower than your safety depth of X m; minimum charted gate depth on this route: Y m"),
If even the relaxed floor fails, keep today's unreachable error.
Constraints / design notes
Navigability is decided at query time (cellDepth >= safetyDepthM), so the fallback is pure re-query — no mask regeneration involved.
The warning must be honest and prominent: the app is a passage-planning aid, not a navigation device — copy must say the charted data may understate/overstate real depths (dredged channels are exactly the case where the chart data is pessimistic), not imply the route is verified safe.
Both rig runs (genoa + fock) should relax consistently so the rig comparison stays apples-to-apples.
Plan stays structured-clone-safe; new warning fields must fit that contract.
All new user-facing strings go through both i18n dicts (de/en).
Relaxation multiplies solver runs — mind worker-time budget and progress reporting; the relaxed retries should reuse the already-transferred mask, not re-transfer it.
app/src/routing/realmask.repro.test.ts currently pins Flensburg → Marstal at 2.3 m with a comment saying "at 3.0 m 'unreachable' is the CORRECT answer for this data" — after this feature, the spec acceptance case should plan at DEFAULT_SETTINGS and assert a route with shallow warnings instead.
Acceptance criteria
Flensburg → Marstal at default settings (3.0 m safety depth) returns a route, flagged with shallow-water warnings, instead of unreachable.
The UI shows a clear warning (banner/summary + highlighted legs) identifying where and how shallow the flagged segments are.
Relaxation never goes below boat draft; a genuinely unreachable destination still errors as today.
Warnings persist with the saved plan and render identically on reload (IndexedDB round-trip).
de/en strings added to both dicts; realmask acceptance test updated to default settings.
Related: #9 (mask connectivity limits — this issue is the UX mitigation for routes those sub-cell features block).
Problem
Planning Flensburg → Marstal at the default safety depth (3.0 m) fails outright with
error.noRoute.unreachable("No route found — the destination cannot be reached without crossing land or too-shallow water."). In reality the passage is fine for a 2.1 m-draft boat: Marstal's dredged approach channel is deep enough, but EMODnet bathymetry can't resolve it at 46 m cells, so in the shipped mask Marstal's snap cell sits in a 119-cell pocket that only 4-connects to open water at gate depths ≤ 2.3 m (documented inapp/src/routing/realmask.repro.test.ts:114-122,CONNECTIVITY_EXCEPTIONS_Minpipeline/verify_mask.py, PR #8, #9).A hard failure is the wrong UX for this class of data limitation. The user gets a dead end with no way forward except manually guessing a lower safety depth in settings.
Expected behavior
When no route exists at the requested safety depth, the router should degrade gracefully instead of failing completely:
no-route:unreachableerror.Constraints / design notes
cellDepth >= safetyDepthM), so the fallback is pure re-query — no mask regeneration involved.Planstays structured-clone-safe; new warning fields must fit that contract.app/src/routing/realmask.repro.test.tscurrently pins Flensburg → Marstal at 2.3 m with a comment saying "at 3.0 m 'unreachable' is the CORRECT answer for this data" — after this feature, the spec acceptance case should plan atDEFAULT_SETTINGSand assert a route with shallow warnings instead.Acceptance criteria
unreachable.Related: #9 (mask connectivity limits — this issue is the UX mitigation for routes those sub-cell features block).