refactor: migrate 17 domain services to Sebuf RPC infrastructure (#1311)#1399
refactor: migrate 17 domain services to Sebuf RPC infrastructure (#1311)#1399lspassos1 wants to merge 4 commits intokoala73:mainfrom
Conversation
|
@lspassos1 is attempting to deploy a commit to the Elie Team on Vercel. A member of the Team first needs to authorize it. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
cc94c9a to
7b8fab2
Compare
SebastienMelki
left a comment
There was a problem hiding this comment.
Thorough Review of PR #1399
Scope: 189K additions, 224 files, 4 commits. Bulk is bundled api/*/v1/[rpc].js files (~187K lines) + generated client/server TS. Actual source changes: ~6,900 lines across proto files, server handlers, client services, tests, and config.
CRITICAL ISSUES
1. Missing INT64_ENCODING_NUMBER on 8 new int64 timestamp fields
Per project convention, all int64 time fields must use (sebuf.http.int64_encoding) = INT64_ENCODING_NUMBER so TypeScript gets number instead of string. The following fields are missing the annotation:
| File | Field |
|---|---|
get_company_enrichment.proto |
int64 enriched_at_ms = 6 |
get_company_enrichment.proto (HNMention) |
int64 created_at_ms = 5 |
list_company_signals.proto (Response) |
int64 discovered_at_ms = 5 |
list_company_signals.proto (CompanySignal) |
int64 timestamp_ms = 6 |
list_oref_alerts.proto (Response) |
int64 timestamp_ms = 6 |
list_oref_alerts.proto (OrefAlert) |
int64 timestamp_ms = 6 |
list_oref_alerts.proto (OrefWave) |
int64 timestamp_ms = 2 |
list_telegram_feed.proto (TelegramMessage) |
int64 timestamp_ms = 5 |
Impact: TS clients will receive these as string instead of number, causing runtime bugs. Compare with list_gps_interference.proto which correctly annotates its int64 fetched_at = 4.
2. TrackAircraft changed from unary to server-streaming (BREAKING)
- rpc TrackAircraft(TrackAircraftRequest) returns (TrackAircraftResponse)
+ rpc TrackAircraft(TrackAircraftRequest) returns (stream TrackAircraftResponse)This is a wire-incompatible breaking change. Existing clients expecting a single response will fail. The cache tier also changed from no-store to medium, meaning tracked aircraft data will now be CDN-cached — which seems wrong for real-time tracking data.
Action needed: Confirm this is intentional and ALL client callers handle streaming responses.
3. GetCountryFacts RPC removed from IntelligenceService (BREAKING)
Both the import of get_country_facts.proto and the RPC definition are removed without deprecation notice. Any client using this endpoint will break.
4. Client construction inconsistencies — wrong base URL and fetch binding
Multiple new client instantiations deviate from the established pattern:
// ✅ Correct pattern (used by 30+ existing clients):
new XxxServiceClient(getRpcBaseUrl(), { fetch: (...args) => globalThis.fetch(...args) })
// ❌ What this PR does in several places:
new InfrastructureServiceClient('', { fetch: (input, init) => globalThis.fetch(input, init) }) // bootstrap.ts, live-news.ts, oref-alerts.ts, telegram-intel.ts
new IntelligenceServiceClient(getApiBaseUrl()) // gps-interference.ts, satellites.ts — MISSING fetch option entirely
new MilitaryServiceClient(getApiBaseUrl()) // military-flights.ts — wrong base URL + missing fetch
new ConflictServiceClient(getApiBaseUrl(), { fetch: globalThis.fetch }) // conflict/index.ts — direct ref, not wrappedIssues:
''instead ofgetRpcBaseUrl()breaks desktop runtime- Missing
fetchoption meansinstallRuntimeFetchPatch()won't apply getApiBaseUrl()is the wrong function — should begetRpcBaseUrl()- Direct
globalThis.fetchreference won't pick up runtime patches applied after module load
HIGH SEVERITY
5. Secrets now stored in localStorage on web (security regression)
runtime-config.ts removed the if (!isDesktopRuntime()) return; guard from setSecretValue(). API keys are now stored in localStorage on web, accessible to any XSS payload or browser extension. Previously this was explicitly blocked.
Additionally, secretsReadyResolve() is only called on desktop — on web, the secretsReady promise may never resolve, causing a deadlock if anything awaits it.
6. ClassifyEvent HTTP method silently dropped
- option (sebuf.http.config) = {path: "/classify-event", method: HTTP_METHOD_GET};
+ option (sebuf.http.config) = {path: "/classify-event"};The method field was removed. Depending on sebuf's default, this may change from GET to POST, breaking clients. The cache tier entry for this route was also removed from gateway.ts.
7. ACLED token passthrough from client headers
conflict/index.ts sends the ACLED token from browser to server via x-acled-token header. The cache key in _shared/acled.ts includes t-${acledToken.slice(-4)}, leaking the last 4 chars in Redis. This is a design choice but should be documented — any browser user can inject arbitrary tokens.
8. Cache tier regressions
| Route | Old | New | Concern |
|---|---|---|---|
list-airport-delays |
static |
slow |
Downgrade |
get-airport-ops-summary |
static |
slow |
Downgrade |
list-airport-flights |
static |
slow |
Downgrade |
get-flight-status |
fast |
slow |
Significant change |
track-aircraft |
no-store |
medium |
Real-time data now cached |
classify-event |
static |
removed | Falls to default |
MEDIUM SEVERITY
9. No tests for 12+ new server handlers
New handlers added: get-youtube-live-stream-info, get-bootstrap-data, get-ip-geo, reverse-geocode, list-satellites, list-gps-interference, list-oref-alerts, list-telegram-feed, get-company-enrichment, list-company-signals. None have corresponding tests.
10. YouTube live stream isLive: true false assumption
get-youtube-live-stream-info.ts OEmbed fallback: isLive: true — OEmbed succeeds for any valid video ID, not just live ones. Could show non-live videos as "live".
11. as any casts in new code
reverse-geocode.ts:getCachedJson(cacheKey, true) as any— should use the new genericgetCachedJson<T>()military-flights.ts:'MILITARY_OPERATOR_UNSPECIFIED' as any— should use proper enum valuestelegram-intel.ts:(m: any)in map callback — loses type safety on generated response types
12. weather.ts lost bootstrap hydration cache
Old code used getHydratedData('weatherAlerts') (synchronous, pre-fetched). New code always makes a network call via fetchBootstrapKeys. This adds latency to every weather panel render.
13. maritime/index.ts — candidate reports always empty
The simplified RPC-only fetch always returns candidateReports: []. If candidate reports were consumed anywhere, this is a silent regression.
14. Duplicate fetchJSON utility
Both get-company-enrichment.ts and list-company-signals.ts define identical fetchJSON<T> helpers with duplicated JSDoc. Should be extracted to server/_shared/fetch-json.ts.
15. dayNight toggle tests deleted without source verification
tests/globe-2d-3d-parity.test.mjs — the entire dayNight suppression test block (4 tests) is removed. If GlobeMap.ts still contains dayNight suppression logic, these tests are protective and should be retained.
LOW SEVERITY
16. ListOrefAlertsRequest.Mode enum — zero value is semantic
MODE_ALERTS = 0 instead of MODE_UNSPECIFIED = 0. Clients sending a default/empty request implicitly select "alerts" mode. Consider MODE_UNSPECIFIED = 0 for consistency with INTERFERENCE_LEVEL_UNSPECIFIED = 0 pattern used elsewhere.
17. satellite.proto imports unused sebuf/http/annotations.proto
The file only defines a Satellite message and uses no HTTP annotations.
18. @ts-expect-error downgraded to @ts-ignore in gateway.ts
The stricter form is preferred — @ts-ignore silently suppresses even after the error is fixed.
19. OpenSky references in test mocks now stale
tests/redis-caching.test.mjs still references opensky-network.org in mocks, but the OpenSky direct-fetch path was removed from military-flights.ts. Tests pass but are testing dead code paths.
GOOD THINGS
- Proto formatting is consistent (annotation style normalization)
deduct-situation.tsproperly types the Groq API response (eliminatesanycasts)get-risk-scores.tsreplacesany[]with proper typed interfacesgetCachedJson<T>generic type parameter is a good improvement- Maritime service simplification from multi-strategy fetch to single RPC is clean
- Overall migration direction is sound — typed RPC contracts are better than raw REST
ACTION ITEMS (priority order)
- Add
INT64_ENCODING_NUMBERto all 8 missing int64 timestamp fields - Confirm
TrackAircraftstreaming change is intentional + update all callers - Fix client construction — use
getRpcBaseUrl()and proper fetch binding everywhere - Restore
isDesktopRuntime()guard onsetSecretValue()inruntime-config.ts - Confirm
GetCountryFactsremoval is intentional - Confirm
ClassifyEventHTTP method change is intentional - Review cache tier changes — especially
track-aircraftgoing fromno-storetomedium - Add tests for new server handlers (at minimum smoke tests)
|
Hey @lspassos1 — thanks for the massive effort on this migration! Moving 17 domains to typed Sebuf contracts is a huge step forward for the codebase. 🙏 One additional note on the Sebuf doesn't support server-streaming RPCs. So beyond the wire-incompatibility concern, this |
|
Hi @SebastienMelki ! Thank you very much for your incredibly detailed architectural feedback. I really value the work you've put into analysing these points. Yur insights were spot on, especially regarding the Vercel Edge constraints and the cache-layer logic. I’ve been working intensely on this lately and, in the next few days, I’ll be sending over the updates. I'm currently finishing off the final standardisations and running a full battery of tests to ensure the remediation is 100% solid. Thanks once again for your contribution and for such a thorough review! |
|
hey @lspassos1 any update on this one ? |
|
Thanks for this contribution Lucas — the direction is right and the proto migrations are valuable work. However, the PR has a few blocking issues that prevent merging it as-is, and they make a clean rebase impractical. Blocking issues1. Compiled bundles committed to git (CRITICAL)The 22 Add 2. Test deletionsThe PR removes 20+ test files that are still active on 3. Scope (930 files, 4 overlapping commits)Mixing proto schema changes, handler migrations, infra rewrites ( Suggested path forward
The proto/handler work in Closing for now so the branch doesn't show as conflicting indefinitely. Happy to review a focused follow-up. |
…interference, company enrichment Extracted from #1399 (originally by @lspassos1). Adds 12 new proto message/service files and updates service.proto for intelligence, aviation, and infrastructure domains. Intelligence: - ListSatellites + satellite.proto (TLE orbit data) - ListOrefAlerts (Israeli Home Front Command alerts) - ListTelegramFeed (Telegram intelligence feed) - ListGpsInterference + gps_jamming.proto - GetCompanyEnrichment (GitHub/SEC/HN enrichment) - ListCompanySignals Aviation: - GetYoutubeLiveStreamInfo Infrastructure: - GetBootstrapData - GetIpGeo - ReverseGeocode Co-authored-by: Lucas Passos <lspassos1@users.noreply.github.com>
…interference, company enrichment Extracted from #1399 (originally by @lspassos1). Adds 12 new proto message/service files and updates service.proto for intelligence, aviation, and infrastructure domains. Intelligence: - ListSatellites + satellite.proto (TLE orbit data) - ListOrefAlerts (Israeli Home Front Command alerts) - ListTelegramFeed (Telegram intelligence feed) - ListGpsInterference + gps_jamming.proto - GetCompanyEnrichment (GitHub/SEC/HN enrichment) - ListCompanySignals Aviation: - GetYoutubeLiveStreamInfo Infrastructure: - GetBootstrapData - GetIpGeo - ReverseGeocode Co-authored-by: Lucas Passos <lspassos1@users.noreply.github.com>
* feat(proto): add new RPCs for satellites, oref alerts, telegram, GPS interference, company enrichment Extracted from #1399 (originally by @lspassos1). Adds 12 new proto message/service files and updates service.proto for intelligence, aviation, and infrastructure domains. Intelligence: - ListSatellites + satellite.proto (TLE orbit data) - ListOrefAlerts (Israeli Home Front Command alerts) - ListTelegramFeed (Telegram intelligence feed) - ListGpsInterference + gps_jamming.proto - GetCompanyEnrichment (GitHub/SEC/HN enrichment) - ListCompanySignals Aviation: - GetYoutubeLiveStreamInfo Infrastructure: - GetBootstrapData - GetIpGeo - ReverseGeocode Co-authored-by: Lucas Passos <lspassos1@users.noreply.github.com> * chore(proto): regenerate clients/servers/openapi after new RPC additions * fix(proto): restore GetCountryFacts and ListSecurityAdvisories RPCs removed by contributor * chore(handlers): add stub implementations for new proto RPCs * fix(handler): correct stub shapes for GetCompanyEnrichment and ListCompanySignals * fix(proto): fix handler stub shapes for listOrefAlerts, listTelegramFeed, listGpsInterference * fix(proto): fix remaining handler stub shapes for aviation and infrastructure * fix(proto): add cache tier entries for new generated GET routes, remove stale classify-event entry * fix(pr1888): restore rpc contracts and real handlers * fix(oref): read history from Redis instead of re-calling relay relay:oref:history:v1 is seeded by ais-relay on every poll cycle. History mode now reads directly from Redis (no relay hit). Live alerts still call relay (in-memory only), with Redis counts as fallback. * fix(gateway): change youtube-live-stream-info tier from no-store to fast Matches existing api/youtube/live.js which caches at s-maxage=600. fast tier = s-maxage=300 stale-while-revalidate=60 — appropriate for live detection that changes at most every few minutes. * fix(geocode): await setCachedJson to prevent edge isolate termination race * fix(youtube): use CHROME_UA constant in fallback fetch paths * fix(pr1888): address P1/P2 review findings - gateway: oref+telegram slow->fast (matches legacy s-maxage=300/120) - gateway: ip-geo slow->no-store (per-request user data, must not share) - list-gps-interference: recompute stats from filtered hexes when region filter active - get-company-enrichment: throw ValidationError(400) on missing domain+name - list-company-signals: throw ValidationError(400) on missing company * fix(validation): use FieldViolation.description, remove unused buildEmptyResponse --------- Co-authored-by: Lucas Passos <lspassos1@users.noreply.github.com> Co-authored-by: lspassos1 <lspassos@icloud.com>
This PR completes the migration of our data ingestion and relay infrastructure to the Sebuf RPC framework.
Key features:
Services Migrated:
Verified with npm run typecheck:all and npm run test:data.