feat(scoring): federal funder precedent via USASpending (ALN-level)

Precedent was always a valid criterion for federal grants — the index
just didn't cover them. Now: ingest captures ALN/CFDA numbers from
fetchOpportunity (grants.alns); nightly federalPrecedent workflow
(04:45) queries USASpending award search per distinct program (free
official API, 3-year NH lookback) and stamps program_state_award_count
+ sample recipients onto open grants (multi-ALN keeps highest). Match
retrieval feeds the same funderStateGrantCount input and 25-point tiers
foundations use; detail page shows the recipients-evidence table with
an incumbent-renewal caution.

Also: detail refresh now rotates oldest-verified-first
(serverMapGrantVerification) — the Set-based partition re-fetched the
same 200 every pass, leaving 365/565 grants ALN-less.

Live: 564/564 grants ALN-tagged, 156 programs swept, 85 with NH
history, 468 grants carrying precedent, first federal easy-wins (66pts,
25/25 precedent, Aug-24 deadline). 158 tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Croissant Le Doux
2026-07-16 23:18:02 -04:00
parent 4fa0bb1c32
commit 88affbeb4f
22 changed files with 1995 additions and 23 deletions

View File

@@ -28,6 +28,10 @@ import {
runExpireGrantsNow,
setExpireGrantsDeps,
} from './workflows/expire-grants.js';
import {
runFederalPrecedentNow,
setFederalPrecedentDeps,
} from './workflows/federal-precedent.js';
import {
runIngestGrantsNow,
setIngestGrantsDeps,
@@ -58,6 +62,7 @@ const RUNNERS: Record<string, () => Promise<void>> = {
embedGrants: runEmbedGrantsNow,
matchGrants: runMatchGrantsNow,
ingest990pf: runIngest990PfNow,
federalPrecedent: runFederalPrecedentNow,
};
const FIRST_RUN_ORDER = [
@@ -67,6 +72,7 @@ const FIRST_RUN_ORDER = [
'expireGrants',
'enrichOrgs',
'ingest990pf',
'federalPrecedent',
'embedGrants',
'matchGrants',
];
@@ -106,6 +112,7 @@ async function main() {
setEmbedGrantsDeps({ db });
setMatchGrantsDeps({ db });
setIngest990pfDeps({ db });
setFederalPrecedentDeps({ db });
DBOS.setConfig({
name: 'helmdocs-outreach-worker',