{
  "schema": 1,
  "status": "collection-and-design-contract; no production wiring",
  "checked": "2026-10-05",
  "layers": [
    {
      "id": "countries",
      "title": "Countries and regional groups",
      "kind": "reference",
      "observationGrain": "country / country-group",
      "staticRequirement": "country polygons + explicit country-group membership",
      "metric": null,
      "existingReadEndpoint": null,
      "presentations": ["geographic", "tiles"],
      "joinRule": "ISO-like source codes normalised by source; groups are sets of countries.",
      "guard": "A regional group is not a bidding zone. Keep country GB distinct from market GB/SEM."
    },
    {
      "id": "bidding-zones",
      "title": "Electricity bidding zones",
      "kind": "reference",
      "observationGrain": "market-area",
      "staticRequirement": "effective-dated zone definitions, EIC and geometry",
      "metric": null,
      "existingReadEndpoint": "/api/entsoe/registry",
      "presentations": ["geographic"],
      "joinRule": "Reviewed current area identity and effective dates; EIC is contextual, not an import-all rule.",
      "guard": "Retired and virtual EICs remain excluded; unresolved polygons cannot inherit country prices."
    },
    {
      "id": "zone-connections",
      "title": "Electricity zone connections",
      "kind": "network",
      "observationGrain": "market-area pair",
      "staticRequirement": "documented existing/conditional pair topology",
      "metric": null,
      "existingReadEndpoint": null,
      "presentations": ["geographic", "schematic"],
      "joinRule": "Canonical unordered EIC/code pairs with validity and source evidence.",
      "guard": "No capacity, direction or measured flow inferred from connectivity, geography or price differences."
    },
    {
      "id": "physical-interconnectors",
      "title": "Physical electricity interconnectors",
      "kind": "asset",
      "observationGrain": "physical asset",
      "staticRequirement": "station/locality points + explicit mapping to zone pairs",
      "metric": null,
      "existingReadEndpoint": null,
      "presentations": ["geographic"],
      "joinRule": "Native physical line/site IDs, cross-reference to zone pair; one pair can have many assets.",
      "guard": "Do not replace verified station coordinates with country/zone centroids. Approximate localities remain labelled."
    },
    {
      "id": "gas-connections",
      "title": "Gas interconnection points",
      "kind": "network",
      "observationGrain": "physical / commercial / virtual point",
      "staticRequirement": "ENTSOG point identity and reviewed geographic point data",
      "metric": null,
      "existingReadEndpoint": null,
      "presentations": ["geographic", "schematic"],
      "joinRule": "Separate native infrastructure IDs, commercial points and virtual aggregates.",
      "guard": "ENTSOG schematic map X/Y are not longitude/latitude; no automatic coordinate projection is assumed."
    },
    {
      "id": "gas-storage-sites",
      "title": "Gas storage sites",
      "kind": "asset",
      "observationGrain": "source location record / physical site",
      "staticRequirement": "SciGRID coordinates; newer GIE inventory; reviewed reporting crosswalk",
      "metric": null,
      "existingReadEndpoint": "/api/agsi/country/:code/facilities?date",
      "presentations": ["geographic"],
      "joinRule": "Country + operator EIC + facility EIC + validity interval -> reviewed physical site or multi-site group.",
      "guard": "Historical duplicates/conflicts remain distinct until reviewed; never copy one group inventory into several sites."
    },
    {
      "id": "lng-terminal-sites",
      "title": "LNG terminals",
      "kind": "asset",
      "observationGrain": "source project / terminal / unit",
      "staticRequirement": "GEM/SciGRID location data; GIE inventory; operator/EIC crosswalk",
      "metric": null,
      "existingReadEndpoint": "/api/alsi/country/:code/terminals?date",
      "presentations": ["geographic"],
      "joinRule": "Preserve terminal, train, project, expansion and reporting unit identities separately.",
      "guard": "Do not count expansion/project rows as separate operating terminals or imply proposed projects are operational."
    },
    {
      "id": "generation-plants",
      "title": "Generation plants",
      "kind": "asset",
      "observationGrain": "source plant record",
      "staticRequirement": "WRI source plant IDs + technology + nameplate MW",
      "metric": {
        "field": "capacityMw",
        "unit": "MW",
        "time": "source vintage"
      },
      "existingReadEndpoint": null,
      "presentations": ["geographic"],
      "joinRule": "Native plant IDs and explicit cross-references; preserve dataset overlap.",
      "guard": "Installed capacity is not current output; historical inventory and operating-status uncertainty remain visible."
    },
    {
      "id": "hydro-sites",
      "title": "Hydro and pumped-storage sites",
      "kind": "asset",
      "observationGrain": "plant / reservoir",
      "staticRequirement": "JRC plant records and NVE native IDs/zone assignments",
      "metric": {
        "field": "capacityMw / storageCapacityMwh",
        "unit": "MW / MWh",
        "time": "source vintage"
      },
      "existingReadEndpoint": null,
      "presentations": ["geographic"],
      "joinRule": "Use official zone assignment where provided; preserve plant/reservoir distinction.",
      "guard": "Plant generation MW, pumping MW, reservoir water volume and stored energy are separate quantities. Do not sum overlapping source inventories."
    },
    {
      "id": "electricity-price",
      "title": "Day-ahead price",
      "kind": "area-metric",
      "observationGrain": "bidding-zone",
      "staticRequirement": "current zone identity + price display polygon",
      "metric": {
        "field": "avgPriceEur",
        "unit": "EUR/MWh",
        "time": "served day / market interval"
      },
      "existingReadEndpoint": "/api/power/latest?date",
      "presentations": ["geographic", "tiles", "chart"],
      "joinRule": "EIC first, validated short-code fallback. Use source-reported served date, intervals and attribution.",
      "guard": "Price varies over time. Keep zero/negative prices, nulls, incomplete periods and sample data distinct; no unweighted national average of multiple zones."
    },
    {
      "id": "electricity-demand",
      "title": "Actual electricity demand",
      "kind": "area-metric",
      "observationGrain": "country / region; zone in source store",
      "staticRequirement": "country and zone membership",
      "metric": {
        "field": "loadGwh / load",
        "unit": "GWh/day / MW",
        "time": "UTC day / interval"
      },
      "existingReadEndpoint": "/api/entsoe/table?date; /api/entsoe/stack/:place?date&days",
      "presentations": ["geographic", "tiles", "chart"],
      "joinRule": "Reuse existing time-aware aggregation and coverage; country table values remain country-grain.",
      "guard": "Load is not generation. A daily total must not be presented as instantaneous MW; partial coverage stays explicit."
    },
    {
      "id": "generation-mix",
      "title": "Generation and fuel mix",
      "kind": "area-metric",
      "observationGrain": "country / region; production type in source store",
      "staticRequirement": "country/zone membership; PSR-to-fuel mapping",
      "metric": {
        "field": "groups; gasGwh; gasShare; renewablesShare",
        "unit": "MW / GWh / fraction",
        "time": "UTC day / interval"
      },
      "existingReadEndpoint": "/api/entsoe/stack/:place?date&days; /api/entsoe/table?date",
      "presentations": ["geographic", "tiles", "chart"],
      "joinRule": "Country fuel output/mix belongs to the reporting country; all plant points remain a separate overlay.",
      "guard": "gasShare and renewablesShare in the current table divide generation by load, not total generation. Label as share of demand; multiply fractions by100 for percent. Actual fuel mix requires its own generation denominator."
    },
    {
      "id": "gas-storage-level",
      "title": "Gas storage level",
      "kind": "area-metric",
      "observationGrain": "country / reporting group",
      "staticRequirement": "GIE country/reporting identities",
      "metric": {
        "field": "full; gasInStorage; injection; withdrawal",
        "unit": "% / TWh / GWh per day",
        "time": "gas day"
      },
      "existingReadEndpoint": "/api/agsi/snapshot?date; /api/agsi/country/:code?from&to",
      "presentations": ["geographic", "tiles", "chart"],
      "joinRule": "Reuse source country totals and reporting group semantics; sum quantities only across compatible disjoint groups.",
      "guard": "Country % heatmap is possible now. Site % requires reviewed identity linkage; aggregate fill uses inventory/capacity, not an average of site percentages."
    },
    {
      "id": "lng-level",
      "title": "LNG stocks and send-out",
      "kind": "area-metric",
      "observationGrain": "country / terminal reporting group",
      "staticRequirement": "ALSI identities and reviewed terminal crosswalk",
      "metric": {
        "field": "full; lngInventory; sendOut; dtmi",
        "unit": "% / 1000 m3 LNG / GWh per day",
        "time": "gas day"
      },
      "existingReadEndpoint": "/api/alsi/snapshot?date; /api/alsi/country/:code?from&to",
      "presentations": ["geographic", "tiles", "chart"],
      "joinRule": "Keep LNG liquid volume and gas energy fields separately typed.",
      "guard": "Do not add raw LNG volume to gas-storage TWh or convert using an undocumented constant; no site allocation from country totals."
    },
    {
      "id": "hydro-stored-energy",
      "title": "Hydro stored energy",
      "kind": "area-metric",
      "observationGrain": "published aggregate country / place",
      "staticRequirement": "ENTSO-E reporting-area membership",
      "metric": {
        "field": "weeks[].mwh; derived historical-peak ratio",
        "unit": "MWh / % of historical peak",
        "time": "reported week"
      },
      "existingReadEndpoint": "/api/entsoe/reservoirs/:place",
      "presentations": ["geographic", "tiles", "chart"],
      "joinRule": "Aggregate weekly observations join their reporting place, not individual JRC/NVE reservoirs.",
      "guard": "App reservoirFill uses five-year peak, shorter on-record peak with >=52 prior weeks, or no ratio. This is not physical reservoir fullness; retain basis, week, and history completeness."
    },
    {
      "id": "electricity-flows",
      "title": "Measured electricity exchanges",
      "kind": "future-metric",
      "observationGrain": "zone pair / separately identified physical asset",
      "staticRequirement": "zone-pair topology plus measurement adapter",
      "metric": {
        "field": "not currently ingested in this branch",
        "unit": "MW or MWh, explicitly defined",
        "time": "market interval"
      },
      "existingReadEndpoint": null,
      "presentations": ["geographic", "chart"],
      "joinRule": "Future measured/scheduled exchange series need separate product IDs, EIC pair, timestamps and direction convention.",
      "guard": "No current flow layer. Do not derive direction from prices, and do not assign aggregate border flow to named cables without evidence."
    }
  ],
  "compositions": [
    {
      "name": "Electricity system",
      "areaFill": "electricity-price",
      "overlays": ["zone-connections", "generation-plants"],
      "sidebar": ["zone price curve", "generation mix", "source and coverage"]
    },
    {
      "name": "Energy storage",
      "areaFill": "gas-storage-level",
      "overlays": ["gas-storage-sites", "lng-terminal-sites", "hydro-sites"],
      "sidebar": ["selected reporting aggregate", "physical asset identity", "gas or hydro history in native units"]
    },
    {
      "name": "Generation and demand",
      "areaFill": "generation-mix",
      "overlays": ["physical-interconnectors", "hydro-sites"],
      "sidebar": ["stacked generation + load", "fuel contribution", "partial coverage"]
    },
    {
      "name": "Country comparison",
      "view": "tiles",
      "metric": "one selected comparable measure",
      "sidebar": ["full chart", "rank/table", "source dates"],
      "rules": [
        "fixed shared time window and units",
        "common scale by default",
        "explicit independent-scale toggle if offered",
        "missing is not zero",
        "equal tile area is diagrammatic, not geographic size"
      ]
    }
  ],
  "interactionRules": [
    "Use one primary area colour metric at a time; encode a second measure using symbols, sidebar or a linked chart.",
    "Country and zone views can coexist only with clear observation grain; one country aggregate cannot be silently copied to its zones.",
    "Keep one selected entity and date context across geographic map, tile map, sidebar and chart; selected day does not date static infrastructure unless a valid historical version exists.",
    "Store requested and served periods separately; electricity day, gas day and reservoir week need separate visible labels.",
    "Toggle infrastructure, topology and metric layers independently. Virtual/reporting groups receive group indicators, not invented exact facility coordinates.",
    "Snapshot missing/restricted/unreviewed/offline/not-in-scope is separate from confirmed absence.",
    "The tile map is an alternate layout of the same selected measures, not a new calculation pipeline."
  ]
}
