diff --git a/CHANGELOG.md b/CHANGELOG.md index 7799d5c5..8d43a4bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ coverage without changing migrations or enabling automatic refresh. - Fixed map theme ranking so a newer official observation always wins over an older snapshot with a marginally larger feature count. +- Restored the active map theme from the selected dataset when returning to the + Map workspace, keeping viewport queries, legends and zoom guidance aligned. ## Sprint 222 Official source edition probes (2026-07-16) diff --git a/backend/tests/test_sprint223_governed_grb_refresh.py b/backend/tests/test_sprint223_governed_grb_refresh.py index a0947bc5..1dc8134c 100644 --- a/backend/tests/test_sprint223_governed_grb_refresh.py +++ b/backend/tests/test_sprint223_governed_grb_refresh.py @@ -258,3 +258,12 @@ def test_map_theme_ranking_prefers_newer_observation_over_feature_count() -> Non assert observed_sort < feature_tiebreaker assert "new Date(right.observed_at ?? 0).getTime()" in workspace assert "if (observedAtDifference !== 0) return observedAtDifference" in workspace + + +def test_map_workspace_restores_theme_from_selected_dataset() -> None: + root = Path(__file__).resolve().parents[2] + workspace = (root / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8") + assert "function themeIdForDataset(" in workspace + assert "useState(() =>" in workspace + assert "return themeIdForDataset(selectedDataset) ?? 'buildings'" in workspace + assert "const matchingThemeId = themeIdForDataset(selectedMapDataset)" in workspace diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md index a313e313..4c6e7229 100644 --- a/docs/CODEX_EXECUTION_LOG.md +++ b/docs/CODEX_EXECUTION_LOG.md @@ -9365,7 +9365,7 @@ Boundaries: Validation so far: - Backend compile and frontend typecheck passed. - Source-catalog plus governed-refresh focused suite passed: 20 tests. -- Full `scripts/run_readiness_check.sh` passed: 780 backend tests, 110 +- Full `scripts/run_readiness_check.sh` passed: 781 backend tests, 110 documented route contracts, one Alembic head, frontend typecheck/build and all packaged smoke checks. - Live Tower staging completed all 112 municipality/theme partitions for @@ -9379,6 +9379,10 @@ Validation so far: - Live browser validation exposed and fixed additive theme ranking where two extra old water features could outweigh a newer observation date. Ranking is now priority, observation date, import date, then feature-count tie-breaker. +- Post-deploy browser validation also exposed a stale map-theme remount state: + returning from Status to Map could retain the Water legend while the viewport + query and zoom guidance reverted to Buildings. Map state now initializes from + the selected persisted dataset so all four signals remain aligned. Next: - Run the full release gate, deploy to Tower, execute a live read-only plan and diff --git a/frontend/src/components/map/MapWorkspace.tsx b/frontend/src/components/map/MapWorkspace.tsx index 51cabe5a..364a3c62 100644 --- a/frontend/src/components/map/MapWorkspace.tsx +++ b/frontend/src/components/map/MapWorkspace.tsx @@ -308,6 +308,12 @@ function pickThemeDataset( return candidates[0] ?? null } +function themeIdForDataset(dataset: DatasetCreateResponse | null): DataThemeId | null { + return dataset + ? DATA_THEMES.find((theme) => datasetMatchesTheme(dataset, theme))?.id ?? null + : null +} + function temporalSeriesLabel(items: DatasetCreateResponse[]): string { const configuredLabel = items.find((item) => typeof item.source_metadata?.['temporal_series_label'] === 'string') ?.source_metadata?.['temporal_series_label'] @@ -774,7 +780,10 @@ export function MapWorkspace({ onClearQualityEvidence, }: MapWorkspaceProps): JSX.Element { const [advancedMode, setAdvancedMode] = useState(false) - const [activeThemeId, setActiveThemeId] = useState('buildings') + const [activeThemeId, setActiveThemeId] = useState(() => { + const selectedDataset = availableMapDatasets.find((dataset) => dataset.id === selectedMapDatasetId) ?? null + return themeIdForDataset(selectedDataset) ?? 'buildings' + }) const { themeInsights, themeInsightsLoading: themeResultsLoading, @@ -1093,9 +1102,9 @@ export function MapWorkspace({ if (!selectedMapDataset) { return } - const matchingTheme = DATA_THEMES.find((theme) => datasetMatchesTheme(selectedMapDataset, theme)) - if (matchingTheme) { - setActiveThemeId(matchingTheme.id) + const matchingThemeId = themeIdForDataset(selectedMapDataset) + if (matchingThemeId) { + setActiveThemeId(matchingThemeId) } }, [selectedMapDataset])