mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
* 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.
52 lines
2.4 KiB
Markdown
52 lines
2.4 KiB
Markdown
---
|
||
status: pending
|
||
priority: p2
|
||
issue_id: "050"
|
||
tags: [code-review, performance, analytical-frameworks]
|
||
dependencies: []
|
||
---
|
||
|
||
# `country-intel.ts` framework change fires full RPC immediately — no debounce, extra LLM cost
|
||
|
||
## Problem Statement
|
||
`country-intel.ts` subscribes to framework changes for the `'country-brief'` panel and immediately calls `openCountryBriefByCode()` on every change. `openCountryBriefByCode()` initiates a full LLM-backed country brief RPC. There is no debounce. If a user rapidly switches frameworks (common when exploring options), multiple RPC calls fire to the server. The `briefRequestToken` cancels stale renders but the first LLM call runs to completion and bills tokens even though its result is discarded.
|
||
|
||
## Findings
|
||
- **`src/app/country-intel.ts:72-78`** — subscription fires `openCountryBriefByCode()` immediately
|
||
- No debounce wrapper on the callback
|
||
- Under rapid switching: N framework changes = N LLM API calls = N × token cost
|
||
- Flagged by: performance-oracle
|
||
|
||
## Proposed Solutions
|
||
|
||
### Option A: 400ms debounce on the subscription callback (Recommended)
|
||
```ts
|
||
let debounceTimer: ReturnType<typeof setTimeout> | null = null;
|
||
this.frameworkUnsubscribe = subscribeFrameworkChange('country-brief', () => {
|
||
const page = this.ctx.countryBriefPage;
|
||
if (!page?.isVisible()) return;
|
||
const code = page.getCode();
|
||
const name = page.getName() ?? code;
|
||
if (!code || !name) return;
|
||
if (debounceTimer) clearTimeout(debounceTimer);
|
||
debounceTimer = setTimeout(() => void this.openCountryBriefByCode(code, name), 400);
|
||
});
|
||
```
|
||
**Pros:** Coalesces rapid switches into one call, 400ms is imperceptible to deliberate selection | **Effort:** Small | **Risk:** Low
|
||
|
||
### Option B: Cancel the pending LLM call server-side (not just the render)
|
||
Pass an `AbortSignal` to the RPC and cancel it when a new framework change fires.
|
||
**Pros:** Saves server compute too | **Cons:** RPC client may not support AbortSignal in current implementation | **Effort:** Medium | **Risk:** Medium
|
||
|
||
## Technical Details
|
||
- File: `src/app/country-intel.ts`
|
||
- PR: koala73/worldmonitor#2380
|
||
|
||
## Acceptance Criteria
|
||
- [ ] Rapid framework switching triggers only one RPC call (after debounce settles)
|
||
- [ ] Single deliberate selection still triggers the RPC within ~400ms
|
||
- [ ] Debounce timer is cleared on panel destroy / unsubscribe
|
||
|
||
## Work Log
|
||
- 2026-03-27: Identified during PR #2380 review by performance-oracle
|