---
status: pending
priority: p2
issue_id: 178
tags: [code-review, phase-0, regional-intelligence, performance, frontend]
dependencies: [179]
---

# refetchForRegion missing AbortController - rapid clicks fire wasted RPCs

## Problem Statement

`src/components/ForecastPanel.ts:318-331` uses a sequence counter to discard stale UI updates, but every click still fires a full RPC. Clicking MENA → East Asia → Europe issues 3 full HTTP calls. Each hits `getCachedJson(REDIS_KEY)` in `get-forecasts.ts:17` with no in-process memoization, so each is a fresh Redis GET + filter + ~50KB response. The 1st-2nd responses are silently discarded.

Compounded by P2 #179 (server has no `cachedFetchJson` coalescing), the user can trigger an order of magnitude more Redis traffic than necessary.

## Findings

- `src/components/ForecastPanel.ts:318-331` — `regionFetchSeq` guard discards stale results but does not abort in-flight requests.

## Proposed Solutions

### Option 1: AbortController

Thread `signal` through `fetchForecasts` → `IntelligenceServiceClient.getForecasts`. Verify the generated proto-ts client supports `options.abort`.

**Pros:** Explicit cancellation; reduces server work; idiomatic fetch pattern.
**Cons:** Requires verifying proto-ts client signal support and threading it through.
**Effort:** Small.
**Risk:** Low.

### Option 2: Debounce 150ms before issuing the RPC

Wait 150ms after last click before fetching.

**Pros:** Single-line change.
**Cons:** Adds delay on first click; doesn't help the already-fired request; degrades perceived responsiveness.
**Effort:** Small.
**Risk:** Low.

### Option 3: Client-side cache

Add a `Map<regionId, Forecast[]>` keyed on region. Instant back-navigation.

**Pros:** Zero server trips for revisits; instant UI.
**Cons:** Stale until panel re-opens; needs a TTL or invalidation trigger.
**Effort:** Small.
**Risk:** Low.

## Recommended Action

Option 1 + Option 3. Together they prevent server work and give instant return navigation. Option 2 is a fallback if proto-ts signal support is absent.

## Technical Details

Proto-ts clients generated by `make generate` typically accept an `AbortSignal` through an options bag — confirm via the generated `IntelligenceServiceClient` interface before wiring. If the signal path isn't plumbed, wrap the call in a native `fetch`-level abort at the client edge.

Cache shape: `Map<regionId, { data: Forecast[]; ts: number }>` with a 60-second TTL matching server cache. Invalidate on visibility change + explicit refresh button.

## Acceptance Criteria

- [ ] Clicking 5 region pills rapidly issues at most 1 in-flight RPC.
- [ ] Stale RPCs are explicitly aborted (not just UI-discarded).
- [ ] Returning to a previously-fetched region serves from client cache.
- [ ] Cache entries honor a TTL and refresh on visibility change.

## Work Log

## Resources

- PR #2942
- Spec: `docs/internal/pro-regional-intelligence-upgrade.md`
