Skip to content

0.8.1 - 2026-06-13

Choose a tag to compare

@github-actions github-actions released this 13 Jun 19:14
6333bff

Release Notes

Added

  • Dynamic cut-selection method, selected with
    training.cut_selection.method = "dynamic". Rather than carrying the entire cut
    pool into every LP, a dynamic run loads only a small resident subset of cuts per
    solve — keeping per-solve LP size bounded as the pool grows while the full pool
    is retained — and applies uniformly across the backward pass, forward pass, and
    simulation. The resident set is tuned by active_window (the seed window k2,
    below), candidate_window, and nadic, and is mutually exclusive with the
    periodic-pruning methods (level1 / lml1 / domination).

  • training.cut_selection.active_window — a first-class config field for the
    dynamic cut-selection active-set seed window (k2). Applies only when
    method = "dynamic". Default 5; 0 is valid and meaningful (seeds only the
    current iteration's cuts, matching NEWAVE selcor.dat). Previously this value
    had to be supplied through check_frequency, which overloaded the
    periodic-pruning cadence used by the level1 / lml1 / domination methods.

  • Selectable LP backend at build time. A binary is now bound to exactly
    one LP solver backend, chosen via Cargo features:

    • highs (enabled by default) — HiGHS LP solver, MIT-licensed.
    • clp (opt-in) — CLP/CoinUtils LP solver, EPL-2.0-licensed.
      Build with --no-default-features --features clp.

    The two features are mutually exclusive: enabling both is a compile
    error. Enabling clp selects CLP; highs applies only when clp is
    not enabled. The active backend is reflected in cobre version and in
    the solver / solver_version fields of the run output metadata.

    The CLP backend ships the following capabilities: dual and primal
    simplex algorithms; native incremental row and bound mutation
    (appending rows or patching bounds preserves the solver's factorization
    across mutations, enabling warm-start continuity across solve sequences);
    per-phase tuning covering the dual-simplex pricing strategy,
    factorization cadence, feasibility and optimality tolerances, and
    iteration limits; and hot-start (snapshot and restore of the simplex
    rim), delivered through the C++ class interface.

    Each backend is internally deterministic: run-to-run bit-for-bit
    reproducible and declaration-order invariant (a permutation of the
    input entities produces the correspondingly permuted result). Switching
    backends may legitimately change numerical results — the two solvers can
    reach different optimal vertices on degenerate problems — so each
    backend maintains its own deterministic parity baselines.

    Existing builds are unaffected: the default backend remains HiGHS, and
    the CLP backend is strictly opt-in.

  • anticipated_thermal_cost — a new per-stage field in the run cost output that
    attributes the forward-committed (anticipated) thermal commitment cost, so the
    sum of the named cost categories reconciles to immediate_cost. It is zero for
    cases with no anticipated units and is written identically by the CLI and Python
    paths.

  • Dynamic cut selection now reports the per-solve resident-set size — the cuts
    actually loaded into each LP. Surfaced as a run-level mean and max in the console
    summary and training/metadata.json, and as a per-iteration mean_rows_in_lp
    column in training/convergence.parquet. The pool active / generated line is
    retained as the pool/memory-footprint figure. The metric is work-distribution
    invariant (bit-identical across thread counts).

Changed

  • method = "dynamic" no longer reads check_frequency for its k2 window;
    use the new active_window field instead. A dynamic config that relied on
    check_frequency to set k2 now falls back to the default k2 = 5 unless it
    sets active_window. check_frequency remains the periodic-pruning cadence
    for level1 / lml1 / domination, where 0 is still rejected; under
    dynamic an explicit check_frequency is ignored rather than rejected.
  • The deprecated training.cut_selection.threshold and memory_window fields
    are now silently ignored for every method, including dynamic. They were
    previously consumed as undocumented fallbacks for nadic and the
    candidate-recency window (k1) under dynamic; that honoring is removed. The
    fields remain accepted in config files (so existing configs still parse) but
    no longer affect behavior. Configure nadic and candidate_window directly.
  • Distributed release artifacts (CLI archives, Python wheels, MPI tarball) now
    bundle the complete third-party license notices for the Rust dependency graph
    (THIRD_PARTY_LICENSES.md), in addition to the vendored C++ solver attributions
    already recorded in NOTICE and THIRD_PARTY_NOTICES.md.

Fixed

  • Per-entity hydro penalty overrides: the directional water-withdrawal and
    evaporation violation costs (*_violation_pos_cost / *_violation_neg_cost)
    now fall back to the entity's resolved symmetric cost when left unset, instead
    of the global directional default. An entity that overrode only the symmetric
    water_withdrawal_violation_cost / evaporation_violation_cost previously had
    its directional costs silently revert to the global value.
  • PAR(p) estimation no longer panics for studies whose horizon is narrower than
    the season cycle (for example a monthly model running only September–December).
    Seasons that are not lag-reachable are skipped, and for PAR(p > 0) the
    recent-past months before the study start are synthesized from history so their
    seasonal statistics feed the pre-study lags. Studies that span the full cycle
    (or carry no out-of-window history) are unaffected and remain bit-identical.
  • Water-withdrawal violation modeling: the under-delivery slack is now bounded so
    realized withdrawal cannot cross zero past its target. Previously a run-of-river
    plant could "un-withdraw" well beyond its target and inject phantom water; the
    bound is sign-aware for negative/return targets. This affects only degenerate
    cases — realized withdrawal now pins at the target.

cobre-cli 0.8.1

Install cobre-cli 0.8.1

Install prebuilt binaries via shell script

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/cobre-rs/cobre/releases/download/v0.8.1/cobre-cli-installer.sh | sh

Install prebuilt binaries via powershell script

powershell -ExecutionPolicy Bypass -c "irm https://github.com/cobre-rs/cobre/releases/download/v0.8.1/cobre-cli-installer.ps1 | iex"

Download cobre-cli 0.8.1

File Platform Checksum
cobre-cli-aarch64-apple-darwin.tar.xz Apple Silicon macOS checksum
cobre-cli-x86_64-apple-darwin.tar.xz Intel macOS checksum
cobre-cli-x86_64-pc-windows-msvc.zip x64 Windows checksum
cobre-cli-aarch64-unknown-linux-gnu.tar.xz ARM64 Linux checksum
cobre-cli-x86_64-unknown-linux-gnu.tar.xz x64 Linux checksum

cobre-mcp 0.8.1

Install cobre-mcp 0.8.1

Install prebuilt binaries via shell script

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/cobre-rs/cobre/releases/download/v0.8.1/cobre-mcp-installer.sh | sh

Install prebuilt binaries via powershell script

powershell -ExecutionPolicy Bypass -c "irm https://github.com/cobre-rs/cobre/releases/download/v0.8.1/cobre-mcp-installer.ps1 | iex"

Download cobre-mcp 0.8.1

File Platform Checksum
cobre-mcp-aarch64-apple-darwin.tar.xz Apple Silicon macOS checksum
cobre-mcp-x86_64-apple-darwin.tar.xz Intel macOS checksum
cobre-mcp-x86_64-pc-windows-msvc.zip x64 Windows checksum
cobre-mcp-aarch64-unknown-linux-gnu.tar.xz ARM64 Linux checksum
cobre-mcp-x86_64-unknown-linux-gnu.tar.xz x64 Linux checksum