08 Contracts And Quality
Contracts and Quality Gates
Section titled “Contracts and Quality Gates”Status: IMPLEMENTED CORE / ONE PROTECTED FAMILY. Check factories and core gates are fixture-tested. Clinical trials now validates an isolated seventeen-model candidate and promotes it atomically; other query families remain in-place and unprotected. Declarative automation is not loaded. Live/consumer state: no production-scale or consumer-path proof. Denoising state: sharp (noise -> rough -> sharp -> converged) Updated: 2026-07-24
Purpose
Section titled “Purpose”Define the data-contract and quality-gate architecture: which checks exist, which block, how schema drift is caught, and how only quality-passing data plus any reviewed curation overlays reach the q_* layer. Slice docs enumerate concrete checks; this doc fixes the policy.
Asset checks are the primitive
Section titled “Asset checks are the primitive”Quality is expressed as Dagster asset checks — they verify properties of an asset and can block downstream execution. (https://docs.dagster.io/guides/test/asset-checks)
Two complementary gate mechanisms (decided)
Section titled “Two complementary gate mechanisms (decided)”- In-run blocking —
@asset_check(blocking=True)(orAssetCheckSpec(blocking=True)): a failing check stops downstream materialization within the same run. Use inside a producing job. (https://docs.dagster.io/guides/test/asset-checks) - Candidate-generation gating (implemented for clinical trials) — the complete family is frozen and deterministically checked inside the same database transaction that later promotes its stable views. A failing check raises before the serving head can change.
- Declarative-automation gating (target, not loaded today) —
AutomationCondition.all_deps_blocking_checks_passed()on downstream candidate/promotion assets may later gate other event-driven paths. (https://docs.dagster.io/guides/automate/declarative-automation)
In-run blocking alone stops later assets in one selected job, but an in-place producer may already
have mutated shared state before its checks execute. It is a control-flow gate, not a
last-known-good guarantee. Clinical trials closes that gap with candidate isolation plus one atomic
family promotion; every other family still has the in-place limitation. Model-output and verifier
failures remain normal pipeline quarantine; they do not create or mutate
curation.decision_events.
flowchart TD
Upstream[Upstream asset materialized]
ShapeCheck{Schema / shape check}
EvidenceCheck{Evidence and provenance check}
LLMCheck{Model-output and verifier checks}
CurationCheck{Curation review gate<br/>only when override applies}
Canonical[Canonical asset materializes]
Query["q_* read model refreshes"]
Hold["Previous good q_* state remains served"]
Warn[Warning recorded, publication may continue]
Upstream --> ShapeCheck
ShapeCheck -- fail --> Hold
ShapeCheck -- pass --> EvidenceCheck
EvidenceCheck -- fail --> Hold
EvidenceCheck -- pass --> LLMCheck
LLMCheck -- fail --> Hold
LLMCheck -- pass --> CurationCheck
CurationCheck -- fail --> Hold
CurationCheck -- pass --> Canonical --> Query
Upstream -. non-blocking anomaly .-> Warn -. metadata only .-> Query
Blocking vs warning policy (decided)
Section titled “Blocking vs warning policy (decided)”- Blocking (must pass to publish): schema/shape contract, referential integrity, evidence-presence (every assertion has provenance), immutable source-artifact provenance for document/payload-derived claims, source-authority rules, LLM/schema/verifier gates for model-produced high-impact claims, and curation-review gates for override overlays.
- Warning only (observed, non-blocking): freshness drift within tolerance, distribution/volume anomalies, source coverage gaps such as abstract-only publication evidence, unresolved low-severity curation conflicts.
Layered checks (decided skeleton; slices extend)
Section titled “Layered checks (decided skeleton; slices extend)”- sources.*: reachable, parseable, count-delta in bounds, no duplicate source keys, freshness within SLA.
- normalized.*: required source identifiers present, enums mapped-or-quarantined, valid dates, provenance retained.
- evidence.*: output conforms to deterministic/LLM schema, claim has source locator, source authority tier, source artifact version/snapshot where applicable, extractor/prompt/schema/model version recorded.
- resolution.*: no auto-accept of fuzzy match without deterministic/LLM verifier or allowed exact basis, provenance basis recorded, source authority considered, ambiguous terms routed to the resolution/conflict queue; a curation proposal is created only via the separate curator workflow.
- curation.*: override/suppression proposal has actor + timestamp + rationale; high-impact effective overlay has human review; rejection has reason; supersession references prior decision.
- canonical/query.*: only approved/quality-passing assertions present; announcement-vs-confirmed fact semantics preserved; SQL schema contract holds.
SQL query-layer contract (decided)
Section titled “SQL query-layer contract (decided)”For each q_* model: the table/view exists; column names and types match its checked-in contract;
every physical column has generated catalog metadata for description, grain, owner, closed enum,
version, and provenance policy; every required row/fact resolves to q_provenance. Drift is a
breaking-change failure. (See 07-sql-query-layer.md.)
Cross-Slice Gates Discovered from Slice Denoising
Section titled “Cross-Slice Gates Discovered from Slice Denoising”Regulatory approvals, publications, news, development programs, epidemiology, and commercial intelligence add six shared quality pressures:
- Source authority gate: source trust is claim-specific. A regulator label can publish approved indication text with high authority; a press release can publish an announcement event but should not silently become confirmed regulatory truth.
- Source artifact immutability gate: label, publication, filing, registry, API payload, and article claims must preserve the exact artifact version/snapshot/locator, immutable URI, and content hash used for extraction.
- Announcement-vs-fact gate: event claims must preserve whether the source says something was announced, submitted, accepted, approved, rejected, published, or merely mentioned.
- Contextual-state gate: development phase, clinical activity, regulatory state, ownership, and historical maximum remain orthogonal, temporal, and reproducible from milestones.
- Statistical-comparability gate: epidemiology observations compare only when metric, population, geography, period, unit, denominator, and method are compatible.
- Commercial-observation gate: reported sales preserve product, organisation, geography, period, currency, scale, restatement, and source locator; conversions and summaries remain derived.
Acceptance Criteria Matrix
Section titled “Acceptance Criteria Matrix”These are the cross-slice gates a builder should implement before any q_* model is considered publishable.
| Gate id | Applies to | Blocking when | Warning when | Evidence in docs |
|---|---|---|---|---|
schema_contract | every q_* model | table/view, column, type, or reliable table nullability differs from its checked-in contract | additive column undocumented | 07-sql-query-layer.md |
catalog_contract_coverage | terminal query.q_catalog | a physical q_* column has no checked-in contract row | none | 07-sql-query-layer.md |
referential_integrity | every q_* model carrying a resolved_*_key(s), canonical_endpoint_key, segment_key, treatment_line_key, or other cross-slice owner key | a referenced key value has no matching row in its producing owner q_* model | nullable key absent where optional, or owner row is provisional/superseded | owner docs 21-35 |
provenance_coverage | every provenance-required q_* row/fact | required row/fact has no q_provenance receipt; bundle grain does not expand to complete receipts | provenance exists but lacks optional supporting source/decision metadata | all slice docs |
source_locator | evidence claims | no source artifact/row/span locator | locator exists but source text coverage is partial | trials/publications/news/approvals/SOC |
llm_schema_contract | inference-produced evidence/resolution/verifier outputs | contract revision or acceptance decision missing; parsed output fails schema; invalid enum or required field absent | quarantine rate elevated but below blocking threshold | 06-llm-extraction-and-verification.md |
llm_provider_interface | inference-producing assets | asset bypasses InferenceRuntime or hardcodes vendor SDK/request/schema in pipeline code | provider adapter has degraded feature parity but contract tests pass | 06-llm-extraction-and-verification.md |
llm_verifier_required | high-impact model-produced claims/candidates | claim/candidate lacks accepted deterministic/LLM verifier or exact allowed basis | verifier confidence low but subject can remain provisional/searchable | 06-llm-extraction-and-verification.md |
llm_prompt_version_pinned | inference-producing assets | task contract/profile/route revision floats or is absent | owner metadata is incomplete | 06-llm-extraction-and-verification.md |
llm_cache_idempotency | inference lifecycle | one request key maps to different immutable task/input content, or output is reused without a matching accepted policy decision | rejected-attempt churn above threshold | 06-llm-extraction-and-verification.md |
llm_cost_cap_<task> | inference attempts | completed attempt spend exceeds the check’s reviewed window cap | task approaches budget threshold | 06-llm-extraction-and-verification.md |
source_artifact_immutability | document/API/payload-derived claims | immutable URI, content hash, or source version/snapshot id missing | live URL present but archive/storage metadata incomplete | approvals/publications/news/org/trials |
source_authority | canonical assertions | high-impact assertion lacks acceptable source authority or a reviewed curation overlay | lower-authority source used with marker | 20-pipeline-families.md |
document_version | document-derived claims | source document version/release id missing even if a hash exists | version exists but source family uses weak version semantics | approvals/publications/news/org/trials |
resolution_basis | resolved entity links | fuzzy/semantic match publishes without verifier/reviewed-correction/deterministic basis | accepted but low-confidence or stale | all entity-resolution sections |
curation_effective_state | curation overlays and canonical assertions affected by them | superseded/rejected/unreviewed high-impact curation decision appears active or changes publication | unresolved low-severity curation conflict exists | 05-agentic-curation-and-overrides.md |
curation_review_state | curation overlays | high-impact override/suppression lacks human_approved review state | low-risk auto-reviewed subject is due for audit sample | 05-agentic-curation-and-overrides.md |
announcement_semantics | event claims | announcement, submission, acceptance, approval, rejection, and mention collapse into one status | status is source-specific but mapped to generic enum | news/regulatory/publication slices |
temporal_validity | org/SOC/approval/ownership facts | destructive overwrite loses valid-from/valid-to or observed-at state | temporal precision is low/unknown | organisation/SOC/regulatory slices |
search_provenance | discovery/search projections | search row cannot trace to source q_*, evidence, or content item | search index stale but source row still queryable | 27-slice-discovery-search.md |
downstream_boundary | forecasting/TPP support | API/saved-model/app-engine state enters core data model | optional support model lacks downstream owner note | 28-slice-forecasting-tpp.md |
development_program_semantics | program/context, milestone, state-history, landscape, and emerging-evidence assets | program/context grain drifts; state axes collapse; temporal fold cannot reconcile to milestones; unknown context is defaulted; landscape counts or evidence grains collapse | source context is incomplete but explicitly unknown/provisional | 33-slice-development-landscapes.md |
epidemiology_observation_semantics | epidemiology observations, series, and selected summaries | incompatible metric/statistic/unit/denominator/method contexts mix; projected becomes observed; selection loses its source observation | optional strata or uncertainty is absent in the source | 34-slice-epidemiology.md |
commercial_observation_semantics | product sales, FX receipts, and commercial summaries | period/currency/geography grains collide; reported values are overwritten by conversions; restatement chain breaks; forecast becomes actual | source lacks optional market split or comparable prior period | 35-slice-commercial-intelligence.md |
Reusable check-factory contract (decided)
Section titled “Reusable check-factory contract (decided)”Reusable factories live in src/bioloupe_data/lib/checks/. Dagster asset modules attach those factories to concrete assets; slice docs choose the gate ids and thresholds. This keeps gate semantics consistent while preserving slice-local modelling.
Each factory must accept:
asset_key— Dagster asset key being checked;gate_id— one of the cross-slice gate ids above;severity—blockingorwarning;contract_ref— pointer to a YAML/Python contract object or SQL assertion;slice_nameandowner— for metadata and alert routing;- optional
where_clause/partition_key/sample_strategyfor expensive checks.
Each check result must emit metadata:
- row count checked;
- failing row count;
- sample failing keys/locators, capped;
- contract version;
- source/evidence/canonical asset keys involved;
- remediation hint;
publication_protected; it istruefor the clinical-trials family because the same blocking rules run against an isolated candidate before atomic promotion, andfalsefor current in-place families.
Dagster asset checks can be blocking so failed checks stop downstream assets in the same run; automation conditions can also require all upstream blocking checks to pass before downstream publication. (https://docs.dagster.io/guides/test/asset-checks, https://docs.dagster.io/guides/automate/declarative-automation)
Implementable gate factory matrix
Section titled “Implementable gate factory matrix”| Gate id | Factory | Primary input asset family | Default severity | Implementation sketch | Required fixture |
|---|---|---|---|---|---|
schema_contract | make_schema_contract_check | query.q_* | blocking | Compare the live relation to its checked-in contract for existence, columns, SQL types, and table nullability; PostgreSQL view nullability is not treated as authoritative. | One deliberately drifted model and one valid model. |
catalog_contract_coverage | make_gate_check | query.q_catalog | blocking | Fail any physical q_* column whose generated row lacks checked-in contract metadata. | Registered model and unregistered q_* relation. |
referential_integrity | make_referential_integrity_check | query.q_* | blocking | Explicit consumer-to-owner key declarations left join non-null values to their producing owner q_* model. Nullable unresolved keys remain allowed. | Consumer row whose owner key exists, one dangling key, and one nullable-absent key. |
provenance_coverage | make_provenance_coverage_check | query.q_* | blocking | Use the checked-in contract row-key and provenance policy; left join required rows/facts to q_provenance and fail missing receipts. | Published rows with complete bundle, missing bundle, missing fact_path, and partial provenance. |
source_locator | make_source_locator_check | evidence.* | blocking for canonical-bound claims | Assert evidence claims retain source artifact key and locator shape required by the source family. | Claims with API-row locator, document-span locator, and missing locator. |
llm_schema_contract | planned lifecycle check | evidence.*, resolution.* | blocking for persisted model output | Require a schema-valid attempt plus matching accepted decision before an inference projection publishes. | Valid accepted output, invalid enum, missing field, old-policy decision. |
llm_provider_interface | definitions/import test | evidence.*, resolution.* inference assets | blocking in CI/definitions tests | Ensure assets call InferenceRuntime; provider fake tests cover sync + native batch adapters. | Fake provider matrix and one asset that imports a vendor SDK directly. |
llm_verifier_required | make_llm_verifier_required_check | resolution.*, canonical.* | blocking for high-impact subjects | Require accepted deterministic/LLM verifier or exact basis before fuzzy/model-produced links influence canonical/query facts. | Exact link, verifier-pass, verifier-fail, unverified fuzzy candidate. |
llm_cache_idempotency | planned lifecycle check | provenance.inference_* | blocking for identity collisions or invalid reuse | Assert immutable request/attempt identities and accepted-result reuse under the active acceptance-policy hash. Multiple attempts may legitimately disagree. | Accepted reuse, rejected rerun, profile comparison, policy revision. |
llm_prompt_version_pinned | catalog contract test | inference-producing assets | blocking | Reject missing contract/profile revisions and require retained immutable task revisions. | Active route, missing revision, in-flight retained revision. |
llm_cost_cap_<task> | make_llm_cost_cap_check | inference lifecycle | warning by default; blocking if configured | Implemented: sums recent provenance.inference_attempts.cost_usd joined to request task and compares it to the check’s explicit reviewed window cap. It is observability, not a race-safe pre-dispatch budget reservation. | Under-cap, near-cap, over-cap batch run. |
source_artifact_immutability | make_source_artifact_immutability_check | provenance.source_artifacts, evidence.* | blocking for document/payload-derived claims | Require immutable storage URI, content hash + algorithm, source version/release/snapshot id, and observed/fetched timestamps; reject live-URL-only artifacts. | Valid archived artifact, missing hash, live-URL-only artifact, stale re-fetch with changed hash. |
source_authority | make_source_authority_check | canonical.* | blocking for high-impact assertions | Validate claim type against allowed authority tiers; lower-authority facts may publish only with explicit marker or curation override. | Approval/news/publication examples with conflicting authority. |
document_version | make_document_version_check | evidence.*, canonical.* | blocking for document-derived claims | Require source-native document version/release/snapshot id before claims can publish; immutability is checked separately. | Label/publication/news/registry document examples. |
resolution_basis | make_resolution_basis_check | resolution.*, canonical.* | blocking where fuzzy match impacts canonical identity | Reject publishable links whose basis is absent, unsupported, stale, or unverified for that subject class. | Exact id, cross-reference, fuzzy ambiguous, reviewed curation override cases. |
curation_effective_state | make_effective_state_check | curation.*, canonical.* | blocking | Ensure rejected/superseded/unreviewed high-impact curation overlays do not appear active; highest-precedence reviewed decision wins. | Proposal, human approval, supersede, reject, active overlay. |
curation_review_state | make_curation_review_check | curation.* | blocking for high-impact overlays | Require human_approved for high-impact curation subject kinds; allow not_required only for explicitly low-risk subjects. | Pending high-impact proposal, approved override, low-risk auto-reviewed overlay. |
announcement_semantics | make_event_semantics_check | evidence.*, canonical.* event assets | blocking when collapsed status would mislead | Enforce source-specific event status vocabulary and prevent announced/submitted/approved/published collapse. | News announcement vs FDA approval vs publication accepted cases. |
temporal_validity | make_temporal_validity_check | canonical.* temporal assets | blocking for destructive overwrite | Require valid-from/valid-to/observed-at rules for ownership, labels, SOC assertions, and temporal relationships. | Ownership rename/acquisition with overlapping periods. |
search_provenance | make_search_provenance_check | query.q_search_*, query.q_discovery_* | blocking | Implemented: require every search row’s source_q_model_name / source_q_row_key tuple to name an existing query.q_* relation with a matching q_provenance receipt. Embeddings are outside the current discovery contract. | Search row linked to an owner receipt and an orphan source-row tuple. |
downstream_boundary | make_downstream_boundary_check | support query assets | blocking | Reject columns/tables that encode app runtime state, saved scenarios/models, HTTP routes, or downstream engine ownership. | Valid readiness row and invalid saved-scenario/API-shape row. |
development_program_semantics | make_development_program_semantics_check | canonical.development_program_*, query.q_development_* | blocking | Validate program/context uniqueness, non-overlapping temporal state, orthogonal clinical/regulatory axes, milestone reconciliation, unknown-context preservation, declared count grain, and source/arm/population evidence grain. | The ten acceptance scenarios in 33, including active Phase 2 after terminated Phase 3 and approved plus active expansion. |
epidemiology_observation_semantics | make_epidemiology_observation_semantics_check | canonical.epidemiology_*, query.q_epidemiology_* | blocking | Validate metric/statistic/unit context, series comparability signature, periods, denominators, adjustment basis, uncertainty, observed/estimated/projected basis, and selected-summary references. | Crude vs adjusted, count vs rate, multi-year period, restatement, and missing-forecast-input cases from 34. |
commercial_observation_semantics | make_commercial_observation_semantics_check | canonical.product_sales_*, query.q_product_* | blocking | Validate reporting period kinds, Q1-Q4, currency/scale preservation, FX receipts, geography compatibility, restatement chains, active source-fact uniqueness, and actual-vs-forecast evidence kind. | Q4, annual plus Q4, FX, restatement, geography, acquisition, and prose-only cases from 35. |
Factory naming is intentionally domain-readable. A builder should be able to scan defs/<layer>/<slice>.py and see the gate vocabulary from this doc attached directly to assets.
Comparative therapeutic-fact gate fixtures
Section titled “Comparative therapeutic-fact gate fixtures”The first high-value gate fixtures should prove the system distinguishes three comparable-but-not-interchangeable fact rows: registry trial outcomes (21), regulatory label indications (22), and publication outcomes (23).
| Fixture | Expected blocking/warning behavior | Gates exercised |
|---|---|---|
| Registry outcome with missing immutable AACT/CTGov snapshot | block publication of q_trial_outcomes | source_artifact_immutability, provenance_coverage |
| Registry outcome with result group but unaccepted arm link | publish row only with arm_link_state='unlinked'; block if it claims a design arm | resolution_basis, llm_verifier_required |
| Label indication with source text but no region/regulator | block q_approval_indications | schema_contract, source_authority |
| CDE translated indication without original language text or translation version | block translated fields | document_version, source_locator, provenance_coverage |
| Publication outcome with hazard ratio but no text/table locator | block q_publication_outcomes | source_locator, source_artifact_immutability |
| Publication outcome linked to trial by title inference only | block canonical comparison until verifier acceptance or reviewed curation override; may publish as provisional evidence | resolution_basis, llm_verifier_required, curation_review_state |
| Same ORR appears in registry and publication with different values | do not collapse; publish both with conflicting/supporting provenance roles | provenance_coverage, source_authority |
| Approved indication inferred from publication result | block; publication can support evidence but cannot become regulatory truth | source_authority, downstream_boundary |
These fixtures prevent the tempting but wrong simplification into one universal outcome/fact table. The gate question is not “does a numeric value exist?” but “is this value source-authoritative for the fact the query row claims to represent?”
Publication Quality Failure Taxonomy
Section titled “Publication Quality Failure Taxonomy”The legacy publication issue trackers are not historical noise; they are a regression taxonomy for greenfield checks. They show repeated failure modes where LLM extraction, post-processing, views, and query rollups produced plausible-looking but clinically wrong facts. Greenfield keeps them as named gate families with fixtures, rather than prose bug anecdotes (../bioloupe-data-gov/docs/publication_issues_tracker.md, ../bioloupe-data-gov/docs/publication_issues_tracker_2.md, ../bioloupe-data-gov/docs/audit_triage_2026_03_30.md).
Methodologically, these are domain-specific data-quality expectations: Dagster asset checks enforce blocking/warning gates on assets, while custom expectation-style checks express domain rules that generic schema tests cannot capture (Dagster asset checks: https://docs.dagster.io/guides/test/asset-checks; Great Expectations custom expectations: https://docs.greatexpectations.io/docs/oss/guides/expectations/creating_custom_expectations/overview/). The taxonomy covers standard quality dimensions such as accuracy, completeness, consistency, validity, and uniqueness, but translates them into pharmaceutical evidence invariants (IBM data-quality dimensions: https://www.ibm.com/think/topics/data-quality-dimensions).
| Taxonomy id | Legacy evidence | Failure pattern | Gate family | Default severity |
|---|---|---|---|---|
pub_zero_sentinel | Issue 8; Issue 54; audit Finding 4 | unstated values emitted as 0 instead of null/derived value, especially ORR/cORR/N | publication_value_semantics | blocking for published result values |
pub_endpoint_semantic_confusion | Issues 32, 36, 37, 42, 61 | TTP→PFS, cORR→ORR, mean→median, tumor shrinkage→RECIST ORR, OR invisible as ORR | endpoint_semantic_consistency | blocking |
pub_population_denominator_misattribution | Issues 26, 40, 45, 57, 60, 62 | parent population N copied to child subgroup, tested denominator used as positive-subgroup N, disease misattribution, fake arms | population_grain_integrity | blocking |
pub_arm_dose_attribution | Issues 28, 29, 31, 35, 39, 49, 52, 58 | dose/escalation/RP2D data attached to wrong arm, all-arms fan-out, intervention/classification arm mismatch | arm_dose_attribution | blocking |
pub_subgroup_extraction_completeness | Issues 33, 38, 43, 46, 47, 48, 55, 56 | cross-tabulated/secondary-analysis biomarker subgroups or sibling endpoints missing | subgroup_endpoint_completeness | warning by default; blocking for target disease slices |
pub_safety_attribution | Issues 41, 53 | AE/safety data flattened across dose arms or cohorts without subgroup linkage | safety_attribution_integrity | blocking for safety rows |
pub_intervention_identity | Issue 50 | non-drug interventions linked as drugs | intervention_identity_type_safety | blocking; owner spine 29 supplies target semantics |
pub_corpus_identity_uniqueness | Issues 17, 18 | duplicate conference/article records or missing PubMed-indexed publication | publication_corpus_identity | warning/blocking depending on duplicate/missing evidence impact |
Publication-quality gate contract
Section titled “Publication-quality gate contract”Each taxonomy gate must emit metadata that lets a builder or agent diagnose the exact clinical mistake:
| Gate family | Required metadata |
|---|---|
publication_value_semantics | publication id/key, endpoint term/key, subgroup/arm key, extracted value, derived candidate value if any, reason zero/null is invalid, source locator. |
endpoint_semantic_consistency | raw endpoint phrase, canonical_endpoint_key, conflicting candidate endpoint, endpoint spine evidence, source quote. |
population_grain_integrity | parent population key/N, child subgroup key/N, numerator/denominator source expression, disease/biomarker segment keys. |
arm_dose_attribution | source arm label, normalized arm key, intervention key, dose fields, conflicting sibling-arm values, source quote. |
subgroup_endpoint_completeness | expected subgroup/endpoint axes, missing axis, extraction prompt/schema version, source table/text locator. |
safety_attribution_integrity | AE term/key, grade bucket, cohort/arm key, safety N/value, conflicting cohort/arm source text. |
intervention_identity_type_safety | source term, candidate identity type, accepted/rejected resolution basis, drug spine key or NCIt concept key. |
publication_corpus_identity | DOI/PMID/conference id, title hash, abstract/presentation source ids, duplicate/missing classification basis. |
These gates belong in 08/10, not in slice docs, because they cut across publication extraction, endpoint identity (32), drug/intervention identity (29), disease/biomarker identity (30), and query materialization. Slice docs still declare which gate families apply to their assets.
Comparative gate metadata contract
Section titled “Comparative gate metadata contract”When one of the comparative therapeutic-fact fixtures fails, the check result metadata must be useful enough for an agent or human to understand the broken contract without opening the whole database.
| Gate failure | Required metadata |
|---|---|
| Missing source artifact | q_model_name, q_row_key or candidate assertion id, expected source_artifact_key, missing source_content_hash/source_immutable_uri, source family, remediation hint. |
| Missing source locator | evidence claim id, fact_path, source artifact key, expected locator shape (api_row, json_path, xml_path, pdf_page_span, table_cell, etc.), sample source id. |
| Bad source authority | assertion id, attempted query model, claim type, actual source_authority_tier, required tiers, source family, downstream risk. |
| Unaccepted resolution/arm link | resolution candidate id, subject kind, source term, candidate target, basis, verifier state, required basis for publication, whether a reviewed curation override exists. |
| Missing region/regulator | approval/indication assertion id, source family, source record key, missing column names, source locator. |
| Cross-source conflict | compared row keys, model names, fact paths, values, units, source authority tiers, conflict role, whether publication continues as warning. |
| Previous good retained | prior materialization run id, blocked candidate run id, query model name, affected row count, reason previous state remains served. |
Each metadata payload should cap row examples but include enough stable keys for follow-up SQL against q_catalog and q_provenance.
Publication-state behavior
Section titled “Publication-state behavior”The system must prefer a stale-but-known-good query layer over a fresh-but-unverified one. This state machine is implemented for the clinical-trials family and remains the adoption target for other query families.
stateDiagram-v2 [*] --> CandidateMaterialized CandidateMaterialized --> ChecksPassing: blocking gates pass CandidateMaterialized --> HeldBack: any blocking gate fails HeldBack --> PreviousPublishedServed: do not refresh q_* contract PreviousPublishedServed --> CandidateMaterialized: upstream fix or new curation decision ChecksPassing --> Published: atomically replace family serving head Published --> [*]
Warning-only checks must never silently disappear: they emit Dagster check metadata, appear in operations dashboards, and can be promoted to blocking by changing the gate contract.
Check Execution Policy
Section titled “Check Execution Policy”- Checked-in YAML contracts interpreted against Postgres
information_schemaare the current schema authority. A contract library may replace the implementation only if it preserves that reviewable, database-backed behavior. - Expensive LLM evaluations run on an explicit sampled or separate cadence and record the sample contract. They are never hidden inside ordinary materialization and never replace deterministic blocking checks. Dagster permits check-specific automation conditions for this purpose. (https://docs.dagster.io/guides/automate/declarative-automation/automating-asset-checks)