feat(scoring): v4 — peer precedent, mission-fit floor, LLM match judge
Fixes the federal mismatch class (boys' camp × NIH research center): - Peer precedent: federalPrecedent paginates USASpending (≤500 awards/ program) and name-matches every recipient against primary-ICP NH registry orgs (shared normalizeOrgNameForMatching, also used by the self-match gate). The 25-pt precedent tiers now key off program_state_peer_award_count — Dartmouth renewals and SBIR LLCs no longer grant precedent to community nonprofits. Raw count + peer- annotated award list stay as review evidence (peer badges, peers-first). - Mission-fit floor (12/30, grants_gov only): below it a match is stored with fit_viable=false and hidden from the pending queue, hero selection, and easy-win. Foundation-synthesized grants exempt (generic synopses). - Mission-fit judge live (judgeMatches, 06:15, 200/night best-first): JUDGE_MODEL reads the synopsis against the org profile with an explicit ignore-eligibility-breadth instruction; graded verdict with required citations; deterministic verdict→points map (27/18/8/0) sets missionFit, total, easy-win, and viability. Verdicts survive nightly re-scores via an upsert splice and re-enter the judge queue when the org profile is re-researched (org_profiles.updated_at). First sweep: 81/149 programs have NH history, only 6 have peer history; queue-head judging zeroes the research-mechanism garbage (mismatch) while surfacing genuine strong fits. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -29,3 +29,11 @@ Funder precedent now covers federal grants at the **program (ALN/CFDA) level**
|
||||
Ingest refresh also now rotates oldest-verified-first (`serverMapGrantVerification`) — the plain-Set version re-fetched the same head of the search results every pass, which had left 365 of 565 grants without ALNs.
|
||||
|
||||
First sweep: 156 distinct programs, 85 with NH history, 468/564 open federal grants carrying precedent; first federal easy-wins appeared (score 66, precedent 25/25, real Aug-24 deadline).
|
||||
|
||||
## v4 (2026-07-17): peer precedent + mission-fit floor + LLM match judge
|
||||
|
||||
The v3 sweep exposed two structural failures: ALN-level counts were **recipient-blind** (NORC P30 carried 25/25 precedent because ten NH awards existed — all to Dartmouth entities and two biotech LLCs), and **mission fit couldn't veto** (non-mission subscores sum to 50, so a boys' camp scored 60+ on NIH research-center grants). Three fixes, `scoringVersion: v3-peer-precedent`:
|
||||
|
||||
1. **Peer precedent** — `federalPrecedent` now paginates USASpending (up to 500 awards/program, not a 10-row sample) and classifies every recipient against the primary-ICP NH registry by normalized name (`classifyPeerAwards` + `normalizeOrgNameForMatching`, the same normalizer the self-match gate uses; LLC/LTD deliberately not stripped). The 25-point precedent tiers key off `program_state_peer_award_count` — awards won by orgs shaped like our candidates — while the raw count and the peer-annotated award list stay on the grant as review evidence (peers get a green badge, sorted first). Conservative by construction: unmatched/unenriched recipients count as non-peer; missed precedent demotes a real match rather than pitching a false one.
|
||||
2. **Mission-fit floor** (`MISSION_FIT_VIABLE_MIN = 12/30`, federal sources only) — below it a match is stored (`fit_viable = false`) but hidden from the pending queue, hero selection, and easy-win. Foundation-synthesized grants are exempt: their synopses are generic by construction, so embedding fit carries no signal and precedent evidence is the case for the match.
|
||||
3. **Mission-fit judge** (`judgeMatches`, 06:15, `JUDGE_MATCHES_PER_RUN` default 200) — JUDGE_MODEL reads the actual grant synopsis against the org's (researched or stub) profile, with the explicit instruction to **ignore eligibility breadth** and judge what the program funds and who realistically performs that work (NIH R/P/U mechanisms fit only research performers). Graded verdict with required citations from both sides; deterministic code maps verdict → mission-fit points (strong_fit 27 / plausible 18 / weak 8 / mismatch 0), recomputes total + easy-win, and sets `fit_viable` (weak/mismatch → hidden). Judged rows keep their verdict across nightly re-scores (the upsert splices `judge_mission_fit` back in) and re-enter the judge queue only when the org profile is re-researched (`org_profiles.updated_at > judged_at`). Best-scoring first, so the head of the human queue is always LLM-verified before a human reads it. The detail page shows the verdict, rationale, and citations.
|
||||
|
||||
Reference in New Issue
Block a user