|
| 1 | +## Release 4.0.0b19 (1.7.2026) — retiring-unit `existing` map read + Benders cut-tolerance fix |
| 2 | + |
| 3 | +No database migration (schema stays **v62**) and dependency floors unchanged |
| 4 | +(`polar-high>=3.2.0`, `polars>=1.40`, `highspy<=1.14.0`). Two independent |
| 5 | +fixes: one corrects an output/dispatch parameter for retiring units; the other |
| 6 | +removes a spurious hard-failure in the spatial-Benders decomposition solver. |
| 7 | + |
| 8 | +### Outputs / dispatch |
| 9 | + |
| 10 | +- **Read a retiring unit's `existing` capacity by the per-period MAX, not the |
| 11 | + last row.** `_entity_unitsize_lf` gated the `existing`-map cascade input on |
| 12 | + `"period" in columns`, but Spine names a Map's index column with its |
| 13 | + silent-default `"x"`, so the gate never matched and every period row fell |
| 14 | + through to a `unique(keep="last")` that kept the *last* period's value. For a |
| 15 | + unit whose `existing` map decays to `0` at expiry, that collapsed the cascade |
| 16 | + input to `0`, defaulted `unitsize` to `1000`, and turned |
| 17 | + `existing_count = existing/unitsize` into a spurious fraction — capping |
| 18 | + continuous online at that fraction and making integer online impossible to |
| 19 | + commit. The reader now takes the per-entity MAX over whatever period rows |
| 20 | + exist, index-name-agnostically (CLAUDE.md Invariant #2). Byte-identical for |
| 21 | + scalar `existing` (a single-row group-by is a no-op) and for every existing |
| 22 | + test fixture; corrects the reported online/count for retiring-unit models. |
| 23 | + Adds regression tests in the silent-default-index coverage file and a dev-doc |
| 24 | + audit of the readers that live outside the `_param_shapes` resolver. |
| 25 | + |
| 26 | +### Decomposition (Benders) |
| 27 | + |
| 28 | +- **The spatial-Benders cut self-check no longer hard-fails on solver |
| 29 | + round-off.** After each master solve, `_check_cuts_satisfied` asserts every |
| 30 | + just-appended optimality cut is honoured at the new master point. That check |
| 31 | + re-derives a row already present in the master LP, so it can only differ from |
| 32 | + the solved value by the solver's feasibility tolerance — which HiGHS measures |
| 33 | + on its internally-scaled matrix, making the *unscaled* slack scale with the |
| 34 | + cut row's coefficient magnitude, not its right-hand side. On early iterations |
| 35 | + a node group whose recourse cost overshoots produces large reduced-cost |
| 36 | + slopes, so `cost_r` and `Σ slope·f̄` nearly cancel: the rhs collapses to `O(1)` |
| 37 | + while the coefficients stay at `O(1e6)`. The old tolerance keyed off the |
| 38 | + cancelled rhs and demanded a precision the ill-conditioned row cannot deliver, |
| 39 | + aborting an otherwise-converging solve (observed on a 7-node-group hydrogen- |
| 40 | + trade model: a `7e-4` slack on a `2.66e6`-scale row — `2.7e-10` relative). The |
| 41 | + tolerance is now keyed off the row magnitude, matching the fail-safe design of |
| 42 | + the sibling flow-clamp / lower-bound / sandwich guards: numerical noise is |
| 43 | + absorbed, a moderate gap is warned, and only a gross violation (a genuinely |
| 44 | + un-appended cut, whose recourse estimate sits near its large-negative floor) |
| 45 | + still hard-fails — now with the same three-section plain-English diagnostic as |
| 46 | + the other guards. The affected model converges to the monolith objective |
| 47 | + within tolerance. |
| 48 | + |
1 | 49 | ## Release 4.0.0b18 (30.6.2026) — fix zeroed existing capacity for scalar+Map entity classes |
2 | 50 |
|
3 | 51 | No database migration (schema stays **v62**) and dependency floors unchanged |
|
0 commit comments