* feat(frameworks): add settings section and import modal - Add Analysis Frameworks group to preferences-content.ts between Intelligence and Media sections - Per-panel active framework display (read-only, 4 panels) - Skill library list with built-in badge, Rename and Delete actions for imported frameworks - Import modal with two tabs: From agentskills.io (fetch + preview) and Paste JSON - All error cases handled inline: network, domain validation, missing instructions, invalid JSON, duplicate name, instructions too long, rate limit - Add api/skills/fetch-agentskills.ts edge function (proxy to agentskills.io) - Add analysis-framework-store.ts (loadFrameworkLibrary, saveImportedFramework, deleteImportedFramework, renameImportedFramework, getActiveFrameworkForPanel) - Add fw-* CSS classes to main.css matching dark panel aesthetic * feat(panels): wire analytical framework store into InsightsPanel, CountryDeepDive, DailyMarketBrief, DeductionPanel - InsightsPanel: append active framework to geoContext in updateFromClient(); subscribe in constructor, unsubscribe in destroy() - CountryIntelManager: pass framework as query param to fetchCountryIntelBrief(); subscribe to re-open brief on framework change; unsubscribe in destroy() - DataLoaderManager: add dailyBriefGeneration counter for stale-result guard; pass frameworkAppend to buildDailyMarketBrief(); subscribe to framework changes to force refresh; unsubscribe in destroy() - daily-market-brief service: add frameworkAppend? field to BuildDailyMarketBriefOptions; append to extendedContext before summarize call - DeductionPanel: append active framework to geoContext in handleSubmit() before RPC call * feat(frameworks): add FrameworkSelector UI component - Create FrameworkSelector component with premium/locked states - Premium: select dropdown with all framework options, change triggers setActiveFrameworkForPanel - Locked: disabled select + PRO badge, click calls showGatedCta(FREE_TIER) - InsightsPanel: adds asterisk note (client-generated analysis hint) - Wire into InsightsPanel, DailyMarketBriefPanel, DeductionPanel (via this.header) - Wire into CountryDeepDivePanel header right-side (no Panel base, panel=null) - Add framework-selector CSS to main.css * fix(frameworks): make new proto fields optional in generated types * fix(frameworks): extract firstMsg to satisfy strict null checks in tsconfig.api.json * fix(docs): add blank lines around lists/headings to pass markdownlint * fix(frameworks): add required proto string fields to call sites after make generate * chore(review): add code review todos 041-057 for PR #2380 7 review agents (TypeScript, Security, Architecture, Performance, Simplicity, Agent-Native, Learnings) identified 17 findings across 5 P1, 8 P2, and 4 P3 categories.
2.2 KiB
status, priority, issue_id, tags, dependencies
| status | priority | issue_id | tags | dependencies | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| complete | p1 | 037 |
|
|
Legend visibility text-matching breaks on all non-English locales
Problem Statement
updateLegendVisibility() matches legend item text content against hardcoded English strings
('Startup Hub', 'Tech HQ', 'HIGH', 'ELEVATED', 'MONITORING', etc.).
Legend items are built by createLegend() using t('components.deckgl.legend.*') (i18n).
On any non-English locale the translated text never matches the English strings — every legend
item is permanently hidden after the first layer toggle. Affects all 20 non-English locales.
Findings
Example: German locale
t('components.deckgl.legend.startupHub')→'Startup-Zentrum'layerToLabels.startupHubs→['Startup Hub']- Match fails → item hidden forever
Additional mismatch even in English:
conflictZones: ['HIGH', 'ELEVATED', 'MONITORING']—en.jsonvalues are'High Alert','Elevated','Monitoring'(mixed case, not all-caps). These never match.cyberThreats: ['APT']— no'APT'string in en.json legend keys.
Proposed Solutions
Option A: Use t() keys in the mapping
Replace hardcoded strings with t('components.deckgl.legend.*') calls in layerToLabels.
Pros: Simple change
Cons: Still couples updateLegendVisibility() to i18n key knowledge, brittle
Effort: Small | Risk: Low (but partial fix only)
Option B: data-legend-layer attributes (eliminates the problem entirely)
See todo 036 Option B. No text matching at all — uses MapLayers key directly.
Effort: Small-Medium | Risk: Low
Recommended Action
Option B (same as todo 036 — one fix addresses both issues).
Technical Details
- File:
src/components/DeckGLMap.ts - 21 supported locales, only English partially works (and even then
HIGH/APTdon't match) - PR: koala73/worldmonitor#2370
Acceptance Criteria
- Legend visibility works correctly in French, German, Arabic, and other non-English locales
- No hardcoded English label strings in visibility logic
Work Log
- 2026-03-27: Identified during PR #2370 review via security-sentinel + architecture-strategist agents