Files
worldmonitor/todos/016-pending-p3-simulation-package-simplifications.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

3.1 KiB
Raw Permalink Blame History

status, priority, issue_id, tags
status priority issue_id tags
pending p3 016
code-review
deep-forecast
simulation-package
quality

Simplification opportunities in simulation package builders — duplicated patterns + YAGNI items

Problem Statement

Several mechanical duplications and one YAGNI issue in the new simulation package code (~30 lines of avoidable noise in a 405-line addition).

Findings

1. candidates.find() duplicated 3x across builder functions buildSimulationPackageEventSeeds, buildSimulationPackageConstraints, buildSimulationPackageEvaluationTargets each do candidates.find((c) => c.candidateStateId === theater.candidateStateId) per theater loop. Pre-building a Map once in the orchestrator and passing it down eliminates 6 find() calls.

2. entry.text.slice(0, 200) repeated 3x in buildSimulationPackageEventSeeds Extract const MAX_SEED_SUMMARY = 200.

3. name.toLowerCase().replace(/\W+/g, '_') repeated 4x for slugifying entity IDs Extract const slugify = (s) => s.toLowerCase().replace(/\W+/g, '_').

4. Fallback entity block: 3 explicit addEntity(...) calls per theater with identical shape A data-driven FALLBACK_ANCHOR_DEFS array reduces the block from ~30 lines to ~10 and makes adding a fourth anchor class trivial.

5. gateDetails in debug payload hardcodes threshold values instead of reading from getImpactValidationFloors()

gateDetails: { secondOrderMappedFloor: 0.58, ... }

These are already the live values in getImpactValidationFloors('second_order'). When thresholds change again, gateDetails silently shows stale values. Read from the function instead.

6. Actor extraction regex too narrow /^(.+?)\s+remain the lead actors/i — misses "are the primary actors", "continue as the key actors". When this misses, there is no log. Add: console.debug('[SimulationPackage] evidence actor regex miss', entry.text.slice(0, 80)) so the fallback rate is observable.

Proposed Solutions

// In buildSimulationPackageFromDeepSnapshot, before calling builders:
const candidateById = new Map(top.map((c) => [c.candidateStateId, c]));

// Extract helpers near section header:
const slugify = (s) => s.toLowerCase().replace(/\W+/g, '_');
const MAX_SEED_SUMMARY = 200;

// gateDetails reads live values:
const secondOrderFloors = getImpactValidationFloors('second_order');
gateDetails: {
  secondOrderMappedFloor: secondOrderFloors.mapped,
  secondOrderMultiplier: secondOrderFloors.multiplier,
  pathScoreThreshold: 0.50,
  acceptanceThreshold: 0.60,
},

Effort: Small | Risk: Low

Acceptance Criteria

  • slugify and MAX_SEED_SUMMARY extracted as file-local constants
  • candidateById Map built once in buildSimulationPackageFromDeepSnapshot, passed to builders
  • gateDetails reads from getImpactValidationFloors() rather than hardcoding values
  • All existing simulation package tests still pass

Technical Details

  • File: scripts/seed-forecasts.mjs — simulation package section (~line 1172012100)

Work Log

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