07 Sql Query Layer
Agent SQL Query Layer
Section titled “Agent SQL Query Layer”Status: SHARP / PARTIAL RUNTIME. Global SQL contract, generated catalog, and provenance explain surface are implemented. Clinical trials is the first atomically promoted query family; remaining families still publish in place and are not last-known-good protected. Denoising state: sharp (noise -> rough -> sharp -> converged) Updated: 2026-07-24
Purpose
Section titled “Purpose”Specify the only consumer interface. There is no API: agents connect to the database and read stable, documented q_* models. SQL is the contract.
Decided Model
Section titled “Decided Model”- Consumers are read-only. Agents get
SELECT-only access to theq_*schema. All corrective writes happen via the curation decision log (05-agentic-curation-and-overrides.md), never directly againstq_*. q_prefix = the agent query layer. Internal source/normalized/evidence/canonical assets are not part of the consumer contract and may change freely; onlyq_*is stable.- Self-describing database without duplicate truth.
q_catalogis generated from Postgres catalogs/comments plus checked-in contract metadata; it is not a hand-maintained dictionary table. - Provenance, not blanket row-lineage. Pipeline/table/column lineage belongs in Dagster metadata and optional OpenLineage export. Agent-facing trust uses
q_provenance: a generated explain view over immutable source artifacts, extraction activities, evidence claims, resolution/verifier receipts, canonical assertions, and curation overlays when applicable. It is not a separate ledger to manually synchronize. - Search is SQL-native. Trigram, full-text, and vector search are exposed as columns/indexes on
q_*(pg_trgm,tsvector,pgvector), not a separate search service. - Stable names, additive evolution. Prefer adding columns / new versioned models (
q_trials_v2) over breaking changes; deprecate with an overlap window.
flowchart LR Canonical[Canonical quality-passing assets] Query["q_* read models"] Catalog[q_catalog\ngenerated catalog] Provenance[q_provenance\nexplain view] Dagster[Dagster asset metadata\nasset + column lineage] Sources[Immutable source artifacts] Extraction[Extraction runs] Evidence[Evidence claims] Resolution[Resolution/verifier receipts] Curation[Reviewed curation overlays] Assertions[Canonical assertions] Agents[Read-only SQL agents] Canonical --> Query --> Agents Query --> Catalog Query --> Provenance Sources --> Provenance Extraction --> Provenance Evidence --> Provenance Resolution --> Provenance Curation --> Provenance Assertions --> Provenance Query -. transformation lineage .-> Dagster
Materialization and Publication Decision
Section titled “Materialization and Publication Decision”The stable consumer object is a query.q_* view. Its physical backing is an implementation
choice, selected per query family:
- generation table + stable view for a consistency family that needs candidate validation, atomic promotion, and rollback;
- plain view for a cheap projection where recomputation and in-place definition replacement are acceptable;
- materialized view only after profiling proves stored results are useful and its refresh/index contract is explicit;
- table for a large append-only or asset-written projection.
This separates performance from publication safety. A materialized view stores results but does not
by itself provide a validated multi-model promotion boundary. PostgreSQL materialized views are
refreshed explicitly and do not support CREATE OR REPLACE; use them when measured query cost
justifies that lifecycle, not as a blanket default.
(PostgreSQL materialized views,
CREATE MATERIALIZED VIEW)
Current runtime truth:
- the seventeen-model clinical-trials family uses immutable generation tables behind stable views;
q_catalog,q_provenance, and the remaining domain query models are plain views published in place;- no non-trial family may claim last-known-good protection until it adopts the generation protocol and passes the same failure-injection test.
Atomic serving generations
Section titled “Atomic serving generations”clinical_trials is the first implemented publication family:
- one non-subsettable Dagster multi-asset freezes all seventeen checked-in SELECTs into temporary candidate tables under one repeatable-read transaction and a family advisory lock;
- primary keys, physical nullability/allowed-value constraints, schema contracts, provenance, row-count, internal/owner-spine references, source-group/endpoint uniqueness, and result-group, endpoint, and arm-link consistency are checked before serving changes;
- the candidate is copied into a uniquely named retained generation schema whose tables reject insert, update, delete, and truncate operations;
- all stable
query.q_trial*views and the oneops.query_publication_headspointer change in the same transaction; - any exception rolls back the candidate, generation, view changes, head, and event receipt, so the prior generation remains served;
- an explicit rollback repoints the complete family to a retained, mutation-protected generation in one transaction, but refuses a target whose contract versions differ from the current family.
ops.query_publication_generations stores immutable manifests,
ops.query_publication_heads stores the active/previous pointer, and
ops.query_publication_events records promotions and rollbacks. Generation retention/pruning and
adoption by other families remain operational follow-up; no automatic pruning runs today.
Physical namespace and access contract
Section titled “Physical namespace and access contract”All consumer objects live in a dedicated database schema named query.
query.q_trialsquery.q_drug_approvalsquery.q_publication_evidencequery.q_catalogquery.q_provenanceThe q_ prefix remains part of every model name even inside the query schema. This makes exported dumps, copied result sets, and provenance receipts self-describing.
Access rules:
- agent roles receive
USAGEonqueryandSELECTon approvedq_*objects only; - agent roles do not receive write privileges on source, evidence, canonical, or query objects;
- curation override writes use the curation decision-log contract in
05-agentic-curation-and-overrides.md, not ad hoc updates toq_*; - indexes are part of the contract when they enable promised search/filter behavior.
Global q_* Registry Seed
Section titled “Global q_* Registry Seed”This section is a registry, not duplicate ownership. 07 owns the global mechanics (query schema, q_catalog, q_provenance, access rules, metadata/provenance contract). Domain slices own the row grains, semantics, and column-level contracts for their q_* families; the registry only prevents naming drift across docs.
q_trials -- one row per trial; denormalized headline factsq_trial_interventions -- resolved interventions per trial (drug | ncit concept)q_trial_endpoints -- endpoints / outcome measures per trialq_trial_outcomes -- reported outcomes per trial armq_trial_eligibility -- structured eligibility per trialq_regulatory_product_protections -- source-scoped patent/exclusivity records (owned by 22-slice-regulatory-approvals.md)q_drugs -- canonical drug facts (owned by 29-slice-drug-identity.md)q_diseases -- canonical disease facts + hierarchy (owned by 30-slice-disease-biomarker-identity.md)q_targets -- canonical target facts (owned by 31-slice-target-technology-identity.md)q_technologies -- canonical modality/technology facts (owned by 31-slice-target-technology-identity.md)q_endpoints -- canonical endpoint catalog (owned by 32-slice-endpoint-adverse-event-identity.md)q_adverse_event_terms -- standardized adverse-event terms (owned by 32-slice-endpoint-adverse-event-identity.md)q_ae_grade_vocabulary -- CTCAE grade bands, separate from seriousness (owned by 32)q_organisations -- canonical organisation facts (owned by 26-slice-organisation-intelligence.md)q_development_programs -- current contextual therapeutic-development state (owned by 33-slice-development-landscapes.md)q_epidemiology_observations -- full-grain disease-burden observations (owned by 34-slice-epidemiology.md)q_product_sales -- source-reported product commercial observations (owned by 35-slice-commercial-intelligence.md)q_catalog -- generated catalog of q_* models/columns/comments/contractsq_provenance -- explain surface -> source/evidence/resolution-verifier/canonical/curation-overlay receipts(Slice-specific models are defined and owned in their slice docs, not here. Cross-doc naming is reconciled as follows so global query, gates, and tests agree:
- Regulatory approvals own
q_drug_approvals(one approval),q_approval_indications(one indication assertion), and the downstream meaning ofresolved_approval_key(s). They are sibling models at different grains, not renames (22-slice-regulatory-approvals.md). - Publications own
q_publication_evidence(broad evidence search) andq_publication_outcomes(one endpoint/group/statistic).q_publication_outcomesis a sharper-grain sibling ofq_publication_evidence, not a replacement (23-slice-publications.md). - Clinical trials own
q_trials, the downstream meaning ofresolved_trial_key(s), andq_publications-adjacent links viaq_trial_references;q_publicationsitself is owned by the publications slice (21/23). - Discovery/search owns
q_discovery_chunksand the otherq_discovery_*/q_search_*models;resolved_entity_keysis only a reference union over keys owned by other slice/spine docs, not a new identity namespace (27-slice-discovery-search.md). - Standard of care owns
q_standard_of_care_recommendations, the otherq_soc_*models,soc_key, andapproach_key; news ownsq_news_events; organisation intelligence ownsq_organisations-family models and the downstream meaning ofresolved_org_key(s). - Drug identity owns the
q_drugsfamily (q_drugs,q_drug_aliases,q_drug_external_ids,q_drug_brands,q_drug_regimens) and the canonical meaning ofresolved_drug_key(s)(29-slice-drug-identity.md).q_diseases/q_biomarkersfamilies are owned by30-slice-disease-biomarker-identity.md, which also defines the canonical meaning ofresolved_disease_key(s),resolved_biomarker_key(s),segment_key, andtreatment_line_key. Target/technology identity ownsq_targets,q_target_aliases,q_drug_target_actions,q_technologies,q_technology_hierarchy,q_drug_technologies,q_payloads, andq_drug_payloads, plus the canonical meaning ofresolved_target_key(s)andresolved_technology_key(s)(31-slice-target-technology-identity.md). Endpoint/adverse-event identity ownsq_endpoints,q_endpoint_groups,q_adverse_event_terms, andq_ae_grade_vocabulary, plus the canonical meaning ofcanonical_endpoint_keyandresolved_ae_term_key(s)(32-slice-endpoint-adverse-event-identity.md); trials/publications/SOC reference these keys rather than minting endpoint identity, and keep regulatory seriousness separate from CTCAE grade. - Development programs owns
q_development_programs,q_development_program_state_history,q_development_program_milestones,q_development_program_evidence, andq_emerging_clinical_evidence. Drug identity does not own phase or development status (33-slice-development-landscapes.md, ADR 0008). - Epidemiology owns
q_epidemiology_observations,q_epidemiology_series, andq_disease_epidemiology_summary(34-slice-epidemiology.md). Commercial intelligence ownsq_product_salesandq_product_commercial_summary(35-slice-commercial-intelligence.md). Regulatory approvals ownsq_regulatory_product_protections; commercial summaries may project its canonical facts without duplicating ownership.
Any example or fixture in 08/10 must reference one of these owned model names.)
Query-family ownership boundary
Section titled “Query-family ownership boundary”| Query surface | Producing owner | Role of this doc |
|---|---|---|
q_catalog | 07-sql-query-layer.md | Own generated catalog semantics and required metadata fields. |
q_provenance | 07-sql-query-layer.md | Own global explain-view semantics over provenance/evidence/resolution/curation receipts. |
Clinical-trial q_* family | 21-slice-clinical-trials.md | Register names and global contract expectations only. |
Regulatory q_* family | 22-slice-regulatory-approvals.md | Register names and global contract expectations only. |
Publication q_* family | 23-slice-publications.md | Register names and global contract expectations only. |
News/intelligence q_* family | 24-slice-news-intelligence.md | Register names and global contract expectations only. |
Standard-of-care q_* family | 25-slice-standard-of-care.md | Register names and global contract expectations only. |
Organisation q_* family | 26-slice-organisation-intelligence.md | Register names and global contract expectations only. |
Discovery/search q_* family | 27-slice-discovery-search.md | Register names and global contract expectations only. |
Forecasting/TPP support q_* family | 28-slice-forecasting-tpp.md | Register names and global contract expectations only. |
Foundational identity q_* families | 29–32 | Register names and shared-key contract expectations only. |
Development-program/landscape q_* family | 33-slice-development-landscapes.md | Register names and global contract expectations only. |
Epidemiology q_* family | 34-slice-epidemiology.md | Register names and global contract expectations only. |
Commercial-intelligence q_* family | 35-slice-commercial-intelligence.md | Register names and global contract expectations only. |
Metadata responsibilities (decided)
Section titled “Metadata responsibilities (decided)”Do not overload one table with every kind of metadata.
| Concern | Source of truth | Agent-facing surface | Why |
|---|---|---|---|
| Table/column existence, type, nullability, comments | Postgres information_schema / catalogs and COMMENT ON TABLE/COLUMN | q_catalog generated view | The database already knows physical shape and supports comments; duplicating this by hand creates drift. (https://www.postgresql.org/docs/current/information-schema.html, https://www.postgresql.org/docs/current/sql-comment.html) |
| Asset/materialization lineage | Dagster asset graph and materialization metadata | Dagster UI/metadata; optional exported metadata | Dagster assets natively model upstream/downstream dependencies and materializations. (https://docs.dagster.io/guides/build/assets) |
| Column-level transformation lineage | Dagster TableColumnLineage metadata and/or OpenLineage column-lineage facet | Dagster/OpenLineage catalog, not normal agent SQL | Column lineage is transformation metadata, not domain evidence. Dagster has table schema/column-lineage metadata; OpenLineage has a column-lineage facet for dataset fields. (https://docs.dagster.io/api/dagster/metadata, https://openlineage.io/docs/spec/facets/dataset-facets/column_lineage_facet/) |
| Source/evidence/resolution/curation trust for facts | Source artifacts, extraction runs, evidence claims, resolution/verifier receipts, canonical assertions, curation overlays when applicable | q_provenance generated explain view | Agents need receipts: source locator, authority, extractor, verifier state, curation review state when an override exists. This is domain provenance, closer to W3C PROV’s entity/activity/agent framing than to database schema metadata. (https://www.w3.org/TR/prov-overview/) |
q_catalog generated view (decided)
Section titled “q_catalog generated view (decided)”q_catalog is a read-only generated catalog view that makes the SQL layer self-discoverable. It has
one row per published q_* model column and combines:
- Postgres physical metadata from
information_schemaand system catalogs; - Postgres table/column comments;
ops.query_contract_columns, regenerated by the Dagsterops.query_contract_metadataasset from checked-incontracts_schema/*.yaml.
The YAML contracts are the executable source of grain, stable row key, owner, closed enum,
provenance policy, version, and deprecation state. Postgres is the executable source of physical
shape. Product docs explain semantics but are not parsed at runtime. Unregistered q_* relations
remain visible with null contract fields and fail the blocking catalog_contract_coverage check.
| Column | Type | Required | Meaning |
|---|---|---|---|
model_schema | text | yes | Always query unless a future warehouse dialect forces a different namespace. |
model_name | text | yes | Published model name, e.g. q_trials. |
column_name | text | yes | Published column name. |
ordinal_position | integer | yes | Stable display/order position. |
data_type | text | yes | SQL type family exposed to agents. |
udt_name | text | no | Postgres-specific underlying type where useful. |
is_nullable | boolean | yes | Contracted nullability. |
is_primary_key_part | boolean | yes | Whether the column participates in the stable row key. |
grain | text | yes | Row grain for the model, repeated on every column for easy agent discovery. |
allowed_values | text[] | no | Small closed enum values, if applicable. |
description | text | yes | Human-readable column definition. |
owner_slice | text | yes | Slice responsible for the column contract. |
provenance_required | boolean | yes | Whether non-null values need row-level or field-level provenance in q_provenance. |
provenance_grain | text | yes | none, row, field, or bundle. bundle means a stable provenance_key expands into multiple receipts. |
comment_source | text | yes | postgres_comment, contract_metadata, or generated. |
asset_key | text[] | yes | Dagster query asset that owns the column. |
contract_version | text | yes | Version in which the column contract is active. |
contract_status | text | yes | active or deprecated. |
introduced_at | timestamptz | yes | Explicit contract date, version date, or the catalog-baseline date for older undated contracts. |
deprecated_after | date | no | Earliest removal date after overlap, if deprecated. |
Contract rules:
- every published
q_*column must have exactly one active catalog row; q_catalogmust not describe internal source/evidence/canonical tables;- additive columns are allowed only when comments and contract metadata appear in the same change;
- removed or renamed columns require a versioned successor model or a deprecation overlap window.
The catalog intentionally does not invent a generic semantic-type or index-contract language before
the repository has an executable consumer for it. Units, large biomedical vocabularies, and search
behavior remain in owning column comments, vocabulary relations, and query recipes. Small closed
enums use allowed_values. Physical performance indexes remain checked-in SQL and database
catalog facts; adding a stable agent-facing index contract later requires a real checker in the
same change.
q_provenance explain view (decided)
Section titled “q_provenance explain view (decided)”q_provenance is not a monolithic lineage ledger and not a hand-maintained sidecar. It is a generated/read-only SQL explain view over first-class domain provenance tables. Its conceptual shape follows W3C PROV: entities (source artifacts, evidence claims, resolution candidates, verifier receipts, canonical assertions, curation overlays, and query facts), activities (ingestion, extraction, resolution, verification, curation review, materialization), and agents (source systems, extractors, LLM/model/prompt versions, curator agents, and human reviewers). This does not require RDF/PROV-O storage in v1; it requires the relational model to keep the same distinctions. (https://www.w3.org/TR/prov-overview/, https://www.w3.org/TR/prov-dm/)
Where / why / how split
Section titled “Where / why / how split”The word “lineage” overloaded too many jobs, so the greenfield contract splits it:
| Question | Owner | Agent SQL surface | Notes |
|---|---|---|---|
| Where did the value come from? | source artifact + source locator | q_provenance | Exact immutable source snapshot/document/API row/span/table/page/payload path. A live URL alone is never enough. |
| Why is this value trustworthy? | evidence claim + resolution/verifier receipt + canonical assertion + curation overlay if applicable | q_provenance | Receipts for source authority, assertion state, verifier basis, curation review state, and conflict/supersession status. |
| How did pipeline code transform it? | Dagster asset graph, materialization metadata, column lineage; optional OpenLineage export | Dagster/OpenLineage, not normal agent SQL | This is transformation lineage. Dagster has typed metadata including table schema/column lineage; OpenLineage has dataset facets such as column-level lineage. (https://docs.dagster.io/api/dagster/metadata, https://openlineage.io/docs/spec/facets/dataset-facets/column_lineage_facet/) |
q_provenance therefore answers:
For this q_* row or semantic fact, which immutable source artifact, evidence claim,resolution/verifier receipt, canonical assertion, and optional curation overlay make it publishable?It deliberately does not answer:
Which upstream table columns produced this SQL expression?That second question belongs to Dagster/OpenLineage column lineage.
First-class provenance tables behind the view
Section titled “First-class provenance tables behind the view”The generated view expands the following durable nouns. Exact physical schema can be refined per slice, but the concepts must exist before high-impact q_* facts publish.
| Table / asset concept | Grain | Required responsibility |
|---|---|---|
provenance.source_artifacts | one immutable source snapshot, document, release, or API payload | Store source_artifact_key, source family, source native id/version/release/snapshot id, immutable storage URI, content hash + algorithm, source URL if any, observed/fetched timestamps, and retrieval metadata. |
provenance.extraction_runs | one parser/LLM/verifier extraction activity over one artifact or partition | Store extractor code version, prompt/schema/model version where applicable, run id, started/ended timestamps, and deterministic config. |
evidence.evidence_claims | one source-grounded claim extracted from an artifact | Store claim type, subject candidate, claim payload, source locator, source authority tier, extraction run id, and claim state. |
resolution.resolution_candidates | one proposed link from source mention/claim to canonical subject | Store candidate target, basis category, verifier status, ambiguity set, and acceptance/supersession state. |
curation.decision_events | one append-only curator-agent/human-reviewed overlay event | Store actor, decision type, rationale, review state, precedence, idempotency key, supersession link, and affected subject/assertion. |
canonical.canonical_assertions | one effective quality-passing fact or relationship | Store canonical subject, assertion type, value payload, temporal validity, effective state, and owning canonical asset. |
provenance.assertion_provenance_links | one receipt link from canonical/query fact to its support | Join assertions to evidence claims, source artifacts, extraction runs, accepted inference decisions, resolution/verifier receipts, and curation overlays when applicable with role and semantic fact_path. |
This table set keeps domain provenance normalized and queryable without forcing every q_* row to carry dozens of evidence columns. It also lets reviewed curation overlays change effective truth without rewriting immutable source artifacts or historical extraction runs.
Bundle-oriented provenance
Section titled “Bundle-oriented provenance”q_* models should remain readable. Each row has one stable scalar key that maps to
q_provenance.q_row_key; high-impact rows or facts may also carry a compact provenance_key that
represents an explanation bundle. q_provenance expands that key into one or more receipts.
For a single-column primary key, that column is the provenance row key by default. A model with a
natural composite key must expose a deterministic scalar relation key and declare it as
provenance_row_key in the checked-in contract. The provenance gate fails closed when a composite
contract omits this mapping; it never silently uses only the first key component.
query.q_trial_outcomes.provenance_key = 7b3d... -> primary registry result claim -> supporting publication claim -> accepted endpoint-resolution/verifier receipt -> canonical outcome assertion -> Dagster materialization run idUse q_catalog.provenance_grain to declare required coverage:
| Grain | Meaning |
|---|---|
none | Convenience/derived/display value that does not need direct receipts. |
row | One receipt bundle explains the row as a whole. |
field | Specific high-impact scalar fields require their own semantic receipt. |
bundle | A row or fact carries a stable provenance_key that expands into multiple receipts. |
q_provenance columns
Section titled “q_provenance columns”q_provenance has one or more rows per provenance-bearing q_* row/fact. It does not require every low-risk convenience column to explode into sidecar rows; q_catalog.provenance_required and q_catalog.provenance_grain define where provenance is mandatory.
| Column | Type | Required | Meaning |
|---|---|---|---|
provenance_id | uuid | yes | Stable generated provenance row id. |
q_model_name | text | yes | Published model name, e.g. q_trials. |
q_row_key | text | yes | Stable row key used by the model. |
q_row_key_hash | text | yes | Hash for compact joins and drift checks. |
fact_path | text | no | Semantic path to the fact being explained; null means row-level. Use stable business paths, not brittle JSON array indexes. |
receipt_kind | text | yes | source_artifact, extraction_run, evidence_claim, resolution_candidate, verifier_receipt, inference_decision, canonical_assertion, curation_overlay, materialization, or search_source. |
activity_kind | text | no | ingestion, extraction, normalization, resolution, verification, curation_review, canonicalization, query_materialization, or search_projection. |
provenance_role | text | yes | primary, supporting, conflicting, superseded, curation_overlay, or search_source. |
required_for_publication | boolean | yes | Whether this receipt is part of the complete gate-required bundle for the row/fact. |
receipt_status | text | yes | active, superseded, rejected, warning_only, or quarantined. |
provenance_key | uuid | no | Evidence/explanation bundle key when multiple receipts are grouped. |
canonical_asset_key | text[] | no | Dagster asset key for the canonical assertion source. |
canonical_assertion_id | uuid | no | Effective assertion behind the visible row/value. |
evidence_claim_id | uuid | no | Source-grounded evidence claim behind the assertion. |
curation_decision_id | text | no | Opaque effective reviewed curation/override decision id, if applicable. |
resolution_candidate_id | uuid | no | Resolution record used to link a source mention to a canonical subject. |
extraction_run_id | uuid | no | Extraction/verifier activity that produced or checked the claim. |
inference_decision_id | uuid | no | Append-only accepted decision authorizing a projected inference value. |
inference_decision_state | text | no | Decision state retained by the inference lifecycle. Published projected values require accepted. |
inference_policy_key, inference_policy_revision | text | no | Deterministic acceptance policy that authorized reuse/projection. |
inference_attempt_id | uuid | no | Immutable provider attempt selected by the decision. |
inference_profile_key, inference_profile_revision | text | no | Execution profile snapshot identity for the attempt. |
inference_request_key | text | no | Provider-independent semantic request identity. |
inference_task_key, inference_contract_revision, inference_contract_hash | text | no | Exact task contract governing the projected value. |
source_artifact_key | text | no | Immutable source snapshot/document/version key. |
source_immutable_uri | text | no | Internal immutable storage URI; required for document/payload-derived claims. |
source_content_hash | text | no | Hash/checksum of the exact artifact used. |
source_locator | jsonb | no | Row, section, table, span, page, URL, API id, or payload path locator within the artifact. |
source_authority_tier | text | no | Claim-specific trust tier used by quality gates. |
assertion_state | text | yes | accepted, agent_verified, curation_override, provisional, warning_only, etc. |
review_state | text | no | Curation review state when receipt_kind='curation_overlay', e.g. not_required, pending_human_review, human_approved, human_rejected. |
resolution_basis | text | no | exact, cross_reference, context_verified, fuzzy_llm, reviewed_curation_override, etc. |
extractor_version | text | no | Deterministic parser / LLM extractor / prompt schema version. |
materialization_run_id | text | yes | Dagster run id that produced the visible row. |
observed_at | timestamptz | no | Source observation time. |
valid_from | date | no | Start of asserted validity when temporal. |
valid_to | date | no | End of asserted validity when temporal. |
At least one of canonical_assertion_id, evidence_claim_id, or source_artifact_key must be present on each receipt row. A provenance-required row/fact is publishable only when the complete receipt set required by q_catalog.provenance_grain, the source family, and the gate contract is present. High-impact canonical facts must include source artifact, extraction run, evidence, resolution/verifier, and canonical assertion receipts; curation receipts are required when an override affects the fact. Document/payload-derived facts must include immutable artifact URI and content hash. Discovery/search rows must trace to the source q_* row or content item they index.
Semantic fact_path examples
Section titled “Semantic fact_path examples”fact_path names the business fact, not a fragile physical JSON path. Examples:
trial.statustrial_outcome:endpoint=orr:group=experimental:attr=p_valueapproval_indication:drug=trastuzumab:disease=breast_cancer:attr=label_textpublication_outcome:pmid=123:endpoint=pfs:arm=control:attr=hazard_ratioorganisation_relationship:parent=pfizer:child=seagen:attr=valid_fromThe slice docs define allowed fact-path conventions for their query models. A path must remain stable across harmless physical reshaping of arrays, tables, or SQL implementation.
Generated q_fact_path_contract
Section titled “Generated q_fact_path_contract”Field-level provenance needs a generated contract so checks can compare required semantic paths against emitted receipts. The implementation may expose this as a view or as rows inside the same contract registry that generates q_catalog; either way, provenance_coverage must be able to query it.
| Column | Meaning |
|---|---|
model_name | Published q_* model. |
fact_path_pattern | Exact path or parameterized pattern, e.g. trial_outcome:*:attr=p_value. |
column_names | One or more columns whose values require this path. |
required_receipt_kinds | Receipt kinds required for publication, e.g. source artifact + extraction run + evidence claim + verifier receipt. |
source_authority_rule | Allowed source authority tiers for this fact path. |
gate_ids | Gate ids that enforce the path. |
contract_version | Version of the fact-path contract. |
Query row design rule
Section titled “Query row design rule”Each q_* row should include a compact stable row key and, where useful, an explanation handle such as provenance_key or canonical assertion id. The row itself stays readable; detailed receipts live in q_provenance.
select t.trial_key, t.brief_title, t.trial_status, p.source_authority_tier, p.source_locatorfrom query.q_trials tjoin query.q_provenance p on p.q_model_name = 'q_trials' and p.q_row_key = t.trial_keywhere t.trial_key = 'NCT01234567' and (p.fact_path is null or p.fact_path = 'trial.status');Prospective vs retrospective provenance
Section titled “Prospective vs retrospective provenance”- Prospective provenance is the contract/check expectation:
q_catalog.provenance_required,provenance_grain, source-authority rules, and gate factory configuration. - Retrospective provenance is what actually happened for a specific row/fact: the
q_provenancereceipts emitted for a materialization run.
Checks compare the two. If the contract says a fact requires bundle provenance and the materialized row has no complete bundle, publication fails.
Global vs slice-local provenance views
Section titled “Global vs slice-local provenance views”There is one authoritative global q_provenance explain surface. Slice docs may define convenience views such as q_trial_provenance or q_regulatory_provenance, but they must be simple filters/projections over q_provenance; they are not separate stores. Agents can always fall back to:
select *from query.q_provenancewhere q_model_name = 'q_trials' and q_row_key = :row_key;Per-family q_* catalog contract
Section titled “Per-family q_* catalog contract”Each slice doc defines its query-family contract. Checked-in contracts, Postgres metadata, and
database comments are compiled into q_catalog; the prose remains the owning semantic
explanation rather than a second runtime registry.
For every q_* model, specify:
- Purpose — what agent question the model answers.
- Grain — exactly one row per what.
- Stable row key — columns or expression used for
q_row_key. - Required columns — name, type, nullability, semantic type, definition.
- Search affordances — filters, trigram columns,
tsvector, vector embeddings, facets, and required indexes. - Provenance rule — which rows/facts require
q_provenance, whichprovenance_grainapplies, and which source/evidence/resolution-verifier/canonical/curation-overlay ids must appear. - Refresh policy — view/materialized view/table plus cadence/trigger.
- Deprecation policy — how breaking changes are versioned.
This keeps 07 global and lets entity resolution/domain modelling stay slice-local.
SQL Contract Checks
Section titled “SQL Contract Checks”- existence: every catalogued
q_*table/view exists; - shape: column names, types, nullability, and grain match
q_catalog; - catalog generation:
q_catalogmatches actual Postgres schema/comments plus checked-in contract metadata; - provenance: every
q_*row/fact markedprovenance_requiredresolves to the completeq_provenancereceipt set required byq_catalog.provenance_grain,q_fact_path_contract, and the relevant gate ids; - publication gate: only quality-passing assertions plus reviewed curation overlays appear (see
08-contracts-and-quality.md).
Drift in any of the above is a breaking-change failure.
Locked Runtime Defaults
Section titled “Locked Runtime Defaults”- Postgres is the query engine. A warehouse is a future deployment decision only if measured
scale or workload isolation requires it; it does not alter the
q_*SQL contract. - Each model declares its physical materialization and publication-family policy. Concurrent materialized-view refresh is allowed only when its qualifying unique index is part of the checked contract; generation-backed families promote only as complete non-subsettable units.
contract_versionis an opaque, non-empty model contract identifier. Consumers compare it for equality, never parse it. It remains stable across compatible refreshes and changes whenever columns, grain, semantics, or provenance obligations change.