feat(scoring): match-generation workflow — scoring engine v1 (Stage 2, step 2)
matchGrants (nightly 05:15): per candidate org (NH + good standing + primary ICP) ensure a v0 NTEE-derived profile embedding (RETRIEVAL_QUERY, confidence 0.2 stub the Stage 4 profiler upgrades in place), retrieve top-50 open grants by pgvector cosine with SQL-enforced cheap gates (deadline >=21d, ceiling >=10K), run entity/geography gates in TS, score deterministically, upsert pair-keyed matches, reassign hero. Scoring: pure scoreMatch (mission fit 30 / capacity 15 / competition 15 / effort 10 / runway 5; precedent's 25 reserved until the 990-PF index; easy win >= 50/75). Eligibility gate now pattern-matches Grants.gov applicantTypes prose, conservatively (ambiguous entries do not admit). application_form_supported ignored for pass/fail per the manual-first decision, still recorded in rationale. Schema: unique (org_id, grant_id) on matches; unique org_id on org_profiles (latest-profile semantics). Review queue query now ordered hero > easy-win > score and capped at 100. Live run: 64 orgs -> 3,200 matches in 28s, 0 easy wins / max 39 — the honest result of an NIH-heavy 200-grant corpus vs NH service nonprofits; engine mechanics verified, corpus breadth is the next lever. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,10 @@ import {
|
||||
runIngestNhdojOrgsNow,
|
||||
setIngestNhdojOrgsDeps,
|
||||
} from './workflows/ingest-nhdoj-orgs.js';
|
||||
import {
|
||||
runMatchGrantsNow,
|
||||
setMatchGrantsDeps,
|
||||
} from './workflows/match-grants.js';
|
||||
import {
|
||||
runIngestPndRssNow,
|
||||
setIngestPndRssDeps,
|
||||
@@ -48,6 +52,7 @@ const RUNNERS: Record<string, () => Promise<void>> = {
|
||||
enrichOrgs: runEnrichOrgsNow,
|
||||
expireGrants: runExpireGrantsNow,
|
||||
embedGrants: runEmbedGrantsNow,
|
||||
matchGrants: runMatchGrantsNow,
|
||||
};
|
||||
|
||||
const FIRST_RUN_ORDER = [
|
||||
@@ -57,6 +62,7 @@ const FIRST_RUN_ORDER = [
|
||||
'expireGrants',
|
||||
'enrichOrgs',
|
||||
'embedGrants',
|
||||
'matchGrants',
|
||||
];
|
||||
|
||||
if (process.env.DATABASE_URL == null) {
|
||||
@@ -92,6 +98,7 @@ async function main() {
|
||||
setIngestNhdojOrgsDeps({ db });
|
||||
setEnrichOrgsDeps({ db });
|
||||
setEmbedGrantsDeps({ db });
|
||||
setMatchGrantsDeps({ db });
|
||||
|
||||
DBOS.setConfig({
|
||||
name: 'helmdocs-outreach-worker',
|
||||
|
||||
Reference in New Issue
Block a user