Skip to content

v0.5.12

Choose a tag to compare

@github-actions github-actions released this 29 Apr 15:57
· 586 commits to main since this release

What's new in v0.5.12

v0.5.10 added per-region estimation metadata (intensity_estimated, intensity_estimation_method) and surfaced it in JSON, dashboard, and terminal. v0.5.11 added two new TOML knobs (emission_factor_type, temporal_granularity) and migrated the default Electricity Maps endpoint to v4, but did not surface those 3 dimensions of configuration in any rendered output. An operator who set emission_factor_type = "direct" had no way to verify the preference took effect short of reading the daemon's TOML, and a Scope 2 auditor reading a saved baseline could not see which carbon model produced the numbers without the same TOML access. v0.5.12 closes that audit-trail gap.

A new green_summary.scoring_config object exposes 3 fields: api_version (v3 legacy / v4 default / custom for proxies and mock servers without a /vN suffix), emission_factor_type (lifecycle default / direct opt-in), and temporal_granularity (hourly default / 5_minutes / 15_minutes opt-in). The field is omitted on the wire when [green.electricity_maps] is not configured, additive on pre-0.5.12 baselines via #[serde(skip_serializing_if = "Option::is_none", default)] so the report --before <baseline.json> flow keeps parsing any 0.5.x baseline.

The HTML dashboard renders the same 3 dimensions as a chip bandeau above the green-regions table. Default values render as neutral chips, opt-ins (direct, 5_minutes, 15_minutes) as accent chips, the legacy v3 endpoint as a warning chip mirroring the 0.5.11 deprecation warning. Each chip carries a native browser tooltip with methodology guidance. The bandeau is hidden entirely when Electricity Maps is not configured, so dashboards rendered without [green.electricity_maps] are visually identical to v0.5.11. The chip rendering uses textContent and setAttribute("title", ...), both auto-escape, and the bandeau population uses replaceChildren() not innerHTML, so the existing no_forbidden_apis_in_template regression guard keeps its full coverage.

The terminal print_green_summary output prepends a one-liner Carbon scoring: Electricity Maps v4, lifecycle, hourly before the per-region breakdown. The helper format_scoring_config_line returns Cow<'static, str> with two borrowed arms covering the most common shapes (v4 + defaults, v3 + defaults), allocating only on opt-in combinations. The 3 fields are typed Rust enums with bounded variants, so the renderer skips sanitize_for_terminal (unlike intensity_estimation_method which carries a free-form String from --input JSON).

The daemon's /api/export/report snapshot endpoint, which returns GreenSummary::disabled(0) (no live scoring on that path), now patches scoring_config from the loaded Config so the audit chip surfaces on the snapshot whenever Electricity Maps is configured at daemon startup. An operator pulling the snapshot does not get a misleading scoring_config: null while EM is in fact in use.

A small internal refactor extracts the v3 detection from the 0.5.11 is_legacy_v3_endpoint helper into a new public ApiVersion::from_endpoint(&str) -> Self on a 3-variant ApiVersion enum. The deprecation warning at daemon startup now delegates to the same helper, single source of truth for v3 / v4 / custom detection. The sanitize_for_terminal wrap around the operator-supplied endpoint is preserved.

Added

  • green_summary.scoring_config JSON object exposing the active Electricity Maps configuration. The field is Option<ScoringConfig> with #[serde(skip_serializing_if = "Option::is_none", default)]. Omitted when EM is not configured, additive on pre-0.5.12 baselines.
  • Public ScoringConfig struct in score::carbon with from_electricity_maps(&ElectricityMapsConfig) -> Self. Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq. Surfaced on CarbonContext::scoring_config: Option<ScoringConfig> and copied through to GreenSummary::scoring_config at the score_green assembly point.
  • Public ApiVersion enum in score::electricity_maps::config with from_endpoint(&str) -> Self (the new authoritative source of v3 detection) and as_chip_label(self) -> &'static str (stable label for the dashboard and terminal). #[serde(rename_all = "lowercase")], wire form is "v3" / "v4" / "custom".
  • Dashboard scoring config bandeau above the green-regions table. Three chips render systematically when EM is configured. The legacy v3 endpoint shows in warning orange, opt-in values (direct, 5_minutes, 15_minutes) show in accent blue, defaults show in neutral gray. Tooltips carry the methodology guidance. Hidden entirely when EM is not configured.
  • Terminal Carbon scoring: ... header line in print_green_summary output, before the per-region breakdown. Format: Carbon scoring: Electricity Maps v4, lifecycle, hourly. Helper format_scoring_config_line returns Cow<'static, str> with constant arms for the common shapes.
  • Serialize and Deserialize derives on EmissionFactorType and TemporalGranularity. EmissionFactorType uses #[serde(rename_all = "lowercase")]. TemporalGranularity carries explicit #[serde(rename = "5_minutes")] and #[serde(rename = "15_minutes")] because the wire form starts with a digit and is not a valid Rust identifier.

Changed

  • warn_if_legacy_v3_endpoint refactored to delegate detection to ApiVersion::from_endpoint, single source of truth. The local is_legacy_v3_endpoint helper is dropped, its 5 unit tests migrate to ApiVersion::from_endpoint assertions in electricity_maps/config.rs::tests. Behavior unchanged. The sanitize_for_terminal wrap around the operator-supplied endpoint is preserved.
  • HTML chip helpers fall through to a verbatim-text neutral chip on unknown values (buildApiVersionChip, buildEmissionFactorChip, buildTemporalGranularityChip). Forward-compat: a future enum variant added in a later release renders verbatim in an older dashboard instead of silently masquerading as the default.

Behavior

  • Pre-0.5.12 JSON reports without scoring_config deserialize without error, the report --before <baseline.json> flow keeps working with stored baselines from any 0.5.x release.
  • The daemon's /api/export/report snapshot endpoint now patches scoring_config from the loaded Config when EM is configured, even though the snapshot itself does not run a live scoring pass. An operator pulling the snapshot sees the audit chip whenever EM is in fact configured at daemon startup.
  • The 3 fields are typed enums with bounded variants. The terminal renderer skips sanitize_for_terminal because every interpolated string is an enum-derived &'static str. The HTML chip rendering uses textContent and setAttribute("title", ...), no innerHTML/outerHTML/insertAdjacentHTML/document.write/eval/new Function/DOMParser/createContextualFragment. The existing no_forbidden_apis_in_template regression guard keeps full coverage on the new bandeau code.
  • Wire format unchanged for users not opting into Electricity Maps. URL shape, green_summary.regions[] rows, top_offenders, IIS, waste ratio are byte-identical to v0.5.11 in that case.
  • The scoring_config object captures the Electricity Maps client configuration only, not the full SCI input vector. A complete strict-replay of the carbon math from a saved baseline would also need [green] embodied_carbon_per_request_gco2, [green] use_hourly_profiles, [green] per_operation_coefficients, [green] include_network_transport, [green] network_energy_per_byte_kwh, plus the per-region PUE drawn from the embedded provider table. Surfacing the complete methodology footprint is tracked as future work, the 0.5.12 surface closes the audit gap on the Electricity Maps slice specifically.

Install

Prebuilt binaries (Linux amd64 / arm64, macOS arm64, Windows amd64):

curl -LO https://github.com/robintra/perf-sentinel/releases/download/v0.5.12/perf-sentinel-linux-amd64
chmod +x perf-sentinel-linux-amd64
sudo mv perf-sentinel-linux-amd64 /usr/local/bin/perf-sentinel

Linux binaries are statically linked against musl and run on any distribution (Alpine, Debian, RHEL, Ubuntu any version) regardless of glibc version, and inside FROM scratch images.

From crates.io:

cargo install perf-sentinel --version 0.5.12

The Helm chart (chart-v0.2.15) tracks this release as its appVersion.