The chart is the last step. Cloud Storage, Cloud Run,
BigQuery and dbt help turn fixed race results and ERA5 weather into a
checked comparison that the read-only page can show.
Follow one real editionFolkestone Half Marathon · 2019
459 accepted results ·459 weather matches
The evidence below comes from separate verified
executions of this same fixed edition, including an Airflow run. It is
not a continuously updated feed.
The data journey
Six steps from source to screen
The path and its safeguards are visible here. Open a step for the
implementation detail and its evidence.
01Saved race result + ERA5 weatherQualify the inputsCheck the race date, start, course evidence and source files.Input hashes
Why: fixed source bytes and their SHA-256 hashes
make a later run traceable to the exact race and weather inputs.
A matching hash proves identity, while source qualification checks
whether those bytes describe the intended race.
02Audit report JSON + result-row NDJSONValidate and exportPython checks each result and matches ERA5 weather to the run.Validation gate
Why: the Cloud Run export job calls the same
parsing, validation and weather-matching code used locally. It
records candidate outcomes and fails if the source structure or
weather is unusable. Folkestone produced 459 accepted results and
459 weather matches.
03Explicit BigQuery snapshot tableStore and read back the rowsValidate the whole export, then verify the typed warehouse rows.No overwrite
Why: a fixed snapshot has its own destination.
An identical rerun checks the existing rows instead of loading
them again; a changed snapshot needs a separate destination.
The Folkestone cloud export was checked against its protected
459-row table without another load.
04Edition views + course comparison viewBuild the comparison in dbtRun edition models and tests before the comparison build.Tests first
Why: dbt owns pace and weather summaries. The
Cloud Run dbt job uses the same stage runner as local work; it
stops downstream work if an earlier stage fails. Folkestone 2019
and its three-edition comparison passed the native build.
05Reconciliation + execution evidenceCheck the result independentlyCompare important BigQuery values with saved expectations.Readback
Why: a passing dbt command alone is not enough.
Separate readback checks compare counts and statistics after the
models run. Successful and failed executions retain useful
evidence; a failed stage blocks later tasks, although views
already created in BigQuery can remain.
06Prepared mart → API → chartShow the comparisonThe public page reads prepared summaries, not raw result rows.Read only
Why: the Cloud Run API selects approved BigQuery
comparison views and returns aggregate fields. It does not parse
race files or recalculate the statistics. Weather and pace are
shown together as descriptive context, not a measured weather
effect.
The choices follow the workload: saved historical races, repeatable
checks and a small public comparison.
01 / Fixed inputs
Know exactly what was processed.
Source hashes identify each saved race and weather file. Validation
happens before output, and an identical rerun verifies the existing
snapshot. A corrected input gets a distinct snapshot. More elaborate
revision and publication controls can wait for a changing feed.
02 / Shared processing
One set of checks in each environment.
The local export command and Cloud Run export job reuse the tested
Python parsing, validation and export code. The dbt stage runner
also works locally and in Cloud Run. Airflow calls these stages;
source adapters handle formats such as GNR's Top 1,000 sample.
03 / Warehouse models
Calculate once, then serve the result.
BigQuery stores checked rows; dbt builds and tests the edition and
comparison views. The API reads approved aggregate results, so the
chart does not calculate pace statistics.
04 / Airflow
Coordinate without repeating the logic.
Task dependencies stop later steps when validation or an earlier
build fails. Airflow records the run history; the existing Python
and dbt stages still do the processing. A failed dbt build can
leave views that an earlier step already created.
05 / Bounded cloud work
Use the cloud where the project needs it.
Cloud Run serves the page and runs separate export and dbt jobs;
BigQuery holds the snapshots and marts. The managed Composer run
was an exercise. The Composer environment was removed after
verification. New historical runs are currently started manually.
This small dataset does not need cloud scale, but the deployed path
shows how its stages, access and evidence fit together.
Full-results path
What each dbt model represents
GNR's Top 1,000 samples use separate models and a fixed event weather
window rather than individual runner weather matches.
Model
One row means
stg_race_results
One candidate source result, including its validation outcome.
fct_race_results
One accepted result, with pace and matched weather where available.
mart_event_summary
One edition and its counts, pace summary and weather coverage.
mart_course_comparison
One selected edition relative to a named baseline; differences appear only when comparable.
Edition timing methods also matter: Battersea's
unknown chip/gun basis leaves baseline pace changes blank.
What we verified
Two useful run outcomes
Stopped safely
Invalid configuration ended the DAG before Cloud Run.
The first task failed; all five downstream tasks were blocked.
No Cloud Run job was submitted.
The same Folkestone snapshot passed all six tasks again.
The loader verified the existing 459 rows and submitted no new
warehouse load. That run checked an existing snapshot; it did not
demonstrate a fresh insert or transactional rollback.
Terraform records the service and its access. Immutable container
images identify deployed code. CI checks code, models and containers
offline; separate real-cloud runs verify the deployed stages.
Evidence today
Checks leave a trail.
We retain source hashes, validation counts, BigQuery job IDs, dbt
artifacts, reconciliation results and execution logs for success and
failure. These records let us check what happened at each stage.
Cloud Monitoring checks API availability and emails on sustained
failure and recovery. Its dashboard shows requests, errors and latency.
Data correctness comes from dbt tests and reconciliation; this page
does not show live pipeline status.
Course compatibility is checked separately. Different runners enter
each edition, so the comparison does not prove that weather caused a
change in pace.