0.5.0 - 2026-04-25
Release Notes
Major refactor. Consumers must update config.json, any code calling
solver traits, and any tooling reading solver/iterations.parquet
before upgrading.
Breaking Changes
Public Rust API:
TrainingResultis#[non_exhaustive]; useTrainingResult::new(...).SolverInterface::record_padding_stats→record_reconstruction_stats(&mut self).SolverInterface::clear_solver_stateremoved.WarmStartBasisModeandCanonicalStateStrategyenums removed along
with thecanonical_state_strategyconfig fields.- Four classification counters (
basis_preserved,basis_new_tight,
basis_new_slack,basis_demotions) collapsed intobasis_reconstructions. basis_rejections+basis_non_alien_rejections→basis_consistency_failures.add_rows_count,add_rows_time_ms,clear_solver_count, and
clear_solver_failurescounters removed.StoppingRuleResult.rule_nameis now&'static str;
StoppingRuleResult.detailis nowCow<'static, str>. Call
.to_string()onrule_nameor usedetail.as_ref()at consumers
that previously expectedString.TrainingEvent::WorkerTiming.timingsfield type changed from
[f64; 16](where 12 of 16 slots were always zero on per-worker
events) to a newWorkerPhaseTimingsstruct with four named fields:
forward_wall_ms,backward_wall_ms,fwd_setup_ms,bwd_setup_ms.
The output Parquet schema fortraining/timing/iterations.parquet
is unchanged. Consumers that read the variant payload directly must
access the named fields rather than slot indices. The rank-aggregated
WorkerTimingRecordwriter record retains its 16-column layout and
theWORKER_TIMING_SLOT_*constants remain public as the bridge
between named fields and writer slots.
Output schema — solver/iterations.parquet drops from 23 to 19
columns. Added: opening, rank, worker_id (nullable i32),
basis_reconstructions (u64). Removed: the eight counters listed
above. Backward rows gain an opening dimension; forward rows are now
one per (iteration, stage) rather than one per iteration.
cut_selection/iterations.parquet drops active_after_angular
(10 → 9 columns).
Policy FlatBuffer — CUT_FIELD_DOMINATION_COUNT slot removed. Old
policies deserialise via graceful-absence; "domination_count"
disappears from cobre.results.load_policy per-cut dicts.
Added
- Backward-pass basis cache — rank 0 captures a fresh basis per
stage during the backward pass and broadcasts it end-of-iteration;
next-iteration backward solves warm-start from the cache. - Basis reconstruction —
CapturedBasiswrapper with slot and
state metadata;reconstruct_basisapplies a stored basis across
cut-set churn on forward, backward, and simulation paths. Controlled
bytraining.cut_selection.basis_activity_window(1-31, default 5). - Weekly+monthly studies — sub-monthly lag accumulation,
recent_observationsinput for mid-season starts, terminal boundary
cuts (policy.boundary.{path, source_stage}) for Cobre-to-Cobre FCF
coupling, and non-uniform per-stage scenario counts. - Multi-resolution studies — same-season noise group sharing,
observation aggregation from finer to coarser resolution, and
monthly→quarterly PAR transition. - Per-opening solver statistics — backward rows carry
rankand
worker_idmetadata for per-worker parity testing. TrainingEvent::SimulationStartedvariant mirrorsTrainingStarted
for the simulation phase. Carriesn_scenarios,n_stages,ranks,
andthreads_per_rank. Emitted once per rank before the parallel
scenario loop so consumers can render a banner before any scenario
completes.- Non-TTY progress lines (pipes,
mpirunaggregators, log files) now
include an[elapsed HH:MM:SS < eta HH:MM:SS]trailing cell matching
the interactive bar. - Wire-format version bytes added to both the basis broadcast payload
and cut records. The basis version field is at position 1 of the
i32metadata buffer; the cut version byte is at byte 0 of each
serialized cut record. Mismatches between sender and receiver produce
typed validation errors rather than silent data corruption or panics. - Typed errors for MPI correctness conditions:
- Non-uniform worker counts across ranks are detected during the
backward-pass handshake and reported as a validation error naming
both the minimum and maximum observed counts. - Basis broadcast
i32length overflow (more thani32::MAX
elements) is detected before the MPI call and reported as
CommError::InvalidBufferSize. - Wire-format version mismatches in the basis broadcast and in cut
deserialization are reported as validation errors naming both
expected and received versions. - Violated cut-count invariants in
sync_cuts(negotiated count
differs from actual serialized count) are reported as a validation
error. - Stats counter values exceeding
2^53(the f64 integer precision
limit), which would corrupt MPI allreduce sums, are detected before
the allreduce call and reported as an internal error.
- Non-uniform worker counts across ranks are detected during the
Changed
- Lower-bound LP is strictly append-only. Cuts are never removed
from the LB LP, guaranteeing monotonic non-decreasing lower bound.
Cut selection and budget enforcement continue to deactivate cuts in
the shared pool for the forward and backward passes. - Cut management pipeline reduced to two stages: strategy-based
selection followed by budget enforcement. - Internal refactor of
cobre-iosemantic-validation: the
6 319-linevalidation/semantic.rsfile is now split into
7 cohesive domain submodules (hydro,thermal,stages,
scenarios,season,correlation,sobol) plus a
placeholdersharedmodule for future cross-domain helpers.
The two public entry functions
(validate_semantic_hydro_thermal,
validate_semantic_stages_penalties_scenarios) keep their
paths undercobre_io::validation::semantic::*. No semantic-
validation rule was added, removed, or modified. TrainingEvent::SimulationProgress.scenarios_completenow carries a
global estimate under multi-rank execution (local × ranks, clamped
toscenarios_total), matching thescenarios_totalfield's global
scope. Single-rank runs are unchanged. Previously, rank 0 reported
its local count against the global total, producing a misleading
50/100final line on a 2-rank run.cobre-commnow requiresferrompi >= 0.4.0. The MPI bitwise-OR
allreduce used to synchronize the active-window bitmap is dispatched
directly toMPI_AllreducewithMPI_BORinstead of being emulated
via anallgatherv+ bytewise fold workaround.- FPHA hyperplane file is now written to
<output_dir>/hydro_models/fpha_hyperplanes.parquetin both the CLI
(--outputflag) and Python bindings (output_dirparameter).
Previously the file was always written to
<case_dir>/output/hydro_models/, ignoring the caller-specified
output directory. Under multi-rank execution the file is written by
rank 0 only; previously all ranks raced to write the same path. - All sort comparators on
f64in the hot path now usef64::total_cmp
for deterministic NaN handling.partial_cmp(...).unwrap_or(Equal)
patterns on the production training and simulation paths have been
replaced. - Rayon global thread pool initialization failure now emits a structured
warning (configured threads, actual threads, error reason) and
continues using the already-initialized pool. Previously a silent
fallback was applied without any diagnostic output.
Deprecated
RowSelectionConfig::thresholdis deprecated. The field remains
parseable; supplying it now emits aWARN-leveltracingevent
directing the user tomemory_window(for"lml1") or
domination_epsilon(for"domination").
Removed
- Angular diversity pruning — config section, module, output
column, and training event variant. SparseCutmodule — handled by the indexer.CutMetadata::domination_count— unused.- LB LP periodic rebuild and its
CutRowMaphelpers. FerrompiScratchand theFerrompiBackend::scratchinterior-
mutability field. The native bitwise-OR allreduce no longer needs
per-call scratch for counts/displs vectors.
unsafe impl Send + Sync for FerrompiBackendcomments were updated
accordingly.SimulationSummary::stage_stats: Option<Vec<StageSummaryStats>>
field and theStageSummaryStatsstruct were removed; the field was
alwaysNonein production output and had no consumers.ExportsConfigreduced to two flags:statesandstochastic. The
seven previously declared fields (training,cuts,vertices,
simulation,forward_detail,backward_detail,compression)
had no runtime consumers and have been removed from the public
config surface. Existingconfig.jsonfiles that set these keys
will continue to load — the keys are silently ignored.- Cargo features
tcp = []andshm = []removed fromcobre-comm
(no runtime backends were declared under either feature).
highs = []removed fromcobre-solver; the HiGHS FFI is compiled
unconditionally. DownstreamCargo.tomlfiles that specified
cobre-comm = { features = ["tcp"] }or
cobre-solver = { features = ["highs"] }must drop those entries. cobre-sddpcrate root re-export surface reduced from ~85 to ~50
symbols. Implementation-detail types (BackwardOutcome,
CutSyncBuffers,StageIndexer,FphaColumnLayout,EvapConfig,
LbEvalScratch*,PatchBuffer,WorkspacePool,BasisStore*,
CapturedBasis,RiskMeasure*,EvaporationModel*,FphaPlane,
LinearizedEvaporation,MonitorState,TrainingOutcome,
TrainingContext,StageContext, and similar) are no longer
accessible atcobre_sddp::Type. They remain reachable via their
full module path (e.g.,cobre_sddp::cut::pool::CutPool,
cobre_sddp::workspace::SolverWorkspace).
Verified
- D01-D30 + convertido SHA256 map matches v0.4.5 reference except for
the documented schema renames. All 90 stable parquet entries are
byte-identical versus the previous baseline. - D01-D15 parity hash holds across all internal refactors landed in
this release (cut coefficients, primal/dual trajectories,
convergence trajectory bit-for-bit identical).
cobre-cli 0.5.0
Install cobre-cli 0.5.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/cobre-rs/cobre/releases/download/v0.5.0/cobre-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/cobre-rs/cobre/releases/download/v0.5.0/cobre-cli-installer.ps1 | iex"Download cobre-cli 0.5.0
| 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.5.0
Install cobre-mcp 0.5.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/cobre-rs/cobre/releases/download/v0.5.0/cobre-mcp-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/cobre-rs/cobre/releases/download/v0.5.0/cobre-mcp-installer.ps1 | iex"Download cobre-mcp 0.5.0
| 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 |