Files
worldmonitor/todos/011-pending-p1-entity-key-collision-same-domregion.md
Elie Habib 092efd4fe9 fix(panels): always fire background RPC refresh after bootstrap render (#2208)
* fix(panels): always fire background RPC refresh after bootstrap render

Bootstrap hydration (getHydratedData) is one-shot — once rendered from
it, panels never refresh and can show stale or partial data indefinitely.

Affected panels: MacroSignals, ETFFlows, Stablecoins, FuelPrices,
GulfEconomies, GroceryBasket, BigMac.

Pattern: render from bootstrap immediately for fast first paint, then
fire a background RPC call that silently updates the panel with live
data. Errors during background refresh are suppressed when bootstrap
data is already visible (no error flash over valid data).

* fix(panels): guard background RPC refresh against empty response overwriting bootstrap

Empty RPC responses (200 + empty array) no longer overwrite valid bootstrap
data with error/unavailable state across all 7 affected panels:

- ETFFlowsPanel, StablecoinPanel: wrap this.data assignment in
  `if (fresh.xxx?.length || !this.data)` guard
- FuelPricesPanel, GulfEconomiesPanel, GroceryBasketPanel, BigMacPanel:
  add `!data.xxx?.length` check in background .then() before calling render
- MacroSignalsPanel: return false early when error suppressed to skip
  redundant renderPanel() call

* fix(hormuz): fix noUncheckedIndexedAccess TypeScript errors

* fix(todos): add blank lines around headings (markdownlint MD022)

* fix(hormuz): add missing hormuz-tracker service + fix implicit any in HormuzPanel

* revert: remove HormuzPanel.ts from this branch (belongs in PR #2210)
2026-03-24 20:23:40 +04:00

2.6 KiB

status, priority, issue_id, tags
status priority issue_id tags
pending p1 011
code-review
deep-forecast
simulation-package
correctness

Entity key collision: same dominantRegion across multiple candidates silently drops entities + wrong relevanceToTheater

Problem Statement

buildSimulationPackageEntities uses su:${actorName}:${candidate.dominantRegion} and ev:${name}:${candidate.dominantRegion} as Map dedup keys. When two selected theater candidates share the same dominantRegion (e.g., Bab el-Mandeb and Suez Canal both map to "Red Sea"), an actor appearing in both candidates (e.g., "US Navy Fifth Fleet") produces identical keys. The addEntity guard silently drops the second entry, and the kept entity has relevanceToTheater pointing to whichever candidate was processed first — not the one it is most relevant to.

Findings

  • scripts/seed-forecasts.mjsbuildSimulationPackageEntities, su: and ev: key construction:
    const key = `su:${actorName}:${candidate.dominantRegion}`;
    // and
    const key = `ev:${name}:${candidate.dominantRegion}`;
    
  • Red Sea / Bab el-Mandeb / Suez Canal all share dominantRegion: 'Red Sea' in CHOKEPOINT_MARKET_REGIONS
  • The dropped entity causes incorrect relevanceToTheater assignment with no log
  • This is a data correctness issue in the exported schema — downstream simulators/LLMs get wrong theater attribution

Proposed Solutions

const key = `su:${actorName}:${candidate.candidateStateId}`;
// and
const key = `ev:${name}:${candidate.candidateStateId}`;

Effort: Tiny | Risk: Low — candidateStateId is always unique per candidate

Option B: Use actor name only as dedup key, merge relevanceToTheater as array

Allow the same actor to appear once with relevanceToTheater: ['theater-1', 'theater-2']. This is semantically richer for Phase 2 but changes the schema contract. Effort: Small | Risk: Medium (schema change)

Acceptance Criteria

  • Two candidates with same dominantRegion and overlapping actors produce separate entities per candidate in the output
  • Each entity's relevanceToTheater correctly references its source candidate
  • [...seen.values()].slice(0, 20) cap still applies
  • Test: two theater candidates sharing dominantRegion: 'Red Sea', same actor in stateSummary.actors — assert both entities present with correct relevanceToTheater

Technical Details

  • File: scripts/seed-forecasts.mjsbuildSimulationPackageEntities

Work Log

  • 2026-03-24: Found by compound-engineering:review:kieran-typescript-reviewer in PR #2204 review