Skip to content

feat(deep-forecast): Phase 1 simulation package export contract#2204

Merged
koala73 merged 2 commits into
mainfrom
feat/simulation-package-export
Mar 24, 2026
Merged

feat(deep-forecast): Phase 1 simulation package export contract#2204
koala73 merged 2 commits into
mainfrom
feat/simulation-package-export

Conversation

@koala73

@koala73 koala73 commented Mar 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds buildSimulationPackageFromDeepSnapshot(snapshot, priorWorldState) to scripts/seed-forecasts.mjs — the bridge adapter from WorldMonitor's deep forecast pipeline to a MiroFish-compatible simulation package
  • Writes simulation-package.json beside deep-snapshot.json in R2 via fire-and-forget (zero latency impact on the seed critical path)
  • Phase 1 scope: maritime chokepoint + energy/logistics theaters only (Hormuz, Red Sea, Bab al-Mandab, Strait of Malacca, etc.)
  • All builders are fully deterministic — no LLM call, fully cacheable, schema-stable

What's in simulation-package.json

Top-level fields per the gap spec (docs/internal/wm-mirofish-gap.md):

  • schemaVersion: "v1" — explicit export contract version
  • selectedTheaters — up to 3 top maritime/energy candidates with routeFacilityKey, commodityKey, topBucketId, rankingScore
  • simulationRequirement — deterministic template paragraph per theater (route + commodity + horizon + reaction type)
  • structuralWorld — frozen WorldMonitor truth layer: touching stateUnits, worldSignals, marketState buckets, situationClusters
  • entities — 7 entity classes derived from actorRegistry, stateUnit.actors, evidence table, with fallback anchor set
  • eventSeedslive_news + observed_disruption seeds with relative timing (T+0h, T+12h±6h)
  • constraints — hard route/commodity constraints, soft market admissibility + known invalidators
  • evaluationTargets — deterministic per theater: escalation/containment/spillover paths + T+24h/T+48h/T+72h timing markers

Theater filter

A candidate qualifies for Phase 1 if:

  1. routeFacilityKey is a key in CHOKEPOINT_MARKET_REGIONS (the known maritime chokepoints already expanded in PR feat(deep-forecast): Phase 2+3 scoring recalibration + autoresearch prompt self-improvement #2178)
  2. topBucketId ∈ {energy, freight} OR commodityKey ∈ energy commodity set (crude_oil, lng, natural_gas, refined_products, petrochemicals)

Integration point

// In fast seed path — fire-and-forget, no await
const snapshotWrite = await writeDeepForecastSnapshot(snapshotPayload, { runId });
if (snapshotWrite?.storageConfig && candidates.length > 0) {
  writeSimulationPackage(snapshotPayload, { storageConfig: snapshotWrite.storageConfig })
    .catch((err) => console.warn(`[SimulationPackage] Write failed: ${err.message}`));
}

Tests

17 new tests in tests/forecast-trace-export.test.mjs ('simulation package export' suite):

  • Theater filter: accept maritime+energy, reject non-chokepoint, reject non-energy bucket
  • Null return when no qualifying candidates
  • All required top-level fields present + schema version
  • selectedTheaters shape (all fields, cap at 3)
  • simulationRequirement deterministic content (route name, commodity, horizon)
  • eventSeeds with live_news type and T+0h timing
  • Constraints: hard route, hard commodity, soft admissibility
  • Evaluation targets: 3 path types (escalation/containment/spillover), 3 timing markers
  • Entity extraction from actorRegistry
  • buildSimulationPackageKey format (/simulation-package.json suffix)

Post-Deploy Monitoring & Validation

  • What to monitor: R2 bucket for */simulation-package.json keys appearing beside deep snapshot writes on Hormuz/Red Sea eligible runs
  • Validation: node -e "import('./scripts/seed-forecasts.mjs').then(m => console.log(Object.keys(m)))" — confirm buildSimulationPackageFromDeepSnapshot, writeSimulationPackage, isMaritimeChokeEnergyCandidate are exported
  • Expected healthy behavior: On a Hormuz/Red Sea run, R2 should have a simulation-package.json with selectedTheaters.length >= 1, schemaVersion: "v1", and constraints with at least one hard: true entry
  • Failure signal: Console warn [SimulationPackage] Write failed: — non-critical, fire-and-forget write does not affect the main seed path
  • Validation window: Next Hormuz/Red Sea deep forecast run after deploy

Context

This is Phase 1 of the WorldMonitor→MiroFish bridge defined in docs/internal/wm-mirofish-gap.md. The standalone package is consumable by MiroFish, any later simulator, or a structured LLM scenario-analysis workflow without human reformatting.

Phases 2 (theater-limited simulation) and 3 (outcome re-ingestion) are separate follow-up PRs.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vercel

vercel Bot commented Mar 24, 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 Mar 24, 2026 4:38pm

Request Review

koala73 added a commit that referenced this pull request Mar 24, 2026
P1 fixes:
- inferEntityClassFromName: use word-boundary regex to prevent "force"
  substring false positives (e.g. "workforce", "Salesforce")
- buildSimulationPackageEntities: key Map entries by candidateStateId
  instead of dominantRegion to prevent collision across theaters
  sharing the same region
- writeSimulationPackage call site: pass priorWorldState so
  actorRegistry is available to buildSimulationPackageFromDeepSnapshot

P2 fixes:
- buildSimulationRequirementText: apply sanitizeForPrompt to
  theater.label, stateKind, topChannel, and critTypes before
  string interpolation (stored prompt injection risk)
- buildSimulationPackageEventSeeds: apply sanitizeForPrompt to
  entry.text before .slice(0, 200)
- isMaritimeChokeEnergyCandidate: replace new Set() allocation
  per call with Array.includes for 2-element arrays
- buildSimulationPackageEntities: convert allForecastIds to Set
  before actor registry loop (O(n²) → O(n))
- buildSimulationPackageEvaluationTargets: add missing candidate
  guard with console.warn when candidate is undefined for theater
- selectedTheaters map: add label fallback to dominantRegion /
  'unknown theater' to prevent "undefined" in simulationRequirement

Tests: 6 new unit tests covering the word-boundary fix, entity key
collision, injection stripping, and undefined label guard
koala73 and others added 2 commits March 24, 2026 20:34
Add buildSimulationPackageFromDeepSnapshot and writeSimulationPackage to
produce simulation-package.json alongside deep-snapshot.json on every eligible
fast run, completing Phase 1 of the WorldMonitor → MiroFish bridge defined in
docs/internal/wm-mirofish-gap.md.

Phase 1 scope: maritime chokepoint + energy/logistics theaters only.
A candidate qualifies if its routeFacilityKey is a known chokepoint in
CHOKEPOINT_MARKET_REGIONS and the top bucket is energy or freight, or the
commodityKey is an energy commodity.

Package shape (schemaVersion: v1):
- selectedTheaters: top 1–3 qualifying candidates with theater ID, route,
  commodity, bucket, channel, and rankingScore
- simulationRequirement: deterministic template per theater (no LLM, fully
  cacheable), built from label, stateKind, route, commodity, channel, and
  criticalSignalTypes
- structuralWorld: filtered stateUnits, worldSignals, transmission edges,
  market buckets, situationClusters, situationFamilies touching the theater
- entities: extracted from actorRegistry (forecastId overlap), stateUnit
  actors, and evidence table actor entries; classified into 7 entity classes
  (state_actor, military_or_security_actor, regulator_or_central_bank,
  exporter_or_importer, logistics_operator, market_participant,
  media_or_public_bloc); falls back to anchor set if extraction finds nothing
- eventSeeds: headline evidence → live_news, disruption-keyword signal
  evidence → observed_disruption; T+0h timing; relative timing format
- constraints: route_chokepoint_status (hard if criticalSignalLift ≥ 0.25),
  commodity_exposure (always hard), market_admissibility (soft, channel
  routing), known_invalidators (soft, when contradictionScore ≥ 0.10)
- evaluationTargets: deterministic escalation/containment/spillover path
  questions + T+24h/T+48h/T+72h timing markers per theater

Also adds 6 missing chokepoints to CHOKEPOINT_MARKET_REGIONS:
Baltic Sea, Danish Straits, Strait of Gibraltar, Panama Canal,
Lombok Strait, Cape of Good Hope.

writeSimulationPackage fires-and-forgets after writeDeepForecastSnapshot
so it does not add latency to the critical seed path.

17 new unit tests covering: theater filter, package shape, simulationRequirement
content, eventSeeds, constraints (hard/soft), evaluationTargets structure,
entity extraction, key format, and 3-theater cap.

🤖 Generated with Claude Sonnet 4.6 via Claude Code (https://claude.ai/claude-code) + Compound Engineering v2.49.0

Co-Authored-By: Claude Sonnet 4.6 (200K context) <[email protected]>
P1 fixes:
- inferEntityClassFromName: use word-boundary regex to prevent "force"
  substring false positives (e.g. "workforce", "Salesforce")
- buildSimulationPackageEntities: key Map entries by candidateStateId
  instead of dominantRegion to prevent collision across theaters
  sharing the same region
- writeSimulationPackage call site: pass priorWorldState so
  actorRegistry is available to buildSimulationPackageFromDeepSnapshot

P2 fixes:
- buildSimulationRequirementText: apply sanitizeForPrompt to
  theater.label, stateKind, topChannel, and critTypes before
  string interpolation (stored prompt injection risk)
- buildSimulationPackageEventSeeds: apply sanitizeForPrompt to
  entry.text before .slice(0, 200)
- isMaritimeChokeEnergyCandidate: replace new Set() allocation
  per call with Array.includes for 2-element arrays
- buildSimulationPackageEntities: convert allForecastIds to Set
  before actor registry loop (O(n²) → O(n))
- buildSimulationPackageEvaluationTargets: add missing candidate
  guard with console.warn when candidate is undefined for theater
- selectedTheaters map: add label fallback to dominantRegion /
  'unknown theater' to prevent "undefined" in simulationRequirement

Tests: 6 new unit tests covering the word-boundary fix, entity key
collision, injection stripping, and undefined label guard
@koala73
koala73 force-pushed the feat/simulation-package-export branch from b055bc9 to eef5038 Compare March 24, 2026 16:35
@koala73
koala73 merged commit b7e6333 into main Mar 24, 2026
7 checks passed
@koala73
koala73 deleted the feat/simulation-package-export branch March 24, 2026 16:40
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.

1 participant