Files
worldmonitor/todos/161-pending-p2-mapcontainer-supply-chain-panel-bidirectional-coupling.md
Elie Habib 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
2026-04-10 21:31:26 +04:00

3.4 KiB

status, priority, issue_id, tags, dependencies
status priority issue_id tags dependencies
pending p2 161
code-review
architecture
supply-chain
coupling
155

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.tssetSupplyChainPanel() and deactivateScenario() calling this.supplyChainPanel?.hideScenarioSummary()
  • File: src/components/SupplyChainPanel.tssetOnDismissScenario / setOnScenarioActivate callbacks point to MapContainer
  • 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

Instead of MapContainer calling panel.showScenarioSummary() and panel.hideScenarioSummary():

  • Have SupplyChainPanel observe scenario state changes through its existing onScenarioActivate and onDismissScenario callbacks
  • The panel already receives (id, result) in onScenarioActivate — it can call showScenarioSummary on itself
  • MapContainer.activateScenario fires onScenarioActivate → panel handles its own UI update
  • MapContainer.deactivateScenario fires onDismissScenario → panel handles its own dismiss
  • Remove setSupplyChainPanel from MapContainer entirely

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)

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

  • MapContainer has no direct reference to SupplyChainPanel
  • setSupplyChainPanel() removed from MapContainer
  • Panel banner updates triggered via existing onScenarioActivate / onDismissScenario callbacks
  • npm run typecheck passes

Work Log

  • 2026-04-10: Identified by architecture-strategist during PR #2910 review

Resources

  • PR: #2910
  • Related: todo #155 (callbacks not wired — fix first)