[P1] Live simulator crashes when an ascent tick ends just below a planned switch depth #27

Closed
opened 2026-10-27 02:59:42 +00:00 by pedro · 1 comment
Owner

Priority: P1
Type: bug
Source: project review requested 2026-10-26 (second pass)

Location: src/models/zhl16c.ts:175-183 (gasTravel); src/App.tsx live advance

Problem and evidence

gasTravel accepts switches up to 1e-9 m deeper than the start depth. When the diver is a rounding error below an already-crossed switch, the computed split duration is negative and segment throws "Invalid segment" (VPM: "Invalid VPM-B segment."). The live advance runs inside a React state updater with no error handling, so the whole app unmounts.

Reproduction with defaults (ascent 9 m/min, 8×, 1 s tick as in a throttled tab): switch to EAN50 at 21 m; advance(newDive(), 45, 20, 18, 9) then repeatedly advance(d, 0, min(8/60, d.depth/9), 18, 9, switches). Tick 20 lands at 20.99999999999998 m on EAN50; the next tick throws. decompressionPlan and noDecoLimit throw at that state too. A sweep failed in 152 of 735 rate/speed/depth/switch combinations.

Suggested correction

Only split at switches strictly shallower than the start depth (switches at the start depth are applied immediately), clamp split durations at zero, and keep a physics error from unmounting the live app.

Acceptance criteria

Regression for the reproduction across ZHL-16C/B and VPM-B and for exact-boundary switches; existing switch/replay tests pass; pnpm verify passes.

Scope: maintenance of the educational simulator. Preserve historical R1 acceptance and operational-validation limits.

Priority: P1 Type: bug Source: project review requested 2026-10-26 (second pass) Location: `src/models/zhl16c.ts:175-183 (gasTravel); src/App.tsx live advance` Problem and evidence gasTravel accepts switches up to 1e-9 m deeper than the start depth. When the diver is a rounding error below an already-crossed switch, the computed split duration is negative and segment throws "Invalid segment" (VPM: "Invalid VPM-B segment."). The live advance runs inside a React state updater with no error handling, so the whole app unmounts. Reproduction with defaults (ascent 9 m/min, 8×, 1 s tick as in a throttled tab): switch to EAN50 at 21 m; `advance(newDive(), 45, 20, 18, 9)` then repeatedly `advance(d, 0, min(8/60, d.depth/9), 18, 9, switches)`. Tick 20 lands at 20.99999999999998 m on EAN50; the next tick throws. decompressionPlan and noDecoLimit throw at that state too. A sweep failed in 152 of 735 rate/speed/depth/switch combinations. Suggested correction Only split at switches strictly shallower than the start depth (switches at the start depth are applied immediately), clamp split durations at zero, and keep a physics error from unmounting the live app. Acceptance criteria Regression for the reproduction across ZHL-16C/B and VPM-B and for exact-boundary switches; existing switch/replay tests pass; pnpm verify passes. Scope: maintenance of the educational simulator. Preserve historical R1 acceptance and operational-validation limits.
Author
Owner

Fixed on maintenance/review-2026-10-27 in 244c1f8 — PR #40.

Switch splits clamp to the travel interval; live tick and +1:00 pause with an alert on calculation errors instead of unmounting. 735-combination tick sweep 152 crashes → 0 across B/C/VPM; reference output identical.

Branch verification: pnpm verify 145 tests and release budgets; Chromium/Firefox/WebKit review, replay, compatibility and offline lifecycle checks; CI verify runs #111/#112 pass. Record: docs/MAINTENANCE-2026-10-27.md. Closes on merge of PR #40.

Fixed on `maintenance/review-2026-10-27` in `244c1f8` — [PR #40](https://git.guresky.com/pedro/DiveSim/pulls/40). Switch splits clamp to the travel interval; live tick and +1:00 pause with an alert on calculation errors instead of unmounting. 735-combination tick sweep 152 crashes → 0 across B/C/VPM; reference output identical. Branch verification: `pnpm verify` 145 tests and release budgets; Chromium/Firefox/WebKit review, replay, compatibility and offline lifecycle checks; CI verify runs #111/#112 pass. Record: `docs/MAINTENANCE-2026-10-27.md`. Closes on merge of PR #40.
pedro closed this issue 2026-10-27 05:39:05 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: pedro/DiveSim#27
No description provided.