Skip to content

Feat/comparison resolver - #1051

Merged
AlexAxthelm merged 7 commits into
epic/v2from
feat/comparison-resolver
Nov 2, 2026
Merged

AlexAxthelm merged 7 commits into
epic/v2from
feat/comparison-resolver

Conversation

@AlexAxthelm

Copy link
Copy Markdown
Collaborator

Resolve key features scoped to context on the comparison page.


Summary

The comparison grid showed each key feature's widest value, whatever sector and geography the reader selected. So Electrification on Power never fell back and never got a scope badge, as flagged in the #998 review. The detail page has resolved key features for the reader's scope since #998 (#869). This PR brings the comparison page to the same behaviour.

  • Each cell is resolved. Every grid cell is resolved for the page's shared sector and its own column's geography, using the same createKeyFeatureResolver as the detail page. A value inherited from a broader scope gets the scope badge and hover, and a forbidden pair gets 1045's "Not applicable". This also answers the Copilot comment on feat(key-features): forbidden key-feature pairs carry no value (Electrification · Power) #1045 about the grid.
  • Key features count toward what can be selected. A sector or column geography with nothing but key features can now be selected (feat(ui): context filters only clickable when there is relevant data #1017). This is the rule the detail page already uses. The Geographies, Sectors and Metrics coverage sections still flag timeseries data only.
  • The compare link starts columns on the same scope the page allows. The ribbon's compare link and the page now share one rule, comparisonScopeAvailability, so the link always sets a scope the page accepts.
  • The widest-value path is gone. widestValue and its breadth helpers are deleted. That also removes a two-letter rule that ranked JRC's "EU" as a country. FeatureItem now requires a resolution, and KeyFeatures requires a pathway.

Behaviour

Case Before After
ACE on Power: Electrification Widest value, no badge Across-sectors value with an "Across sectors · ASEAN" badge, hover "Electrification does not apply to the Power sector; showing the closest broader scope this pathway reports."
Power-only pathways (JETP-CIPP-2023, SDSN-CW-BAS-SG-2024): Electrification "No information", no hover "Not applicable", hover "Electrification does not apply to the Power sector."
IEA STEPS 2024 on Japan, JRC Reference 2025 on Global Both columns show their widest value Each column resolves for its own geography (badges read "· Japan" and "· Global"), and changing one column's geography changes only that column
IEA STEPS 2024 geography dropdown OECD and Advanced economies cannot be selected Both can be selected, for their key features. They stay outlined in the Geographies section
Search for a geography that has key features but no timeseries (e.g. JRC + Japan), then Compare Column opens on Global Column opens on JP. The plot falls back to Global with its usual note

Commits

  1. feat(compare): resolve key features per column for the selected scope.
  2. feat(compare): count key features toward the selectable scope.
  3. feat(compare): seed the compare link by the page's own availability.
  4. refactor(key-features): remove the widest-value rendering path.
  5. Merge of epic/v2, bringing in feat(key-features): forbidden key-feature pairs carry no value (Electrification · Power) #1045 and feat(scope): list only selectable sectors and geographies in the context filters #1048. The only conflict was a doc comment in ColumnGeographySelect.tsx.
  6. refactor(key-features): drop FeatureItem's checks for a missing resolution. This is cleanup that had to wait for feat(key-features): forbidden key-feature pairs carry no value (Electrification · Power) #1045 to land.

For review: presentation questions

Nothing below is changed in this PR. These are for #837/#859 or for a decision here.

  1. Badge-only cells. The grid has no label column inside the cell, so the scope badge sits alone at the top left and the value sits under it, aligned to the scale. With a centred or right-aligned value ("Low or no change", "Moderate increase") the badge and value don't read as one unit. The badge also looks like the sector chips in the sticky header.
  2. Rows where every column falls back. On ACE + Power, six of eleven feature rows repeat the same "Across sectors · ASEAN" badge in every column. A single note per row might read better.
  3. Rows where every column says "No information". Energy demand on ACE + Power reads "No information" in all three columns. That's the pathways' own answer ("The pathway does not report this."). The row is kept.
  4. "Not applicable" looks the same as "No information". Both use the same grey pill, with the sentiment scale drawn underneath, so only the hover tells them apart.
  5. Dropdown footer. feat(scope): list only selectable sectors and geographies in the context filters #1048's footer says "Only geographies with data in this tool are listed". Options with key features alone (e.g. IEA's OECD) are listed but outlined in the Geographies section below, which suggests they have no data.

Testing

  • npx vitest run --exclude '**/.claude/**': 96 files, 1534 tests, all passing.
  • npm run schema:check: 129 valid items, 0 invalid.
  • ESLint and Prettier are clean.
  • tsc -p tsconfig.app.json reports 203 errors, the same as epic/v2.
  • Mutation checks, each restored afterwards:
    • Resolving every column at a null geography fails the per-column tests.
    • Turning off key-feature availability fails the selectable-scope page tests.
    • Making a key-feature-only geography unselectable in the ribbon fails the compare-link test.
  • Checked in the browser against the dev server:
    • /compare?ids=IEA-STEPS-2024,JRC-GECO-REFERENCE-2025&sector=Power&geography=IEA-STEPS-2024%3AJP%2CJRC-GECO-REFERENCE-2025%3AGlobal: every cell matched the data files, for both column geographies.
    • /compare?ids=ACE-ATS-2024,ACE-BAS-2024,ACE-CNS-2024&sector=Power: fallback badges and hovers.
    • /compare?ids=JETP-CIPP-2023,SDSN-CW-BAS-SG-2024&sector=Power: "Not applicable" and its hover.

🤖 Generated with Claude Code

repro and others added 7 commits October 29, 2026 16:17
Each comparison cell now resolves its key feature for the page's shared
sector and that column's own geography, like the detail page (#869), and
a value inherited from a broader scope carries the scope badge. Fixes
Electrification on Power showing the widest value with no badge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The grid now resolves key features per column, so a sector or column
geography whose only data is key features is worth selecting, as on the
detail page (#1017). The coverage sections keep timeseries-only
availability, so their outlined badges still describe data in this tool.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The compare link chose each column's starting sector and geography from
timeseries data alone, while the page also counts dependencies and key
features. Both now read comparisonScopeAvailability, so a search
geography with key features but no benchmark data carries over (#869),
and the two rules cannot drift apart again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both the detail page and the comparison grid now resolve every key
feature for the reader's scope (#869), so nothing reads the widest value
any more. FeatureItem requires a resolution and KeyFeatures requires a
pathway; widestValue and its breadth helpers go, along with the
two-letter rule that ranked JRC's "EU" as a country.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ution

With the widest-value path gone, FeatureItem always has a resolution,
so the absence tooltip loses its unreachable undefined branch and the
optional chains, and the comment that described the old path now
describes the three kinds of absence instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Memoizes the grid's per-column resolvers, so a page re-render for state
the grid ignores no longer rebuilds every column's geography chain. Adds
a grid test for Electrification on a Power-only pathway reading "Not
applicable" (#1045), and makes the page test check each column's cell
rather than finding the value anywhere on the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings October 30, 2026 13:10
@AlexAxthelm AlexAxthelm self-assigned this Oct 30, 2026
@github-actions

Copy link
Copy Markdown

Azure Static Web Apps: Your stage site is ready! Visit it here: https://proud-glacier-0f640931e-1051.westus2.2.azurestaticapps.net

Copilot AI 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.

🟡 Changes recommended

Two active issues remain: comparison labels can collide between pathway editions, and geography fallback may select a broader region instead of the narrowest matching one.

2 open issues
What changed in this PR

This pull request updates comparison-page scope handling so key features resolve against the shared sector and each column’s selected geography, matching detail-page behavior. It also introduces supporting v2 schema, geography, plotting, edition, accessibility, and design-token updates.

Changes:

  • Resolve key features per comparison column, including broader-scope badges and “Not applicable” states.
  • Include key features when determining selectable sectors and geographies, and seed comparison links from the same availability rules.
  • Add v2 schema validation, geography fallback, timeseries segments, plot-year handling, pathway-edition grouping, reusable UI utilities, and supporting tests.

Unresolved review comments:

  • src/context/ComparisonContext.tsx — moderate, 1 vote: de-duplicate restored comparison IDs.
  • src/hooks/useDropdown.ts — moderate, 1 vote: route outside-click dismissal through close() to restore focus.
  • src/hooks/useElementWidth.ts — moderate, 1 vote: observe elements that attach after the initial effect.
  • src/utils/comparisonScope.ts — moderate, 2 votes: disambiguate labels for multiple editions of the same pathway.
  • src/utils/geographyFallback.ts — critical, 2 votes: select the narrowest containing geography rather than the first declared region.
File Summary
testdata/​valid/​pathwayMetadata_v2_minimal.json Adds a minimal valid v2 metadata fixture.
testdata/​valid/​pathwayMetadata_sample_03.json Updates region membership data for v2 validation.
testdata/​valid/​pathwayMetadata_sample_02.json Updates region membership data for v2 validation.
testdata/​valid/​pathwayMetadata_minimal.json Updates region membership data for v2 validation.
src/​utils/​tooltipUtils.ts Adds sector-segment tooltip resolution and updated key-feature typing.
src/​utils/​tooltipUtils.test.tsx Tests sector-segment tooltip coverage.
src/​utils/​timeseriesSegments.ts Derives plotted sector segments from timeseries rows.
src/​utils/​timeseriesSegments.test.ts Tests segment filtering and ordering.
src/​utils/​timeseriesIndex.ts Exposes synchronous timeseries-index access.
src/​utils/​timeseriesAvailability.ts Handles v2 geography tokens and optional metric taxonomies.
src/​utils/​timeseriesAvailability.test.ts Tests exact geography matching and optional metric definitions.
src/​utils/​searchUtils.test.tsx Updates geography fixtures for populated region membership.
src/​utils/​scopeLabel.ts Formats selected scope labels for user-facing copy.
src/​utils/​scopeLabel.test.ts Tests scope-label formatting.
src/​utils/​scopeAvailability.ts Determines selectable sectors and geographies from available data.
src/​utils/​scopeAvailability.test.ts Tests timeseries, dependency, and key-feature availability.
src/​utils/​plotYears.ts Caps plotted years and detects extended downloads.
src/​utils/​plotYears.test.ts Tests plot-year capping behavior.
src/​utils/​pathwayEditions.ts Groups pathway records into publication editions.
src/​utils/​pathwayEditions.labels.test.tsx Tests edition-label disambiguation.
src/​utils/​loadData.ts Adds Vite development-mode detection.
src/​utils/​loadData.test.tsx Tests development-mode detection.
src/​utils/​geographyUtils.ts Updates geography mappings and canonical keys.
src/​utils/​geographyUtils.test.tsx Updates geography mapping and membership tests.
src/​utils/​geographyFallback.ts Resolves missing plot geographies with fallback notices.
src/​utils/​filterRegions.ts Clarifies filter-region and pathway-geography handling.
src/​types/​pathwayTimeseries.v2.d.ts Adds generated v2 timeseries types.
src/​types/​pathwayMetadata.v1.d.ts Regenerates v1 metadata types and technology values.
src/​types/​index.ts Switches application metadata typing to v2 and exports scope types.
src/​types/​common/​technology.v1.d.ts Regenerates technology vocabulary types.
src/​types/​common/​sectorSegment.v1.d.ts Adds sector-segment types.
src/​types/​common/​scopeSector.v2.d.ts Adds scoped-sector types.
src/​types/​common/​scopeGeography.v2.d.ts Adds scoped-geography types.
src/​types/​common/​metric.v1.d.ts Regenerates simplified metric types.
src/​types/​common/​geography.v1.d.ts Updates populated-region geography types.
src/​types/​common/​dataAvailabilityMetric.v1.d.ts Adds data-availability metric types.
src/​types/​common/​dataAvailability.v1.d.ts Adds data-availability vocabulary types.
src/​test/​setup.ts Adds a native-dialog test shim.
src/​test/​mockIntersectionObserver.ts Extends intersection-observer test support.
src/​schema/​pathwayTimeseries.v2.test.ts Tests v2 timeseries schema constraints.
src/​schema/​pathwayMetadata.v1.json Corrects v1 schema documentation.
src/​schema/​common/​technology.v1.json Expands the technology vocabulary.
src/​schema/​common/​sectorSegment.v1.json Adds the sector-segment schema.
src/​schema/​common/​scopeSector.v2.json Adds the scoped-sector schema.
src/​schema/​common/​scopeGeography.v2.json Adds the scoped-geography schema.
src/​schema/​common/​metric.v1.json Removes the obsolete metric sector-scope field.
src/​schema/​common/​index.ts Registers new common schemas.
src/​schema/​common/​geography.v1.json Requires populated region membership.
src/​schema/​common/​dataAvailabilityMetric.v1.json Adds data-availability metric vocabulary.
src/​schema/​common/​dataAvailability.v1.json Adds data-availability vocabularies and constraints.
src/​pages/​resources/​ResourcesMethodologyPage.tsx Updates geography and technology documentation.
src/​pages/​resources/​ResourcesMethodologyPage.test.tsx Updates methodology-page assertions.
src/​pages/​PathwaySearch.tsx Groups edition series and integrates the editions modal.
src/​pages/​PathwaySearch.test.tsx Tests edition grouping in search results.
src/​pages/​PathwayDetailPage.disclaimer.test.tsx Updates detail-page fixtures and providers.
src/​pages/​LandingPage.tsx Updates landing-page copy.
src/​pages/​ComparisonPage.disclaimer.test.tsx Updates comparison fixtures and asynchronous waits.
src/​index.css Adds segment colors and edition-modal styling.
src/​hooks/​useUrlParamState.ts Adds reusable URL-backed selection state.
src/​hooks/​useUrlParamState.test.tsx Tests URL selection behavior.
src/​hooks/​useSessionFlag.ts Adds session-scoped boolean preferences.
src/​hooks/​useSessionFlag.test.tsx Tests session preference persistence and failures.
src/​hooks/​useElementWidth.ts Adds ResizeObserver-based width tracking.
src/​hooks/​useElementWidth.test.tsx Tests width measurement and quantization.
src/​hooks/​useDropdown.ts Adds shared dropdown interaction behavior.
src/​data/​pathwayMetadata.ts Loads v2 metadata and warns about remaining v1 files.
src/​context/​ComparisonContext.tsx Validates and restores stored comparison selections.
src/​context/​ComparisonContext.test.tsx Updates comparison persistence tests.
src/​context/​ComparisonContext.restore.test.tsx Tests stale and incompatible selection restoration.
src/​components/​TextWithTooltip.tsx Supports button-based tooltip triggers.
src/​components/​TextWithTooltip.test.tsx Tests button-trigger tooltip behavior.
src/​components/​SectionIntro.tsx Adds shared section-introduction styling.
src/​components/​ScopeFilterNotice.tsx Adds scoped-content notices.
src/​components/​ScopeAxisRow.tsx Adds shared scope-axis layout and overflow controls.
src/​components/​RegionMembersTooltip.tsx Updates region-member count rendering.
src/​components/​RegionMembersTooltip.test.tsx Updates region tooltip tests.
src/​components/​PlotSelector.tsx Adds sector-segment data to plot rows.
src/​components/​PlotSelector.test.tsx Updates plot fixtures with segments.
src/​components/​PathwayCard.test.tsx Tests stale comparison IDs and comparison limits.
src/​components/​PathwayCard.editions.test.tsx Tests edition pills and labels.
src/​components/​NormalizedStackedAreaChart.tsx Updates technology colors for the v2 taxonomy.
src/​components/​NormalizedStackedAreaChart.test.ts Verifies technology color coverage.
src/​components/​GeographyDivergenceNotice.tsx Adds notices for differing column geographies.
src/​components/​EditionsModal.tsx Adds the pathway-editions dialog.
src/​components/​DropdownFacetShell.tsx Reuses the shared dropdown hook.
src/​components/​DownloadDataset.tsx Explains when downloads extend beyond plotted years.
src/​components/​DownloadDataset.test.tsx Tests extended-download messaging.
src/​components/​CoreDrivers.tsx Adds reusable core-driver rendering.
src/​components/​CoreDrivers.test.tsx Tests core-driver rendering and labels.
src/​components/​ComparisonRibbon.tsx Seeds comparison URLs with valid shared scope.
src/​components/​ComparisonDependencies.tsx Adds dependency rendering to comparisons.
src/​components/​Badge.tsx Adds scope and sector-segment variants.
src/​components/​Badge.test.tsx Tests badge variants and theme-token coverage.
scripts/​timeseries-csv.ts Adds timeseries segment and publisher CSV helpers.
scripts/​timeseries-csv.test.ts Tests CSV generation helpers.
scripts/​schema-check-files.ts Validates v1/v2 schemas and cross-file constraints.
scripts/​codemod-timeseries-v1-to-v2.test.ts Tests timeseries migration behavior.
scripts/​build-design-tokens.ts Generates design tokens from CSS theme colors.
scripts/​build-design-tokens.test.ts Tests design-token parsing and generation.
README.md Documents pathway and benchmark-data import workflows.
package.json Adds design-token tooling and Excel support.
docs/​design/​README.md Documents design assets and token maintenance.
.gitignore Ignores virtual environments and TypeScript build artifacts.
.github/​workflows/​node-build-committed-files.yml Adds CI validation for committed design tokens.

Review effort: Lite

Comment thread src/utils/geographyFallback.ts Resolved
Comment thread src/utils/comparisonScope.ts Resolved
@AlexAxthelm
AlexAxthelm changed the base branch from main to epic/v2 October 30, 2026 13:47
@RMI RMI deleted a comment from github-actions Bot Oct 30, 2026
@AlexAxthelm
AlexAxthelm requested a lite review from Copilot October 30, 2026 13:48
@AlexAxthelm
AlexAxthelm marked this pull request as ready for review October 30, 2026 13:48

Copilot AI 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.

🟢 Approval recommended

The recorded review outcome identifies no active issues, so the change can proceed.

No open issues 🎉

2 resolved since last review

Review effort: Lite

@jacobvjk
jacobvjk self-requested a review October 30, 2026 16:25
@AlexAxthelm
AlexAxthelm merged commit b7f002d into epic/v2 Nov 2, 2026
14 checks passed
@AlexAxthelm
AlexAxthelm deleted the feat/comparison-resolver branch November 2, 2026 09:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants