Counter-Prior Catalogue¶
Each file in this directory documents one corpus pathology — a pattern LLM training data biases models toward — and Dazzle's counter-prior: the right shape, why the wrong shape is load-bearing-bad, and which substrate layer enforces the fix.
The three substrate layers (see dev_docs/2026-05-25-substrate-audit.md and the project memory project_prior_correction_substrate.md for the framing):
- Grammar (layer 1) — the DSL excludes the bad shape by construction. Strongest counter-prior.
- Inference (layer 2) — agent instructions / KB entries injected at the right moment. This catalogue.
- Filter (layer 3) — drift gates / conformance / fitness that catch what the first two layers let through.
Each entry's frontmatter declares which layer it primarily belongs to, plus triggers (natural-language fragments and code-shape regexes) that the bootstrap and knowledge counter_prior MCP path use to surface it at relevant moments.
Entries are agent-scannable: each row is a counter-prior that prevents a wrong emission.
Active entries¶
- domain-coupled-keywords — Naming DSL keywords / field names after the source spec's domain (
pupil_card,customer_id). Domain values belong at the adapter layer; the grammar stays generic. - duplicated-parent-fields — Copying a parent's field onto a child alongside the
ref. The Repository auto-includes ref data; the copy goes stale, the framework can't keep it in sync. - exceptions-as-control-flow —
try/except: pass/ fallback control flow / EAFP misused. Counters silent failures in user app code. - god-entities — Single-entity-spans-everything modelling. Decompose through refs so RBAC, scope, and lifecycle match conceptual boundaries.
- hand-rolled-soft-delete — Manual
deleted_atcolumn + per-surfacescope: deleted_at = null. Use thesoft_delete:keyword (#1218); the substrate filters tombstones centrally. - hand-rolled-temporal — Manual
start_date/end_date+ per-surface current-row scopes + custom as-of handlers. Usetemporal:(#1223); keyword wires auto-filtering, uniqueness, URL param, andlatest_onetraversal. - magic-string-typing — bare
strfor identifier classes (user_id: str), status discriminators, or lookup keys. Pairs withdazzle.types.NewType,enum.StrEnum, andPA-LLM-10. - n-plus-one-in-user-code — Naive ORM-shaped loops over related rows in
app/code. Framework paths aggregate centrally; user code re-introduces N+1 unless explicitly batched. - optional-instead-of-result —
def f(...) -> T | Nonecollapsing multiple distinct failure modes into a single None sentinel. Pairs withdazzle.resultandPA-LLM-09. - polymorphic-associations — Rails-style
belongs_to :commentable, polymorphic: trueand(subject_type, subject_id)discriminator pairs. Closed by ADR-0027; pairs with the four-question interrogation. - raw-sql-string-building — f-string /
+SQL in user code. Framework paths parameterise by construction; raw SQL bypasses the predicate algebra and re-introduces injection class. - regex-in-dsl-parser —
re.compilein parser code. A regex on a DSL shape signals a missing IR type. ADR-0024 + drift gate; allowlist sits at zero. - shell-without-strict-mode — Shell scripts missing
set -euo pipefail. Silent continuation past failed commands is the corpus shape and the highest-leverage one-line fix in the catalogue. - stringly-typed-refs —
customer_email: strinstead ofcustomer: ref Customer. The FK graph + scope predicate algebra depend on typed refs. - subtype-polymorphism-default —
subtype_of:reached for reflexively whenever a spec mentions "variants of X." Walk the three alternatives (separate entities, state machine, nullable fields) first.
Adding a new entry¶
- Write
docs/counter-priors/<id-in-kebab-case>.mdwith YAML frontmatter (see existing entries for the schema). - The four sections
## The corpus prior/## Wrong shape/## Right shape/## Why this matters hereare mandatory — the drift test enforces them. - Bump
SEED_SCHEMA_VERSIONinsrc/dazzle/mcp/knowledge_graph/seed.pyso deployed KGs re-seed. - Add a one-line entry to this index.
- The drift test (
tests/unit/test_counter_priors_drift.py) will fail until every file is well-formed and every KG row maps back to a markdown file.