Repository navigation
Feat/resolver (key features) - #998
Conversation
First slice of #869. Adds src/utils/keyFeatureRules.ts, holding: - the scope sentinels - the forbidden Electrification x Power combination - the "Not applicable at this scope level" check - declaredTokenCodes, the countries one of a pathway's own geography tokens covers - widestSector and widestGeography The module has only type imports, so validateScopes.ts can import it under ts-node in a later PR. keyFeatureScope.ts now re-exports the sentinels from it instead of defining its own copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds src/utils/keyFeatureResolution.ts. For the selected sector and geography, resolveKeyFeature returns the value a pathway reports and where it was found. The lookup is an exact token match: it walks the selected sector through the geography chain first, then the same chain under "across sectors". - geographyChain: the selection, then every declared token that contains it (smallest first), then "across regions", then "Global" - A missing entry or a "Not applicable at this scope level" cell keeps the walk going; an authored "No information", "None" or "No new technologies" ends it - Electrification x Power returns "forbidden" before the walk, so it never inherits an "across sectors" value - An empty selection axis is filled with the pathway's widest scope - sourceScopeLabel names the source scope for the fallback badge asEntries is now exported from keyFeatureScope.ts so the resolver reuses the same malformed-input handling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KeyFeatures takes optional pathway and scope props. With a pathway, it resolves each feature for the scope and passes the result to FeatureItem, which renders: - an inherited value with an outlined badge beside the label naming where it came from, e.g. "Across sectors · South East Asia" - authored and exhausted "No information" with different tooltips - a forbidden combination (Electrification x Power) as "Not applicable", with nothing selected Adds the outlined neutral "scope" Badge variant. Without a pathway, rendering is unchanged; the comparison page keeps using that until 1b. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both KeyFeatures panels on the detail page now receive the pathway and the ribbon's scope, so each key feature shows the value for the selected sector and geography, badged when it is inherited from a broader scope. The scope and tabs page tests now spell the sector sentinel "across sectors": the resolver looks scopes up exactly, so the retired "cross-sector" matched nothing. The scope test now checks that changing the ribbon changes the resolved value and its badge, on both axes. Also updates comments that still described #869 as future work or said the resolver uses the search filter regions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
createKeyFeatureResolver works out the effective scope and the sector and geography fallback order once for a pathway and selection, and returns a function that resolves one field at a time. KeyFeatures now creates one per render instead of rebuilding them for each of the 11 features. resolveKeyFeature remains as a one-field wrapper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Expected version change and release notes🚨 WARNING: This PR is not expected to trigger a new versionTo trigger a version bump, use at least one conventional commit message in this branch. See: https://www.conventionalcommits.org/en/v1.0.0/ |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://proud-glacier-0f640931e-998.westus2.2.azurestaticapps.net |
There was a problem hiding this comment.
🟡 Changes recommended
Valid country-scoped values can be skipped during fallback, and unavailable tooltips overstate the absence of data.
2 open issues
What changed in this PR
Adds scope-aware key-feature resolution to the pathway detail page, while preserving comparison-page rendering.
Changes:
- Introduces shared scope rules and sector-first fallback resolution.
- Adds inherited-scope badges and distinct absence states.
- Expands resolver, component, and detail-page tests.
| File | Description |
|---|---|
| src/utils/scopeSeed.ts | Corrects scope terminology in comments. |
| src/utils/keyFeatureScope.ts | Reuses shared constants and exports entry helper. |
| src/utils/keyFeatureRules.ts | Defines shared scope and applicability rules. |
| src/utils/keyFeatureRules.test.ts | Tests shared rules. |
| src/utils/keyFeatureResolution.ts | Implements fallback resolution and source labels. |
| src/utils/keyFeatureResolution.test.ts | Tests resolution ordering and edge cases. |
| src/utils/filterRegions.ts | Clarifies search versus resolver behavior in comments. |
| src/pages/PathwayDetailPage.tsx | Passes ribbon scope into key features. |
| src/pages/PathwayDetailPage.tabs.test.tsx | Updates fixture scope tokens. |
| src/pages/PathwayDetailPage.scope.test.tsx | Tests scope-dependent values and badges. |
| src/components/KeyFeatures.tsx | Renders resolved values and explanatory states. |
| src/components/KeyFeatures.test.tsx | Tests resolver-driven rendering. |
| src/components/Badge.tsx | Adds neutral scope-badge styling. |
| src/components/Badge.test.tsx | Tests scope-badge styling. |
| PLAN.md | Documents implementation and follow-up work. |
Review effort: Balanced
scopeSelectionLabel now writes "all sectors" for "across sectors" and "all regions" for "across regions". A scope filled in from empty axes reads "No value for all sectors in all regions" rather than "across sectors in across regions". The ribbon never selects either sentinel, so existing notices are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KeyFeatureKey in keyFeatureRules.ts replaces FeatureKey in KeyFeatures.tsx, KeyFeatureSection in tooltipUtils.ts and the inline keyof in ScopedKeyFeature. It stays in keyFeatureRules so the validator can import it under ts-node. Type-only change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The scope test now runs on the At a glance tab (the default) as well as Overview. Each tab renders its own KeyFeatures panel, and until now only Overview's wiring was covered, so At a glance could lose its scope without a test failing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The v2 schema added SMR (cookbook decision 0020), but the pill options, the tooltips and the methodology page never listed it. A pathway that reported SMR showed nothing selected, or "No information". A new test checks every feature's options against the schema, so the next value the schema adds can't go missing the same way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Expected version change and release notes🚨 WARNING: This PR is not expected to trigger a new versionTo trigger a version bump, use at least one conventional commit message in this branch. See: https://www.conventionalcommits.org/en/v1.0.0/ |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://proud-glacier-0f640931e-998.westus2.2.azurestaticapps.net |
|
@jacobvjk An outstanding question at this point: fallback for single-country regions (IEA STEPS/CPS 2025 have regions like "Japan" = JP, "Brazil" = BR) isn't clearly defined. Selecting the region "Japan" never looks at a value recorded at the country JP, even though they cover the same place. Nothing is recorded that way today, but the data checks allow it. One more point to discuss on the key-features PR: values recorded at a country that sits inside a region. The data checks let a key feature be recorded at any country inside one of the pathway's regions, even if that country isn't listed on its own. No pathway does this today, but two things go wrong if one does:
Questions:
|
@AlexAxthelm if we treat "Japan" = JP as a region Japan that is an exact match to JP (intuitively right), what would that mean at the level of the UI? does this somehow look different to just a plain country mapping? Ideally I would think it should not. |
Probably not too much at the level of the UI immediately, but for example in STEPS 2025, there aren't any "individual countries" in the authored data, but the Japan region happens to only map to one country.
We're already doing set comparison between the set of ISOs in the context and the set in each region. I think it's pretty easy to extend that so if the set size is
This is what already happens (like the "Bananas" region pill on the scenario card would float to the front, etc). But right now, if you filter "Bananas", you don't get "DE" results. I think that's the change we want to go with.
Collapsing this in authoring would also be fine. we could set the schema so that regions have to have at least 2 countries 🤷 What I outlined above gives a bit more authorial flexibility, if there's a reason to use a different name (the "Bananas" example above).ab We also have some regions right now that don't have mappings, so we would need to figure out how we want to handle those |
I would tend to argue that:
|
Electrification can't apply to the Power sector, and the detail page opens on Power for almost every pathway, so showing "Not applicable" hid electrification wherever readers first saw it. The resolver now skips Power's rows for that field and falls back to across sectors like any missing value. The badge's tooltip says the feature doesn't apply to Power. A pathway with nothing across sectors shows "No information", as any exhausted fallback does. Replaces the "forbidden" resolution and its "Not applicable" rendering. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The resolver no longer keeps its own list of forbidden field and sector pairs. A "Not Applicable" cell is skipped like the scope-level sentinel, so Electrification x Power still falls back to across sectors, and the badge still says the feature doesn't apply there. Which pairs must be "Not Applicable", and that it appears nowhere else, becomes PR 2's validation rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Expected version change and release notes🚨 WARNING: This PR is not expected to trigger a new versionTo trigger a version bump, use at least one conventional commit message in this branch. See: https://www.conventionalcommits.org/en/v1.0.0/ |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://proud-glacier-0f640931e-998.westus2.2.azurestaticapps.net |
|
For "Electrification", when there is only power sector coverage, I realize that we record "No information" (based on the cookbook), not "Not applicable". Does this mean that there is effectively not situation left, when we would display "Not applicable"? https://proud-glacier-0f640931e-998.westus2.2.azurestaticapps.net/pathway/SDSN-CW-BAU-SG-2024?tab=overview |
… fixtures and tests that treated empty or single-country regions as real data now describe data the schema rejects. Their fixtures no longer type-check. This follows e124bd2: comments updated, the empty-set guards kept for stale tokens and malformed input, fixtures given two or more members, and the single-country cases rewritten as countries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n select The detail page resolves key features for the selected scope (#869), so a sector or geography whose only data is key features now has something to show. scopeAvailability counts informative key-feature values at exactly that token when asked: not the not-applicable markers or "No information", and an across-sectors or Global value doesn't stand in for other tokens. The detail page turns this on. The comparison page leaves it off until it resolves key features per column (noted for 1b in PLAN.md). Gives 32 pathways their first selectable geography, including IEA STEPS/CPS 2025 and every Power-only SDSN pathway, and makes IEA 2025's country-level key features reachable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Expected version change and release notes🚨 WARNING: This PR is not expected to trigger a new versionTo trigger a version bump, use at least one conventional commit message in this branch. See: https://www.conventionalcommits.org/en/v1.0.0/ |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://proud-glacier-0f640931e-998.westus2.2.azurestaticapps.net |
Expected version change and release notes🚨 WARNING: This PR is not expected to trigger a new versionTo trigger a version bump, use at least one conventional commit message in this branch. See: https://www.conventionalcommits.org/en/v1.0.0/ |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://proud-glacier-0f640931e-998.westus2.2.azurestaticapps.net |
…its title Assumptions tab, "Assumptions & Trends Preview" on At a glance), so two scope tests waiting for "Assumptions & Trends Overview" timed out once the PR was merged into epic/v2. They now wait for the Emissions group heading they assert on, which neither tab renames. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Expected version change and release notes🚨 WARNING: This PR is not expected to trigger a new versionTo trigger a version bump, use at least one conventional commit message in this branch. See: https://www.conventionalcommits.org/en/v1.0.0/ |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://proud-glacier-0f640931e-998.westus2.2.azurestaticapps.net |
| : feature.options.map((opt) => | ||
| pill(opt, selectedArr.includes(opt)), | ||
| )} |
|
Opening for review. I'll have a followup PR to handle a last edge case around the forbidden combos stuff (electrification/power), but that one is going to be a lot smaller than this. My general approach there (if you agree) is going to be:
other than that, there's a few small wording things that I may bother opening PRs for, but none of them are for paths/combos that exist in the current data. Claude outlines all of it below:following up on your question about Electrification on Power-only pathways (whether there's any case left where we'd show "Not applicable"): Today: no. Electrification on Power never shows "Not applicable" any more. Power's "Not Applicable" cell is skipped and the across-sectors value is shown with a badge, e.g. IEA NZE 2024. On a Power-only pathway there's nothing across sectors, so it falls through to "No information", and the hover wrongly says "Nothing is recorded for this pathway at any scope" (e.g. JETP CIPP; 57 pages like this). Proposed approach:
The page side is a small change and could go into this PR before merge. The validator rule and the data clean-up would go in the validation PR, which will fail CI until the workbook is updated. Does that work for you, and is the cookbook OK with dropping these rows? Two smaller wording points:
|





Resolve key features according to context (sector/geography selection).
Summary
Key features on the pathway detail page now follow the scope ribbon (sector + geography), like the plots and tables already do. Each feature shows the value the pathway records for the selected scope. Where there is none, it falls back to the closest broader scope, and a badge says where the value came from.
How a value is chosen
across regions, andGlobal. Only then does it try the same geographies underacross sectors. SoPower · Globalbeatsacross sectors · Thailand.What readers see
Not changed here: the comparison page still shows each pathway's widest value. Resolving it per column is the stacked follow-up PR.
Code
keyFeatureRules.ts(new): scope sentinels, the "not applicable" checks, which countries a pathway's own geography token covers, and a pathway's widest sector and geography. It has only type imports, so the schema-check script can import it under ts-node.keyFeatureResolution.ts(new):createKeyFeatureResolver/resolveKeyFeature,geographyChainandsourceScopeLabel.KeyFeatures/FeatureItemrender from a resolution when given apathwayandscope. Without them, the output is byte-identical to before (checked across real pathways and every display mode).scopeBadge variant;scopeAvailabilitytakes{ keyFeatures: true };scopeSelectionLabelwords the sentinels in prose.Related issues
Part of #869 (resolver) and #859 (scope badges), for the detail page; the comparison page follows in a stacked PR. Builds on #872, #1017 and #1035.
Testing
Follow-ups (not in this PR)
{ keyFeatures: true }to itsscopeAvailability;KeyFeatures'keyFeaturesprop;widestValueand the breadth helpers.FeatureItem; the detail page rendering one frame at its widest scope before the ribbon's scope applies.Checklist
AI assistance: implemented with Claude Code (Claude Opus 5.5) from a written plan, in reviewed steps; the author reviewed each change and directed the design decisions.
🤖 Generated with Claude Code