> ## Documentation Index
> Fetch the complete documentation index at: https://docs.textql.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Module 3 · Validate Against Your Schema

> The dry run is discovery; validation/validate_tql.py is the mechanical gate. It verifies every governed surface against your warehouse: each logical name resolves, each referenc… (~25 min)

## 2.1 · The dry run — required

```text Prompt theme={null}
Look at the ontology repo, then inspect my warehouse. Pull the information schema for my claims tables and tell me where the ontology's expected table and column names don't match what I actually have. Propose the exact changes to ontology/schema.tql.
```

<Check>
  **You'll see:** Ana discover your schema, diff it against the ontology, and hand you a precise list of fixes — table backings, column names. (A ready-made version of this check lives in `validation/dry-run-prompt.md`.)
</Check>

## 2.2 · Run the validator — required

The dry run is discovery; `validation/validate_tql.py` is the mechanical gate. It verifies every governed surface against your warehouse: each logical name resolves, each referenced column exists, each query compiles. **Ana runs it for you** — no terminal needed:

```text Prompt theme={null}
Run validation/validate_tql.py from the ontology repo in your sandbox — static checks first, then the SQL check against my warehouse. Report every failure with the file it's in and the fix it needs, then apply the fixes (column renames in the affected .tql, table renames in schema.tql only) and re-run until clean.
```

<Check>
  **You'll see:** the typo'd-backing, wrong-alias, and missing-column bug classes caught here — instead of surfacing as wrong numbers in front of stakeholders.
</Check>

<Note>
  **Prefer the terminal?** —

  The same gate runs locally: `python3 validation/validate_tql.py` (static — no warehouse needed) · `--check-sql` (paste the output into Ana: rows = missing columns) · `--dsn "&lt;dsn&gt;" --explain` (live column check + compile test).
</Note>

## 2.3 · Apply the fixes as a PR — required

```text Prompt theme={null}
Make those changes and open a pull request.
```

<Check>
  **You'll see:** Ana edit the files and open a reviewable PR in **your** repo. Every physical table name lives in one place (`ontology/schema.tql`) — re-point it and the metric logic stays put. If you have a real member/patient table, point `person_grain` at it: one line.
</Check>

<Frame caption="Validation lands as a reviewable PR — not silent edits.">
  <img src="https://textqllabs.github.io/workshops/healthcare-starter/assets/hc-m2-pr.png" alt="Schema validation PR" />
</Frame>

<Note>
  **Why this step matters** —

  Every customer's warehouse differs from the reference shape somewhere — a renamed column, a missing table, a different grain. Finding those *before* you trust a number is the difference between a defensible metric and a debugging session in front of stakeholders.
</Note>

## 2.4 · Decide your claim grain & verify your joins — required

Two decisions shape everything downstream, and both are prompts:

```text Prompt theme={null}
Read ontology/notes/claim-grain.md, then inspect my claims tables. Is our model wide (one row per line, header flattened on) or normalized header/line/event? Recommend which table anchors claims, where the cost columns live, and how the member key is reached — and record the decision in databases/[ourschema]/README.md (copy databases/tuva/ as the template).
```

<Check>
  **You'll see:** the grain decision made and written down *before* anything gets edited — it shapes every other step.
</Check>

```text Prompt theme={null}
Per ontology/notes/join-key-verification.md, verify every join the ontology relies on against my warehouse: does the key exist on both sides, what's the overlap rate, and is the grain 1:1 or 1:N? Record each verdict in databases/[ourschema]/README.md and flag any join we shouldn't trust.
```

<Check>
  **You'll see:** a join-by-join verdict list. Even the starter's own demo schema teaches the lesson — there's **no `patient` table** (demographics live on `eligibility`) and codes live in `normalized_code`. Expect quirks like these in yours.
</Check>

```text Prompt theme={null}
Find the dataset-specific literals flagged inline in the .tql files — encounter_type values, normalized_code_type spelling, and the cost basis default (charge vs allowed vs paid) — check each against what's actually in my warehouse, and propose the corrections in the same PR.
```

<Check>
  **You'll see:** the enumerations the validator can't know, corrected from your real data instead of assumed.
</Check>

<Note>
  **The full checklist** —

  This module covers the core; `MIGRATION.md` is the complete 8-step re-point (discover → grain → schema.tql → joins → validator → literals → governance → glossary → goldens). Half a day with warehouse access; most of it is verification, not editing.
</Note>

<Note>
  **Different warehouse dialect?** —

  The starter is authored Redshift-first with BigQuery equivalents inline. On **Databricks, Snowflake, or another engine**, extend the dry-run ask: *"…also flag any Redshift-specific SQL in the .tql surfaces and propose \[dialect] equivalents."* Dialect adaptation rides the same PR loop as schema fixes.
</Note>

### ✅ Checkpoint

* [ ] Ana produced a concrete mismatch list (or confirmed a clean match)
* [ ] The fixes landed as a PR you can review — not silent edits
* [ ] You merged the PR (or know who reviews it)

### Verify the pack’s assumptions against your data

This starter already handles the healthcare cases that break naive ontologies — claim adjustments and reversals, dual-eligible members, capitated and encounter data — but it assumes a representation. Confirm yours matches before you trust the numbers.

```text Prompt theme={null}
Check how our data represents claim adjustments and reversals, dual-eligible members, and capitated / encounter data. Compare each to what the starter ontology assumes, flag any mismatch, and propose the exact fix.
```
