Repository navigation
dataAvailability field + download/link table #870
Description
Part of #860 (parallel track). Adds a stored dataAvailability structure describing, per metric,
where and how the underlying data can be obtained, and a table UI to present it. Design refined with
Jacob (see the model below); example content is still being finalized, so the schema/UI can proceed
against the agreed shape while values land later.
Goal
Replace today's derived data-availability signal with authored, per-metric availability that drives a
table: each row is a metric, showing the segments included in that metric and a single value per
metric per column (granularity / limitations / coverage / …), with an "Overall" summary row; each row
links to a download or the publisher, with format/paywall indicators.
Background — the real-world cases (from Alex)
- Timeseries, hosted by us → download available; the data lives in the timeseries metrics JSON and
we link to it for download (as today, via the generated indexsrc/data/index.gen.ts/
public/data/index.json, surfaced byavailabilityForinsrc/utils/searchUtils.ts:178). - Single / small, non-timeseries data → may be downloadable somehow — hosting mechanism still
TBD. - Not hostable → refer to the publisher; indicate whether the metric is available there in
tables or in the body text, and whether the pathway is free or paywalled.
Note: today dataAvailability is derived, not stored (availabilityFor in src/utils/searchUtils.ts);
this ticket introduces the authored, stored form. (The DataAvailability = "Foo" staleness previously
flagged here is already fixed in code — the type is "Download" | "Link" | "Unavailable".)
Table model (refined with Jacob)
The table is organised per metric, not as a flat field array:
- Rows = metrics. For each metric, show which segments are included in that metric, then a
single value per metric per column for the descriptive axes (granularity / limitations /
coverage / time resolution / format / …). One value per cell — not a list. - "Children" are included. The more-granular geography/sector values under a metric appear in the
table. There is no need to show every granular value at once when the user is viewing the widest
scope (ties to the display simplification in Frontend: scoped values + scope/fallback badges #859). - "Overall" row/section. A summary describing the current full-timeseries data file, plus anything
that doesn't fit the per-metric structure. - "No information" is shown at the correct granularity where a metric/segment has none (consistent
with the v2 schema + data codemod #858/Frontend: scoped values + scope/fallback badges #859 sentinel), rather than an empty cell.
Underlying per-metric fields (from the redesign doc; enum vocabularies to be confirmed against the
finalized example data):
| Field | Type | Notes |
|---|---|---|
metricName |
enum | sector-conditional; shares vocabulary with metric |
sector |
enum | existing sector enum |
sectorSegment |
enum | sector-conditional (e.g. Power: Power generation / Storage / T&D / …) |
geographyCoverage |
enum | global / regional / country |
timeResolution |
enum | 2050 point / medium-term / 10-yr / 5-yr / 1-yr / 5–10-yr / other / unavailable |
dataFormat |
enum | in tool / tabular-in-pub (free | paywall) / text-in-pub (free | paywall) |
granularity |
string[] | null |
metric-conditional (e.g. Power capacity: Coal/Gas/Wind/Solar/…) |
scopeLimitations |
string | null |
free text |
dataFormat = "in tool" rows link to the existing timeseries download. Case (2) above (small,
non-timeseries downloadable data) becomes a new dataFormat value once the hosting mechanism is
decided — that hosting decision is tracked as its own ticket (see README), not blocked here.
Scope
- Add
dataAvailabilityto the schema as a v2 point release (pathwayMetadata.v2.x) +
regenerate types. Does not block the initial v2 cut in v2 schema + data codemod #858 — lands after this design settles
and the example values are final. - Author
dataAvailabilityfor existing pathways (content work; values pending from Jacob). - Build the per-metric table UI (rows = metrics → segments → single value per column, plus the
"Overall" summary and "children"); wire "in tool" rows to the timeseries download, others to the
publisher; show free/paywall + tables/text indicators; render "No information" at the right
granularity. - The table lives on the detail page and is scoped by the sticky Geo/sector filter bar (Details page updates for fine grained pathway details #872).
- Decide the fate of the derived
availabilityForfacet (retire vs. keep as fallback) now that
availability is authored.
Acceptance criteria
- Detail page renders the per-metric table (segments + single value per column + "Overall") from
the storeddataAvailability, respecting the Details page updates for fine grained pathway details #872 filter selection. - "In tool" rows download the timeseries; publisher rows link out with free/paywall + tables/text
indicators; "No information" shown at the correct granularity. -
dataAvailabilityvalidates under the v2.x schema; types regenerated;vitestgreen.
Notes / links
- Part of Epic: Best-effort / inheritance search #860; does not block Inheritance resolver engine + search integration #869 / the inheritance engine (descriptive data, not part of the
fallback chain). - Touches the same timeseries index infrastructure as the current download link.
- Presented on the detail page under the Details page updates for fine grained pathway details #872 filter bar.
- Spins off a small-download hosting mechanism ticket (case 2) — see README.
Activity
Add authored per-metric dataAvailability (#870)
Merge branch 'main' into feat/metadata-v2-schema
feat(ui): source segment tooltips from the timeseries taxonomy
jacobvjk commentedon Sep 11, 2026
Status after #936 and #946.
src/components/DataAvailabilityTable.tsx, Feat/UI tabs #936) and isnow filtered by the detail page's scope selection (Feat/detail scope filters #946), as the schema
comment on
byMetric[].geographyanticipated.geography), omitting
sectorfrom the uniqueness tuple the schema enforces,so a multi-sector pathway reporting the same metric twice rendered one row
twice. Sector and geography scope are now visible as conditional columns.
Blocker on observing any of it: no pathway in
src/data/hasbyMetricpopulated. Onlytestdata/valid/pathwayMetadata_v2_full.jsonandtest fixtures exercise the table, so this ships invisible in the running app.
Authoring it for one real pathway is probably worth its own task.
Vocabulary change to be aware of (#936):
sectorSegmentrenamedStorage→
Energy storage, and a newFuel extraction and processingsegment wasadded. Schema enum, generated types and fixtures updated; no authored data
needed migrating because none used a named segment.
jacobvjk commentedon Sep 24, 2026
This PR splits
dataFormatinto two separate columns:dataFromatandaccess: https://github.com/RMI/tpr/pull/898/changes#diff-0dc51340471f147cebec4629b65693571cc18b10b34e328fb7ddac1e5f1e011bThe rational is that one describes the actual format that the data is available in and the other describes how users can access that information. That is a good idea. However, we only host data and pathways that are available for free at this point anyway, and the
"free"value in theaccessvariable does not really convey the details that may come with data licenses anyway. Likewise, there is no point in mixing information on data format/access within this tool (value:"in tool") with source data format information. So "in tool" should be dropped. The final version of this variable should instead be the following:jacobvjk commentedon Sep 24, 2026
Following up on my comment above —
dataFormatis now authored in the cookbook, so the vocabulary is settled. RMI/tpr-tpc#20.The allowed values
dataFormatis a single-valued enum with exactly four members, spelled as follows:TabularTextFigureNot coveredSpelling matters — these are the literal strings. Two differences from what's in
dataAvailability.v1.jsonon the #898 branch:Tabular in publication/Text in publication. WithIn toolgone, every value is in-publication by definition, so the qualifier carries nothing.tabular / text / figureas shorthand; the cookbook's house style for allowed values isTabular,Text,Figure, matchingNot covered,Medium-termand the rest.What needs to change on this side
accessentirely, including thevalidateScopedEntriesbiconditional that ties it toIn tool. There's nothing left for it to hold.In tool.dataFormatdescribes the source publication only. Whether we host a file is something the repository knows about itself, not a classification judgement about the pathway — that was the whole point of separating the two. If the "we serve this / go to the publisher" signal is still wanted in the UI, it should be derived from the timeseries index as it is today, or become its own field. It should not come back as adataFormatmember.Not covered. This one isn't in Feat/metadata v2 schema #898 at all and is easy to miss. The cookbook requires a row for every allowable (sector, metric) pair in a covered sector, even when the pathway reports nothing for it — an omitted row is a completeness defect, not an absence. SoNot coveredis a real value that will appear in authored data, not a null.Unspecified, unliketimeResolution. A metric whose values you can see at all has a visible form.One rule that affects authoring
When a metric appears in more than one form, the most extractable wins:
Tabular>Text>Figure. This comes up immediately — AGF Laos justifies eight rows with "Technology-level reporting in tables/figures", so a publication that prints a chart and ships the underlying spreadsheet isTabular.Related: judge where the metric's values are, not where it's mentioned. JETP CIPP's Power technology cost is
Figure— the LCOE numbers are in Figure 5.2-10 — even though surrounding prose references cost baselines.Provenance
Cookbook:
docs/cookbook/split/data_availability/data_format.md, cookbook versiontpr_cookbook_20260924. Reasoning and the rejected alternatives are in decision record 0021. The classification template gainedData formatandData format_Justification.Worth knowing for planning: the classification side has the columns and the validator enforces the enum, but no pathway has authored
Data formatvalues yet — the gold workbooks carryNULLpending an authoring pass. So this unblocks the schema and UI work, but real values arrive separately, same as thebyMetricsituation flagged in the #936/#946 status above.feat(schema): align dataAvailability with the cookbook vocabulary
jacobvjk commentedon Sep 25, 2026
The vocabulary is in, but the table can't be filled in yet
The schema and UI now match cookbook
tpr_cookbook_20260924—dataFormatisTabular / Text / Figure / Not covered,accessandIn toolare gone, the timeresolutions use the cookbook's exact wording, geography coverage is the list of
geographies rather than a Global/Regional/Country label, and
UnspecifiedvsNot coveredreplaces blank cells everywhere. Pushed to #898, #936, #946 and #954.Before anyone starts an authoring pass, though, there's a gap worth knowing about. It
isn't a problem with this ticket's design — it's a collision with something #860 parked.
The tool only knows 5 metrics; the cookbook's table needs up to 13
The Data Availability section has its own metric list — the cookbook calls it
"Metrics – Extended" and is explicit that it's a different thing from the pathway-level
Metricfield: it's what defines a row in the table.The tool currently accepts five metrics anywhere: Emissions Intensity, Capacity,
Generation, Technology Mix, Absolute Emissions. The cookbook's table wants:
(The Steel count is generous: it assumes our single "Emissions Intensity" stands in for
the cookbook's three — total, primary and secondary — which it can't distinguish.)
Missing across every sector: Technology cost, Investment requirement, Asset
lifetime. Plus Transmission lines for Power; Scrap share, Steel production by
technology and the split Emissions intensity (total / primary / secondary) for
Steel; and all the Aviation demand metrics.
In practice: a row for one of those is rejected when the file is saved. So today you
could fill in about half of a Power pathway's rows and none of the Steel- or
Aviation-specific ones.
A second, less obvious blocker
The tool also currently requires every Data Availability row to name a metric the
pathway already lists in its own top-level "Metrics" field. The cookbook says the
opposite: a covered sector gets a row for every metric in the extended list,
whether or not the pathway reports it — an unreported one is recorded as
Not covered.So that rule has to go as well. While it stands,
Not coveredrows are impossible towrite, which is exactly the completeness rule the section is built around.
Why this wasn't just fixed alongside the rest
Two reasons, and both need a decision rather than code.
It's user-facing. The metric list isn't only used here — it's the Metrics filter
dropdown on the search page. Adding nine-plus values changes what every visitor sees,
so it isn't a quiet internal change.
The cookbook hasn't settled it either. Its own register (T1) flags that the Data
Availability metric list has
Transmission lineswhere the pathway-level list hasStorage capacity, notes the two disagree, and records it as unresolved.This is the "sector-aware restructuring of the
metricfield" that #860 lists underOut of scope ("separate future release; structure TBD"). So it belongs in its own
ticket rather than being smuggled in here.
Suggestion
Raise it as a ticket now and sequence it before any authoring pass, since the
cookbook's "a row for every allowable pair" rule can't be met until it lands. Two things
to decide:
pathway-level one, or a genuinely separate vocabulary that happens to overlap? That
determines whether the search dropdown grows.
Transmission linesorStorage capacityfor Power — the cookbook's two listsdisagree, and we'd be picking a side.
What did land
Everything else in the section.
granularityalso gained the emissions-scope values(
Scope 1,Scope 1 & 2, …) that Absolute Emissions and Emissions Intensity need,since those two metrics do exist. The rest of the cookbook's per-metric granularity
vocabularies — the Steel production routes, the Aviation propulsion types — are waiting
on the same decision, because they hang off metrics the tool can't name yet.
Worth noting alongside the
byMetricsituation already flagged above: no pathway insrc/datahas any of this authored, so nothing in the running app changes yet.feat(schema): complete the sector-conditional vocabularies
feat(import): import data availability, and stop the import losing data
data: import data availability, restore 13 descriptions, add Singapore
jacobvjk commentedon Oct 2, 2026
Correction, and the table now has real data
Correction to my earlier comment. I said the extra metrics (Transmission lines, Technology cost, Investment requirement, Asset lifetime, and the Steel and Aviation lists) were blocked behind #860's deferred restructure of the
metricfield, because adding them would change the search filter. That was wrong. Cookbook register item D16 says the pathway-level Metric list and the Data Availability Metrics – Extended list are meant to differ. So the availability table got its own metric list, and the search filter is unchanged. Nothing was blocked. This is done on #898.Where things stand. The import on #935 now fills the table from the
draft_data_availabilitysheet: 171 rows across 24 pathways. You can see it on the #937 preview, for example ACE-ATS-2024 → Scope & Granularity.Held back, and why. 45 of the sheet's 216 rows are not imported yet, each named in the import report:
One more to check: for Singapore BAS SG, the metadata lists Capacity as a reported metric, but its availability row says Capacity is "Not covered".