Skip to content

Build against component-graph v0.6.0#91

Merged
shsms merged 4 commits into
frequenz-floss:v0.x.xfrom
shsms:meter-subtraction
Jul 17, 2026
Merged

Build against component-graph v0.6.0#91
shsms merged 4 commits into
frequenz-floss:v0.x.xfrom
shsms:meter-subtraction

Conversation

@shsms

@shsms shsms commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Version 0.6.0 of the frequenz-microgrid-component-graph Rust crate is released. This PR builds the Python bindings against it and aligns the binding's defaults, docs, and tests with the new release.

Changes

  • Update the frequenz-microgrid-component-graph crate from 0.5 to v0.6.0. The release rewrites the formula fallback engine: formulas can now contain meter-subtraction and diamond terms, and the consumer formula measures the components behind one internal meter as one group.
  • Default prefer_meters_in_component_formulas to False (component reading primary, meter fallback), matching the new upstream default.
  • Rename "device" to "component" in the binding docs and tests, matching the crate's vocabulary.
  • Add a stub-drift test that compares __init__ default values between the type stub and the runtime signature, so a default flipped on only one side fails CI.

Breaking

  • Per-category formulas are component-first by default. Set prefer_meters_in_component_formulas=True to restore the old meter-first order (order only; the new fallback terms are used either way).
  • Formula strings can differ from the previous release, even for the same graph. The consumer formula now subtracts the components behind one internal meter as one group.
  • Graph validation failures now raise InvalidGraphError messages starting with Graph validation failed: (one indented line per problem); some graph-building errors keep the old InvalidGraph: format.

shsms added 3 commits June 24, 2026 19:36
Update the frequenz-microgrid-component-graph dependency to v0.6.0.
This release rewrites the formula fallback engine and adds the
component-first default for per-category formulas: the component
reading is the primary source and the meter is the fallback. Update
the steam-boiler and wind-turbine formula tests to match the new
default, add a test that pins the consumer formula's new
meter-subtraction grouping, and document the Python-visible changes
(formula terms, consumer formula grouping, validation error format)
in the release notes and in the phantom-loads stub docstring.

Signed-off-by: Sahas Subramanian <sahas.subramanian@proton.me>
component-graph flipped the prefer_meters_in_component_formulas default
to false (component reading primary, meter as fallback). Mirror it in the
binding so an explicit ComponentGraphConfig() matches both the no-config
path and the upstream default, instead of forcing the old meter-first
behavior. Update the type stub and the preference tests.

Signed-off-by: Sahas Subramanian <sahas.subramanian@proton.me>
Pure terminology: the per-category formulas' non-meter source is a
component, matching component-graph's vocabulary (the flag is
prefer_meters_in_component_formulas). Rename _DEVICE_PRIMARY and the
"device" wording in the type stub and preference tests to "component";
no behavior change.

Signed-off-by: Sahas Subramanian <sahas.subramanian@proton.me>
@github-actions github-actions Bot added part:docs Affects the documentation part:tests Affects the unit, integration and performance (benchmarks) tests part:tooling Affects the development tooling (CI, deployment, dependency management, etc.) labels Jun 24, 2026
@shsms
shsms force-pushed the meter-subtraction branch from f886a24 to d3b3a19 Compare July 15, 2026 15:02
The stub-drift test compared only method and parameter names, so a
default changed on one side only (the Rust pyo3 signature or the type
stub) would pass CI while type checkers report the wrong default.
The prefer_meters_in_component_formulas flip is exactly this kind of
change. Add a test that compares the __init__ default values from the
stub AST against the runtime signature. Defaults that are not plain
literals are marked and fail the comparison loudly; classes without an
introspectable runtime signature can not be checked; the known set of
those classes is pinned, so a new silent skip also fails the test.

Signed-off-by: Sahas Subramanian <sahas.subramanian@proton.me>
@shsms
shsms force-pushed the meter-subtraction branch from d3b3a19 to 1acb778 Compare July 16, 2026 12:47
@shsms shsms changed the title Default to component-first per-category formulas Build against component-graph v0.6.0 Jul 16, 2026
@shsms
shsms marked this pull request as ready for review July 16, 2026 13:05
@shsms
shsms requested a review from a team as a code owner July 16, 2026 13:05
@shsms
shsms requested review from llucax and removed request for a team July 16, 2026 13:05
@shsms
shsms force-pushed the meter-subtraction branch 2 times, most recently from e76fbe4 to a9fd1a7 Compare July 17, 2026 10:24

@llucax llucax left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 rAIview (AI review here!)

Solid, well-scoped PR: the v0.6.0 dependency bump, the default flip to component-first per-category formulas, the device→component rename, and the new stub-drift default-value test are all clean, and the final HEAD state is consistent (CI green). No functional bugs or security concerns found in the merged result.

The main point worth addressing is a commit-split issue: the wind/steam formula expectation updates were placed in df7d2cc, but the default flip they depend on only happens in the following commit cdcb3cf, so df7d2cc fails its own suite (bisect hazard, and the commit message claims to "match the new default" that isn't set yet). Beyond that, only low-severity items: the newly-documented breaking InvalidGraphError message format and the phantom-load meter-subtraction edge case are untested, and one docstring paragraph under include_phantom_loads_in_consumer_formula reads as contradictory. Details inline.

assert (
graph.wind_turbine_formula(wind_turbine_ids={ComponentId(3)})
== "COALESCE(#2, #3, 0.0)"
== "COALESCE(#3, #2, 0.0)"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Broken intermediate commit: default-flip test expectations land before the flip

Commit df7d2cc (Build against component-graph v0.6.0) updates the test_wind_turbine_graph and test_steam_boiler_graph assertions from meter-first COALESCE(#2, #3, 0.0) to component-first COALESCE(#3, #2, 0.0). However, the actual default flip (prefer_meters_in_component_formulas truefalse in src/graph.rs and __init__.pyi) happens only in the next commit cdcb3cf (Default to component-first per-category formulas).

At df7d2cc the runtime default is still meter-first, so:

  • these two updated assertions expect component-first output that the binding does not yet produce, and
  • tests/test_formula_preferences.py::test_default_config_prefers_meter (unchanged at that commit) still asserts the default is meter-first.

The two files directly contradict each other and the test suite is red at df7d2cc. The commit message also states it updates the tests "to match the new default", but that default is not set in this commit.

Impact

git bisect can land on a commit with a failing suite, and anyone checking out df7d2cc in isolation sees failures unrelated to their change. The commit message does not match the diff. The final merged state is correct (CI is green on HEAD), so this only affects history quality — harmless under squash-merge, but a real hazard if commits are preserved.

Related locations

Suggested fix

Move the wind/steam expectation updates (this hunk and the steam one) into the default-flip commit cdcb3cf, or move the graph.rs/stub default flip into df7d2cc, so each commit is self-consistent and its suite is green. Adjust the df7d2cc message accordingly.


🟡 Medium Severity: does not affect the merged result, but breaks bisectability and the commit message is inaccurate; best fixed before merge unless the PR is squash-merged.

Comment thread RELEASE_NOTES.md

- The consumer formula now measures the non-consumer components behind one internal meter as one group: it subtracts `COALESCE(#meter, component readings...)` instead of each component on its own. Note: if such a meter also carries a load that is not in the component graph, that load is now subtracted together with the group while the meter reading is used.

- Graph validation failures now raise `InvalidGraphError` with a message that starts with `Graph validation failed:`, followed by one indented line per problem. The old format was `InvalidGraph: <description>`. Note: some errors found while building the graph, for example a missing grid component, still use the old format. Code that matches on the message text of validation failures must be updated.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 New InvalidGraphError message format is documented as breaking but untested

This release note flags a user-facing breaking change: graph validation failures now raise InvalidGraphError with a message starting Graph validation failed: (one indented line per problem), replacing the old InvalidGraph: <description> format, and explicitly warns that "Code that matches on the message text of validation failures must be updated."

No test pins this new format. The only related test, tests/test_microgrid_component_graph.py:466, asserts the exception type only (pytest.raises(InvalidGraphError)), not the message. A future crate bump could silently change the message again with nothing to catch it.

Impact

A behavior the PR itself calls out as breaking for downstream code has no regression guard. Since the message is now a documented contract, drift would go unnoticed until it breaks a consumer.

Related locations

Suggested tests

Build a graph that fails validation (rather than fails at graph construction) and assert the message starts with Graph validation failed:, so the documented format is pinned.


🔵 Low Severity: nice-to-have coverage for a documented breaking behavior.

excluding production and battery components from the grid measurements.
The non-consumer components behind one internal meter are excluded
as one group: the meter reading first, the component readings as
the fallback. While the meter reading is used, a load behind

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Docstring: meter-subtraction note under the "when false" branch reads as contradictory

This grouping description is placed inside the include_phantom_loads_in_consumer_formula "When false" branch (the mode that, per the line just above, generates the consumer formula without including phantom loads). Yet it then states that "a load behind that meter that is not in the component graph is then also excluded together with the group" — i.e. a phantom load being subtracted in the very mode that is supposed to exclude phantom-load handling.

This is the exact subtlety the release note calls out (RELEASE_NOTES.md:15), and it is accurate, but as written under the "when false" bullet it reads as self-contradictory and is easy to misread.

Impact

Readers configuring include_phantom_loads_in_consumer_formula may be confused about which loads are actually included/excluded in the default (False) mode.

Suggested fix

Reword to make explicit that this is a side effect of grouping-by-meter (the meter reading is used as the primary term, so anything behind that meter — including an off-graph load — is captured by that single term), not the phantom-load feature being partially enabled.


🔵 Low Severity: documentation clarity only.

)


def test_consumer_formula_meter_subtraction() -> None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 consumer_formula meter-subtraction: only the clean happy path is covered

This new test pins the clean grouping MAX(#2 - COALESCE(#3, #4, 0.0), 0.0), which is good. But the release notes and the stub docstring highlight a more consequential, subtle behavior of the new grouping: when the internal meter also carries a load that is not in the component graph, that off-graph load is now subtracted together with the group (because the meter reading is the primary term). That semantic change — the whole point of "meter-subtraction as one group" — is not exercised by any test.

Impact

The most user-visible risk of the v0.6.0 rewrite (a phantom load being netted into a producer group) is undocumented by tests, so a future regression in that grouping would pass CI.

Suggested tests

Add a case where meter #3 has both the PV inverter and a second successor that maps to an off-graph/phantom load, and assert the resulting consumer formula groups them under the single COALESCE(#3, ...) term as documented.


🔵 Low Severity: additional edge-case coverage for the headline behavior of this release.

@llucax llucax left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM and the AI review seems to only point to minor issues.

I didn't get the last commit though, I don't know exactly what kind of black magic the tests are doing with introspection, but being only tests I am not too concerned.

Approving.

@shsms
shsms added this pull request to the merge queue Jul 17, 2026
Merged via the queue into frequenz-floss:v0.x.x with commit 78b6568 Jul 17, 2026
9 checks passed
@shsms
shsms deleted the meter-subtraction branch July 17, 2026 12:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

part:docs Affects the documentation part:tests Affects the unit, integration and performance (benchmarks) tests part:tooling Affects the development tooling (CI, deployment, dependency management, etc.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants