Files
worldmonitor/todos/014-pending-p2-simulation-package-perf-set-intersectany.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.7 KiB
Raw Permalink Blame History

status, priority, issue_id, tags
status priority issue_id tags
pending p2 014
code-review
deep-forecast
simulation-package
performance

Two performance issues in simulation package builders: new Set in filter predicate + intersectAny O(n²)

Problem Statement

Two patterns in the new simulation package code introduce unnecessary allocations and O(n×m) comparisons that will grow with the actor registry size.

Findings

CRITICAL-1: intersectAny uses Array.includes — O(n×m) in the actor registry loop

buildSimulationPackageEntities builds allForecastIds as a flat array via flatMap, then passes it to intersectAny which calls right.includes(item) for each item in actor.forecastIds. With a 200-actor registry and 8 forecast IDs each, this is ~38,400 comparisons per call.

const allForecastIds = candidates.flatMap((c) => c.sourceSituationIds || []);
for (const actor of (actorRegistry || [])) {
  if (!intersectAny(actor.forecastIds || [], allForecastIds)) continue;

Fix: convert allForecastIds to a Set once before the loop.

CRITICAL-2: new Set(candidate.marketBucketIds || []) inside filter predicate

isMaritimeChokeEnergyCandidate constructs a new Set from marketBucketIds (typically 2-3 elements) on every candidate, then calls .has() twice. At 50 candidates this is 50 Set allocations for a 2-element array check. Array.includes is faster for arrays of this size.

const buckets = new Set(candidate.marketBucketIds || []);
return buckets.has('energy') || buckets.has('freight') || ...

Proposed Solutions

// Fix 1: Set-based forecast ID lookup
const allForecastIdSet = new Set(candidates.flatMap((c) => c.sourceSituationIds || []));
for (const actor of (actorRegistry || [])) {
  if (!(actor.forecastIds || []).some((id) => allForecastIdSet.has(id))) continue;

// Fix 2: Array.includes instead of Set for small arrays
const bucketArr = candidate.marketBucketIds || [];
return bucketArr.includes('energy') || bucketArr.includes('freight') || topBucket === 'energy' || topBucket === 'freight'
  || SIMULATION_ENERGY_COMMODITY_KEYS.has(candidate.commodityKey || '');

Effort: Tiny | Risk: Low

Acceptance Criteria

  • allForecastIds is a Set before the actor registry loop in buildSimulationPackageEntities
  • isMaritimeChokeEnergyCandidate uses Array.includes or Array.some instead of new Set for marketBucketIds check
  • All existing simulation package tests still pass

Technical Details

  • File: scripts/seed-forecasts.mjsisMaritimeChokeEnergyCandidate, buildSimulationPackageEntities

Work Log

  • 2026-03-24: Found by compound-engineering:review:performance-oracle in PR #2204 review