feat(resilience): add headlineEligible field to score + ranking responses (plan 002 PR 2)#3457
Conversation
…nses (plan 002 PR 2 §U3) Plan 2026-04-26-002 §U3 (PR 2 in the 8-PR sequence) — introduces a new `bool headline_eligible = N;` field on `GetResilienceScoreResponse` and `ResilienceRankingItem`. PR 2 populates `true` for every successful score build (no behavior change); PR 6 / §U7 swaps the population logic to the actual eligibility gate (coverage ≥ 0.65 AND (population ≥ 200k OR coverage ≥ 0.85) AND !lowConfidence) and the headline ranking endpoint filters by this field. Why land this as a precursor: the proto + generated TS surface change is itself a noisy diff (regenerated openapi yaml/json + client/server stubs) that's easier to review on its own than mixed in with PR 6's gate logic. Downstream consumers (widget, raw API) can begin reading the field informationally before the gate flips, avoiding a coupled "field + behavior" PR. Files: - `proto/worldmonitor/resilience/v1/get_resilience_score.proto` — `bool headline_eligible = 17;` on `GetResilienceScoreResponse` - `proto/worldmonitor/resilience/v1/resilience.proto` — `bool headline_eligible = 7;` on `ResilienceRankingItem` - `make generate` regenerated openapi + TS client/server bindings - `server/worldmonitor/resilience/v1/_shared.ts:buildResilienceScore` and the two fallback paths in `ensureResilienceScoreCached` populate the field. Happy path → `true`; invalid country code or missing-cache fallback → `false` (the conservative default — those countries can't pass the PR-6 gate either) - `buildRankingItem` passes through from the source-of-truth response; null-response fallback returns `false` - `src/components/resilience-widget-utils.ts:LOCKED_PREVIEW` carries `headlineEligible: true` (informational; widget renders nothing different yet) - New test `tests/resilience-headline-eligible-field.test.mts` (5 pinning tests) — pass-through, fallback default, contract enforcement 7502/7502 tests pass (npm run test:data); typecheck + typecheck:api clean; lint exit 0. Plan: docs/plans/2026-04-26-002-feat-resilience-universe-coverage-rebuild-plan.md PR 3+4+5 just merged: #3452 (commit ba5474f).
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
Greptile SummaryThis PR adds
Confidence Score: 3/5Safe to merge with caution — the stale-cache gap will cause headlineEligible to be absent from API responses for up to 6 h after deploy, which is low-impact now but needs fixing before PR 6 uses the field as a filter A single P1 is present (stale Redis entries serving undefined instead of true), pulling below the 4/5 ceiling. The bug is time-bounded (6 h TTL) and the field is informational-only in this PR, so catastrophic impact is unlikely before PR 6, but it represents a real contract violation of the declared boolean type. server/worldmonitor/resilience/v1/_shared.ts — specifically the payload assignment on line 684 and the missing backward-compat fixup for pre-PR cache entries Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[GET /get-resilience-score] --> B{normalizeCountryCode}
B -- empty/invalid --> C[Return fallback\nheadlineEligible: false]
B -- valid --> D{cachedFetchJson}
D -- cache miss --> E[buildResilienceScore\nheadlineEligible: true]
E --> F[Write to Redis\nwith _formula tag]
D -- cache hit same formula --> G{payload from Redis}
G -- has headlineEligible --> H[Return\nheadlineEligible: true]
G -- missing headlineEligible\npre-PR entry --> I[Return\nheadlineEligible: undefined]
D -- cache hit stale formula --> J[Rebuild score\nheadlineEligible: true]
J --> K[Write new entry to Redis]
K --> H
L[buildRankingItem] --> M{response null?}
M -- yes --> N[Return fallback\nheadlineEligible: false]
M -- no --> O[Pass through\nresponse.headlineEligible]
|
| describe('PR 2 contract: every code path emits the field', () => { | ||
| it('happy-path response includes headlineEligible (compile-time + runtime)', () => { | ||
| // The TypeScript compiler enforces this at compile time via the | ||
| // generated proto type GetResilienceScoreResponse. This runtime | ||
| // assertion exists to catch a future contributor who silently | ||
| // makes the field optional or omits it from a stub. | ||
| const stub = { | ||
| countryCode: 'US', | ||
| overallScore: 73, | ||
| baselineScore: 82, | ||
| stressScore: 58, | ||
| stressFactor: 0.21, | ||
| level: 'high', | ||
| domains: [], | ||
| trend: 'stable', | ||
| change30d: 0, | ||
| lowConfidence: false, | ||
| imputationShare: 0.1, | ||
| dataVersion: 'v16', | ||
| pillars: [], | ||
| schemaVersion: '2.0', | ||
| headlineEligible: true, | ||
| }; | ||
| assert.ok('headlineEligible' in stub, | ||
| 'every response object must carry the headlineEligible field per PR-2 §U3'); | ||
| assert.equal(typeof stub.headlineEligible, 'boolean', | ||
| 'headlineEligible must be a boolean (no null/undefined sentinel)'); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Happy-path test exercises only a stub literal, not the real build function
The test at line 84 asserts 'headlineEligible' in stub and typeof stub.headlineEligible === 'boolean' against a hand-crafted object. Because the stub is defined inline and unconditionally contains the field, this test would pass even if buildResilienceScore or ensureResilienceScoreCached were changed to omit headlineEligible. The PR notes TypeScript enforces this at compile time, which is true for non-optional fields — but that does not catch a future change to mark the field optional (headlineEligible?: boolean).
Consider replacing with an integration call to ensureResilienceScoreCached for a known-valid country code, or at minimum calling buildRankingItem with an actual score built from buildResilienceScore, to validate the PR-2 "true-by-default" contract end-to-end at runtime.
… v16 entries (PR #3457 review round 1) Reviewer P1: PR #3452 (just merged) wrote v16 score + ranking cache entries before this PR added the headlineEligible field. The cache keys are NOT bumped in this PR (it's a no-behavior-change field addition; bumping would force a 6h recompute window for an informational field). So existing cache hits return objects missing the now-required field — TypeScript types are erased at runtime, so the wire shape would carry `undefined` instead of a boolean, breaking any downstream `=== true / === false` discriminator that PR 6 will introduce. Fix: backfill on read in two sites: - `_shared.ts:stripCacheMeta` — invoked by `ensureResilienceScoreCached` on every score cache hit. Default missing `headlineEligible` to `true` (matches the PR-2 happy-path contract for successful score builds). - `get-resilience-ranking.ts` cache-hit branch — invoked when a cached ranking payload is served before recompute. Backfill items[] AND greyedOut[] with the same `true` default. Once the cache cycles to post-PR-2 writes (next cron tick, ~6h TTL), the backfill becomes a no-op for the steady state. Pre-PR-6 the default is the same as the build-time value (`true`); PR 6 / §U7 will flip the build-time value to actual eligibility logic, at which point the new payloads overwrite the legacy default on the next write. Tests: - Updated 2 existing ranking-test fixtures to include `headlineEligible: true` (representing the post-PR-2 steady state) - Added a new ranking-test "backfills headlineEligible on cached items written before PR 2" with a fixture that deliberately omits the field on every item, asserting the backfill defaults to `true` - Added a new score-test "stripCacheMeta defaults headlineEligible=true when the cached payload predates the field" 7504/7504 tests pass; typecheck + typecheck:api clean.
… actually exercises the cache path (PR #3457 review round 2) Reviewer P2: the cache-backfill test in tests/resilience-headline-eligible-field.test.mts:90-117 used setCachedJson directly. Without UPSTASH_REDIS_REST_URL/TOKEN env vars that helper silently no-ops; ensureResilienceScoreCached then took the build-path and returned a fresh response that legitimately has headlineEligible:true (because the build-path sets it that way) — so the test "passed" without ever exercising the cache-read backfill it claims to test. With env vars present, it would have written to real Redis (worse). Fix: switch to the fake-upstash pattern used by every other ranking/ score test in this codebase: - import { installRedis } from './helpers/fake-upstash-redis.mts' - const { redis } = installRedis({}) - redis.set(legacyKey, JSON.stringify(legacyPayload)) Plus two new assertions to PROVE the cache path was exercised (not the build path silently passing): - assert.equal(response.overallScore, 60) — the cached payload's value, NOT what buildResilienceScore would compute for an empty-fixture (typically 0) - assert.equal(response.dataVersion, 'v16') — also from the cached payload Mutation-test verified the new wiring actually catches regressions: disabling the stripCacheMeta backfill makes this test fail (and the other 5 in the suite still pass), confirming the backfill assertion is now load-bearing. Note: also pinned `_formula: 'd6'` on the legacy fixture so the stale- formula gate in ensureResilienceScoreCached doesn't reject the legacy payload (which would force a rebuild and silently route through the build-path again — the same trap as the original bug). 7504/7504 tests pass; typecheck clean.
…ntry assertion (PR #3457 review round 3) Greptile P2: the "happy-path response includes headlineEligible" test was a hand-crafted literal stub that asserted `'headlineEligible' in stub`. Because the stub was defined inline and unconditionally contained the field, it would have passed even if buildResilienceScore or ensureResilienceScoreCached stopped emitting the field. TypeScript type enforcement also doesn't catch a future contributor who marks the field optional (`headlineEligible?: boolean`). First-cut fix asserted on the response of ensureResilienceScoreCached — but that path goes through stripCacheMeta which BACKFILLS missing headlineEligible to true (PR-2 review round 1 defense-in-depth). So even with buildResilienceScore not emitting the field, the response would still test as `true`. Correct approach: drive a real cache-miss → build → store sequence, then read the RAW cache entry directly from fake-redis. The raw stored payload bypasses stripCacheMeta's backfill, so a missing field in buildResilienceScore propagates straight through and the assertion fires. Mutation-verified: removing `headlineEligible: true` from the buildResilienceScore return object now causes this test to fail (1/6 in the suite). With the field present, all 6 pass. Net change: 1 test, ~30 LOC, now actually exercises the contract it claims to enforce instead of asserting a tautology over a hand-crafted literal.
… v16→v17) (#3469) Plan 2026-04-26-002 §U7 (PR 6 in the 8-PR sequence) — flips `headlineEligible` from PR 2's "true everywhere" no-behavior-change contract to the actual eligibility logic (origin Q2 + Q5): coverage >= 0.65 AND (population >= 200k OR coverage >= 0.85) AND !lowConfidence The headline ranking endpoint (`get-resilience-ranking.ts`) now filters items[] by `headlineEligible: true`; ineligible items move to `greyedOut`. Raw API endpoints (per-country score) keep returning the full set with the field surfaced — only the *ranking* endpoint applies the filter. §Files - `_shared.ts`: new `computeHeadlineEligible()` + 3 exported constants (HEADLINE_ELIGIBLE_MIN_COVERAGE=0.65, _MIN_POPULATION_MILLIONS=0.2, _HIGH_COVERAGE=0.85). Wired into `buildResilienceScore`'s response population. Reader memoization extended so the new IMF labor read (for population) shares the per-build cache with `scoreAllDimensions`. - `_dimension-scorers.ts`: exported `RESILIENCE_IMF_LABOR_KEY` + new `readCountryPopulationMillionsForGate()` helper. Differs from the §U6 `readPopulationMillions` in two ways: returns `null` for unknown-pop countries (instead of the 0.5M default — the gate must distinguish "known small" from "unknown"), and DOES NOT apply the §U6 0.5M tiny-state floor (gate needs the real population to decide). - `get-resilience-ranking.ts`: `passesHeadlineGate` predicate combines the existing GREY_OUT_COVERAGE_THRESHOLD (0.40) with the new `headlineEligible === true` check. Items[]/greyedOut[] split by it. - `tests/helpers/resilience-release-fixtures.mts`: add `economic:imf:labor:v1` fixture (uniform 50M placeholder for all 43 G20+EU27 countries) so the release-gate test's countries pass the population branch of the new filter. §Cache prefixes (per cache-prefix-bump-propagation-scope skill): - RESILIENCE_SCORE_CACHE_PREFIX v16 → v17 (pre-PR-6 score entries carry headlineEligible:true unconditionally; would let ineligible countries through the headline filter for the full 6h TTL) - RESILIENCE_RANKING_CACHE_KEY v16 → v17 (same — pre-PR-6 ranking cache reflects "all true" world) - RESILIENCE_HISTORY_KEY_PREFIX v11 → v12 (lockstep — bump pattern consistency + audit-trail clean even though history doesn't carry the field) - 10 hardcoded literal sites bulk-updated across tests/, scripts/, api/health.js - Stale "(v16)" test descriptions updated to "(v17)" in two files §Tests - New `tests/resilience-headline-eligible-gate.test.mts` (10 tests): truth-table coverage of `computeHeadlineEligible` — happy path, lowConfidence short-circuit, the 0.65 floor, the 200k population boundary, the 0.85 high-coverage compensator, and the unknown-pop conservative default. - 7556/7556 tests pass; typecheck + typecheck:api + lint all clean. Plan: docs/plans/2026-04-26-002-feat-resilience-universe-coverage-rebuild-plan.md Predecessor: PR #3457 (PR 2 / §U3 — added the headlineEligible field) Next: PR 7 / §U8 (methodology rewrite + widget badge polish)
…nses (plan 002 PR 2) (koala73#3457) * feat(resilience): add headlineEligible field to score + ranking responses (plan 002 PR 2 §U3) Plan 2026-04-26-002 §U3 (PR 2 in the 8-PR sequence) — introduces a new `bool headline_eligible = N;` field on `GetResilienceScoreResponse` and `ResilienceRankingItem`. PR 2 populates `true` for every successful score build (no behavior change); PR 6 / §U7 swaps the population logic to the actual eligibility gate (coverage ≥ 0.65 AND (population ≥ 200k OR coverage ≥ 0.85) AND !lowConfidence) and the headline ranking endpoint filters by this field. Why land this as a precursor: the proto + generated TS surface change is itself a noisy diff (regenerated openapi yaml/json + client/server stubs) that's easier to review on its own than mixed in with PR 6's gate logic. Downstream consumers (widget, raw API) can begin reading the field informationally before the gate flips, avoiding a coupled "field + behavior" PR. Files: - `proto/worldmonitor/resilience/v1/get_resilience_score.proto` — `bool headline_eligible = 17;` on `GetResilienceScoreResponse` - `proto/worldmonitor/resilience/v1/resilience.proto` — `bool headline_eligible = 7;` on `ResilienceRankingItem` - `make generate` regenerated openapi + TS client/server bindings - `server/worldmonitor/resilience/v1/_shared.ts:buildResilienceScore` and the two fallback paths in `ensureResilienceScoreCached` populate the field. Happy path → `true`; invalid country code or missing-cache fallback → `false` (the conservative default — those countries can't pass the PR-6 gate either) - `buildRankingItem` passes through from the source-of-truth response; null-response fallback returns `false` - `src/components/resilience-widget-utils.ts:LOCKED_PREVIEW` carries `headlineEligible: true` (informational; widget renders nothing different yet) - New test `tests/resilience-headline-eligible-field.test.mts` (5 pinning tests) — pass-through, fallback default, contract enforcement 7502/7502 tests pass (npm run test:data); typecheck + typecheck:api clean; lint exit 0. Plan: docs/plans/2026-04-26-002-feat-resilience-universe-coverage-rebuild-plan.md PR 3+4+5 just merged: koala73#3452 (commit ba5474f). * fix(resilience): backfill headlineEligible on cache read for pre-PR-2 v16 entries (PR koala73#3457 review round 1) Reviewer P1: PR koala73#3452 (just merged) wrote v16 score + ranking cache entries before this PR added the headlineEligible field. The cache keys are NOT bumped in this PR (it's a no-behavior-change field addition; bumping would force a 6h recompute window for an informational field). So existing cache hits return objects missing the now-required field — TypeScript types are erased at runtime, so the wire shape would carry `undefined` instead of a boolean, breaking any downstream `=== true / === false` discriminator that PR 6 will introduce. Fix: backfill on read in two sites: - `_shared.ts:stripCacheMeta` — invoked by `ensureResilienceScoreCached` on every score cache hit. Default missing `headlineEligible` to `true` (matches the PR-2 happy-path contract for successful score builds). - `get-resilience-ranking.ts` cache-hit branch — invoked when a cached ranking payload is served before recompute. Backfill items[] AND greyedOut[] with the same `true` default. Once the cache cycles to post-PR-2 writes (next cron tick, ~6h TTL), the backfill becomes a no-op for the steady state. Pre-PR-6 the default is the same as the build-time value (`true`); PR 6 / §U7 will flip the build-time value to actual eligibility logic, at which point the new payloads overwrite the legacy default on the next write. Tests: - Updated 2 existing ranking-test fixtures to include `headlineEligible: true` (representing the post-PR-2 steady state) - Added a new ranking-test "backfills headlineEligible on cached items written before PR 2" with a fixture that deliberately omits the field on every item, asserting the backfill defaults to `true` - Added a new score-test "stripCacheMeta defaults headlineEligible=true when the cached payload predates the field" 7504/7504 tests pass; typecheck + typecheck:api clean. * test(resilience): wire backfill regression test to fake-upstash so it actually exercises the cache path (PR koala73#3457 review round 2) Reviewer P2: the cache-backfill test in tests/resilience-headline-eligible-field.test.mts:90-117 used setCachedJson directly. Without UPSTASH_REDIS_REST_URL/TOKEN env vars that helper silently no-ops; ensureResilienceScoreCached then took the build-path and returned a fresh response that legitimately has headlineEligible:true (because the build-path sets it that way) — so the test "passed" without ever exercising the cache-read backfill it claims to test. With env vars present, it would have written to real Redis (worse). Fix: switch to the fake-upstash pattern used by every other ranking/ score test in this codebase: - import { installRedis } from './helpers/fake-upstash-redis.mts' - const { redis } = installRedis({}) - redis.set(legacyKey, JSON.stringify(legacyPayload)) Plus two new assertions to PROVE the cache path was exercised (not the build path silently passing): - assert.equal(response.overallScore, 60) — the cached payload's value, NOT what buildResilienceScore would compute for an empty-fixture (typically 0) - assert.equal(response.dataVersion, 'v16') — also from the cached payload Mutation-test verified the new wiring actually catches regressions: disabling the stripCacheMeta backfill makes this test fail (and the other 5 in the suite still pass), confirming the backfill assertion is now load-bearing. Note: also pinned `_formula: 'd6'` on the legacy fixture so the stale- formula gate in ensureResilienceScoreCached doesn't reject the legacy payload (which would force a rebuild and silently route through the build-path again — the same trap as the original bug). 7504/7504 tests pass; typecheck clean. * test(resilience): replace stub-literal contract test with raw-cache-entry assertion (PR koala73#3457 review round 3) Greptile P2: the "happy-path response includes headlineEligible" test was a hand-crafted literal stub that asserted `'headlineEligible' in stub`. Because the stub was defined inline and unconditionally contained the field, it would have passed even if buildResilienceScore or ensureResilienceScoreCached stopped emitting the field. TypeScript type enforcement also doesn't catch a future contributor who marks the field optional (`headlineEligible?: boolean`). First-cut fix asserted on the response of ensureResilienceScoreCached — but that path goes through stripCacheMeta which BACKFILLS missing headlineEligible to true (PR-2 review round 1 defense-in-depth). So even with buildResilienceScore not emitting the field, the response would still test as `true`. Correct approach: drive a real cache-miss → build → store sequence, then read the RAW cache entry directly from fake-redis. The raw stored payload bypasses stripCacheMeta's backfill, so a missing field in buildResilienceScore propagates straight through and the assertion fires. Mutation-verified: removing `headlineEligible: true` from the buildResilienceScore return object now causes this test to fail (1/6 in the suite). With the field present, all 6 pass. Net change: 1 test, ~30 LOC, now actually exercises the contract it claims to enforce instead of asserting a tautology over a hand-crafted literal.
… v16→v17) (koala73#3469) Plan 2026-04-26-002 §U7 (PR 6 in the 8-PR sequence) — flips `headlineEligible` from PR 2's "true everywhere" no-behavior-change contract to the actual eligibility logic (origin Q2 + Q5): coverage >= 0.65 AND (population >= 200k OR coverage >= 0.85) AND !lowConfidence The headline ranking endpoint (`get-resilience-ranking.ts`) now filters items[] by `headlineEligible: true`; ineligible items move to `greyedOut`. Raw API endpoints (per-country score) keep returning the full set with the field surfaced — only the *ranking* endpoint applies the filter. §Files - `_shared.ts`: new `computeHeadlineEligible()` + 3 exported constants (HEADLINE_ELIGIBLE_MIN_COVERAGE=0.65, _MIN_POPULATION_MILLIONS=0.2, _HIGH_COVERAGE=0.85). Wired into `buildResilienceScore`'s response population. Reader memoization extended so the new IMF labor read (for population) shares the per-build cache with `scoreAllDimensions`. - `_dimension-scorers.ts`: exported `RESILIENCE_IMF_LABOR_KEY` + new `readCountryPopulationMillionsForGate()` helper. Differs from the §U6 `readPopulationMillions` in two ways: returns `null` for unknown-pop countries (instead of the 0.5M default — the gate must distinguish "known small" from "unknown"), and DOES NOT apply the §U6 0.5M tiny-state floor (gate needs the real population to decide). - `get-resilience-ranking.ts`: `passesHeadlineGate` predicate combines the existing GREY_OUT_COVERAGE_THRESHOLD (0.40) with the new `headlineEligible === true` check. Items[]/greyedOut[] split by it. - `tests/helpers/resilience-release-fixtures.mts`: add `economic:imf:labor:v1` fixture (uniform 50M placeholder for all 43 G20+EU27 countries) so the release-gate test's countries pass the population branch of the new filter. §Cache prefixes (per cache-prefix-bump-propagation-scope skill): - RESILIENCE_SCORE_CACHE_PREFIX v16 → v17 (pre-PR-6 score entries carry headlineEligible:true unconditionally; would let ineligible countries through the headline filter for the full 6h TTL) - RESILIENCE_RANKING_CACHE_KEY v16 → v17 (same — pre-PR-6 ranking cache reflects "all true" world) - RESILIENCE_HISTORY_KEY_PREFIX v11 → v12 (lockstep — bump pattern consistency + audit-trail clean even though history doesn't carry the field) - 10 hardcoded literal sites bulk-updated across tests/, scripts/, api/health.js - Stale "(v16)" test descriptions updated to "(v17)" in two files §Tests - New `tests/resilience-headline-eligible-gate.test.mts` (10 tests): truth-table coverage of `computeHeadlineEligible` — happy path, lowConfidence short-circuit, the 0.65 floor, the 200k population boundary, the 0.85 high-coverage compensator, and the unknown-pop conservative default. - 7556/7556 tests pass; typecheck + typecheck:api + lint all clean. Plan: docs/plans/2026-04-26-002-feat-resilience-universe-coverage-rebuild-plan.md Predecessor: PR koala73#3457 (PR 2 / §U3 — added the headlineEligible field) Next: PR 7 / §U8 (methodology rewrite + widget badge polish)
Summary
Plan 2026-04-26-002 §U3 (PR 2 in the 8-PR sequence) — adds
bool headline_eligibletoGetResilienceScoreResponse(field 17) andResilienceRankingItem(field 7). PR 2 populates the fieldtruefor every successful score build (no behavior change). PR 6 / §U7 will swap the population logic to the actual eligibility gate (coverage ≥ 0.65 AND (population ≥ 200k OR coverage ≥ 0.85) AND !lowConfidence) and the headline ranking endpoint will filter by this field.Why land this as a precursor
The proto + generated TS surface change is itself a noisy diff (regenerated openapi yaml/json + client/server stubs) that's easier to review on its own than mixed in with PR 6's gate logic. Downstream consumers (widget, raw API) can begin reading the field informationally before the gate flips, avoiding a coupled "field + behavior" PR.
Behavior
headlineEligible: trueheadlineEligible: falseheadlineEligible: falseheadlineEligible: falseThe conservative
falsedefaults on fallback paths match the future PR-6 gate (countries without a successful score build can't pass the coverage gate either).Files
proto/worldmonitor/resilience/v1/get_resilience_score.proto— add field 17proto/worldmonitor/resilience/v1/resilience.proto— add field 7 toResilienceRankingItemmake generateregenerated openapi + TS client/server bindingsserver/worldmonitor/resilience/v1/_shared.ts— populate inbuildResilienceScore, bothensureResilienceScoreCachedfallback paths, andbuildRankingItemsrc/components/resilience-widget-utils.ts—LOCKED_PREVIEWcarriesheadlineEligible: true(informational only; widget renders nothing different yet)tests/resilience-headline-eligible-field.test.mts(new) — 5 pinning tests for the PR-2 contractTest plan
npm run typecheckcleannpm run typecheck:apicleannpm run lintclean (exit 0)npm run test:data— 7502/7502 pass (5 new + 7497 existing)References
docs/plans/2026-04-26-002-feat-resilience-universe-coverage-rebuild-plan.mddocs/brainstorms/2026-04-26-002-resilience-universe-coverage-rebuild-requirements.mdheadlineEligiblefromtrue-by-default to the real gate, and add the ranking-endpoint filter + widget badge