Skip to content

feat!: scope audits, schemas and hooks, add seed audits and gate targets on attached audits - #855

Merged
kvlonge merged 18 commits into
mainfrom
feat/chi-405-406-scoped-declarations
Sep 27, 2026
Merged

kvlonge merged 18 commits into
mainfrom
feat/chi-405-406-scoped-declarations

Conversation

@kvlonge

@kvlonge kvlonge commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Why

Generic audits, reusable schemas and named hooks were project-wide only, singular audits accepted single-model checks, seeds had no audits, and attached audits that read other resources ran at the end of the build after their target was already published.

Changes

  • Audits, schemas and SQL/Python hooks follow the existing macro placement rule: top-level when used across a resource tree, <folder>/_sqlbuild/ when used under one folder, visible only where placed. Unused ones are errors; [scopes] enforce_placement = false reports placement findings as warnings.
  • Singular audits must check two or more models, or a model plus a source, seed or table function (P004). The audits/ fallback is removed.
  • Seed YAML audits: run after the seed loads in sqb build; error failures block dependants.
  • Attached audits always gate their target: extra reads become ordering edges, following the target's promotion mode and run scope. An audit reading something built from its own target is P005. Singular audit attachment is unchanged.
  • S301 names the audit when a missing resource is needed only by an audit read.
  • Warehouse errors in source, seed and end-of-build audits become failed audit results instead of crashing the build.
  • sqb scope --json schema_version 2; Rules scope metadata version 3.
  • Docs updated; benchmark generators stop writing unattached hooks.

BREAKING CHANGE: audits, schemas and hooks must be placed and used per the scope rules, singular audits must be cross-resource, and cross-resource attached audits now gate their target.

Verification

  • make test (7,814 passed) and make check-ci pass; hygiene scan clean.
  • New E2E: scoped declarations, seed audits, attached-audit gating for models, sources and seeds (serial and concurrent), P005, partial builds, --no-audits, audit execution errors.
  • Compile guard fingerprints checked locally.
  • One independent review plus a follow-up; findings fixed and re-verified.

Generic and singular audits, reusable schemas, and named SQL and Python
hooks become declaration kinds in the existing declaration-scope
machinery. They can live in project-wide roles or under
<folder>/_sqlbuild/ roles, and follow the macro placement and
visibility rules; attachments generated by audit factories count as
consumers. Declaration files resolve macros, enums, and constants from
their owner folder.

Singular audits must reference two or more models, or a model plus a
source, seed, or table function (P004). Audit files are discovered only
from generic/ and singular/ roles.

Seed YAML audits now compile and run after the seed loads in sqb build,
blocking dependants on error. Unknown seed YAML keys are compile errors.

BREAKING CHANGE: audit files outside audits/generic/ and
audits/singular/ no longer compile; single-model, source-only,
seed-only, and resource-free singular audits fail with P004; top-level
audits, schemas, and hooks used only under one folder must move to that
folder's _sqlbuild/ roles; unknown seed YAML keys are rejected.
Update the declaration-scope overview, placement, and visibility pages, the audits, seeds, schemas, hooks, and sqb init pages, and state that functions stay project-wide. Regenerate the bundled skill references.
…rces or table functions

Also stop rejecting organizational folders named audits, schemas, or hooks inside project-wide declaration roles; only _sqlbuild and legacy macro, enum, and constant role names are rejected there.
Scoped audits, schemas, and hooks change the resource and declaration
kinds in scope output, so sqb scope --json moves to schema_version 2 and
the scope metadata consumed by Rules moves to 3. Document the project-wide
[scopes] enforce_placement switch for staged adoption.

BREAKING CHANGE: sqb scope --json reports schema_version 2.
Named hooks are now scoped declarations, so hooks that no model attaches
are unused declarations. The generated benchmark projects never attached
theirs; stop writing them and refresh the affected summaries and output
fingerprints. Compile output is otherwise unchanged.
An attached audit that read anything besides its target (and, for models,
the target's upstream) used to fall back to the end of the build, so an
error failure no longer protected the target or its dependants.

Attached audits now always gate their target. Every other model, seed,
source, or table function an audit reads becomes an ordering edge: model
and seed targets wait for those reads, and a source target's dependent
models do. Model audits still run against the staged relation before
promotion, source and seed audits before any dependant is built, and an
error failure blocks the target and everything downstream. Partial builds
read unselected resources from their existing tables. reuse_from never
reuses proof for audits that read outside the target's lineage.

An attached audit that reads a resource built from its own target is now
a compile error (P005) pointing to a singular audit. This replaces the
blanket rejection of source audits that reference models: a source audit
may read a model that is not built from the source and waits for it.

BREAKING CHANGE: attached audits that read a resource built from their
target fail to compile with P005 instead of running at the end of the
build; move those checks into singular audits.
A source's audits run before any model that has the source among its
execution dependencies, including a source added by another audit's read.
Gate edges only covered models whose SQL read the source, so a source audit
reached through another audit could run before the resources it reads were
built. Compute the triggering models to a fixed point over lineage and
gate edges so every one of them waits for the source audit's reads.
Singular-audit attachment was inferred from the execution graph, which now
includes attached-audit gate edges, so an unrelated attached audit could
move a singular audit from the end of the build onto a model. Infer it from
lineage dependencies only.
@kvlonge
kvlonge enabled auto-merge (squash) September 27, 2026 16:57
Attached audits now gate their target, so a model whose audit reads an
unselected seed needs that seed to exist, like any other upstream
dependency. The parity test planned against an empty warehouse.
@kvlonge
kvlonge disabled auto-merge September 27, 2026 17:33
Source, seed, and end-of-build audits ran outside any node's exception
boundary, so an audit query that raised crashed sqb build with a traceback
and no JSON. Catch Exception around those audit executions, as the model
node boundary does, and record an error result carrying the message. Like a
model audit that raises, it fails whatever its severity: dependants of the
target are blocked and the build exits non-zero. The message appears in the
check's execution_error JSON field and in the terminal failure summary.
sqb audit already reports these errors through its own path.
Selecting +x follows data lineage, but buildability also checks resources
that attached audits read, so a missing audit read failed with a generic
"missing upstream dependencies" list. When a missing resource is required
only through an audit's ordering edge, S301 now names the audit, its target,
and the read. Data-lineage misses keep the existing wording, and mixed
failures list both kinds. Edge origins no longer record audit reads that
are already data-lineage edges.
Identical output has measured 12.5-18.4 s across CI runs; the same-runner
ratio guard remains the regression gate.
@kvlonge
kvlonge enabled auto-merge (squash) September 27, 2026 17:55
Fixed wall-clock budgets set just above the last CI measurement kept
failing on runner noise (identical output varies by up to 50% between
runs). Set them to about 1.5x typical CI time so they catch gross
regressions; the same-runner ratio guards remain the precise gate.
The scoped-declarations E2E hook created its log table on first use, so
two models running the hook concurrently raced on CREATE TABLE in DuckDB.
Create it before the build. Dense 3000 and 5000 budgets become loose
ceilings like the fresh and cache budgets; the same-runner ratio stays
the regression gate.
@kvlonge
kvlonge merged commit 8966898 into main Sep 27, 2026
31 checks passed
@kvlonge
kvlonge deleted the feat/chi-405-406-scoped-declarations branch September 27, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant