Skip to content

Feat: make soc-min and soc-max canonical with sensor defaults parked pending (#2395) - #2267

Open
BelhsanHmida wants to merge 64 commits into
mainfrom
feat/dynamic-soc-bounds-defaults
Open

Feat: make soc-min and soc-max canonical with sensor defaults parked pending (#2395)#2267
BelhsanHmida wants to merge 64 commits into
mainfrom
feat/dynamic-soc-bounds-defaults

Conversation

@BelhsanHmida

@BelhsanHmida BelhsanHmida commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Description

  • Make soc-min and soc-max the canonical fields for fixed and dynamic storage SoC boundaries.
  • Allow dynamic soc-min / soc-max values through sensor references and time-series specifications.
  • Add a generic default field to sensor references for filling missing sensor values.
  • Keep soc-minima and soc-maxima supported as deprecated legacy aliases.
  • Reject ambiguous combinations of canonical and legacy dynamic fields.
  • Preserve backwards compatibility for fixed SoC bounds and fixed-plus-legacy configurations.
  • Make scalar soc-min / soc-max follow the default SoC relaxation behavior.
  • Reject default: null.
  • Update the API, UI, scheduling documentation, changelog, and OpenAPI specifications.
  • Allow configuring sensor-reference fallbacks through the flex-model UI
  • Add changelog entry

Look & Feel

N/A

Example API flex-model shape:

{
  "soc-at-start": "12 kWh",
  "soc-min": {
    "sensor": 300,
    "default": "10 kWh"
  },
  "soc-max": {
    "sensor": 301,
    "default": "25 kWh"
  },
  "power-capacity": "5 kW"
}

How to test

  • pytest:
uv run pytest \
  flexmeasures/data/schemas/tests/test_sensor.py \
  flexmeasures/data/schemas/tests/test_scheduling.py \
  flexmeasures/data/models/planning/tests/test_storage.py \
  flexmeasures/data/models/planning/tests/test_utils_fresh_db.py \
  tests/documentation/test_openapi_spec.py
  • Manual API-style check:
    Use a storage flex-model where soc-min and soc-max are dynamic sensor references with defaults:
{
  "flex-model": {
    "soc-at-start": "12 kWh",
    "soc-min": {
      "sensor": 300,
      "default": "10 kWh"
    },
    "soc-max": {
      "sensor": 301,
      "default": "25 kWh"
    },
    "power-capacity": "5 kW"
  }
}

Expected behavior: soc-min and soc-max are treated as dynamic SoC boundaries, missing sensor values are filled with the provided default values, default: null is rejected, and scalar soc-min / soc-max are soft by default when SoC relaxation is active.

Further Improvements

Related Items


Sign-off

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on code under GPL or other license that is incompatible with FlexMeasures

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
@BelhsanHmida BelhsanHmida self-assigned this Jul 6, 2026
BelhsanHmida and others added 17 commits July 13, 2026 09:22
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
…into feat/dynamic-soc-bounds-defaults

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

# Conflicts:
#	documentation/changelog.rst
#	documentation/tut/flex-model-v2g.rst
#	flexmeasures/data/models/planning/storage.py
#	flexmeasures/data/models/planning/tests/test_storage.py
#	flexmeasures/data/schemas/sensors.py
#	flexmeasures/data/schemas/tests/test_scheduling.py
#	flexmeasures/ui/static/openapi-specs.json
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Both relax-soc-constraints and relax-constraints default to True, so the
former's default swallowed an explicit opt-out through the umbrella flag.
Now an explicit relax-soc-constraints wins and otherwise the umbrella
relax-constraints decides, per the semantics discussed in PR #2267:
setting either flag to False keeps SoC minima/maxima hard.

Also document why DBFlexContextSchema turns the relaxation defaults off.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pt-out

The capacity bounds (power-capacity and site-power-capacity) still remain
hard constraints after relaxation; mention them again alongside soc-min,
soc-max and soc-targets, and explain that setting either
relax-soc-constraints or relax-constraints to false keeps SoC
minima/maxima hard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ounds-defaults

Reconciles this branch with the updated base, which now includes main
(notably the off-tick SoC projection of PR #2194, which restructured the
soc-minima/maxima commitments flow) and the base's review fixes:

- Drop this branch's pre-projection commitments blocks (main moved that
  logic into the projection-scoped section) and fold the scalar
  soc-min/soc-max relaxation into the new location instead, after
  off-tick projection and gated on the same per-stock scoping. When
  relaxation was auto-enabled purely for off-tick projection, scalar
  bounds stay hard, respecting the user's explicit opt-out.
- Keep the base's opt-out precedence (an explicit relax-soc-constraints
  wins over relax-constraints; otherwise the umbrella decides). The
  off-tick projection machinery relies on this precedence, as it injects
  an explicit relax-soc-constraints=true.
- Update the off-tick projection test: with a breach price, the global
  soc-min now folds into the soft commitments instead of remaining hard.
- Drop the flooring of SoC field datetimes, per the base's off-tick
  design (soc-min/soc-max event datetimes are projected, not floored).
- Guard the %-SoC-sensor capacity lookup against raw dicts/lists from
  the DB flex-model (clean ValueError instead of a pint crash).
- Revert unrelated whitespace changes to repo tooling files.
- Document that a sensor-reference default densifies sparse sensors.
- Regenerate the OpenAPI specs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The previous merge commit accidentally captured a stale index, missing the
actual reconciliation work:

- Remove the broken flooring_resolution loop from StorageFlexModelSchema
  (main's off-tick design projects SoC datetimes instead of flooring them).
- Excise the pre-projection soc-minima/maxima commitments blocks that the
  merge resurrected; fold scalar soc-min/soc-max into the projection-scoped
  relaxation path instead (hard bounds are kept when relaxation was
  auto-enabled purely for off-tick projection).
- Restore the explicit-specific-wins opt-out precedence in check_prices,
  which the off-tick projection machinery relies on.
- Guard the %-SoC-sensor capacity lookup against raw dicts/lists.
- Update tests and the OpenAPI specs accordingly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Correct RELAX_CONSTRAINTS metadata text: it now defaults to True, not False.
- Give DBFlexContextSchema's relax flags their own description, since a
  stored flex-context defaults to False, unlike the True scheduling-time
  default applied after merging with the request.
- Align the hard-constraints list in scheduling.rst with introduction.rst
  (both now mention power-capacity / site-power-capacity).
- Add the missing v3.0-32 API changelog entry for the relax-soc-constraints
  default flip and the retired fallback scheduler's effect on GET schedule.
- Drop now-tautological assertions checking for "StorageFallbackScheduler"
  in belief sources, since that class no longer exists in the codebase.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Harden the '%'-unit soc-max guard in _build_soc_schedule to also reject
  dict/list values, matching the sibling guard in
  _get_soc_capacity_for_percent_conversion that was already hardened for
  raw DB flex-model shapes.
- Fix VariableQuantityField._serialize crashing when dumping a
  SensorReference's `default` on a denominator-only to_unit (e.g. "/MWh"):
  the default was already resolved to a concrete unit at deserialization
  time, so there's nothing left to convert to in that case.
- Add the missing v3.0-32 API changelog entry for canonical dynamic
  soc-min/soc-max, the generic sensor-reference `default` fallback, and
  the soc-minima/soc-maxima deprecation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
# Conflicts:
#	documentation/api/change_log.rst
…dynamic-soc-bounds-defaults

# Conflicts:
#	documentation/api/change_log.rst
#	documentation/features/scheduling.rst
)
SOC_MINIMA_BREACH_PRICE = MetaData(
description="""This **penalty value** is used to discourage the violation of ``soc-minima`` constraints in the flex-model, which the scheduler will attempt to minimize.
description="""This **penalty value** is used to discourage the violation of dynamic lower SoC boundary constraints in the flex-model, which the scheduler will attempt to minimize.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should mark the (user-facing) deprecation more explicitly (e.g. in the first words of this explanation).

Also, maybe even remove the user-facing documentation of it (e.g. on the feastures/scheduling) page. I would favor that last part because the list of documented fields is becoming long.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parking this for now the soc-minima/soc-maxima deprecation is one of the pieces held back pending #2395 (see split suggestion), so I'd rather not word the deprecation notice before we know whether the deprecation stands. Noted for when this comes back including your point about trimming the field list on the scheduling page, which I think is right regardless.

@Flix6x

Flix6x commented Aug 5, 2026

Copy link
Copy Markdown
Member

Flagging #2395 here, because it has a bearing on the part of this PR that changes SoC constraint hardness.

The short version: stocks are the half of the flex-model that already separates physics from preference cleanly, and it is worth preserving that. soc-min / soc-max act as a hard envelope that both fills gaps and clips the dynamic bounds into itself (in add_storage_constraints), while soc-minima / soc-maxima become StockCommitments with the hard constraint dropped. Flows lack that separation, which is what #2395 is about.

So my suggestion is to split this PR:

Land now — the default field on sensor references, and the docs / OpenAPI / UI work. These are uncontroversial and answer most of #2251.

Hold — the soc-minsoc_minima folding, the scalar softening (_relax_scalar_soc_minimum / _relax_scalar_soc_maximum), and the deprecation labelling of soc-minima / soc-maxima. Together these collapse two tiers into one, and I would rather settle the hardness question across the whole flex-model first.

One point that is worth making regardless of how the hardness question lands, because it is a silent behaviour change:

default is not soc-min. A default fills the slots where the sensor is silent — the fillna. soc-min additionally clips, including the slots where the sensor did speak. So a sensor reporting a bad value (a unit slip, a negative SoC) is clamped today and would not be after the fold. That loss is independent of the hard-versus-soft question and would need addressing either way.

Apologies for the moving target here — this is a design question that took a few rounds to pin down, and none of it reflects on the implementation work, which is solid.

@Flix6x Flix6x added this to the 1.1.0 milestone Aug 5, 2026
BelhsanHmida and others added 2 commits August 5, 2026 23:47
Conflicts were in four files:

- storage.py: keep the removal of StorageFallbackScheduler (main had since
  changed its return_multiple block to dedupe shared sensors).
- test_sensor_schedules.py: keep both main's new
  test_get_schedule_unfinished_job_returns_202_when_sunset_active and this
  branch's renamed test_get_schedule_infeasible_storage_job_without_fallback;
  drop the two retired fallback tests.
- test_scheduling_sequential.py: keep both this branch's no-fallback
  assertions and main's new test_create_sequential_jobs_with_sign_explicit_context.
- api/change_log.rst: keep both sides' entries.

Also clean up the deferred subjobs in the no-fallback sequential test. With
the fallback retired nothing unblocks them, so they used to leak into the
next test and break main's new sign-explicit-context test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ounds-defaults

Signed-off-by: Mohamed Belhsan Hmida <149331360+BelhsanHmida@users.noreply.github.com>
BelhsanHmida added a commit that referenced this pull request Aug 7, 2026
This branch was carved out of #2267, which was stacked on
feat/retire-fallback-scheduler, so #2252's commits travelled along with it.
Now that this PR targets main, drop that content here: the tree of this
commit equals main plus the sensor-reference `default` work alone.

No behaviour of this PR changes; #2252 lands on its own.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
@BelhsanHmida BelhsanHmida changed the title Feat: make soc-min and soc-max canonical with sensor defaults Feat: make soc-min and soc-max canonical with sensor defaults parked pending (#2395) Aug 7, 2026
Flix6x added a commit that referenced this pull request Aug 7, 2026
* feat: relax storage SoC bounds by default

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* feat: remove storage fallback scheduler

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* feat: remove storage fallback policy helper

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: cover SoC relaxation schema defaults

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: use default SoC breach prices

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: expect storage infeasibility without fallback

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: assert storage schedules do not fall back

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: update sequential scheduling fallback case

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: describe default SoC relaxation metadata

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: update storage scheduling infeasibility guide

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: clarify fallback redirects for custom schedulers

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: scope fallback redirect configuration

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: refresh SoC relaxation OpenAPI text

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: add fallback scheduler changelog entry

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: allow small unit conversion drift

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: avoid exact quantity string comparisons

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: clarify storage infeasibility behavior

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: simplify storage fallback assertion comment

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: regenerate openapi-specs.json

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* fix: preserve explicit zero breach prices

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* chore: align agent instructions with main

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: fix jobs OpenAPI description indentation

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* fix(schema): let relax-constraints=false keep SoC constraints hard

Both relax-soc-constraints and relax-constraints default to True, so the
former's default swallowed an explicit opt-out through the umbrella flag.
Now an explicit relax-soc-constraints wins and otherwise the umbrella
relax-constraints decides, per the semantics discussed in PR #2267:
setting either flag to False keeps SoC minima/maxima hard.

Also document why DBFlexContextSchema turns the relaxation defaults off.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: restore hard-constraints list and describe the SoC relaxation opt-out

The capacity bounds (power-capacity and site-power-capacity) still remain
hard constraints after relaxation; mention them again alongside soc-min,
soc-max and soc-targets, and explain that setting either
relax-soc-constraints or relax-constraints to false keeps SoC
minima/maxima hard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: restore config via monkeypatch and fix truncated docstring

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs+test: fix review follow-ups for relax-soc-constraints default

- Correct RELAX_CONSTRAINTS metadata text: it now defaults to True, not False.
- Give DBFlexContextSchema's relax flags their own description, since a
  stored flex-context defaults to False, unlike the True scheduling-time
  default applied after merging with the request.
- Align the hard-constraints list in scheduling.rst with introduction.rst
  (both now mention power-capacity / site-power-capacity).
- Add the missing v3.0-32 API changelog entry for the relax-soc-constraints
  default flip and the retired fallback scheduler's effect on GET schedule.
- Drop now-tautological assertions checking for "StorageFallbackScheduler"
  in belief sources, since that class no longer exists in the codebase.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs: describe what this PR actually changes about SoC relaxation

SoC constraints are already soft by default on main: relax-soc-constraints
defaults to False there, but the umbrella relax-constraints defaults to True
and check_prices fills the default breach prices on either flag. So "SoC
constraints are now relaxed by default" reads as a behaviour change that
already shipped, and invites users to brace for breaching schedules they are
already getting.

What this PR changes is the opt-out: an explicit relax-soc-constraints: false
is now honoured, where main silently overrode it with the relax-constraints
default. Lead with the fallback retirement, which is the actual headline.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* Let an explicit relax flag take precedence over the umbrella relax-constraints, for site capacities too

An unset relax-soc-constraints or relax-site-capacity-constraints now loads as None,
meaning the umbrella relax-constraints flag decides;
an explicitly set specific flag wins in either direction.
This extends the fix for 'the field had no effect on its own' from SoC constraints to site capacity constraints,
via a shared relaxation_asked_for helper (also used by the commodity-context zero-capacity defaulting).

Signed-off-by: F.N. Claessen <claessen@seita.nl>

* Fill default breach prices per field for the SoC and site capacity pairs

Setting one breach price of a relaxed-by-default pair explicitly no longer silently hardens its twin;
the twin still gets the default breach price.
The device capacity pair keeps its pair-as-unit semantics (an explicit opt-in puts the caller in charge of both directions),
as established in PR #2398.
Also, an explicitly set breach price (including a zero price, which is falsy as a quantity) is never overwritten anymore.

Signed-off-by: F.N. Claessen <claessen@seita.nl>

* Replace the DB schema's relax-flag overrides with a single fill switch

A stored asset flex-context is only validated (never scheduled directly),
so DBFlexContextSchema now simply skips filling default breach prices,
instead of overriding the relax-flag defaults with misleading per-field descriptions.
The relax flags keep uniform defaults and documentation across both schemas;
scheduling-time defaults are applied after the stored flex-context is merged with the request's flex-context.

Signed-off-by: F.N. Claessen <claessen@seita.nl>

* chore: increment StorageScheduler version

Scheduler behaviour changed since v0.33.1 for identical inputs,
through this PR (explicit relax-flag opt-outs are honoured, explicit breach prices are no longer overwritten, no more fallback schedules)
as well as PR #2398 and PR #2345 (device capacity and zero-capacity relaxation semantics),
so data sources should distinguish v9 schedules from v8 ones.

Signed-off-by: F.N. Claessen <claessen@seita.nl>

* docs: cover the full relaxation-semantics change and name the removed plugin symbols

Adds an upgrade warning for the retired fallback scheduler (naming the removed importable symbols),
splits the changelog entry into the fallback retirement and the relaxation-semantics fixes,
and extends the API changelog with the site-capacity opt-out and the never-overwrite/per-field breach price behaviour.

Signed-off-by: F.N. Claessen <claessen@seita.nl>

* docs: describe the relaxation change relative to the last release

In v0.33.1 all four relax flags defaulted to False and the specific flags were independent opt-ins,
so 'these flags had no effect on their own' only ever described unreleased main (after the umbrella default flipped to True).
Reframe both changelog entries accordingly and split the API entry in two,
so the fallback retirement stands alone.
The never-overwrite fix does describe released behaviour and stays.

Signed-off-by: F.N. Claessen <claessen@seita.nl>

* Cover the fallback machinery for custom schedulers at the API level

Salvages the retired built-in fallback scheduler's API tests,
substituting a custom scheduler (via the sensor's custom-scheduler attribute) that defines a fallback scheduler:
clients get a 303 redirect to the fallback schedule under FLEXMEASURES_FALLBACK_REDIRECT = True,
or the fallback schedule directly under the default False.
Also cushions the changelog warning (the fallback is expected to be needed much less,
now that SoC constraints are relaxed by default) and fixes a stale fallback comment in the highspy tests.

Signed-off-by: F.N. Claessen <claessen@seita.nl>

* docs: shorten the relax-flag field descriptions

The precedence rule now lives in full on relax-constraints only;
the specific flags carry a two-sentence echo,
the device-capacity rationale moves to relax-capacity-constraints,
and soc-minima/soc-maxima point at relax-soc-constraints with a shared soft_by_default footnote in the docs.

Signed-off-by: F.N. Claessen <claessen@seita.nl>

* docs: frame the fallback retirement as preference-softening plus physics-hardening

The previous wording asserted a one-directional softening trend,
while #2398 and #2345 hardened physical statements at the same time.
Reframe: preferences (SoC minima/maxima, site capacities) are soft by default,
and contradictory physics could never yield an executable schedule,
so failing with the reason beats a fallback schedule that ignored the contradiction.

Signed-off-by: F.N. Claessen <claessen@seita.nl>

* Validate power bounds for every device, and stop a stock-less device from disabling validation

A device without a stock set the shared skip_validation flag,
which silently disabled constraint validation for all subsequent devices in the same flex-model;
stock-constraint validation is now tracked per device.
Also add validate_power_constraints, run for every device (stock-less included):
derivative min <= derivative max, and derivative equals within those bounds,
reported through the existing per-time-step violations message,
so a contradictory hard power bound fails usefully instead of as a bare solver infeasibility.
This matters more now that no fallback schedule cushions such failures.

Signed-off-by: F.N. Claessen <claessen@seita.nl>

---------

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: F.N. Claessen <claessen@seita.nl>
Base automatically changed from feat/retire-fallback-scheduler to main August 7, 2026 15:42
BelhsanHmida added a commit that referenced this pull request Aug 7, 2026
* feat: relax storage SoC bounds by default

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* feat: remove storage fallback scheduler

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* feat: remove storage fallback policy helper

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: cover SoC relaxation schema defaults

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: use default SoC breach prices

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: expect storage infeasibility without fallback

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: assert storage schedules do not fall back

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: update sequential scheduling fallback case

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: describe default SoC relaxation metadata

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: update storage scheduling infeasibility guide

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: clarify fallback redirects for custom schedulers

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: scope fallback redirect configuration

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: refresh SoC relaxation OpenAPI text

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: add fallback scheduler changelog entry

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: allow small unit conversion drift

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: avoid exact quantity string comparisons

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: clarify storage infeasibility behavior

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* test: simplify storage fallback assertion comment

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: regenerate openapi-specs.json

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* fix: preserve explicit zero breach prices

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* chore: align agent instructions with main

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: fix jobs OpenAPI description indentation

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* fix(schema): let relax-constraints=false keep SoC constraints hard

Both relax-soc-constraints and relax-constraints default to True, so the
former's default swallowed an explicit opt-out through the umbrella flag.
Now an explicit relax-soc-constraints wins and otherwise the umbrella
relax-constraints decides, per the semantics discussed in PR #2267:
setting either flag to False keeps SoC minima/maxima hard.

Also document why DBFlexContextSchema turns the relaxation defaults off.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: restore hard-constraints list and describe the SoC relaxation opt-out

The capacity bounds (power-capacity and site-power-capacity) still remain
hard constraints after relaxation; mention them again alongside soc-min,
soc-max and soc-targets, and explain that setting either
relax-soc-constraints or relax-constraints to false keeps SoC
minima/maxima hard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: restore config via monkeypatch and fix truncated docstring

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs+test: fix review follow-ups for relax-soc-constraints default

- Correct RELAX_CONSTRAINTS metadata text: it now defaults to True, not False.
- Give DBFlexContextSchema's relax flags their own description, since a
  stored flex-context defaults to False, unlike the True scheduling-time
  default applied after merging with the request.
- Align the hard-constraints list in scheduling.rst with introduction.rst
  (both now mention power-capacity / site-power-capacity).
- Add the missing v3.0-32 API changelog entry for the relax-soc-constraints
  default flip and the retired fallback scheduler's effect on GET schedule.
- Drop now-tautological assertions checking for "StorageFallbackScheduler"
  in belief sources, since that class no longer exists in the codebase.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: support a `default` fallback on sensor references

A sensor reference on any flex-model or flex-context field may now carry a
`default` quantity, e.g. {"sensor": 50, "default": "0 kWh"}. It fills the
time slots for which the referenced sensor holds no value, and is settable
from the flex-model UI.

This is the uncontroversial half of #2267, split out on Felix's suggestion
so it can land while the SoC constraint hardness question is settled across
the whole flex-model (see #2395). The canonical soc-min/soc-max work stays
on feat/dynamic-soc-bounds-defaults.

Note that a default fills *every* slot the sensor leaves empty, so a sensor
recording only occasional setpoints becomes densely constrained; the field
documentation says so.

Also omit `default` from serialized sensor references when it is unset,
rather than emitting `default: None`, which is not valid input on the way
back in and broke the forecaster config round-trips.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* docs: scope the sensor-reference `default` to variable-quantity fields

`default` is declared on the shared SensorReferenceSchema, so it is accepted
on every sensor reference in the API — but it is only applied in
get_series_from_quantity_or_sensor. Sensor references resolved by
get_power_values (inflexible devices) and by the forecasting pipelines
(regressors) ignore it, silently.

Rather than claim more than the code does, say where the field takes effect.
Applying it in those two paths is worth a follow-up.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* revert the fallback-scheduler content from this branch

This branch was carved out of #2267, which was stacked on
feat/retire-fallback-scheduler, so #2252's commits travelled along with it.
Now that this PR targets main, drop that content here: the tree of this
commit equals main plus the sensor-reference `default` work alone.

No behaviour of this PR changes; #2252 lands on its own.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

* Warn about a zero fallback on a directional capacity

Since #2345, a consumption-capacity or production-capacity that is zero
throughout the scheduling window is read as a physical statement about the
device and enforced strictly. A default fills every slot the sensor leaves
empty, so a fallback of 0 on one of those fields turns a silent sensor into a
hard bound, which is not what "use this value when the sensor has nothing to
say" sounds like it does.

Regenerating the specs here also restores their version to 1.0.0. The generator
takes it from the installed FlexMeasures, so the 0.33.2 in the previous revision
records a stale environment rather than an intended change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: F.N. Claessen <claessen@seita.nl>

---------

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <149331360+BelhsanHmida@users.noreply.github.com>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: F.N. Claessen <claessen@seita.nl>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make soc-minima and soc-maxima the default, simplifying usage

4 participants