Summary
_check_ppo2 bounds oxygen exposure by instantaneous partial pressure only — the --ppo2-limit flag and the 1.6 bar ceiling both check "is ppO2 too high right now," never "how much oxygen has this diver absorbed over the whole dive." CNS clock (percentage of the single-exposure limit used up) and OTU (cumulative pulmonary toxicity units) are absent entirely.
Why it matters
A dive can clear every ppO2 check and still be an oxygen problem: a long dive at 1.3 bar never trips the 1.4 bar working limit, but NOAA's single-exposure tables cap that same ppO2 at 150 minutes on CNS grounds alone. Deco gas switching (#2) makes this worse, not better — richer gas at the shallow stops is exactly where CNS loading and OTU both accumulate fastest, and issue #2 explicitly flags this as follow-on work. Right now the tool has no way to say "this plan is fine on ppO2 but the diver has used 340% of their CNS budget."
Design sketch
Both are running totals over the dive, computed the same way the ascent walk already accumulates tissue pressure:
- CNS: NOAA single-exposure limits are a step table (ppO2 -> minutes-to-100%). Each step contributes
duration / limit_at(ppo2); sum across the dive, surface interval decays it (~90 min half-time is the common approximation).
- OTU:
OTU = duration * ((ppo2 - 0.5) / 0.5) ** 0.83 for ppo2 > 0.5, summed per step; tracked as a daily and (optionally) repetitive total.
Scope
model/dive_state.py or a new model/oxygen_toxicity.py — CNS and OTU accumulators, likely stepping alongside tissue loading rather than as a separate pass.
configs/limits.py — NOAA CNS table, OTU coefficients.
processors/dive_analysis.py — a new Violation kind for CNS/OTU exceeded, reported like OXYGEN (MOD) is today.
utils/state_store.py — CNS/OTU need to persist and decay between dives the same way tissue pressures do; likely another SCHEMA_VERSION bump.
README.md — replace the line 620 caveat with the real behavior.
Open questions
- CNS decay during a surface interval is commonly modeled as a 90-minute half-time, but sources disagree on the exact curve — worth picking one and stating the assumption rather than chasing precision the underlying model doesn't have elsewhere either.
- Whether OTU should gate the ascent walk (like the decompression ceiling does) or only report after the fact. Clamping on OTU the way
analyse_profile clamps on ceiling would be a bigger change than reporting a finding.
Summary
_check_ppo2bounds oxygen exposure by instantaneous partial pressure only — the--ppo2-limitflag and the1.6 barceiling both check "is ppO2 too high right now," never "how much oxygen has this diver absorbed over the whole dive." CNS clock (percentage of the single-exposure limit used up) and OTU (cumulative pulmonary toxicity units) are absent entirely.Why it matters
A dive can clear every ppO2 check and still be an oxygen problem: a long dive at 1.3 bar never trips the 1.4 bar working limit, but NOAA's single-exposure tables cap that same ppO2 at 150 minutes on CNS grounds alone. Deco gas switching (#2) makes this worse, not better — richer gas at the shallow stops is exactly where CNS loading and OTU both accumulate fastest, and issue #2 explicitly flags this as follow-on work. Right now the tool has no way to say "this plan is fine on ppO2 but the diver has used 340% of their CNS budget."
Design sketch
Both are running totals over the dive, computed the same way the ascent walk already accumulates tissue pressure:
duration / limit_at(ppo2); sum across the dive, surface interval decays it (~90 min half-time is the common approximation).OTU = duration * ((ppo2 - 0.5) / 0.5) ** 0.83for ppo2 > 0.5, summed per step; tracked as a daily and (optionally) repetitive total.Scope
model/dive_state.pyor a newmodel/oxygen_toxicity.py— CNS and OTU accumulators, likely stepping alongside tissue loading rather than as a separate pass.configs/limits.py— NOAA CNS table, OTU coefficients.processors/dive_analysis.py— a newViolationkind for CNS/OTU exceeded, reported likeOXYGEN (MOD)is today.utils/state_store.py— CNS/OTU need to persist and decay between dives the same way tissue pressures do; likely anotherSCHEMA_VERSIONbump.README.md— replace the line 620 caveat with the real behavior.Open questions
analyse_profileclamps on ceiling would be a bigger change than reporting a finding.