perf sentinelperf sentineldocs
ENFRGitHub
Documentation / Schema

Schema reference: perf-sentinel-report v1.8

This document describes the JSON shape of a periodic disclosure report in prose. The machine-readable JSON Schema lives at docs/schemas/perf-sentinel-report-v1.json (draft 2020-12). Two filled examples sit under docs/schemas/examples/.

v1.1 adds the canonical_waste and operational_waste tiers to aggregate. v1.2 adds aggregate.temporal_coverage (a measurement-continuity signal), scope_manifest.coverage_basis (a provenance marker), and the reserved integrity.cross_period_log hook. v1.3 adds methodology.standard_crosswalk (an interpretive ESRS E1 datapoint crosswalk) and per-pattern applications[].anti_patterns[].rgesn_criteria (RGESN 2024 criteria). v1.4 adds aggregate.database_waste (the avoidable energy and carbon of SQL work at both thresholds, with its provenance models, an informational breakdown never added on top of a total). v1.5 adds messaging support: two PatternName values (n_plus_one_messaging, slow_messaging) and aggregate.messaging_waste, emitted once broker publish spans are ingested. messaging_waste is the twin of database_waste for publish work, equally informational and equally never added on top of a total, though which way it errs depends on its model tag (see Limitations). Both waste blocks also gain declared_windows and declared_energy_kwh, which hold the share of the figure an operator declared rather than measured, so a provisioned-cluster declaration is never published inside measured_energy_kwh. They are omitted when zero. v1.6 makes the carbon parameters visible, through four methodology.calibration_inputs fields. carbon_methodologies holds the SCI tags observed on the period's windows, which say whether network transport entered the numerator. embodied_gco2_total is the SCI M term summed over the period. embodied_gco2_per_request is that total divided by total_requests, so it is comparable across reports and independent of traffic volume. scoring_coefficients holds the coefficients the windows were scored with, as key=value strings, two entries for one key meaning it changed mid-period. The settings behind these fields, starting with [green] embodied_carbon_per_request_gco2 and [green] network_energy_per_byte_kwh, scale published figures and appeared nowhere in the report, so halving a coefficient left no trace. carbon_methodologies, embodied_gco2_total and scoring_coefficients are read off the archived windows rather than off the configuration of whichever machine runs disclose, which is the only correct source when a period was produced elsewhere. Several carbon_methodologies entries mean the period spans legacy and current numerator methodologies, or, with sci_v1_numerator+transport+hosts next to sci_v1_numerator+transport, that some windows were scored with a database or broker host source configured. v1.6 also splits the published total: aggregate.carbon_breakdown gives the operational, embodied and transport terms, which sum to total_carbon_kgco2eq. Only the operational term carries an avoidable share, the one the waste tiers quantify. Amortised hardware and network transport cannot be reduced by fixing an anti-pattern, so reading the total alone mixes what an operator can act on with what they cannot. The block also carries database_kgco2eq_out_of_total and messaging_kgco2eq_out_of_total for the measured, modeled or declared database and broker figures a window kept beside its totals: windows archived before host energy entered the totals, or whose figure carried no carbon. Estimated fallback carbon is already included in the service total and is excluded here. Both sit outside the sum and outside total_carbon_kgco2eq. They are published here so every carbon figure a run produced can be read in one place. Every term of the split is omitted when its value is zero, so an unmeasured term never reads as measured at zero, and the methodology still records that transport is part of the current numerator. Transport stays the least certain of the three when present: published figures span two orders of magnitude, so its coefficient is fixed since 0.9.25 (0.04 kWh/GB, no longer configurable, every disclosure scales the same traffic identically). The term is also published under the sourced coefficient bracket, transport_kgco2eq_low (0.001 kWh/GB, Cloud Carbon Footprint) and transport_kgco2eq_high (0.059 kWh/GB, Sustainable Web Design Model v4 network segment, a ceiling). v1.6 also fills integrity.trace_integrity_chain, reserved and always null until now. The daemon hash-chains every archived window as it writes it, and disclose walks that chain while aggregating, publishing how many windows verified, how many carry no chain (written before this existed) and how many breaks were found. A break means a window was edited, removed or reordered after it was written. Breaks found in the same files but outside the period are counted apart, under breaks_outside_period, since one rolling archive can span years and this report only answers for its own period. The report is still produced and says so instead of failing, so a truncated archive or a rotation still yields a partial report that does not hide its gaps. The chain has two limits. It does not see a clean truncation of an archive's tail, which leaves a shorter self-consistent chain that no field inside the file can contradict. And it does not attest the source: whoever controls the daemon and its files can regenerate a consistent chain, and the field sits under the content_hash so a break count cannot be rewritten to zero under a valid signature. Closing that last gap needs an external anchor for the chain head, which is what integrity.cross_period_log stays reserved for. v1.7 completes the chain verdict with two trace_integrity_chain fields derived from the cumulative drops counter each archive line carries since v1.7. windows_dropped counts the windows the daemon produced but could not archive over the period (a full channel, an exited writer, a serialization or write failure). drop_counter_resets counts how many times the counter went backwards inside the period, one per daemon restart, each making windows_dropped a lower bound over the gap it spans. The figure says nothing about windows never produced (a stopped daemon): aggregate.temporal_coverage bounds those. Both fields are omitted when no archived line carried the counter, so an archive written before v1.7 never reads as zero drops. v1.8 adds the grid operator feeds to methodology.calibration_inputs.carbon_intensity_source: rte_eco2mix, neso, fingrid, energinet, ree_esios, open_electricity, mavir and em6. v1.8 also adds aggregate.carbon_breakdown.database_kgco2eq and messaging_kgco2eq, the measured, modeled or declared database and broker host carbon the windows counted inside their totals. The breakdown then has five in-total terms, which sum to total_carbon_kgco2eq on windows tagged +transport, and an in-total host figure never reaches the *_out_of_total fields. Both waste blocks gain five fields, each omitted at zero or empty: in_totals_energy_kwh and in_totals_windows (the host share the windows counted inside their totals), placements (the declared host placements), and modeled_energy_kwh and modeled_windows (a fourth provenance bucket, for host energy interpolated from a CPU reading). The disclosure remains a directional estimate, not regulatory-grade. The schema accepts perf-sentinel-report/v1.0 through v1.8. Every added field defaults when absent, so older readers and reports remain valid and the content_hash of an older report is unchanged when re-hashed on a newer binary.

Top-level keys

keytyperequirednotes
schema_versionstring (enum)yes"perf-sentinel-report/v1.8" (also accepts "…/v1.7", "…/v1.6", "…/v1.5", "…/v1.4", "…/v1.3", "…/v1.2", "…/v1.1", "…/v1.0")
report_metadataobjectyessee Report metadata
organisationobjectyessee Organisation
periodobjectyessee Period
scope_manifestobjectyessee Scope manifest
methodologyobjectyessee Methodology
aggregateobjectyessee Aggregate
applicationsarrayyeshomogeneous: all G1 or all G2 entries, see Applications
integrityobjectyessee Integrity
notesobjectyessee Notes

The schema does not set additionalProperties: false. New fields can be added in a SemVer-minor schema bump without breaking consumers that read only the documented set.

Report metadata

A disclosure document carries three orthogonal axes that consumers should read before parsing any data. intent says who the report is for (a private draft, an external publication, or a third-party-audited publication). confidentiality_level says how much per-service detail is exposed (full G1 anti-pattern breakdown vs aggregated G2 counts). integrity_level says which cryptographic primitives back the document (none, content hash only, Sigstore-signed, signed with SLSA build attestation). Together they let an auditor or a journalist filter the corpus before trusting any number inside.

intent is one of internal | official | audited. audited is reserved for a future release: the JSON schema accepts the value for forward compatibility, but the CLI refuses it today with exit code 2. confidentiality_level is one of internal | public. integrity_level is one of none | hash-only | signed | signed-with-attestation | audited. By default the CLI produces hash-only. generated_at is an RFC 3339 UTC timestamp. generated_by is one of daemon | cli-batch | ci. perf_sentinel_version is the SemVer string of the binary that wrote the file. report_uuid is a v4 UUID stamped per run.

Organisation

name is required and non-empty. country is ISO 3166-1 alpha-2, upper case. identifiers is an open object with optional siren, vat, lei, opencorporates_url, domain. sector is an optional NACE rev2 code.

The publication domain (e.g. transparency.example.fr) is treated as an implicit identifier when notes.reference_urls.project is published from that host. The schema does not enforce this.

Period

from_date and to_date are ISO 8601 calendar dates (YYYY-MM-DD). period_type is one of calendar-quarter | calendar-month | calendar-year | custom. days_covered is to_date - from_date + 1. The official-intent validator enforces days_covered >= 30.

Scope manifest

total_applications_declared is the size of the organisation's application portfolio. applications_measured is the count of services for which the disclosure carries data. Each entry in applications_excluded carries service_name and a non-empty reason. environments_measured lists the operator-defined environments observed (e.g. ["prod"]). total_requests_in_period is an optional operator estimate, requests_measured is what Perf Sentinel observed. coverage_percentage is requests_measured / total_requests_in_period * 100 when the former is set.

coverage_basis (v1.2) makes the trust boundary explicit in-band. It lists which scope fields are operator_declared (unaudited assertions the binary cannot verify, the denominators total_applications_declared and total_requests_in_period, plus the exclusion lists) versus machine_derived (computed by the aggregator from the archives, applications_measured, requests_measured, coverage_percentage). A reader of coverage_percentage should treat its denominator as operator-asserted: an operator who sets total_requests_in_period low can present near-100% coverage of a self-defined universe. This is inherent to a self-disclosure model. The cryptographic integrity guarantees bind the published report, not the honesty of the declared portfolio size. See 08 · Periodic disclosure.

Methodology

sci_specification references the SCI revision (e.g. "ISO/IEC 21031:2024"). perf_sentinel_version mirrors the report metadata field for consumers that index only the methodology block. enabled_patterns and disabled_patterns each carry pattern names taken from the closed set defined by FindingType::as_str() (12 values). core_patterns_required is the closed list of patterns whose remediation directly cuts I/O and carbon: n_plus_one_sql, n_plus_one_http, redundant_sql, redundant_http. conformance is one of core-required | extended | partial. core-required is the minimum bar for an intent = "official" disclosure. calibration_inputs.carbon_intensity_source is one of electricity_maps | rte_eco2mix | neso | fingrid | energinet | ree_esios | open_electricity | mavir | em6 | static_tables | mixed. rte_eco2mix, neso, fingrid, energinet, ree_esios, open_electricity, mavir and em6 name the free feeds of the French, British, Finnish, Danish, Spanish, Australian, Hungarian and New Zealand grid operators, direct-emissions figures that are not comparable with an Electricity Maps lifecycle intensity. specpower_table_version is the version of the embedded SPECpower / CCF coefficient table, declared in the org config TOML or, when the org config omits it, filled by disclose with the running binary's table date. binary_specpower_vintage (0.7.3+) is the vintage string the running binary embeds at build time, populated automatically by perf-sentinel disclose. Consumers may compare both strings to detect drift between operator disclosure and embedded data. scaphandre_used flags whether the runtime energy proxy came from Scaphandre RAPL. It is a historical, Scaphandre-specific field: it predates the other measured-energy backends and was never generalized, so it stays false for a period measured with Alumet, Kepler or Redfish. energy_source_models is the general source of truth for which energy sources produced a period's figures. It is derived automatically from the archived windows and carries every backend's tag (alumet_rapl, scaphandre_rapl, kepler_ebpf, redfish_bmc, cloud_specpower, io_proxy_v*). kepler_ebpf is a historical name: since Kepler 0.10, the only version Perf Sentinel reads, the source is RAPL (sysfs/powercap, hwmon experimental), not eBPF. Consumers should read energy_source_models and treat scaphandre_used as a legacy hint. Generalizing the field would break a published, hashed and attested schema, so it is deferred to a future schema revision. standard_crosswalk (v1.3) is an interpretive map from this report's figures to ESRS E1 datapoints (total_energy_kwh to E1-5, the operational carbon term to E1-6 Scope 2 location-based, embodied carbon to E1-6 Scope 3). It carries its own caveats array. It is a mapping aid, not a certification. The location-based figure is not the market-based Scope 2 value ESRS also requires, and the 2x uncertainty bracket still applies. Absent on pre-v1.3 reports.

calibration_applied (0.7.0+) is true if any scoring window in the period had operator-supplied per-service calibration coefficients applied to the proxy energy. The flag is methodologically distinct from scaphandre_used and energy_source_models: those describe which energy source produced the numbers, this flag describes whether those numbers were further adjusted by operator coefficients.

Aggregate

See also. The Energy and SCI primer in the methodology doc defines SCI v1.0 terms (E, I, M), efficiency_score, io_waste_ratio, Scaphandre, SPECpower and the related vocabulary used by every field below.

Sums across the entire period and the entire applications array. total_requests, total_energy_kwh, total_carbon_kgco2eq, and estimated_optimization_potential_kgco2eq are non-negative finite numbers. aggregate_waste_ratio is in [0, 1]. aggregate_efficiency_score is in [0, 100] and equals clamp(100 - 100 * io_waste_ratio, 0, 100). anti_patterns_detected_count is the sum of every per-service occurrences count, including non-avoidable patterns.

Waste tiers (1.1+)

The report carries the avoidable energy and carbon at two N+1 detection thresholds, side by side, so the gap between them is auditable:

  • canonical_waste is computed at a fixed N+1 threshold pinned in the binary (2), not the operator's config. It is the non-manipulable figure: an operator cannot shrink it by loosening their own threshold. This is the headline avoidable number, and the flat estimated_optimization_potential_kgco2eq, aggregate_waste_ratio, and aggregate_efficiency_score fields alias this tier since v1.1 (they carried the operational value in v1.0).
  • operational_waste is computed at the operator's configured N+1 threshold and records that threshold in n_plus_one_threshold. Comparing it against canonical_waste shows how much avoidable waste the operator's threshold hides.

Each tier carries n_plus_one_threshold (integer), energy_kwh and carbon_kgco2eq (non-negative), waste_ratio ([0, 1]), and efficiency_score ([0, 100]). For intent = "official", the validator requires canonical_waste.n_plus_one_threshold to equal the binary's canonical threshold. The operational threshold is the operator's recorded choice and is not range-checked, since a loose threshold is what that tier exists to surface. The total energy and carbon (total_energy_kwh, total_carbon_kgco2eq) are span-derived and independent of either threshold.

Database waste (v1.4)

database_waste is an optional object carrying the avoidable energy and carbon of SQL work over the period. It is an informational breakdown of the totals and the waste tiers, never added on top of total_energy_kwh, total_carbon_kgco2eq, canonical_waste or operational_waste, and absent on pre-v1.4 reports and when no window carried the figure. The per-window figure is an energy multiplied by the SQL-only waste ratio, and that energy is either database host energy or the estimated fallback. Host energy comes from one of three sources. Measured (alumet_rapl), when [green.alumet.database] is configured and a reading landed: the energy of the declared Alumet database cgroup, a CPU-only lower bound of that host. Modeled (cloud_specpower), when [green.database_static] declares a cpu_query: the SPECpower envelope of its instance_type interpolated at that CPU reading, neither a reading of the host's power nor a ceiling. Declared (database_specpower), when [green.database_static] declares nodes and instance_type without a cpu_query: the cluster's SPECpower ceiling, an operator statement about provisioned hosts. The same tag covers the stretches where a dedicated declaration with a cpu_query had no fresh reading for three scrape intervals, a daemon start before its first reading included, and its ceiling billed. A window counts its host figure inside its totals and both waste tiers once its carbon converts, and its archived figure then carries in_totals: true, with the placement of [green.database_static] when one is declared. Those totals already hold it, its carbon published as carbon_breakdown.database_kgco2eq. A host figure a window kept beside its totals, archived before host energy entered them or without carbon, feeds database_kgco2eq_out_of_total instead. Estimated, otherwise: the application-side share of the window's SQL spans, the energy the span scoring gave the services that issued them, already inside the totals, and its waste share already inside the waste tiers. The estimated figure holds no database host energy, and adding it to canonical_waste would count the same SQL operations twice, priced two ways. models carries the distinct provenance tags observed over the period, so an auditor can tell measurement from model without leaving the report. Four buckets split the windows and the energy by provenance: measured_*, modeled_*, declared_* and estimated_windows, and when any is non-zero measured_windows + modeled_windows + declared_windows + estimated_windows equals windows_with_figure. in_totals_energy_kwh and in_totals_windows give the host share the windows counted inside their totals: a part of energy_kwh already inside total_energy_kwh, never an addend, at most energy_kwh, and over at most the measured, modeled and declared windows. placements lists the placements declared over the period (dedicated, shared), an operator declaration of where the hosts run, not a measurement. messaging_waste reads the same way: alumet_rapl, cloud_specpower and broker_specpower are broker host energy from [green.alumet.broker] or [green.broker_static], inside the totals under the same rule (carbon_breakdown.messaging_kgco2eq), estimated is the application-side share of the publish spans. windows_with_figure counts the windows that carried the block. The operational_* figures use the operator's N+1 threshold. The canonical_* figures recompute the SQL ratio at the binary-pinned canonical threshold against the same energy, the same anti-manipulation construction as the waste tiers above.

Quality signals (0.7.0+)

The aggregate carries four optional fields that describe the quality of the source archives, not the workload itself. These let auditors gauge how much of the period was directly measured versus inferred from a proxy.

  • period_coverage is in [0, 1] and equals runtime_windows / (runtime_windows + fallback_windows). A value of 1.0 means every scoring window in the period carried runtime-calibrated energy (Scaphandre or cloud SPECpower). A value of 0.0 means every window fell back to the I/O proxy. The validator refuses an intent = "official" disclosure with period_coverage < 0.75, see 08 · Periodic disclosure for the threshold rationale.
  • runtime_windows_count and fallback_windows_count carry the absolute counts behind that ratio, so a reader can distinguish "9 out of 10 windows runtime-calibrated" from "900 out of 1000".
  • binary_versions is the set of distinct Perf Sentinel binary versions that produced the archives folded into this period. A period spanning several versions (daemon upgrade mid-quarter, async releases across teams) flags this set with more than one entry, which the report disclaimer surfaces.

Per-service quality fields (0.7.0+)

  • per_service_energy_models maps each service to the set of energy-model tags observed across the period (scaphandre_rapl, cloud_specpower, io_proxy_v3, etc.). The +cal suffix is stripped before insertion. The period-wide calibration_applied flag in methodology.calibration_inputs carries that information instead.
  • per_service_measured_ratio is the per-service mean of the per-window fraction of spans whose energy was resolved by Scaphandre or cloud SPECpower. A value close to 1.0 means the service is fully measured across the period, 0.0 means it relies on proxy fallback. This is a simple arithmetic mean of per-window ratios, not span-weighted: a window with 10 spans and a window with 10000 spans contribute equally to the mean.

Temporal coverage (v1.2)

temporal_coverage is a continuity signal: how much of the declared period carried measurements. It is an object with temporal_coverage (in [0, 1], equal to observed_days / days_in_period), observed_days (distinct UTC calendar days carrying at least one archived window), days_in_period (mirrors period.days_covered), and largest_gap_days (the longest run of consecutive in-period days with no windows).

Read it as a lower bound on activity, not as daemon uptime. Daemon archiving is traffic-gated: a window with no traffic writes nothing, so legitimately quiet days (nights, weekends, low-traffic services) lower the figure. For that reason it is never a hard official gate. The disclose CLI publishes the value, emits a stderr warning below an informational threshold, and appends an in-band disclaimer carrying the same caveat. It exists so a reader can tell a continuously-measured period from one where the daemon ran only a handful of days, which the per-calendar-day days_covered alone cannot reveal.

Applications

Two granularities, homogeneous per disclosure. The validator rejects a disclosure that mixes the two. In both, endpoints_observed counts the distinct endpoints a service served over the period, tracked up to 1024 per service. A service that reaches that cap reports 1024, a lower bound on its real count.

G1 (intent internal)

Each entry carries the service-level totals plus an anti_patterns: [...] array. Every anti-pattern detail has type (one of the 12 known patterns), occurrences, estimated_waste_kwh, estimated_waste_kgco2eq, first_seen, and last_seen. occurrences counts the findings a service owns, while estimated_waste_* also carries its share of findings whose spans it emitted under another service's finding (since 0.18.0, on windows archived by 0.18.0 or later), so a row may show waste with zero occurrences. estimated_waste_kwh is the pattern's avoidable I/O operations times the service's own energy per operation over the period, its energy_kwh divided by its I/O operations (zero when it recorded none). A row can exceed the service's energy_kwh when its avoidable operations were counted in windows that recorded no I/O for that service. It shares the boundary of the application's energy_kwh: the emitting service's host, no database or broker host. estimated_waste_kgco2eq is that energy times the service's carbon_kgco2eq / energy_kwh. Priced at a period average, these rows do not sum to canonical_waste or operational_waste, which price each window at its own operational carbon. Timestamps are RFC 3339 UTC. rgesn_criteria (v1.3) is the interpretive list of RGESN 2024 criteria the pattern relates to (see Methodology), empty for slow_* and absent on pre-v1.3 reports. display_name and service_version are optional hints.

G2 (intent official with confidentiality public)

Each entry carries the same service-level totals but replaces the array with a single anti_patterns_detected_count integer. The schema enforces that G2 entries do not carry an anti_patterns field, and vice versa.

The two granularities are encoded in the JSON Schema with mutually exclusive not: { required: [...] } clauses to make the discrimination explicit to schema validators.

Integrity

See also. The Sigstore primer in the supply-chain doc defines Cosign, Fulcio, Rekor, in-toto, OIDC and SLSA used throughout this section.

content_hash is "sha256:<64-hex>" over the canonical JSON form of the document with the content_hash field blanked to an empty string. The schema also accepts an empty string for the field so example files can ship without a baked-in hash. binary_hash is "sha256:<64-hex>" of the Perf Sentinel binary that produced the file. binary_verification_url points at the release artefact where consumers can fetch the same binary. trace_integrity_chain carries the source-chain verdict since v1.6 and is null on reports written before it, never omitted, since dropping the key would change the canonical bytes of every already-published report.

signature (0.7.0+) is either null (hash-only report) or a typed object with format ("sigstore-cosign-intoto-v1"), bundle_url, signer_identity, signer_issuer, rekor_url, rekor_log_index, and signed_at. The fields collectively let a verifier locate the cosign bundle and the Rekor inclusion proof.

binary_attestation (0.7.0+) is optional and, when present, carries a format ("slsa-provenance-v1"), attestation_url, builder_id, git_tag, git_commit, and slsa_level ("L2" for official releases, the level GitHub documents for artifact attestations on their own. The schema also accepts "L3", for a build isolated in a reusable workflow). Consumers verify the binary downloaded from binary_verification_url with gh attestation verify <binary> --owner robintra --signer-repo robintra/perf-sentinel for 0.7.1 to 0.26.2, gh attestation verify <binary> --repo Institut-du-Numerique-Responsable/perf-sentinel for later releases, or with slsa-verifier verify-artifact --provenance-path multiple.intoto.jsonl ... for the legacy 0.7.0 release.

cross_period_log (v1.2) is reserved and absent today. It is the schema hook for an external append-only or Rekor-style log that chains successive periodic reports, so a third party can detect an operator who silently stopped publishing for several periods, the one gap the per-report integrity guarantees cannot close. It will be populated only under a future intent = "audited", alongside the external audit attestation.

integrity_level in report_metadata is one of none, hash-only, signed, signed-with-attestation (0.7.0+), audited. The reader can use it as a fast filter before parsing the integrity block.

Notes

disclaimers carries eight default statements: the two standard uncertainty disclaimers (directional estimate, ~2x multiplicative bracket; the SCI specification itself defines no uncertainty provisions), the embodied-carbon scope clarification (excluded from optimization potential), the embodied-per-service note (operational only at the service level, full at the aggregate), the runtime-attribution caveat (runtime-calibrated archives carry per-service data, older archives fall back to I/O share), two regulatory-fitness lines (not for CSRD / GHG Scope 3, methodology reference), and the ESRS E1 crosswalk note (the standard_crosswalk mapping is an aid, not a substitute for an audited CSRD inventory). Operators can override the list in their org-config TOML. reference_urls is an open object mapping short keys (methodology, schema, project) to URLs. Operators can add custom keys.

Boavizta and other omitted fields

boavizta_version was considered for calibration_inputs but is not part of the schema today because Perf Sentinel does not currently consume Boavizta data. The field will be re-introduced when the integration ships. Schema consumers MUST tolerate unknown fields gracefully because Perf Sentinel will add them in minor revisions.

Versioning

A backward-incompatible change to the schema increments the major version inside schema_version (v2.0, v3.0). Additive changes (new optional fields, new enum values that consumers can treat as unknown) increment the minor part (v1.1, v1.2). The JSON Schema $id URL contains the major version only.

Cross-references

  • Reporting is the operator-facing usage guide.
  • Methodology covers the calculation chain that fills aggregate and the per-application energy/carbon fields.
  • docs/schemas/perf-sentinel-report-v1.json is the canonical JSON Schema.
  • docs/schemas/examples/example-internal-G1.json and example-official-public-G2.json are filled examples.