chore(resilience): T1.9 cache-key health sync + Phase 1 scorecard close-out#2965
Conversation
…se-out
Final PR of the Phase 1 reference-grade upgrade. Closes out the Phase 1
acceptance gate with two deliverables:
1. T1.9 cache-key / health-registry sync regression test
New tests/resilience-cache-keys-health-sync.test.mts asserts that
the RESILIENCE_RANKING_CACHE_KEY string from _shared.ts literally
appears in api/health.js, and that the score/history prefixes match
the expected resilience:<kind>:v<n>: shape. This guards against
future silent version drift where a cache-key bump in _shared.ts
could leave the health registry watching the old key indefinitely.
No cache keys were bumped in Phase 1 because every schema addition
(imputationClass, freshness) was additive with default fallbacks on
the existing resilience:score:v7 / ranking:v8 / history:v4 keys.
2. Methodology changelog v1.1 + Phase 1 self-assessment scorecard
docs/methodology/country-resilience-index.mdx:
- v1.0 entry trimmed to only reference the actual v1.0 baseline PRs
(#2821, #2847, #2858). Moved from "Current published version" to
"Baseline".
- New v1.1 entry inserted between v1.0 and v2.0, marked as "Current
published version". Lists all Phase 1 tasks T1.1-T1.9 with the
specific PRs that shipped each slice.
- New "Scorecard (v1.1 self-assessment)" section at the end of the
changelog with ratings on six standard composite-indicator review
axes: Methodology 7.5, Explainability 7.5, Reproducibility 8.0,
Source quality 7.0, Timeliness 6.5, Sensitivity 7.0. Every axis has
a named rationale and a named gap tied to a Phase 2 or Phase 3
task. Both Phase 1 required thresholds (Methodology >=7.5,
Explainability >=7.5) are met.
docs/internal/country-resilience-upgrade-plan.md:
- Phase 1 acceptance checklist: 7 of 7 items flipped to [x] with
PR references.
- T1.9 task bullet closed out with a reference to this PR.
What is deliberately NOT in this PR
- No code changes to the scorer, response builder, or widget.
- No new proto fields or schema changes.
- No cache-key bumps.
- No external expert review (Phase 3 T3.8b, runs in parallel).
- No Phase 2 work.
Depends on nothing at code level; references PRs 2959/2961/2962/2964
which are still in the review queue. This PR can land independently.
Verified
- tests/resilience-cache-keys-health-sync.test.mts 3/3 passing
- methodology doc linter (T1.8) still passes on the updated mdx
- lint:md clean
- test:data clean (4355/4355)
- typecheck clean
- typecheck:api clean
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis is the Phase 1 close-out PR: it adds a cache-key / health-registry drift guard test (
Confidence Score: 5/5Safe to merge; only remaining finding is a P2 documentation inaccuracy in the scorecard text that does not affect runtime behavior. All three changed files are docs and a regression test. The test is correct and consistent with codebase conventions. The single P2 finding is a misleading Timeliness gap description in the scorecard, not a code defect. docs/methodology/country-resilience-index.mdx — Timeliness scorecard gap text should be corrected before publishing. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["_shared.ts constants\n(RESILIENCE_RANKING_CACHE_KEY\nRESILIENCE_SCORE_CACHE_PREFIX\nRESILIENCE_HISTORY_KEY_PREFIX)"] -->|"T1.9 drift guard\n(this PR)"| B["resilience-cache-keys-health-sync.test.mts"]
B --> C{"ranking key in\napi/health.js?"}
C -->|pass| D["health probe watches\ncorrect key"]
C -->|fail| E["CI blocks merge\n— key bumped without\nupdating health.js"]
B --> F{"score prefix matches\nresilience:score:v<n>:?"}
F -->|pass| G["shape invariant holds"]
F -->|fail| H["typo/rename caught\nat test time"]
B --> I{"history prefix matches\nresilience:history:v<n>:?"}
I -->|pass| G
I -->|fail| H
Reviews (1): Last reviewed commit: "chore(resilience): T1.9 cache-key health..." | Re-trigger Greptile |
| | **Explainability** | 7.5 | Per-dimension confidence grid in the widget shows coverage %, imputation class, and freshness for every dimension on every country. Tooltip text is generated from the taxonomy so analysts can click through to the meaning without reading this document. Gap: no waterfall chart of individual signal contributions yet, that lands in Phase 3 T3.3. | | ||
| | **Reproducibility** | 8.0 | Every dimension's sourceKey, cadence, and goalpost lives in `_indicator-registry.ts` and is linted against this doc. Cache keys are versioned (`resilience:score:v7`, `ranking:v8`, `history:v4`). `dataVersion` is written by the seed and plumbed to the widget footer. Gap: the benchmark and backtest scripts do not yet run on a CI cron; those land in Phase 2 T2.7. | | ||
| | **Source quality** | 7.0 | World Bank, IMF, WHO, IEA, UNHCR, UCDP, IPC, BIS, FAO, RSF, GPI: all authoritative. Gap: curated-list sources (BIS ~40 economies, WTO) do not cover the full WorldMonitor country set, which is why the `unmonitored` imputation class exists. Phase 2 T2.9 adds language-normalized information signal to reduce English-press bias. | | ||
| | **Timeliness** | 6.5 | Annual sources dominate (WGI, GPI, RSF, WHO). Freshness classifier makes this visible at the dimension level so users can see which parts of a country score are fresh vs. 12 months old. Gap: no real-time signals in v1.1; Phase 2 adds FX volatility, conflict events, and power outages at daily cadence. | |
There was a problem hiding this comment.
Timeliness gap description contradicts the existing indicator registry
The gap note claims "no real-time signals in v1.1; Phase 2 adds FX volatility, conflict events, and power outages at daily cadence," but the Dimensions and Indicators tables in this same document already list ucdpConflict (Realtime), internetOutages (Realtime), infraOutages (Realtime), unrestEvents (Realtime), and socialVelocity (Realtime) as live signals — and these predate Phase 1. "Conflict events" and "power outages" are therefore not Phase 2 additions. A reader scoring the index against this section will reach a false conclusion about what data it currently uses.
| | **Timeliness** | 6.5 | Annual sources dominate (WGI, GPI, RSF, WHO). Freshness classifier makes this visible at the dimension level so users can see which parts of a country score are fresh vs. 12 months old. Gap: no real-time signals in v1.1; Phase 2 adds FX volatility, conflict events, and power outages at daily cadence. | | |
| | **Timeliness** | 6.5 | Annual sources dominate (WGI, GPI, RSF, WHO). Freshness classifier makes this visible at the dimension level so users can see which parts of a country score are fresh vs. 12 months old. Gap: most structural indicators (WGI, GPI, RSF, WHO) are annual only; BIS FX data is monthly; the majority of indicator weight comes from annual sources even though several stress signals (conflict, outages, unrest, social velocity) are already realtime or daily. Phase 2 adds FX volatility at daily cadence and raises the share of high-frequency signals across more dimensions. | |
Greptile P2 finding: the Timeliness row in the Phase 1 self-assessment
scorecard claimed "no real-time signals in v1.1" and described
conflict events and power outages as Phase 2 additions, which is
factually wrong. Thirteen stress-side indicators already run at
realtime or daily cadence via the cross-source stack:
realtime: ucdpConflict, internetOutages, infraOutages,
unrestEvents, socialVelocity
daily: sanctionCount, cyberThreats, gpsJamming,
shippingStress, transitDisruption, gasStorageStress,
energyPriceStress, newsThreatScore
The real cadence gap is that structural sources (WGI, GPI, RSF, WHO,
IMF macro) are annual and still carry the majority of index weight,
while the live-shock pillar is already rolling. Phase 2 T2.2 adds
FX volatility at daily cadence to narrow the gap on the
currency-external dimension.
Score itself unchanged (6.5), it was a defensible number. Only
the gap rationale is corrected to match reality.
|
Thanks, P2 was valid. Fixed in 325a60a. Corrected the Timeliness row gap rationale to match the actual Verified against origin/main's registry:
The real timeliness gap is that structural sources (WGI/GPI/RSF/WHO/IMF macro) remain annual and still carry the majority of weight, while the live-shock pillar is already rolling. Phase 2 T2.2 adds FX volatility daily to narrow the gap on currency-external. Score itself unchanged (6.5), it was a defensible number, only the gap rationale needed correcting.
|
Summary
Final PR of the Phase 1 reference-grade upgrade. Closes out the Phase 1 acceptance gate defined in
docs/internal/country-resilience-upgrade-plan.md.Does not depend on other Phase 1 PRs at the code level
This PR references PRs #2959 (T1.7 schema), #2961 (T1.5 propagation), #2962 (T1.6 full grid), #2964 (T1.7 source-failure wiring) in the changelog but does not edit any code they touch. All five Phase 1 PRs can merge in any order.
What this PR commits
1. T1.9 cache-key / health-registry sync regression test
New
tests/resilience-cache-keys-health-sync.test.mtsasserts that the resilience cache-key constants from_shared.tsliterally appear inapi/health.jsand match the expected version shape. This guards against future silent drift where a cache-key bump could leave the health registry watching the old key indefinitely. No cache keys were bumped in Phase 1 because every schema addition was additive with default fallbacks on the existing keys.2. Methodology changelog v1.1 + Phase 1 self-assessment scorecard
docs/methodology/country-resilience-index.mdx:3. Plan doc acceptance checklist
docs/internal/country-resilience-upgrade-plan.md: 7 of 7 Phase 1 acceptance items flipped to[x]with PR references. T1.9 task bullet closed.Phase 1 acceptance gate status: MET
data_versionnon-null on every country score response (T1.4 feat(resilience): surface dataVersion in widget footer (T1.4) #2943)What is NOT in this PR
Test plan
tests/resilience-cache-keys-health-sync.test.mtspasses (drift guard)npm run test:datastill passes (no regression)npm run lint:mdcleannpm run typecheckcleanPhase 2 kickoff (not this PR)
Phase 2 begins once all five Phase 1 PRs merge:
schemaVersion: "2.0"feature flagPost-Deploy Monitoring & Validation
No additional operational monitoring required: this PR is docs + one regression test. No runtime behavior change, no response schema change, no new Redis keys. The cache-key drift test is CI-gated and will fail loudly on any future silent drift.