relation "staging.stg_ees_ks4_destinations" does not exist
in model fact_ks4_destinations
relation "staging.stg_ees_ks5_destinations" does not exist
in model fact_ks5_destinations
fact_ks4_destinations and fact_ks5_destinations (added 28 Aug) join dim_school, so the daily build's stg_gias_establishments+ selects them. So does the monthly Ofsted build's dim_school+. They also read stg_ees_ks4/ks5_destinations, which only the manually triggered EES DAG builds. Where that DAG hasn't run since the destinations models landed, dbt_build fails, and sync_typesense and invalidate_cache never run. This is the likely reason production's register data is stuck at about 25 Aug 2026: 133 closed schools still shown as open, new academies missing (finding H1 of the 3 Oct accuracy audit).
Change
Both scheduled builds exclude stg_ees_ks4_destinations+ stg_ees_ks5_destinations+, as the daily build already excludes the KS2/KS4 lineage models. The EES DAG still rebuilds the destinations marts when their data changes.
pipeline/tests/test_dag_selectors.py reads the model graph from the SQL files, since CI has no dbt. It checks that every scheduled build only reads models it builds or the daily build builds. Before this change it failed for school_data_daily and school_data_monthly_ofsted; it now passes.
Verification
dbt ls with the new selectors: daily = dim_location, dim_school, int_school_lineage, map_school_lineage, stg_gias_establishments, stg_gias_links; monthly Ofsted = dim_school, fact_ofsted_inspection, int_ofsted_latest, stg_ofsted_inspections. Neither contains a destinations mart. The test's own selection matched dbt ls before the change.
Until this reaches an environment, triggering school_data_annual_ees there once also unblocks the daily run, because it creates the missing tables.
After the first green daily run, select count(*) from marts.dim_school where urn = 121245 (Thetford Grammar School, closed 31 Aug) should return 0, and the site should drop it once the cache is invalidated.
## Problem
The daily DAG's `dbt_build` fails:
```
relation "staging.stg_ees_ks4_destinations" does not exist
in model fact_ks4_destinations
relation "staging.stg_ees_ks5_destinations" does not exist
in model fact_ks5_destinations
```
`fact_ks4_destinations` and `fact_ks5_destinations` (added 28 Aug) join `dim_school`, so the daily build's `stg_gias_establishments+` selects them. So does the monthly Ofsted build's `dim_school+`. They also read `stg_ees_ks4/ks5_destinations`, which only the manually triggered EES DAG builds. Where that DAG hasn't run since the destinations models landed, `dbt_build` fails, and `sync_typesense` and `invalidate_cache` never run. This is the likely reason production's register data is stuck at about 25 Aug 2026: 133 closed schools still shown as open, new academies missing (finding H1 of the 3 Oct accuracy audit).
## Change
- Both scheduled builds exclude `stg_ees_ks4_destinations+ stg_ees_ks5_destinations+`, as the daily build already excludes the KS2/KS4 lineage models. The EES DAG still rebuilds the destinations marts when their data changes.
- `pipeline/tests/test_dag_selectors.py` reads the model graph from the SQL files, since CI has no dbt. It checks that every scheduled build only reads models it builds or the daily build builds. Before this change it failed for `school_data_daily` and `school_data_monthly_ofsted`; it now passes.
## Verification
- `dbt ls` with the new selectors: daily = dim_location, dim_school, int_school_lineage, map_school_lineage, stg_gias_establishments, stg_gias_links; monthly Ofsted = dim_school, fact_ofsted_inspection, int_ofsted_latest, stg_ofsted_inspections. Neither contains a destinations mart. The test's own selection matched `dbt ls` before the change.
- `python -m pytest backend/tests pipeline/tests scripts/ci/tests -q`: 334 passed.
## After merge
- Until this reaches an environment, triggering `school_data_annual_ees` there once also unblocks the daily run, because it creates the missing tables.
- After the first green daily run, `select count(*) from marts.dim_school where urn = 121245` (Thetford Grammar School, closed 31 Aug) should return 0, and the site should drop it once the cache is invalidated.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
fact_ks4_destinations and fact_ks5_destinations join dim_school, so the
daily build's stg_gias_establishments+ and the monthly Ofsted build's
dim_school+ both selected them. They also read stg_ees_ks4/ks5_destinations,
which only the manually triggered EES DAG builds. Where that DAG hasn't run
since the destinations models landed, dbt_build fails with "relation
staging.stg_ees_ks4_destinations does not exist", and sync_typesense and
invalidate_cache never run. Production's register data has been stuck at
about 25 Aug 2026.
Both builds now exclude the descendants of the two EES staging models, as
the daily build already does for the KS2/KS4 lineage models. The EES DAG
still rebuilds the marts when their data changes.
test_dag_selectors reads the model graph from the SQL (CI has no dbt) and
checks that every scheduled build only reads models it or the daily build
builds. It failed for the daily and monthly Ofsted builds before this change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The daily GIAS dbt build and the monthly Ofsted dbt build now exclude the marts downstream of the EES KS4/KS5 destinations staging models. Those marts are built by the EES DAG and fail in a database where that DAG hasn't run. A new static test parses the model SQL and the DAG file to check that every scheduled build only selects models whose parents are built. The change looks correct and low risk, and I found no blocking issues.
🟡 Minor
pipeline/tests/test_dag_selectors.py: The graph comes from a regex over ref('...') calls. It misses refs written with double quotes, and it misses refs built dynamically or inside Jinja conditionals, so a future parent could silently go unchecked. The test also does not check that the EES DAG actually selects the destinations marts that the other two DAGs now exclude. If it stopped selecting them, they would never be rebuilt, and the test would not notice.
## 🤖 AI Code Review (Claude Code)
The daily GIAS dbt build and the monthly Ofsted dbt build now exclude the marts downstream of the EES KS4/KS5 destinations staging models. Those marts are built by the EES DAG and fail in a database where that DAG hasn't run. A new static test parses the model SQL and the DAG file to check that every scheduled build only selects models whose parents are built. The change looks correct and low risk, and I found no blocking issues.
### 🟡 Minor
- **pipeline/tests/test_dag_selectors.py**: The graph comes from a regex over `ref('...')` calls. It misses refs written with double quotes, and it misses refs built dynamically or inside Jinja conditionals, so a future parent could silently go unchecked. The test also does not check that the EES DAG actually selects the destinations marts that the other two DAGs now exclude. If it stopped selecting them, they would never be rebuilt, and the test would not notice.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
The daily DAG's
dbt_buildfails:fact_ks4_destinationsandfact_ks5_destinations(added 28 Aug) joindim_school, so the daily build'sstg_gias_establishments+selects them. So does the monthly Ofsted build'sdim_school+. They also readstg_ees_ks4/ks5_destinations, which only the manually triggered EES DAG builds. Where that DAG hasn't run since the destinations models landed,dbt_buildfails, andsync_typesenseandinvalidate_cachenever run. This is the likely reason production's register data is stuck at about 25 Aug 2026: 133 closed schools still shown as open, new academies missing (finding H1 of the 3 Oct accuracy audit).Change
stg_ees_ks4_destinations+ stg_ees_ks5_destinations+, as the daily build already excludes the KS2/KS4 lineage models. The EES DAG still rebuilds the destinations marts when their data changes.pipeline/tests/test_dag_selectors.pyreads the model graph from the SQL files, since CI has no dbt. It checks that every scheduled build only reads models it builds or the daily build builds. Before this change it failed forschool_data_dailyandschool_data_monthly_ofsted; it now passes.Verification
dbt lswith the new selectors: daily = dim_location, dim_school, int_school_lineage, map_school_lineage, stg_gias_establishments, stg_gias_links; monthly Ofsted = dim_school, fact_ofsted_inspection, int_ofsted_latest, stg_ofsted_inspections. Neither contains a destinations mart. The test's own selection matcheddbt lsbefore the change.python -m pytest backend/tests pipeline/tests scripts/ci/tests -q: 334 passed.After merge
school_data_annual_eesthere once also unblocks the daily run, because it creates the missing tables.select count(*) from marts.dim_school where urn = 121245(Thetford Grammar School, closed 31 Aug) should return 0, and the site should drop it once the cache is invalidated.🤖 Generated with Claude Code
🤖 AI Code Review (Claude Code)
The daily GIAS dbt build and the monthly Ofsted dbt build now exclude the marts downstream of the EES KS4/KS5 destinations staging models. Those marts are built by the EES DAG and fail in a database where that DAG hasn't run. A new static test parses the model SQL and the DAG file to check that every scheduled build only selects models whose parents are built. The change looks correct and low risk, and I found no blocking issues.
🟡 Minor
ref('...')calls. It misses refs written with double quotes, and it misses refs built dynamically or inside Jinja conditionals, so a future parent could silently go unchecked. The test also does not check that the EES DAG actually selects the destinations marts that the other two DAGs now exclude. If it stopped selecting them, they would never be rebuilt, and the test would not notice.