Skip to content

fix(seed): don't crash seed-conflict-intel when ACLED creds are absent#5126

Merged
koala73 merged 1 commit into
mainfrom
worktree-warm-sparking-crayon
Jul 9, 2026
Merged

fix(seed): don't crash seed-conflict-intel when ACLED creds are absent#5126
koala73 merged 1 commit into
mainfrom
worktree-warm-sparking-crayon

Conversation

@koala73

@koala73 koala73 commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Problem — chronic graceful crash, surfaced by /diagnose-railway-seeders

seed-conflict-intel was classified GRACEFUL·CHRONIC: it crashed gracefully (exit 75, one "Deploy Crashed!" alert each) on every ~30-min cron tick — 3 crashes in the hour before diagnosis (15:02 / 15:30 / 16:00 UTC). Same evidence each run:

FETCH FAILED: ACLED display fetch failed for conflict:acled:v1:all:0:0;
refusing to let auxiliary conflict/intel feeds mask the primary feed
(ACLED credentials not configured …)
=== Failed gracefully ===

Root cause

  • The seed reads ACLED_EMAIL/ACLED_PASSWORD or ACLED_ACCESS_TOKEN (scripts/seed-conflict-intel.mjs:40-61). No valid ACLED credential exists in production — the Railway service has only VITE_ACLED_ACCESS_TOKEN set to an empty string (and the seed doesn't read that VITE_-prefixed name).
  • Running without ACLED has been the intended, supported mode since fix(seeds): allow conflict-intel seed to succeed without ACLED keys #1651 ("allow conflict-intel seed to succeed without ACLED keys") and fix(feeds+seeds): graceful ACLED skip + USNI Google News proxy #2288 ("graceful ACLED skip"); auxiliary feeds (PizzINT/GDELT/HAPI) carry it and acledIntel has always been empty.
  • fix(forecast): fail ACLED seed when primary feed is unavailable #5106 (merged the same day) changed return ac || {events:[]} into a hard, non-retryable throw for any missing ac — treating "ACLED absent" (intended) the same as "primary feed broken" (alarming). A seed that had run fine for months began crashing every tick. Only alert-fatigue + wasted compute resulted; no data was lost (auxiliary keys still written).

Fix

Distinguish the two cases in fetchAll():

This stops the crash immediately without needing ACLED credentials. (Provisioning a real ACLED token to actually populate the empty acledIntel feed is a separate, deferred ops task.)

Tests

tests/acled-resolution-feed-seed.test.mjs — the #5106 contract block is replaced with two guards (one per branch). Both fail against the pre-fix code and pass after. Full file + tests/forecast-resolution-eval.test.mjs: 30 pass / 0 fail. node --check + biome lint clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_0199ZmFiQztqqHdAdptCq5K8

#5106 made a *missing* ACLED credential a hard, non-retryable throw. But
ACLED has never been provisioned in production (the seed-conflict-intel
Railway service has only an empty VITE_ACLED_ACCESS_TOKEN, which the seed
doesn't even read), so the seed — which had run fine in its long-standing
auxiliary-only mode (#1651/#2288) — began crashing gracefully (exit 75)
on every ~30-min cron tick, firing a "Deploy Crashed!" alert each time
(GRACEFUL·CHRONIC).

Distinguish the two cases in fetchAll():
- ACLED creds ABSENT (fetchAcledEvents → null → fulfilled): publish the
  auxiliary feeds (already written) + an empty ACLED payload and exit 0,
  as before #5106. No data lost, no alert-fatigue.
- ACLED creds PRESENT but display fetch failed (rejected): keep #5106's
  guard — refuse to let auxiliary feeds silently mask the broken primary
  feed; throw (retryable unless the source marked it non-retryable).

Regression guards added in tests/acled-resolution-feed-seed.test.mjs for
both branches.

Claude-Session: https://claude.ai/code/session_0199ZmFiQztqqHdAdptCq5K8
@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
worldmonitor Ready Ready Preview, Comment Jul 9, 2026 4:55pm

Request Review

@greptile-apps

greptile-apps Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a chronic graceful crash in seed-conflict-intel introduced by #5106: when ACLED credentials are absent (the long-standing production state), the seeder now returns an empty payload and exits 0 rather than throwing every ~30-minute cron tick. The two cases — "no credentials" versus "credentials present but fetch failed" — are now distinguished via the Promise.allSettled settlement status of the ACLED display fetch.

  • scripts/seed-conflict-intel.mjs: In fetchAll(), a new if (missingCredentials) branch returns { events: [], pagination: undefined } early and logs the auxiliary-only mode, while the rejected-status path preserves fix(forecast): fail ACLED seed when primary feed is unavailable #5106's error-throw to guard against a configured-but-broken primary feed.
  • tests/acled-resolution-feed-seed.test.mjs: The single merged contract test is replaced with two focused regression guards, one per branch, ensuring both the graceful-skip and the error-throw behaviors are independently verified.

Confidence Score: 5/5

Safe to merge — the fix directly resolves a production crash loop with a minimal, targeted change, and auxiliary feeds continue to be written before the early return path.

The two-branch distinction in fetchAll() correctly maps fulfilled-with-null to the no-credentials case and rejected to the fetch-failure case. The early return of an empty-but-valid payload passes the existing validate() and declareRecords() contracts, auxiliary keys are already written before the guard, and both new test cases fail against the pre-fix code and pass after.

No files require special attention.

Important Files Changed

Filename Overview
scripts/seed-conflict-intel.mjs Adds a two-branch guard in fetchAll(): gracefully return an empty ACLED payload when credentials are absent, preserve the error-throw path when credentials are present but fetch fails.
tests/acled-resolution-feed-seed.test.mjs Replaces the single merged contract test with two focused regression guards, one per branch.

Reviews (1): Last reviewed commit: "fix(seed): don't crash seed-conflict-int..." | Re-trigger Greptile

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.

1 participant