fix(ingestion): drain the Grants.gov backlog + source-filtered review queue
ingest-grants spent its 200-detail budget on hits.slice(0, 200) — the same head of the search results every night; the backlog never drained. Now new opportunities fill the budget first (serverListGrantSourceUrls partition), remaining budget refreshes known ones; search cap raised to 2,000. Full eligible pool turns out to be 565 federal opportunities — drained in two passes, 366 newly embedded. Review queue gains a source badge column and All/Foundations/Federal RFPs filter (?source=) — foundation easy-wins otherwise bury posted-RFP matches, which score lower by design (no precedent, national pools) but are the deadline-driven sends. Immediate proof: DOJ OVW FY2026 DV program (closes 9/8) matched five NH domestic-violence orgs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { desc, eq } from 'drizzle-orm';
|
||||
import { and, desc, eq } from 'drizzle-orm';
|
||||
|
||||
import type { NpOutreachDatabase, NpOutreachTransaction } from '#~/db/db.js';
|
||||
import { schema } from '#~/db/db.js';
|
||||
@@ -14,6 +14,7 @@ export interface PendingReviewMatch {
|
||||
orgName: string;
|
||||
grantTitle: string;
|
||||
funder: string;
|
||||
source: string;
|
||||
totalScore: number;
|
||||
easyWin: boolean;
|
||||
isHero: boolean;
|
||||
@@ -22,6 +23,7 @@ export interface PendingReviewMatch {
|
||||
|
||||
export async function serverListPendingReviewMatches(
|
||||
db: NpOutreachDatabase | NpOutreachTransaction,
|
||||
{ source }: { source?: string } = {},
|
||||
): Promise<PendingReviewMatch[]> {
|
||||
return db
|
||||
.select({
|
||||
@@ -29,6 +31,7 @@ export async function serverListPendingReviewMatches(
|
||||
orgName: schema.orgs.name,
|
||||
grantTitle: schema.grants.title,
|
||||
funder: schema.grants.funder,
|
||||
source: schema.grants.source,
|
||||
totalScore: schema.matches.totalScore,
|
||||
easyWin: schema.matches.easyWin,
|
||||
isHero: schema.matches.isHero,
|
||||
@@ -37,7 +40,14 @@ export async function serverListPendingReviewMatches(
|
||||
.from(schema.matches)
|
||||
.innerJoin(schema.orgs, eq(schema.matches.orgId, schema.orgs.id))
|
||||
.innerJoin(schema.grants, eq(schema.matches.grantId, schema.grants.id))
|
||||
.where(eq(schema.matches.reviewStatus, 'pending'))
|
||||
.where(
|
||||
source == null
|
||||
? eq(schema.matches.reviewStatus, 'pending')
|
||||
: and(
|
||||
eq(schema.matches.reviewStatus, 'pending'),
|
||||
eq(schema.grants.source, source as never),
|
||||
),
|
||||
)
|
||||
// Reviewers see the best candidates first: heroes, then easy wins,
|
||||
// then raw score. Capped — nightly re-scoring generates thousands of
|
||||
// pending pairs and the queue is worked top-down, not exhaustively.
|
||||
|
||||
Reference in New Issue
Block a user