Skip to content

feat(freshness): surface seed health in risk panel#3493

Merged
koala73 merged 7 commits into
koala73:mainfrom
lspassos1:feat/data-freshness-surface
May 26, 2026
Merged

feat(freshness): surface seed health in risk panel#3493
koala73 merged 7 commits into
koala73:mainfrom
lspassos1:feat/data-freshness-surface

Conversation

@lspassos1

Copy link
Copy Markdown
Collaborator

Summary

Surfaces seed-health freshness in the Strategic Risk panel by ingesting /api/health cadence metadata into the existing dataFreshness tracker. Analysts get a compact data freshness signal without blocking the main risk refresh path.

cc @koala73

Refs #3296

Type of change

  • New feature
  • Refactor / code cleanup

Affected areas

  • API endpoints (/api/*)
  • Other: Strategic Risk panel freshness UI and health ingestion

Root cause

The frontend freshness tracker was mostly session-local. The backend already knows seed age, cadence, and health state, but that signal was not visible in the Strategic Risk panel, so stale or missing seeded data could be hard to distinguish from genuinely quiet conditions.

Changes

  • Add refreshDataFreshnessFromHealth() to fetch /api/health, map health checks to frontend data sources, and record cadence-aware seed health.
  • Extend dataFreshness with seed-health metadata, per-source maxStaleMin, and error/no-data handling for health statuses.
  • Surface a compact Data Freshness list in StrategicRiskPanel with source state and last-update timing.
  • Run health freshness polling as a non-blocking background task so risk rendering is not serialized behind /api/health.
  • Localize the active/total source badge detail.
  • Add drift and severity tests for health-check mapping, shared-source worst-status selection, and Redis outage status handling.

Validation

Risk

Low to moderate. The health fetch is additive and non-blocking; if it fails, existing session-local freshness remains in use. The mapping guard test should catch future drift between frontend source IDs and /api/health check names.

@vercel

vercel Bot commented Apr 28, 2026

Copy link
Copy Markdown

@lspassos1 is attempting to deploy a commit to the World Monitor Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps

greptile-apps Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR surfaces backend seed-health metadata from /api/health in the Strategic Risk panel by adding a new health-freshness service, extending dataFreshness.recordSeedHealth() with cadence-aware thresholds, and rendering a compact per-source freshness list. The health fetch runs as a non-blocking background task so the main risk refresh path is unaffected, and a drift-detection test guards against the frontend source map falling out of sync with the backend check registry.

Confidence Score: 4/5

Safe to merge; only P2 findings present, both isolated to StrategicRiskPanel.refreshHealthFreshness().

All findings are P2. The dead .catch() is harmless dead code, and the optimistic throttle timestamp is a minor resilience gap on a non-critical background path. Core logic in health-freshness.ts and data-freshness.ts is correct.

src/components/StrategicRiskPanel.ts — refreshHealthFreshness throttle stamping and dead catch handler.

Important Files Changed

Filename Overview
src/components/StrategicRiskPanel.ts Adds non-blocking health freshness polling and a compact freshness surface to the risk panel; two minor issues: dead .catch() handler and optimistic throttle-timestamp stamping before the fetch completes.
src/services/health-freshness.ts New service that fetches /api/health, maps check names to frontend source IDs, applies "worst status wins" per shared source, and forwards updates to dataFreshness.recordSeedHealth(). Logic is well-structured with correct deduplication and staleness-ratio tiebreaking.
src/services/data-freshness.ts Extends DataSourceState with maxStaleMin/healthStatus, adds recordSeedHealth() that correctly derives status via calculateStatus (which already handles lastError → 'error' priority), and refactors threshold computation to use per-source cadence.
src/locales/en.json Adds two i18n keys (dataFreshness and sourcesDetail) required by the new freshness surface and badge detail; changes are minimal and correct.
tests/data-freshness-health.test.mts Four well-targeted test cases covering cadence hydration, drift detection against api/health.js, worst-status selection for shared sources, and Redis outage severity ranking; assertions are correct against the implementation logic.

Sequence Diagram

sequenceDiagram
    participant Panel as StrategicRiskPanel
    participant HF as health-freshness.ts
    participant API as /api/health
    participant DF as dataFreshness (singleton)
    participant UI as render()

    Panel->>Panel: refresh()
    Panel-->>HF: void refreshHealthFreshness() [non-blocking]
    Panel->>DF: getSummary()
    Panel->>UI: render() → renderFreshnessSurface()
    UI->>DF: getAllSources()
    DF-->>UI: sources (status recalculated)

    Note over HF,API: runs concurrently
    HF->>API: GET /api/health
    API-->>HF: { checkedAt, checks: { ... } }
    HF->>HF: map check names → DataSourceId[]
    HF->>HF: deduplicate (worst-status wins per source)
    HF->>DF: recordSeedHealth(updates)
    DF->>DF: calculateStatus() with maxStaleMin cadence
    DF-->>Panel: notifyListeners() → triggers next refresh
Loading

Reviews (1): Last reviewed commit: "fix(freshness): decouple health polling ..." | Re-trigger Greptile

Comment thread src/components/StrategicRiskPanel.ts Outdated
Comment on lines +85 to +87

public async refresh(): Promise<boolean> {
void this.refreshHealthFreshness().catch((error) => {

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.

P2 Dead .catch() handler — never fires

refreshHealthFreshness() has its own try/catch that swallows every exception without rethrowing, so the promise it returns can never reject. The .catch() registered here is unreachable dead code and will mislead future readers into thinking errors can surface from this call.

Suggested change
public async refresh(): Promise<boolean> {
void this.refreshHealthFreshness().catch((error) => {
void this.refreshHealthFreshness();

Comment thread src/components/StrategicRiskPanel.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 44d6ff7399

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/services/health-freshness.ts Outdated
Comment thread src/services/data-freshness.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 88b32fc05f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/services/data-freshness.ts Outdated
Comment thread src/components/StrategicRiskPanel.ts
@lspassos1

Copy link
Copy Markdown
Collaborator Author

Follow-up pushed in 88b32fc0 for the freshness outage review.

Changes:

  • /api/health top-level REDIS_DOWN or REDIS_PARTIAL without per-check details now marks every mapped source unhealthy instead of applying zero updates.
  • COVERAGE_PARTIAL no longer renders as fresh; recent partial coverage is treated as stale.
  • StrategicRiskPanel now updates the health refresh throttle only after a successful fetch, so failed health calls do not block retries for 60s.
  • Removed the redundant outer background .catch() around the health freshness refresh.
  • Added regression tests for top-level Redis outage payloads and partial coverage.

Validation:

  • npx tsx --test tests/data-freshness-health.test.mts
  • npm run typecheck
  • npx biome lint src/services/health-freshness.ts src/services/data-freshness.ts src/components/StrategicRiskPanel.ts tests/data-freshness-health.test.mts
  • git diff --check

@vercel

vercel Bot commented May 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
worldmonitor Ready Ready Preview, Comment May 26, 2026 6:50pm

Request Review

@koala73 koala73 merged commit 69d2b2f into koala73:main May 26, 2026
11 checks passed
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.

2 participants