Skip to content

feat: implement deduct situation feature (#636)#642

Merged
koala73 merged 157 commits intokoala73:mainfrom
fuleinist:feature/deduct-situation
Mar 1, 2026
Merged

feat: implement deduct situation feature (#636)#642
koala73 merged 157 commits intokoala73:mainfrom
fuleinist:feature/deduct-situation

Conversation

@fuleinist
Copy link
Contributor

@fuleinist fuleinist commented Mar 1, 2026

Resolves #636.

Summary of Changes

  1. API Layer: Added DeductSituation RPC endpoint to process timeline and impact deductions, including query and geo_context fields.
  2. Backend: Built the intelligence handler leveraging Groq LLM. It includes robust caching, markdown analysis, and prompt engineering tailored for geopolitical forecasting.
  3. Frontend UI: Integrated a new DeductionPanel component into the FULL layout containing a text area for queries and Markdown-rendering for AI predictions. Available via the command palette (CMD+K -> "deduction").
image

koala73 and others added 30 commits February 27, 2026 18:42
)

* feat: add Security Advisories panel with government travel advisory feeds

Adds a new panel aggregating travel/security advisories from official
government foreign affairs agencies (US State Dept, AU DFAT Smartraveller,
UK FCDO, NZ MFAT). Advisories are categorized by severity level
(Do Not Travel, Reconsider, Caution, Normal) with filter tabs by
source country. Includes summary counts, auto-refresh, and persistent
caching via the existing data-freshness system.


* chore: update package-lock.json


* fix: event delegation, localization, and cleanup for SecurityAdvisories panel

P1 fixes:
- Use event delegation on this.content (bound once in constructor) instead
  of direct addEventListener after each innerHTML replacement — prevents
  memory leaks and stale listener issues on re-render
- Use setContent() consistently instead of mixing with this.content.innerHTML
- Add securityAdvisories translations to all 16 non-English locale files
  (panels name, component strings, common.all key)
- Revert unrelated package-lock.json version bump

P2 fixes:
- Deduplicate loadSecurityAdvisories — loadIntelligenceData now calls the
  shared method instead of inlining duplicate fetch+set logic
- Add Accept header to fetch calls for better content negotiation

* feat(advisories): add US embassy alerts, CDC, ECDC, and WHO health feeds

Adds 21 new advisory RSS feeds:
- 13 US Embassy per-country security alerts (TH, AE, DE, UA, MX, IN, PK, CO, PL, BD, IT, DO, MM)
- CDC Travel Notices
- 5 ECDC feeds (epidemiological, threats, risk assessments, avian flu, publications)
- 2 WHO feeds (global news, Africa emergencies)

Panel gains a Health filter tab for CDC/ECDC/WHO sources.
All new domains added to RSS proxy allowlist.
i18n "health" key added across all 17 locales.
)

When upstream APIs return errors (HTTP 403, 429, timeout), fetchers
return null. Previously null results were not cached, causing repeated
request storms against broken APIs every refresh cycle.

Now caches a sentinel value ('__WM_NEG__') with a short 2-minute TTL
on null results. Subsequent requests within that window get null
immediately without hitting upstream. Thrown errors (transient) skip
sentinel caching and retry immediately.

Also filters sentinels from getCachedJsonBatch pipeline reads and fixes
theater posture coalescing test (expected 2 OpenSky fetches for 2
theater query regions, not 1).
…la73#468)

* feat: convert 52 API endpoints from POST to GET for edge caching

Convert all cacheable sebuf RPC endpoints to HTTP GET with query/path
parameters, enabling CDN edge caching to reduce costs. Flatten nested
request types (TimeRange, PaginationRequest, BoundingBox) into scalar
query params. Add path params for resource lookups (GetFredSeries,
GetHumanitarianSummary, GetCountryStockIndex, GetCountryIntelBrief,
GetAircraftDetails). Rewrite router with hybrid static/dynamic matching
for path param support.

Kept as POST: SummarizeArticle, ClassifyEvent, RecordBaselineSnapshot,
GetAircraftDetailsBatch, RegisterInterest.

Generated with sebuf v0.9.0 (protoc-gen-ts-client, protoc-gen-ts-server).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add rate_limited field to market response protos

The rateLimited field was hand-patched into generated files on main but
never declared in the proto definitions. Regenerating wiped it out,
breaking the build. Now properly defined in both ListEtfFlowsResponse
and ListMarketQuotesResponse protos.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove accidentally committed .planning files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
….app (koala73#471)

Route web production RPC traffic through api.worldmonitor.app via fetch
interceptor (installWebApiRedirect). Add default Cache-Control headers
(s-maxage=300, stale-while-revalidate=60) on GET 200 responses, with
no-store override for real-time endpoints (vessel snapshot). Update CORS
to allow GET method. Skip Vercel bot middleware for API subdomain using
hostname check (non-spoofable, replacing CF-Ray header approach). Update
desktop cloud fallback to route through api.worldmonitor.app.
BETA_MODE now couples the badge AND model loading — the summarization-beta
model starts loading on startup instead of waiting for the first summarization call.
…oala73#472)

Vercel's `api/[domain]/v1/[rpc].ts` captures one dynamic segment.
Path params like `/get-humanitarian-summary/SA` add an extra segment
that has no matching route file, causing 404 on both OPTIONS preflight
and direct requests. These endpoints were broken in production.

Changes:
- Remove `{param}` from 5 service.proto HTTP paths
- Add `(sebuf.http.query)` annotations to request message fields
- Update generated client/server code to use URLSearchParams
- Update OpenAPI specs (YAML + JSON) to declare query params
- Add early-return guards in 4 handlers for missing required params
- Add happy.worldmonitor.app to runtime.ts redirect hosts

Affected endpoints:
- GET /api/conflict/v1/get-humanitarian-summary?country_code=SA
- GET /api/economic/v1/get-fred-series?series_id=T10Y2Y&limit=120
- GET /api/market/v1/get-country-stock-index?country_code=US
- GET /api/intelligence/v1/get-country-intel-brief?country_code=US
- GET /api/military/v1/get-aircraft-details?icao24=a12345
… blocks (koala73#473)

- Advisory feeds were fetched directly from the browser, hitting CORS
  on all 21 feeds (US State Dept, AU Smartraveller, US Embassies, ECDC,
  CDC, WHO). Route through /api/rss-proxy on web, keep proxyUrl for desktop.
- Fix double slash in ECDC Avian Influenza URL (323//feed → 323/feed)
- Add feeds.news24.com to RSS proxy allowlist (was returning 403)
…a73#474)

* fix: move 5 path-param endpoints to query params for Vercel routing

Vercel's `api/[domain]/v1/[rpc].ts` captures one dynamic segment.
Path params like `/get-humanitarian-summary/SA` add an extra segment
that has no matching route file, causing 404 on both OPTIONS preflight
and direct requests. These endpoints were broken in production.

Changes:
- Remove `{param}` from 5 service.proto HTTP paths
- Add `(sebuf.http.query)` annotations to request message fields
- Update generated client/server code to use URLSearchParams
- Update OpenAPI specs (YAML + JSON) to declare query params
- Add early-return guards in 4 handlers for missing required params
- Add happy.worldmonitor.app to runtime.ts redirect hosts

Affected endpoints:
- GET /api/conflict/v1/get-humanitarian-summary?country_code=SA
- GET /api/economic/v1/get-fred-series?series_id=T10Y2Y&limit=120
- GET /api/market/v1/get-country-stock-index?country_code=US
- GET /api/intelligence/v1/get-country-intel-brief?country_code=US
- GET /api/military/v1/get-aircraft-details?icao24=a12345

* feat(cache): add tiered edge Cache-Control aligned to upstream TTLs

Replace flat s-maxage=300 with 5 tiers (fast/medium/slow/static/no-store)
mapped per-endpoint to respect upstream Redis TTLs. Adds stale-if-error
resilience headers and X-No-Cache plumbing for future degraded responses.
X-Cache-Tier debug header gated behind ?_debug query param.
…ala73#475)

- CISA Advisories used dead rss.worldmonitor.app domain (404), switch to rss() helper
- Remove Vite build from pre-push hook (tsc already catches errors)
…oala73#476)

* fix(tech): use rss() for CISA feed, drop build from pre-push hook

- CISA Advisories used dead rss.worldmonitor.app domain (404), switch to rss() helper
- Remove Vite build from pre-push hook (tsc already catches errors)

* fix(desktop): enable click-to-play for YouTube embeds in WKWebView

WKWebView blocks programmatic autoplay in cross-origin iframes regardless
of allow attributes, Permissions-Policy, mute-first retries, or secure
context. Documented all 10 approaches tested in docs/internal/.

Changes:
- Switch sidecar embed origin from 127.0.0.1 to localhost (secure context)
- Add MutationObserver + retry chain as best-effort autoplay attempts
- Use postMessage('*') to fix tauri://localhost cross-origin messaging
- Make sidecar play overlay non-interactive (pointer-events:none)
- Fix .webcam-iframe pointer-events:none blocking clicks in grid view
- Add expand button to grid cells for switching to single view on desktop
- Add http://localhost:* to CSP frame-src in index.html and tauri.conf.json
…koala73#477)

Stale cached client bundles still send POST to endpoints converted to
GET in PR koala73#468, causing 404s. The gateway now parses the POST JSON body
into query params and retries the match as GET.
…oala73#478)

Add CDN-Cache-Control headers to all proxy endpoints so Cloudflare can
cache responses at the edge independently of browser Cache-Control:

- RSS: 600s edge + stale-while-revalidate=300 (browser: 300s)
- UCDP: 3600s edge (matches browser)
- OpenSky: 15s edge (browser: 30s) for fresher flight data
- WorldBank: 1800s/86400s edge (matches browser)
- Polymarket: 120s edge (matches browser)
- Telegram: 10s edge (matches browser)
- AIS snapshot: 2s edge (matches browser)

Also fixes:
- Vary header merging: sendCompressed/sendPreGzipped now merge existing
  Vary: Origin instead of overwriting, preventing cross-origin cache
  poisoning at the edge
- Stale fallback responses (OpenSky, WorldBank, Polymarket, RSS) now
  set Cache-Control: no-store + CDN-Cache-Control: no-store to prevent
  edge caching of degraded responses
- All no-cache branches get CDN-Cache-Control: no-store
- /opensky-reset gets no-store (state-changing endpoint)
- Tighten AbortError filter to match "AbortError: The operation was aborted"
- Filter "The user aborted a request" (normal navigation cancellation)
- Filter UltraViewer service worker injection errors (/uv/service/)
- Filter Huawei WebView __isInQueue__ injection
* fix(gateway): harden POST→GET shim with scalar guard and size limit

- Only convert string/number/boolean values to query params (skip objects,
  nested arrays, __proto__ etc.) to prevent prototype pollution vectors
- Skip body parsing for Content-Length > 1MB to avoid memory pressure

* feat: make API base URL configurable via VITE_WS_API_URL

Replace hardcoded api.worldmonitor.app with VITE_WS_API_URL env var.
When empty, installWebApiRedirect() is skipped entirely — relative
/api/* calls stay on the same domain (local installs). When set,
browser fetch is redirected to that URL.

Also adds VITE_WS_API_URL and VITE_WS_RELAY_URL hostnames to
APP_HOSTS allowlist dynamically.
)

Vercel's :path* wildcard doesn't match trailing slashes that
PostHog SDK appends (e.g. /ingest/s/?compression=...), causing 404s.
Switch to :path(.*) which matches all path segments including
trailing slashes. Ref: PostHog/posthog#17596
With 20k requests/30min (60% of proxy traffic) and per-PoP caching,
a 2s edge TTL expires before the next request from the same PoP arrives,
resulting in near-zero cache hits. 10s allows same-PoP dedup while
keeping browser TTL at 2s for fresh vessel positions.
…koala73#483)

The shared circuit breaker (cacheTtlMs: 0) cached the stocks response,
then the stale-while-revalidate path returned that cached stocks data
for the subsequent commodities fetch. Skip SWR when caching is disabled.
…policy (koala73#484)

- Add 11 missing GET routes to RPC_CACHE_TIER map (8 slow, 3 medium)
- Add response-headers side-channel (WeakMap) so handlers can signal
  X-No-Cache without codegen changes; wire into military-flights and
  positive-geo-events handlers on upstream failure
- Add env-controlled per-endpoint tier override (CACHE_TIER_OVERRIDE_*)
  for incident response rollback
- Add VITE_WS_API_URL hostname allowlist (*.worldmonitor.app + localhost)
- Fix fetch.bind(globalThis) in positive-events-geo.ts (deferred lambda)
- Add CI test asserting every generated GET route has an explicit cache
  tier entry (prevents silent default-tier drift)
Covers PRs koala73#452koala73#484: Cloudflare edge caching, commodities SWR fix,
security advisories panel, settings redesign, 52 POST→GET migrations.
…la73#486)

Feed has no <pubDate> fields and latest content is from April 2022.
Not referenced in any feed config — only in the proxy domain allowlist.
- Add ko.json with all 1606 translation keys matching en.json structure
- Register 'ko' in SUPPORTED_LANGUAGES, LANGUAGES display array, and locale map
- Korean appears as 🇰🇷 한국어 in the language dropdown
)

Add api.axios.com to proxy allowlist and CSP connect-src, register
Axios feed under US category as Tier 2 mainstream source.
* perf: bootstrap endpoint + polling optimization (phases 3-4)

Replace 15+ individual RPC calls on startup with a single /api/bootstrap
batch call that fetches pre-cached data from Redis. Consolidate 6 panel
setInterval timers into the central RefreshScheduler for hidden-tab
awareness (10x multiplier) and adaptive backoff (up to 4x for unchanged
data). Convert IntelligenceGapBadge from 10s polling to event-driven
updates with 60s safety fallback.

* fix(bootstrap): inline Redis + cache keys in edge function

Vercel Edge Functions cannot resolve cross-directory TypeScript imports
from server/_shared/. Inline getCachedJsonBatch and BOOTSTRAP_CACHE_KEYS
directly in api/bootstrap.js. Add sync test to ensure inlined keys stay
in sync with the canonical server/_shared/cache-keys.ts registry.

* test: add Edge Function module isolation guard for all api/*.js files

Prevents any Edge Function from importing from ../server/ or ../src/
which breaks Vercel builds. Scans all 12 non-helper Edge Functions.

* fix(bootstrap): read unprefixed cache keys on all environments

Preview deploys set VERCEL_ENV=preview which caused getKeyPrefix() to
prefix Redis keys with preview:<sha>:, but handlers only write to
unprefixed keys on production. Bootstrap is a read-only consumer of
production cache — always read unprefixed keys.

* fix(bootstrap): wire sectors hydration + add coverage guard

- Wire getHydratedData('sectors') in data-loader to skip Yahoo Finance
  fetch when bootstrap provides sector data
- Add test ensuring every bootstrap key has a getHydratedData consumer
  — prevents adding keys without wiring them

* fix(server): resolve 25 TypeScript errors + add server typecheck to CI

- _shared.ts: remove unused `delay` variable
- list-etf-flows.ts: add missing `rateLimited` field to 3 return literals
- list-market-quotes.ts: add missing `rateLimited` field to 4 return literals
- get-cable-health.ts: add non-null assertions for regex groups and array access
- list-positive-geo-events.ts: add non-null assertion for array index
- get-chokepoint-status.ts: add required fields to request objects
- CI: run `typecheck:api` (tsconfig.api.json) alongside `typecheck` to catch
  server/ TS errors before merge
…a73#496)

* feat(military): server-side military bases with 125K entries + rate limiting (koala73#485)

Migrate military bases from 224 static client-side entries to 125,380
server-side entries stored in Redis GEO sorted sets, served via
bbox-filtered GEOSEARCH endpoint with server-side clustering.

Data pipeline:
- Pizzint/Polyglobe: 79,156 entries (Supabase extraction)
- OpenStreetMap: 45,185 entries
- MIRTA: 821 entries
- Curated strategic: 218 entries
- 277 proximity duplicates removed

Server:
- ListMilitaryBases RPC with GEOSEARCH + HMGET + tier/filter/clustering
- Antimeridian handling (split bbox queries)
- Blue-green Redis deployment with atomic version pointer switch
- geoSearchByBox() + getHashFieldsBatch() helpers in redis.ts

Security:
- @upstash/ratelimit: 60 req/min sliding window per IP
- IP spoofing fix: prioritize x-real-ip (Vercel-injected) over x-forwarded-for
- Require API key for non-browser requests (blocks unauthenticated curl/scripts)
- Input validation: allowlisted types/kinds, regex country, clamped bbox/zoom

Frontend:
- Viewport-driven loading with bbox quantization + debounce
- Server-side grid clustering at low zoom levels
- Enriched popup with kind, category badges (airforce/naval/nuclear/space)
- Static 224 bases kept as search fallback + initial render

* fix(military): fallback to production Redis keys in preview deployments

Preview deployments prefix Redis keys with `preview:{sha}:` but military
bases data is seeded to unprefixed (production) keys. When the prefixed
`military:bases:active` key is missing, fall back to the unprefixed key
and use raw (unprefixed) keys for geo/meta lookups.

* fix: remove unused 'remaining' destructure in rate-limit (TS6133)

* ci: add typecheck:api to pre-push hook to catch server-side TS errors

* debug(military): add X-Bases-Debug response header for preview diagnostics

* fix(bases): trigger initial server fetch on map load

fetchServerBases() was only called on moveend — if the user
never panned/zoomed, the API was never called and only the 224
static fallback bases showed.
…tier (koala73#497)

- Add 300ms debounce on moveend to prevent rapid pan flooding
- Fixes stale-bbox bug where pendingFetch returns old viewport data
- Upgrade edge cache tier from medium (5min) to static (1hr) — bases are
  static infrastructure, aligned with server-side cachedFetchJson TTL
- Keep error logging in catch blocks for production diagnostics
…3#498)

Replace Math.random() jitter with DJB2 hash seeded by the threat
indicator (IP/URL), so the same threat always maps to the same
coordinates across requests while different threats from the same
country still spread out.

Closes koala73#203

Co-authored-by: Chris Chen <fuleinist@users.noreply.github.com>
Replace direct `VAR=value command` syntax with cross-env/cross-env-shell
so dev, build, test, and desktop scripts work on Windows PowerShell/CMD.

Co-authored-by: facusturla <facusturla@users.noreply.github.com>
…3#504)

- Filter null/undefined values before storing in hydration cache to
  prevent future consumers using !== undefined from misinterpreting
  null as valid data
- Debounce wm:intelligence-updated event handler via requestAnimationFrame
  to coalesce rapid alert generation into a single render pass
- Include alert IDs in StrategicRiskPanel change fingerprint so content
  changes are detected even when alert count stays the same
- Replace JSON.stringify change detection in ServiceStatusPanel with
  lightweight name:status fingerprint
- Document max effective refresh interval (40x base) in scheduler
koala73 and others added 20 commits March 1, 2026 03:25
…oala73#610)

- Remove useFallbackOnly from RT channel — RT is HLS-only (banned from
  YouTube), so the flag was causing undefined videoId on HLS failure
  instead of graceful offline state
- Add response-headers shim to redis-caching test so military flights
  bbox tests can import list-military-flights.ts
- Restore LiveNOW from FOX fallbackVideoId (removed in channel audit)
koala73#612)

Reduces upstream RSS polling frequency and extends client-side cache
lifetime to lower API load and bandwidth usage.
Comprehensive changelog for 2026-03-01 release including Iran Attacks
layer, Telegram Intel panel, OREF sirens, GPS jamming, AviationStack,
breaking news alerts, and strategic risk score.
…oala73#618)

- Fetch and display alert history waves in OrefSirensPanel (cap 50 most recent)
- Last-hour waves highlighted with amber border and RECENT badge
- Translate Hebrew history alerts via existing translateAlerts pipeline
- Guard formatAlertTime/formatWaveTime against NaN from unparseable OREF dates
- Cap relay history bootstrap to 500 records
- Add 3-minute TTL to prevent re-fetching history on every 10s poll
- Remove dead .oref-footer/.oref-history CSS; add i18n key for history summary
…ull feature parity (koala73#619)

- Fix URL restore: lat/lon now override view center when explicitly provided
- Fix touch scroll: 8px threshold before drag activation, preventDefault once active
- Add location bootstrap: timezone-first detection, optional geolocation upgrade
- Enable DeckGL on mobile with deviceMemory capability guard
- Add DeckGL state sync on moveend/zoomend for URL param updates
- Fix breakpoint off-by-one: JS now uses <= to match CSS max-width: 768px
- Add country-click on SVG fallback with CSS transform inversion
- Add fitCountry() to both map engines (DeckGL uses fitBounds, SVG uses projection)
- Add SVG inertial touch animation with exponential velocity decay
- Add mobile map e2e tests for timezone, URL restore, touch, and breakpoint
…koala73#624)

- Fix: `this.player.pauseVideo()` → `this.player.pauseVideo?.()` at
  LiveNewsPanel line 1301 (6 Sentry issues, 33 events)
- Noise: Chrome extension "Could not establish connection"
- Noise: Safari "webkitCurrentPlaybackTargetIsWireless" internal
- Noise: Sentry SDK crash on iOS "a.theme"
- Noise: Broaden Can't find variable to include EmptyRanges
- Noise: Catch stale cached builds with /this.player.\w+ is not a function/
- Replace manual getCachedJson/setCachedJson with cachedFetchJson for
  intl delays — prevents thundering herd (concurrent misses each firing
  93 API calls independently)
- Bump Redis cache TTL from 30min to 2h
- Bump frontend polling from 10min to 2h to match server cache
- Bump circuit breaker browser cache from 5min to 2h
- Bump CDN edge tier from medium (5min) to static (1h)
- Bump cache key to v3 to force fresh entry with new TTL
…y ~95% (koala73#622)

Phase 1: Force CDN caching on rss-proxy (s-maxage=300 for 2xx, short
TTL for errors) — fixes bug where upstream no-cache headers were passed
through verbatim, defeating Vercel CDN.

Phase 2: Add ListFeedDigest RPC that aggregates all feeds server-side
into a single Redis-cached response. Client makes 1 request instead of
~90 per cycle. Includes circuit breaker with persistent cache fallback,
per-feed AI reclassification, and headline ingestion parity.

Phase 3: Increase polling interval from 5min to 7min to offset CDN
cache alignment.

New files:
- proto/worldmonitor/news/v1/list_feed_digest.proto
- server/worldmonitor/news/v1/{_feeds,_classifier,list-feed-digest}.ts
- src/services/ai-classify-queue.ts (extracted from rss.ts)
…lay (koala73#625)

When RSS cache expires, send If-None-Match/If-Modified-Since headers
on revalidation. Upstream 304 responses refresh the cache timestamp
and serve cached body with zero bandwidth, cutting egress ~80-95%
for feeds that support conditional GET.
…koala73#621)

Layer toggles were not updating the browser URL, so shared links
would not carry the user's current layer state. Extracted the
debounced URL sync to a reusable class method and call it on
every layer change.
…la73#626)

Audit and raise every cache/poll under 5 min to reduce upstream API
pressure and Vercel function invocations across 31 files:

Frontend polling: markets 4→8min, crypto 4→8min, predictions 5→10min,
natural 5→1hr, cableHealth 5→2hr, oref 10s→2min, maritime 30s→5min,
IntelligenceGapBadge 1→3min.

Circuit breakers: PizzINT 2→30min, aviation 5→20min, seismology/weather/
outages/statuses/wildfires 5→30min, military-vessels/flights/GDACS/
maritime/polymarket/GDELT 5→10min, chokepoint 5→20min.

Server Redis: market-quotes 2→8min, stablecoins 2→8min/5→10min,
vessel-snapshot 10s→5min, earthquakes 5→30min, sector 5→10min,
predictions/crypto/commodities 5→10min, outages/statuses 5→30min,
macro-signals/chokepoints 5→15min, aviation-sim 5→15min.

CDN edge: market RPCs fast→medium, infra/seismology fast→slow.
koala73#627)

* fix(military): narrow hex ranges and callsign regex to stop civilian false positives (koala73#462)

MILITARY_HEX_RANGES used entire country ICAO allocations instead of
military-specific sub-ranges (sourced from tar1090-db/ranges.json).
This flagged ALL commercial aircraft from Italy, Spain, Japan, India,
South Korea, etc. as military activity.

Key changes:
- Remove A00000-A3FFFF (US civilian N-numbers) — military starts at ADF7C8
- Italy 300000-33FFFF → 33FF00-33FFFF (top 256 codes only)
- Spain 340000-37FFFF → 350000-37FFFF (upper 3/4 confirmed military)
- Japan 840000-87FFFF removed (no confirmed JASDF sub-range)
- France narrowed to 3AA000-3AFFFF + 3B7000-3BFFFF
- Germany narrowed to 3EA000-3EBFFF + 3F4000-3FBFFF
- India 800000-83FFFF → 800200-8002FF (256 codes)
- Canada C00000-C0FFFF → C20000-C3FFFF (upper half)
- Remove unconfirmed: South Korea, Sweden, Singapore, Pakistan
- Add confirmed: Austria, Belgium, Switzerland, Brazil
- Drop overly broad /^[A-Z]{4,}\d{1,3}$/ callsign regex from server

* fix(military): constrain short prefixes + add classification tests

Move ambiguous 2-letter prefixes (AE, RF, TF, PAT, SAM, OPS, CTF,
IRG, TAF) to SHORT_MILITARY_PREFIXES — these now only match when
followed by a digit (e.g. AE1234=military, AEE123=Aegean Airlines).

Add 97-case test suite covering:
- Military callsign detection (19 known patterns)
- Short prefix digit gating (6 cases)
- Civilian airline non-detection (26 airlines)
- Short prefix letter rejection (6 cases)
- Military hex range boundaries (7 confirmed ranges)
- Civilian hex non-detection (19 codes)
- Boundary precision (ADF7C8 start, 33FF00 start, etc.)
- No-full-allocation guard (10 countries)

* fix: use charAt() instead of bracket indexing for strict TS
…koala73#632)

Both keys were added to Rust SUPPORTED_SECRET_KEYS and runtime-config.ts
but the sidecar's own ALLOWED_ENV_KEYS was never updated. This caused
"key not in allowlist" 403 when saving/verifying these keys from the
desktop settings UI.

Also adds AviationStack API validation in validateSecretAgainstProvider.
…indow (koala73#633)

Three bugs combine to burn 130% CPU when sidecar auth fails:

1. RefreshScheduler resets backoff multiplier to 1 (fastest) on error,
   causing failed endpoints to poll at base interval instead of backing off.
   Fix: exponential backoff on errors, same as unchanged-data path.

2. classify-event batch system ignores 401 (auth failure) — only pauses
   on 429/5xx. Hundreds of classify calls fire every 2s, each wasted.
   Fix: pause 120s on 401, matching the 429/5xx pattern.

3. Fetch patch retries every 401 (refresh token + retry), doubling all
   requests to the sidecar even when token refresh consistently fails.
   Fix: 60s cooldown after a retry-401 still returns 401.

Also shrinks settings window from 760→600px (min 620→480) to reduce
the empty whitespace below content on all tabs.
@vercel
Copy link

vercel bot commented Mar 1, 2026

@fuleinist is attempting to deploy a commit to the Elie Team on Vercel.

A member of the Team first needs to authorize it.

…posture, and tech events with associated backend services and E2E tests.
koala73 added 6 commits March 1, 2026 19:49
- Gate DeductionPanel creation behind isDesktopApp check
- Gate deduce buttons in StrategicPosturePanel and TechEventsPanel behind isDesktopRuntime()
- Remove deduction from FULL_PANELS (runtime-only on desktop)
- Add DOMPurify to sanitize marked.parse() output before innerHTML
- Revert shared _shared.ts: restore UPSTREAM_TIMEOUT_MS=30_000, hardcoded GROQ_API_URL/MODEL
- Define local DEDUCT_TIMEOUT_MS=120_000, DEDUCT_API_URL, DEDUCT_MODEL in handler
- Fix dead API key guard: remove 'ollama-local' fallback, skip if no key
- Strip all console.log from deduct-situation handler (keep console.error)
- Bump max_tokens 500→1500 for meaningful analysis
- Fix cache key: deduct:sebuf→deduct:situation
- Add 5s client-side rate limit cooldown on submit button
- Move @types/marked to devDependencies, add dompurify + @types/dompurify
- Add DeductContextDetail shared interface in types/index.ts
- Extract buildNewsContext helper to src/utils/news-context.ts
- Pass getLatestNews to StrategicPosturePanel constructor
- Fix E2E test: .deduction-markdown-content→.deduction-result
- Revert emoji escapes in commands.ts to unicode format
- Revert variant-switcher whitespace in panel-layout.ts
Generated IranEvent.timestamp is string but consumers expected number.
- Coerce timestamps via Number() in data-loader before passing to aggregators
- Accept string|number in MapPopup IranEventPopupData interface
- Fix scrapedAt fallback type in conflict/index.ts
- Coerce timestamp in country-intel.ts and DeckGLMap.ts sort
…ion RPC

Reverts all src/generated/ files to origin/main except the intelligence
service client/server which retains the new deductSituation RPC added by
this PR. Fixes scrapedAt type to match generated number type.
The Gulf Economies panel (PR koala73#667) added this RPC after the feature
branch was forked. Bring handler and registration from main.
- P1: Fix event listener leak — store handler ref, remove in destroy()
- P1: Prevent cooldown bypass via requestSubmit when button disabled
- P2: Read process.env inside function body for runtime secret updates
- P3: Use \u{1F9E0} unicode escape in StrategicPosturePanel (consistency)
Merge origin/main into feature/deduct-situation, resolving all conflicts.
Re-applied PR-specific changes: DeductionPanel desktop gating, DOMPurify,
deductSituation RPC client method, IranEvent timestamp coercion, and
missing markNoCacheResponse import.
@koala73 koala73 merged commit a7efa7d into koala73:main Mar 1, 2026
1 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] Add ability to "deduce" the future events and news

6 participants