* 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
3.4 KiB
status, priority, issue_id, tags, dependencies
| status | priority | issue_id | tags | dependencies | |||||
|---|---|---|---|---|---|---|---|---|---|
| pending | p2 | 161 |
|
|
MapContainer ↔ SupplyChainPanel Bidirectional Coupling via setSupplyChainPanel
Problem Statement
MapContainer has a setSupplyChainPanel(panel) setter that stores a direct reference to SupplyChainPanel. This creates a bidirectional dependency: SupplyChainPanel calls into MapContainer via callbacks (correct direction), and MapContainer calls back into SupplyChainPanel via showScenarioSummary / hideScenarioSummary (reverse direction). This circular architecture makes both components harder to test and violates the unidirectional data flow established by every other panel in the system.
Findings
- File:
src/components/MapContainer.ts—setSupplyChainPanel()anddeactivateScenario()callingthis.supplyChainPanel?.hideScenarioSummary() - File:
src/components/SupplyChainPanel.ts—setOnDismissScenario/setOnScenarioActivatecallbacks point toMapContainer - All other panels (MonitorPanel, CountryDeepDivePanel, etc.) use one-way callbacks: panel → map, never map → panel
- The bidirectional link was noted in the Sprint E plan as deferred to this issue
- Identified by architecture-strategist during PR #2910 review (see todo #155 for the more urgent wiring issue)
Proposed Solutions
Option A: Remove showScenarioSummary/hideScenarioSummary from MapContainer dispatch (Recommended)
Instead of MapContainer calling panel.showScenarioSummary() and panel.hideScenarioSummary():
- Have
SupplyChainPanelobserve scenario state changes through its existingonScenarioActivateandonDismissScenariocallbacks - The panel already receives
(id, result)inonScenarioActivate— it can callshowScenarioSummaryon itself MapContainer.activateScenariofiresonScenarioActivate→ panel handles its own UI updateMapContainer.deactivateScenariofiresonDismissScenario→ panel handles its own dismiss- Remove
setSupplyChainPanelfromMapContainerentirely
Pros: Breaks the circular reference, consistent with all other panels Cons: Requires refactoring how the panel receives activation events (it already does via callbacks) Effort: Medium | Risk: Low
Option B: Keep setSupplyChainPanel but document the coupling explicitly
Add a JSDoc comment acknowledging the bidirectional dependency and track via this todo. Pros: No refactor needed now Cons: Coupling persists indefinitely, harder to unit-test Effort: Trivial | Risk: None (deferred tech debt)
Recommended Action
Apply Option A in a follow-up PR after P1 issues (#155) are fixed. The coupling is architectural debt but not a blocking bug.
Technical Details
- Affected files:
src/components/MapContainer.ts,src/components/SupplyChainPanel.ts - Dependency: Fix todo #155 first (wiring), then restructure the callback flow here
Acceptance Criteria
MapContainerhas no direct reference toSupplyChainPanelsetSupplyChainPanel()removed fromMapContainer- Panel banner updates triggered via existing
onScenarioActivate/onDismissScenariocallbacks npm run typecheckpasses
Work Log
- 2026-04-10: Identified by architecture-strategist during PR #2910 review
Resources
- PR: #2910
- Related: todo #155 (callbacks not wired — fix first)