CARE-OS · data-mart serving contract converged 2026-07-09 design locked · assembly in progress

How a caregiver's question becomes one honest answer.

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.

the stance

We optimize for useful answers, not false certainty.

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.

Merge, don’t kill

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.

Applicability over a phone number

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.

Provenance kept, not centered

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.

where we genuinely are

Extraction-rich, assembly-poor.

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.

1.21M
canonical entities, 4 layers
~15K
merges judged, 0 applied
0
cross-layer links
67,356
provider first-party facts

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.

the shape of the work

One spine, one fold.

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.

SOURCE LAYERS facilities · 528K nonprofits · 308K food sites · 213K programs · 163K IDENTITY SPINE 5 grains, within-grain org · site · provider regional_svc · program endpoint intersection phone / addr / domain vector recall, not verdict SERVICES evidence → assertion → offering typed service tags pantry · hot meal respite · transport benefits · legal aid SERVING FOLD grain = offering discovery_resource routable only geo · eligibility honesty-labeled repeatable release the answer canonical data + full provenance stay authoritative underneath: the serving pool is a versioned read model, never a rewrite.
Fig 1 - the assembly pipeline. The raw material is in hand; every stage shown is assembly.
object-relation diagram

What connects to what.

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.

careos_er cluster_identity IDENTITY  ·  who is this real-world thing? cluster_services SERVICES  ·  evidence → assertion → offering cluster_advisory GEOGRAPHY & ELIGIBILITY  ·  advisory: rank & explain, never gate cluster_serving SERVING FOLD  ·  grain = actionable offering identity_node identity_node identity_node_id (PK) grain: org | site | provider | regional_service | program normalized_name · legal_name · dba[] address_key · geocode issued_ids[] · domains[] · phones[] source_layer · data_release_id endpoint_profile endpoint_profile endpoint_profile_id (PK) kind: phone | address | domain normalized_value · match_eligible mask_reason (platform/shared) 2+ agree=near-certain · 0=name floor identity_node->endpoint_profile has physical identity_decision_edge identity_decision_edge (node_a, node_b) (PK) decision_type: same · different · possible_match · terminal · related relation_type (13 typed) evidence · tier · decision_version identity_node->identity_decision_edge pairs identity_component identity_component component_id (PK) guarded union of nodes (single grain) = serve.entity identity_decision_edge->identity_component guarded union serve_entity serve.entity resolved cluster (FK component) serve.entity_relation (typed) identity_component->serve_entity becomes component_guards component_guard_run / _result grain · issued-id conflict · geo HQ/local · parent/branch · jurisdiction ALL pass -> union_application component_guards->identity_component gate service_evidence_unit service_evidence_unit evidence_unit_id (PK) one source record / prose block normalized_text_hash · section service_assertion service_assertion assertion_id (PK) subject (FK) · subject_scope service_type_code (FK, leaf) provider_role · polarity · activity delivery[] · audience[] · access[] · cost[] location/coverage/eligibility/schedule refs evidence_span · confidence · tax_version service_evidence_unit->service_assertion backs service_taxonomy service_taxonomy code (PK) · parent_code · is_leaf ~28 leaves, OPEN/data-driven facets kept separate (not leaves) service_assertion->service_taxonomy typed leaf service_offering service_offering offering_id (PK) rollup per subject/location/ coverage/access context via service_offering_assertion junction service_assertion->service_offering rollup serve_offering serve.offering offering grain · routability derived serve.offering_service (leaf) serve.location · serve.contact_point contact: safe_to_route, not laundered service_offering->serve_offering folds to coverage_for_index coverage_for_index recall only · never a claim the state floor lives here coverage_for_claim coverage_for_claim geo_claim_level 1-7 weak levels never positive "serves county" = L1 only coverage_for_index->coverage_for_claim recall vs claim serve_advisory serve.geo_coverage / eligibility_rule honesty-labeled overlays on offering serve.review_rollup (broker never transfers) coverage_for_claim->serve_advisory geo overlay eligibility_rule eligibility_rule advisory only · quote-first · no binary rule_subject (8, spouse≠veteran) criteria taxonomy (discovered, Amdt 4.2) eligibility_rule->serve_advisory elig overlay serve_entity->serve_offering 1..* access_endpoint access_endpoint (the directory fence) subject: entity OR offering (program intake never laundered to org) owner_type: direct_provider · public_agency · nonprofit · gov_portal · broker · marketplace · directory (quarantined, never surfaced) function · pii_risk · consent · rank_policy route_edge -> END resource, depth 1 serve_entity->access_endpoint access discovery_resource serve.discovery_resource  (the search index) the lean index a caregiver query hits grouped by caregiver_card_group_id excludes quarantined · unroutable · unsafe serve.entity_record = hydration artifact serve_offering->discovery_resource materialize serve_advisory->discovery_resource labels serve_ledger serve.fact_ledger / field_choice every source fact accounted (merge-not-kill) release-pinned · repeatable checksum serve_ledger->serve_offering accounts access_endpoint->discovery_resource filtered / ranked
Fig 2 - the full entity-relationship model, rendered hierarchically. Teal = the identity and serving spine; amber = advisory geography and eligibility; rose = the directory/broker fence. Three contact concepts stay distinct: endpoint_profile (match key, never shown), access_endpoint (route ownership, ranking, quarantine), serve.contact_point (safe display). Scroll sideways to read field detail.
the hardest question

Are these two records the same real place?

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.

candidate pair exact key · endpoint · vector recall endpoint overlap? 2+ endpoints agree phone + address + domain = near-certain 1 endpoint shared strong candidate, corroborate 0 overlap, names/desc only even word-for-word, NOT a merge same_identity guarded union same / different on corroboration possible_match parked, shown separately
Fig 3 - if we can’t find a place by phone, address, or website, we can’t send a person there. Endpoints are both the match key and the routability test.
how a match happens

A person is an intersection of tags.

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.

Endpoints are tag-sets

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.

A person is a tag-intersection

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.

Labels are data-driven

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.

the four fences

Where honesty is enforced, not hoped for.

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.

directory fence

Directories are for mining, not for sending people to.

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.)

geography fence

“Serves your county” must be earned.

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.

eligibility fence

Discover the rules, then extract them. Advisory always.

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.”

merge-not-kill fence

Nothing is lost in consolidation.

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.

the roadmap

Three moves to a gated shadow pool, then promotion.

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.

1

Lock the executable contract

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.

$01-2 sessions
2

Execute merges, cross-layer resolution, eligibility

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).

~$0-67+ 1 GPU embed pass
3

Shadow serving fold, then gate it

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.

~$60fold $0 · services
direction set · 2026-07-10

The four calls, decided.

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.
taxonomy

No canonical count. However many honest categories the data reveals.

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.

eligibility

Two singular sweeps, ASAP, not a ranked family backlog.

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.

directories

A source to fully mine, never a destination to surface.

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.

the eval

Match real tags, not miracle scenarios.

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.

CARE-OS data-mart serving contract - converged plan of 2026-07-09 with amendments 1-4. Diagrams reflect the agreed model; the enforcing implementation is in progress. Caregiver-facing wording shown here is illustrative and pending clinical and legal review. Source of record: docs/data/DATAMART-CONVERGENCE-FINAL-20260709.md.