We have assembled ~1.2 million records about places that may feed, shelter, and support people in crisis. This is the contract for turning those scattered records into a single pool that can answer “who near me provides this, and can I actually reach them?” without inventing certainty the internet never had. The design is converged; assembly is the work ahead.
No data on the internet is certain by nature. A small nonprofit changes its phone and nobody updates the website; a pantry moves; a program's hours drift. So the contract does not chase certainty about any single field. It chases the thing a caregiver actually needs: the right service, reachable, plausibly applicable, in the right place.
Five records for one pantry become one rich entry: phone from one source, hours from another, services from a third. Consolidation never deletes; conflicts are kept and explained.
A number can change tomorrow. What holds value is what they do, who they serve, where, and how you reach them. That is where the work concentrates.
We never lose where a fact came from. We just don’t organize the product around it: provenance is a byproduct of doing the merge right, not the point.
Every component the product needs already exists somewhere in our corpus. Nothing reads it all together yet. Every independent review of the corpus reached the same diagnosis: the bottleneck is not more data, it is assembly.
The four layers (facilities ~528K, nonprofits ~308K, food/meal records ~213K, benefit programs ~163K) each resolved in isolation. A food pantry that is also a nonprofit that also runs a benefits program is three unlinked cards with split services, contacts, and reviews. Enrichment (contacts, service areas, eligibility, first-party facts) sits in separate overlays, never folded into one per-entity record. Closing that gap is the whole job below.
Records flow left to right: canonicalize what we have, resolve identity into five grains, turn evidence into typed service offerings, then fold everything into a serving pool that a caregiver query reads. The sequence is deliberate: design locked first assembly lands incrementally gated before it serves.
The contract keeps four zones at their proper grains and links them with typed relationships. It never collapses them into one flat table. Identity answers “who is this?”; offerings answer “what help, where, on what terms?” Those are different questions, so they get different graphs.
Easy when they share a license number or exact address. Genuinely hard when it’s “ABC Home Care, Reno” vs “ABC Home Care, Sparks”. The contract separates proposing a merge from applying one, and never merges on evidence that cannot route a person.
There is no miracle. You have a set of services and eligibility, and the only way to help someone is to match them to the closest, most applicable option for their needs. So the whole system reduces to one honest operation: intersect the person’s tags with the endpoints’ tags, and rank what actually fits.
Every place we can route to carries tags: what service, for whom, where, on what terms, how to reach it. Those tags come from the data we mined, not from a wish list.
Some tags they choose explicitly (“overnight respite, my father, this ZIP”); some are already wired from their profile if they filled it in. Their situation is the intersection of those tags.
We can only match to what exists. The set of matching labels is defined by the datasets, not by invented scenarios. You cannot route a need that has no endpoint behind it.
This is why the taxonomy is open rather than a fixed list, why eligibility is discovered before it is extracted, and why the eval is grounded in real tag combinations, not hand-written “what if.” The direction below makes each of those concrete.
These are the places a data mart quietly harms a caregiver. Each is a hard rule the contract has to make executable: an enforced check, not a label in prose.
A directory is a source we fully mine, never a destination we surface. Even the good ones (Alzheimer’s Association, Aging in Place, Senior Care) get harvested completely into our own index: if we pulled 500 of 1,000 organizations, we go back for the other 500, and mark whatever we missed. But we never hand a caregiver a link to a directory, because that just restarts the directory-hopping they came to us to escape. We take people to endpoints, the place service is actually delivered. We become the directory-of-record. (Predatory lead-gen and consent-before-handoff stay a secondary guard, not the sorting axis.)
A regional service with no published area is indexed under its state so it can still be found, but a state floor is recall, not a claim. Only explicit ZIP / county / polygon / radius evidence can say “serves your area.” A nearby office is not coverage. The claim level (1 to 7) is a hard column, and weak levels can never render as a positive local claim.
We don’t presume the eligibility criteria. Two sweeps: first discover the dimensions that exist from our own corpus and a scan of what eligibility exists for caregivers and the elderly (religion-preference, minority or LGBTQ focus, veteran or dependent, income, diagnosis, membership, geography). Then extract every eligibility signal from the corpus against those dimensions, with the right subject (“spouse of a veteran” is not “veteran”). Presentation stays advisory: quote-first, ceiling label “May fit; check eligibility,” never “you qualify.”
A fact ledger accounts for every source fact by exhaustive cross-check: anything missing surfaces as an error. Consolidation can demote or re-scope, never silently drop. Scope can’t widen (an org’s fact can’t become a site’s), a contaminated contact can’t be made safe by a merge, and the same inputs always rebuild to an identical checksum.
Cheap-value-first. The first two moves reuse what we already hold; the only new compute is one embedding run and a small measured model pass.
The database schema, its fixed vocabularies, and a test harness where every prohibited row is rejected with the expected error, not merely absent from fixtures. in rebuild - an earlier draft passed self-checks but did not reject all prohibited cases, so the gates are being rebuilt around explicit rejections.
Apply the ~15K already-judged merges through the guards; run rule-based identity matching across the four layers on issued IDs and endpoint intersections; a dense-vector (Qwen3-Embedding) recall pass over rich description text on the corpus host to surface candidates string-matching misses; a richer-evidence re-judge of the 67,125 pairs previously judged “can’t tell.” In parallel, the two eligibility sweeps (discover, then extract).
Materialize the offering-grain pool and populate the service taxonomy the data reveals (deterministic rules first, then a small model pass on the remainder). Publish as a shadow release and run it against caregiver scenarios grounded in real tags (dozens for smoke-testing, ~100 before promotion): broker-capture, false-local-claim, and wrong-service traps, before anything reaches a person.
The through-line: the product is a tag-intersection matcher over a fully-mined, endpoint-indexed, data-driven label space. Categories emerge from the data; directories are mined into it; a person is a tag-intersection; we route to endpoints.
Not 28, not 38. overnight_respite goes in because it is real; a category-emergence
sweep proposes the rest. The contract gates the current set and grows by version, never by a
silent recount.
Discover the dimensions that exist (from our corpus and a speculative web scan), then extract every eligibility signal from what we captured, with correct subject. Presentation stays advisory. It is two corpus sweeps, not a prioritized queue.
Mine every directory completely into our index (go back for the unmined remainder); never surface one as a result; take people to endpoints. The axis is endpoint-vs-directory, not SEO-vs-honest.
A person’s situation is an intersection of tags (explicit plus profile); we can only match to what exists in the data. The eval validates matching over real tag combinations; scenarios are welcome but must be grounded in the actual tag space.