CancerIndex — AI policy
Status: not implemented in Phase 1. No language model is called anywhere in the platform today;
the ai_answers and entity_embeddings tables exist so that the policy below can be enforced by the
schema when the feature ships (spec §62-66, §158-159, §322).
Principles
- Database-grounded only. An AI answer may only state facts that exist as rows in the CancerIndex database at answer time (observations, curated evidence, approvals, trials, publications, computed metrics). The model receives those rows as context and is instructed to answer exclusively from them. Anything not in the database is answered with "CancerIndex has no data on this" — never with general knowledge.
- Every claim cites. Each sentence that carries a fact must reference the
CI-*id (and provenance) of the row it comes from; the UI renders these as the same source badges used elsewhere. Answers without a resolvable citation are rejected before display. - The label is
ai_generated_synthesis. AI text is displayed with its own category and is never merged with observed, curated or regulatory content (safety labels, CLAUDE.md §3, §12). - No medical advice. Questions asking for diagnosis, prognosis for a person, or treatment choice receive a fixed refusal with pointers to population statistics and to a clinician. Population survival is never phrased as an individual prediction (§325).
- Reconciliation stays deterministic. Models may only propose candidate mappings for the
curation queue (
unresolved_labels.suggested_*); they never create aliases, merge entities or write canonical data (CLAUDE.md §5). - Reproducibility. Every answer is cached in
ai_answerswithmodel,prompt_version,question_hash, thesource_snapshot(ids + values that were shown to the model) anddata_as_of. A cached answer is invalidated when any referenced row changes (change_events). - Privacy. Questions are not stored with user identity; API keys are never sent to a provider; provider calls are server-side only, with the provider recorded per answer.
Answer contract
json
{
"kind": "cancer_summary | ask",
"subjectId": "CI-CAN-00000364",
"answer": {
"text": "…",
"claims": [{ "sentence": 0, "refs": ["epidemiology_observations:1234", "rankings:5678"] }],
"refusals": [],
"limitations": ["No survival data available for this entity (SEER awaiting credentials)."]
},
"model": "provider/model-id",
"promptVersion": "ci-summary-v1",
"sourceSnapshot": { "rows": ["…"] },
"dataAsOf": "2026-09-08T06:30:00Z",
"category": "ai_generated_synthesis"
}Planned implementation (Phase 5)
- Retrieval: SQL over canonical/derived tables first; pgvector (
entity_embeddings, model recorded per row) only for entity discovery, never as a source of facts. - Providers: optional
ANTHROPIC_API_KEY/OPENAI_API_KEY/OPENAI_BASE_URL(.env.example); the platform works fully without them. - Evaluation: a fixture set of questions with expected refusals and citations must pass before the feature is enabled in production.