mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
60e727679c36aef4e95d1ec7fc2f61816709aab8
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
60e727679c |
feat(supply-chain): Sprint E — scenario visual completion + service parity (#2910)
* feat(supply-chain): Sprint E — scenario visual completion + service parity - E1: fetchSectorDependency exported from supply-chain service index - E2: PRO gate + all-renderer dispatch in MapContainer.activateScenario - E3: scenario summary banner in SupplyChainPanel (dismiss wired) - E4: "Simulate Closure" trigger button in expanded chokepoint cards - E5: affectedIso2s heat layer in DeckGLMap (GeoJsonLayer, red tint) - E6: SVG renderer setScenarioState (best-effort iso2 fill) - E7: Globe renderer scenario polygons via flushPolygons - E8: integration tests for scenario run/status endpoints * fix(supply-chain): address PR #2910 review findings (P1 + P2 + P3) - Wire setOnScenarioActivate + setOnDismissScenario in panel-layout.ts (todo #155) - Rename shadow variable t→tmpl in SCENARIO_TEMPLATES.find (todo #152) - Add statusResp.ok guard in scenario polling loop (todo #153) - Replace status.result! non-null assertion with shape guard (todo #154) - Add AbortController to prevent concurrent polling races (todo #162) - Add polygonStrokeColor scenario branch (transparent) in GlobeMap (todo #156) - Re-export SCENARIO_TEMPLATES via src/config/scenario-templates.ts (todo #157) - Cache affectedIso2Set in DeckGLMap.setScenarioState (todo #158) - Add scenario paths to PREMIUM_RPC_PATHS for auth injection (todo #160) - Show template name in scenario banner instead of raw ID (todo #163) * fix(supply-chain): address PR #2910 review findings - Add auth headers to scenario fetch calls in SupplyChainPanel - Reset button state on scenario dismiss - Poll status immediately on first iteration (no 2s delay) - Pre-compute scenario polygons in GlobeMap.setScenarioState - Use scenarioId for DeckGL updateTriggers precision * fix(supply-chain): wire panel instance to MapContainer, stop button click propagation - Call setSupplyChainPanel() in panel-layout.ts so scenario banner renders - Add stopPropagation() to Simulate Closure button to prevent card collapse |
||
|
|
12ea629a63 |
feat(supply-chain): Sprint C — scenario engine (templates, job API, Railway worker, map activation) (#2890)
* feat(supply-chain): Sprint C — scenario engine templates, job API, Railway worker, map activation
Adds the async scenario engine for supply chain disruption modelling:
- src/config/scenario-templates.ts: 6 pre-built ScenarioTemplate definitions
(Taiwan Strait closure, Suez+BaB simultaneous, Panama drought, Hormuz blockade,
Russia Baltic grain suspension, US electronics tariff shock) with costShockMultiplier
and optional HS2 sector scoping. Exports ScenarioVisualState + ScenarioResult
types (no UI imports, avoids MapContainer <-> DeckGLMap circular dep).
- api/scenario/v1/run.ts: PRO-gated edge function — validates scenarioId against
template registry and iso2 format, enqueues job to Redis scenario-queue:pending
via RPUSH. Returns {jobId, status:'pending'} HTTP 202.
- api/scenario/v1/status.ts: Edge function — validates jobId via regex to prevent
Redis key injection, reads scenario-result:{jobId}. Returns {status:'pending'}
when unprocessed, or full worker result when done.
- scripts/scenario-worker.mjs: Always-on Railway worker using BLMOVE LEFT RIGHT for
atomic FIFO dequeue+claim. Idempotency check before compute. Writes result with
24h TTL; writes {status:'failed'} on error; always cleans processing list in finally.
- DeckGLMap.ts: scenarioState field + setScenarioState(). createTradeRoutesLayer()
overrides arc color to orange for segments whose route waypoints intersect scenario
disruptedChokepointIds. Null state restores normal colors.
- MapContainer.ts: activateScenario(id, result) and deactivateScenario() broadcast
ScenarioVisualState to DeckGLMap. Globe/SVG deferred to Sprint D (best-effort).
🤖 Generated with Claude Sonnet 4.6 via Claude Code (https://claude.com/claude-code) + Compound Engineering v2.49.0
Co-Authored-By: Claude Sonnet 4.6 (200K context) <noreply@anthropic.com>
* fix(supply-chain): move scenario-templates to server/ to satisfy arch boundary
api/ edge functions may not import from src/ app code. Move the authoritative
scenario-templates.ts to server/worldmonitor/supply-chain/v1/ and replace
src/config/scenario-templates.ts with a type-only re-export for src/ consumers.
* fix(supply-chain): guard scenario-worker runWorker() behind isMain check
Without the isMain guard, the pre-push hook picks up scenario-worker.mjs
as a seed test candidate (non-matching lines pass through sed unchanged)
and starts the long-running worker process, causing push failures.
* fix(pre-push): filter non-matching lines from seed test selector
The sed transform passes non-matching lines (e.g. scenario-worker.mjs)
through unchanged. Adding grep "^tests/" ensures only successfully
transformed test paths are passed to the test runner.
* fix(supply-chain): address PR #2890 review findings — worker data shapes + status PRO gate
Three bugs found in PR #2890 code review:
1. [High] scenario-worker.mjs read wrong cache shape for exposure data.
supply-chain:exposure:{iso2}:{hs2}:v1 caches GetCountryChokepointIndexResponse
({ iso2, hs2, exposures: [{chokepointId, exposureScore}], ... }), not a
chokepointId-keyed object. Worker now iterates data.exposures[], filters by
template.affectedChokepointIds, and ranks by exposureScore (importValue does
not exist on ChokepointExposureEntry). adjustedImpact = exposureScore x
(disruptionPct/100) x costShockMultiplier.
2. [Medium] api/scenario/v1/status.ts was not PRO-gated, allowing anyone with
a valid jobId to retrieve full premium scenario results. Added isCallerPremium()
check; returns HTTP 403 for non-PRO callers, matching run.ts behavior.
3. [Low] Worker parsed chokepoint status cache as Array but actual shape is
{ chokepoints: [], fetchedAt, upstreamUnavailable }. Fixed to access
cpData.chokepoints array.
* fix(scenario): per-country impactPct + O(1) route lookup in arc layer
- impactPct now reflects each country's relative share of the worst-hit
country (0-100) instead of the flat template.disruptionPct for all
- Pre-build routeId→waypoints Map in createTradeRoutesLayer() so
getColor() is O(1) per segment instead of O(n) per frame
* fix(scenario): rate limit, pipeline GETs, error sanitization, processing state, orphan drain
- Add per-user rate limit (10 jobs/min) + queue depth cap to run.ts
- Replace 594 sequential Redis GETs with single Upstash pipeline call
- Sanitize worker err.message to 'computation_error' in failed results
- Remove dead validateApiKey() calls (isCallerPremium covers this)
- Write processing state before computeScenario() starts
- Add SIGTERM handler + startup orphan drain to worker loop
- Validate dequeued job payload fields before use as Redis key fragments
- Fix maxImpact divide-by-zero with Math.max(..., 1)
- Hoist routeWaypoints Map to module level in DeckGLMap
- Add GET /api/scenario/v1/templates discovery endpoint
- Fix template sync comment to reference correct authoritative file
* docs(plan): mark Sprint C complete, record deferrals to Sprint D
- Sprint status table added: Sprints 0-2 merged, C ready to merge (#2890), A/B/D not started
- Sprint C checklist: 4 ACs checked off, panel UI + tariff-shock visual deferred
- Sprint D section updated to carry over Sprint C visual deferrals
- PR #2890 added to Related PRs
---------
Co-authored-by: Claude Sonnet 4.6 (200K context) <noreply@anthropic.com>
|