Skip to content

refactor: migrate 17 domain services to Sebuf RPC infrastructure (#1311)#1399

Closed
lspassos1 wants to merge 4 commits intokoala73:mainfrom
lspassos1:refactor/sebuf-rpc-migrations
Closed

refactor: migrate 17 domain services to Sebuf RPC infrastructure (#1311)#1399
lspassos1 wants to merge 4 commits intokoala73:mainfrom
lspassos1:refactor/sebuf-rpc-migrations

Conversation

@lspassos1
Copy link
Copy Markdown
Collaborator

This PR completes the migration of our data ingestion and relay infrastructure to the Sebuf RPC framework.

Key features:

  • Migrated 17 domains (Intelligence, Military, Aviation, Infrastructure, Satellites, etc.) to typed Protobuf contracts.
  • Removed legacy REST relay handlers in /api in favor of centralized Sebuf handlers in /server.
  • Introduced new RPCs for Company Enrichment and Signal Discovery.
  • Full type safety for all network calls via auto-generated Sebuf clients.
  • Cleaned up stale configuration flags and credentials.

Services Migrated:

Verified with npm run typecheck:all and npm run test:data.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 11, 2026

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

A member of the Team first needs to authorize it.

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@koala73 koala73 requested a review from SebastienMelki March 11, 2026 04:21
@lspassos1 lspassos1 force-pushed the refactor/sebuf-rpc-migrations branch from cc94c9a to 7b8fab2 Compare March 11, 2026 21:24
Copy link
Copy Markdown
Collaborator

@SebastienMelki SebastienMelki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 wrapped

Issues:

  • '' instead of getRpcBaseUrl() breaks desktop runtime
  • Missing fetch option means installRuntimeFetchPatch() won't apply
  • getApiBaseUrl() is the wrong function — should be getRpcBaseUrl()
  • Direct globalThis.fetch reference 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 generic getCachedJson<T>()
  • military-flights.ts: 'MILITARY_OPERATOR_UNSPECIFIED' as any — should use proper enum values
  • telegram-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.ts properly types the Groq API response (eliminates any casts)
  • get-risk-scores.ts replaces any[] with proper typed interfaces
  • getCachedJson<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)

  1. Add INT64_ENCODING_NUMBER to all 8 missing int64 timestamp fields
  2. Confirm TrackAircraft streaming change is intentional + update all callers
  3. Fix client construction — use getRpcBaseUrl() and proper fetch binding everywhere
  4. Restore isDesktopRuntime() guard on setSecretValue() in runtime-config.ts
  5. Confirm GetCountryFacts removal is intentional
  6. Confirm ClassifyEvent HTTP method change is intentional
  7. Review cache tier changes — especially track-aircraft going from no-store to medium
  8. Add tests for new server handlers (at minimum smoke tests)

@SebastienMelki
Copy link
Copy Markdown
Collaborator

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 TrackAircraft streaming change (item #2 in the review above):

Sebuf doesn't support server-streaming RPCs. So beyond the wire-incompatibility concern, this returns (stream TrackAircraftResponse) declaration simply won't work with the current framework. This should stay as a unary RPC, or if real-time streaming is needed for aircraft tracking, it would need a different transport mechanism (e.g., WebSocket, SSE) outside of Sebuf.

@lspassos1
Copy link
Copy Markdown
Collaborator Author

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!

Repository owner deleted a comment from ashsolei Mar 14, 2026
@koala73
Copy link
Copy Markdown
Owner

koala73 commented Mar 19, 2026

hey @lspassos1 any update on this one ?

@koala73
Copy link
Copy Markdown
Owner

koala73 commented Mar 19, 2026

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 issues

1. Compiled bundles committed to git (CRITICAL)

The 22 api/*/v1/[rpc].js files (~189,000 lines) are esbuild build artifacts — minified compiled output with all dependencies inlined. These should never be in source control. Vercel compiles the existing [rpc].ts handlers at deploy time; adding pre-built .js counterparts alongside them creates a route ambiguity and bloats the repo with machine-generated code that's impossible to review or audit.

Add api/**/[rpc].js to .gitignore and drop these files entirely.

2. Test deletions

The PR removes 20+ test files that are still active on main (e.g. chokepoint-transit-counter, circuit-breaker-persistent-stale-ceiling, forecast-history, handlers, etc.). These tests guard real production behavior — removing them without replacement would leave regressions undetectable.

3. Scope (930 files, 4 overlapping commits)

Mixing proto schema changes, handler migrations, infra rewrites (vite.config.ts +1173 lines, vercel.json), docs, and workflow changes in a single branch makes review impossible and merge conflicts inevitable. Main has moved ~100 commits ahead since this was last synced.

Suggested path forward

  1. Drop the compiled .js bundles, add them to .gitignore
  2. Split into focused PRs:
    • Proto schema additions (new RPCs: satellites, oref alerts, telegram, company enrichment, etc.)
    • Handler migrations per domain (one PR per service or logical group)
    • Infrastructure changes (vercel.json, vite.config) separately with clear rationale
  3. Keep the existing tests unless you're replacing them with equivalent coverage

The proto/handler work in proto/worldmonitor/intelligence/v1/ is clean and worth landing — it just needs to come in through a scoped PR that doesn't carry the bundle artifacts or test deletions.

Closing for now so the branch doesn't show as conflicting indefinitely. Happy to review a focused follow-up.

@koala73 koala73 closed this Mar 19, 2026
koala73 added a commit that referenced this pull request Mar 19, 2026
…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>
koala73 added a commit that referenced this pull request Mar 21, 2026
…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>
koala73 added a commit that referenced this pull request Mar 21, 2026
* 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>
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.

3 participants