From ef81013e96f81a8562a897d5665b2145f2a097ed Mon Sep 17 00:00:00 2001 From: znetsixe Date: Mon, 11 May 2026 17:13:21 +0200 Subject: [PATCH] B1.2: drop legacy 'overfillLevel' alias from thresholdValidator Decision 2026-05-11: 'highVolumeSafetyLevel' is canonical. The legacy 'overfillLevel' name is gone from computeSafetyPoints + the validator issue tuple. 'overfillVol' parallel alias kept (out of scope for this task; flagged for follow-up). 130/130 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/basin/thresholdValidator.js | 28 ++++++++------------- test/basic/thresholdValidator.basic.test.js | 15 +++++------ 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/basin/thresholdValidator.js b/src/basin/thresholdValidator.js index 50bb69e..1768778 100644 --- a/src/basin/thresholdValidator.js +++ b/src/basin/thresholdValidator.js @@ -19,8 +19,8 @@ function computeSafetyPoints(basin, safety = {}) { const dryRunPct = Number(safety.dryRunThresholdPercent) || 0; const rawHighPct = safety.highVolumeSafetyThresholdPercent ?? safety.overfillThresholdPercent; // When neither high-volume nor overfill pct is supplied, use 100 % so - // the validator's `maxLevel <= overfillLevel` check is a no-op (the - // basin can't physically exceed overflow anyway). Tests pin this. + // the validator's `maxLevel <= highVolumeSafetyLevel` check is a no-op + // (the basin can't physically exceed overflow anyway). Tests pin this. const highPct = Number(rawHighPct); const effectiveHighPct = Number.isFinite(highPct) ? highPct : 100; const minVol = Number(basin?.minVol) || 0; @@ -41,7 +41,6 @@ function computeSafetyPoints(basin, safety = {}) { highVolumeSafetyVol, highVolumeSafetyLevel, // Back-compat alias — pre-basin-docs name. - overfillLevel: highVolumeSafetyLevel, overfillVol: highVolumeSafetyVol, }; } @@ -55,22 +54,17 @@ function computeSafetyPoints(basin, safety = {}) { function validateThresholdOrdering(basin, levelbased, safety) { const lvl = levelbased || {}; const points = computeSafetyPoints(basin, safety); - const { dryRunLevel, overfillLevel } = points; + const { dryRunLevel, highVolumeSafetyLevel } = points; - // basin-docs added `startLevel <= inflowLevel` and `inflowLevel < - // maxLevel`; HEAD had only the `startLevel < maxLevel` and - // `maxLevel <= overfillLevel` checks. We keep the `overfillLevel` - // name (rather than basin-docs's `highVolumeSafetyLevel`) for - // back-compat with consumers reading issue.bName. const checks = [ - ['outflowLevel', basin.outflowLevel, '<', 'inflowLevel', basin.inflowLevel], - ['inflowLevel', basin.inflowLevel, '<', 'overflowLevel', basin.overflowLevel], - ['overflowLevel', basin.overflowLevel, '<=', 'basinHeight', basin.heightBasin], - ['dryRunLevel', dryRunLevel, '<=', 'minLevel', lvl.minLevel], - ['minLevel', lvl.minLevel, '<=', 'startLevel', lvl.startLevel], - ['startLevel', lvl.startLevel, '<=', 'inflowLevel', basin.inflowLevel], - ['startLevel', lvl.startLevel, '<', 'maxLevel', lvl.maxLevel], - ['maxLevel', lvl.maxLevel, '<=', 'overfillLevel', overfillLevel], + ['outflowLevel', basin.outflowLevel, '<', 'inflowLevel', basin.inflowLevel], + ['inflowLevel', basin.inflowLevel, '<', 'overflowLevel', basin.overflowLevel], + ['overflowLevel', basin.overflowLevel, '<=', 'basinHeight', basin.heightBasin], + ['dryRunLevel', dryRunLevel, '<=', 'minLevel', lvl.minLevel], + ['minLevel', lvl.minLevel, '<=', 'startLevel', lvl.startLevel], + ['startLevel', lvl.startLevel, '<=', 'inflowLevel', basin.inflowLevel], + ['startLevel', lvl.startLevel, '<', 'maxLevel', lvl.maxLevel], + ['maxLevel', lvl.maxLevel, '<=', 'highVolumeSafetyLevel', highVolumeSafetyLevel], ]; const issues = []; diff --git a/test/basic/thresholdValidator.basic.test.js b/test/basic/thresholdValidator.basic.test.js index 26c93f3..7481439 100644 --- a/test/basic/thresholdValidator.basic.test.js +++ b/test/basic/thresholdValidator.basic.test.js @@ -8,7 +8,8 @@ const { validateThresholdOrdering } = require('../../src/basin/thresholdValidato const BasinGeometry = require('../../src/basin/BasinGeometry'); // A valid baseline: outlet 0.2 < inflow 3 < overflow 4.5 ≤ height 5, -// dryRun = 0.2 * 1.10 = 0.22 ≤ minLevel 1 ≤ start 2 < max 4 ≤ overfill 4.275. +// dryRun = 0.2 * 1.10 = 0.22 ≤ minLevel 1 ≤ start 2 < max 4 +// ≤ highVolumeSafetyLevel 4.275. function validBasinAndCfg() { const basin = new BasinGeometry( { volume: 50, height: 5, inflowLevel: 3, outflowLevel: 0.2, overflowLevel: 4.5 }, @@ -40,17 +41,17 @@ test('outflowLevel >= inflowLevel triggers issue with correct shape', () => { assert.match(hit.msg, /outflowLevel.*<.*inflowLevel/); }); -test('maxLevel >= overfillLevel triggers issue', () => { +test('maxLevel >= highVolumeSafetyLevel triggers issue', () => { const { basin } = validBasinAndCfg(); - // overfillLevel = overflowLevel × overfillPct/100 = 4.5 × 0.80 = 3.6. - // maxLevel 4 > 3.6 → expect a `maxLevel <= overfillLevel` issue. + // highVolumeSafetyLevel = overflowLevel × highPct/100 = 4.5 × 0.80 = 3.6. + // maxLevel 4 > 3.6 → expect a `maxLevel <= highVolumeSafetyLevel` issue. const issues = validateThresholdOrdering( basin, { minLevel: 1, startLevel: 2, maxLevel: 4 }, { dryRunThresholdPercent: 10, overfillThresholdPercent: 80 } ); - const hit = issues.find((i) => i.aName === 'maxLevel' && i.bName === 'overfillLevel'); - assert.ok(hit, 'expected a maxLevel <= overfillLevel issue'); + const hit = issues.find((i) => i.aName === 'maxLevel' && i.bName === 'highVolumeSafetyLevel'); + assert.ok(hit, 'expected a maxLevel <= highVolumeSafetyLevel issue'); assert.equal(hit.op, '<='); assert.equal(hit.a, 4); assert.ok(Math.abs(hit.b - 3.6) < 1e-9); @@ -66,7 +67,7 @@ test('NaN / undefined values are skipped, not flagged as issues', () => { // dryRunLevel <= minLevel skipped (minLevel undefined → NaN) // minLevel <= startLevel skipped (both NaN-ish) // startLevel < maxLevel skipped (startLevel NaN) - // maxLevel <= overfillLevel still checked → 4 ≤ 4.275 OK. + // maxLevel <= highVolumeSafetyLevel still checked → 4 ≤ 4.275 OK. // Geometry checks also OK. assert.deepEqual(issues, []); });