fix(sanctions): pass timeRange filter to sanctions pressure API#2455
fix(sanctions): pass timeRange filter to sanctions pressure API#2455Jayanth-reflex wants to merge 8 commits intokoala73:mainfrom
Conversation
The sanctions panel was ignoring the user-selected timeRange filter, causing newEntryCount to always show 0. The API endpoint never received the timeRange parameter, so it could not filter entries by their effectiveAt timestamp. Changes: - Add time_range query param to ListSanctionsPressureRequest proto - Update generated client/server to pass and parse time_range - Server handler now recomputes isNew, newEntryCount, and per-country/ per-program counts based on the requested time window - Client service accepts and forwards timeRange to the API - Data loader passes ctx.currentTimeRange to fetchSanctionsPressure - Panel layout triggers sanctions reload on timeRange change Fixes koala73#2437 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@Jayanth-reflex is attempting to deploy a commit to the Elie Team on Vercel. A member of the Team first needs to authorize it. |
Greptile SummaryThis PR fixes the root cause of the always-zero
Confidence Score: 4/5The server-side filtering logic is sound, but two client-side caching bugs will cause incorrect data to be displayed when switching time ranges — the feature's primary user path. There are two P1 defects in sanctions-pressure.ts: (1) the circuit breaker cache is not keyed on timeRange, so switching windows silently serves stale data from the previous window; (2) bootstrap hydrated data bypasses the timeRange filter on first render. Both directly break the core behaviour this PR is meant to fix. Score 4 to indicate these should be resolved before merging. src/services/sanctions-pressure.ts — circuit breaker cacheKey and hydration bypass both need fixes here. Important Files Changed
|
…ntryCount The previous approach built countryMap/programMap by iterating entries, which silently dropped countries or programs not referenced by any entry's countryCodes/programs arrays. Now we start from the original data.countries and data.programs arrays and only patch newEntryCount, guaranteeing every item from the seed dataset is preserved. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Good catch — fixed in b92b46d. The approach now starts from Before (buggy): After (fixed): Same pattern applied to programs. |
…n when filtered Two P1 client-side bugs: 1. Cache keyed on timeRange: breaker.execute() was called without a cacheKey, so all time-range variants shared the same 30-min cache slot. Switching from '7d' to '1h' silently returned stale '7d' data. Fix: pass cacheKey = timeRange || 'all' so each window has its own slot, and forward the same key to breaker.clearCache(). 2. Bootstrap hydration bypasses timeRange: getHydratedData returns the seed script's static isNew flags and cannot be re-filtered. With a non-default timeRange the hydrated path was returning incorrect counts on initial render. Fix: skip the hydration path entirely when a timeRange is set, falling through to the circuit-breaker path which sends timeRange to the server and gets correctly filtered data. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Both P1 issues fixed in 41a24a8: 1. Circuit breaker cache keyed on Each distinct window now gets its own cache slot: const cacheKey = timeRange || 'all';
return breaker.execute(fn, emptyResult, {
cacheKey,
shouldCache: (result) => result.totalCount > 0,
});
2. Bootstrap hydration bypasses The hydration path is now skipped when a if (!timeRange) {
const hydrated = getHydratedData('sanctionsPressure') ...
if (hydrated?.entries?.length || ...) {
// only reached when no filter — static flags are valid
return toResult(hydrated);
}
}
// timeRange set → always fetch live with the filter applied |
|
@koala73 , kindly review this PR |
SebastienMelki
left a comment
There was a problem hiding this comment.
Well-reasoned fix. Author self-corrected all three Greptile P1s (circuit breaker cache key on timeRange, hydration bypass, country/program preservation). Proto → generated stubs → service → panel wiring is clean. LGTM.
|
@SebastienMelki , could you please guide me on how I can get the pending checks done |
I just launched the workflows, they should run in a few seconds |
Thanks, @SebastienMelki. I see the Vercel check is failing. Could you please suggest how we can fix this? |
|
Hi @SebastienMelki, @koala73, could you please help me with the Vercel check and retrigger the workflows, so I can merge this PR? |


Summary
time_rangequery parameter toListSanctionsPressureRequestproto and generated client/servernewEntryCount(and per-country/per-program counts) by comparing each entry'seffectiveAtagainstDate.now() - windowMs, so the "New" badge accurately reflects the user-selected time window (1h, 6h, 24h, 48h, 7d)timeRangefrom the app context to the API callRoot cause
The sanctions panel never passed
timeRangeto its API endpoint. The server returned the seed script's diff-basedisNewflags regardless of the UI filter, causingnewEntryCountto always show 0 when no entries had been added since the last seed run.Files changed
proto/.../list_sanctions_pressure.prototime_rangefield (field 2)src/generated/client/.../service_client.tstimeRangeto request interface + query param serializationsrc/generated/server/.../service_server.tstimeRangeto request interface + query param parsingserver/.../list-sanctions-pressure.tsapplyTimeRangeFilter()— recomputesisNew,newEntryCount, country & program counts based oneffectiveAtwithin the time windowsrc/services/sanctions-pressure.tsfetchSanctionsPressure()now accepts optionaltimeRangeparamsrc/app/data-loader.tsthis.ctx.currentTimeRangetofetchSanctionsPressure()src/app/panel-layout.tsonTimeRangeChangedcallback; triggers sanctions reload on range changesrc/App.tsonTimeRangeChangedtodataLoader.loadSanctionsPressure()Test plan
7d→ verify API call includes?time_range=7dnewEntryCountreflects entries witheffectiveAtwithin the last 7 days (not always 0)7dto24h→ panel reloads with updated countsallor omit → verify existing behavior (no filtering)newEntryCountbadges update correctlynpm run typecheck:all— passes cleanlyFixes #2437
🤖 Generated with Claude Code