Appendix I: The Kestrel Platform
The complete inventory of what the book builds, chapter by chapter, so you can check what you have and find what you are missing.
⚠️ This appendix contains the Chapter 38 reconciliation figures. It is one of the four places
validate.pypermits them. Do not read §I.9 before computing the capstone yourself.
I.1 The Repository
kestrel-platform/
├── docker-compose.yml App. A
├── .env gitignored
├── requirements.txt
├── platform/
│ ├── ingest/ ch 13-16
│ │ ├── load_orders.py batch + high-water mark
│ │ ├── load_customers.py full refresh
│ │ ├── cdc_replay.py ch14
│ │ ├── api_client.py ch16: retries, backoff, pagination
│ │ └── timestamp_audit.py ch34 CS2: flags offsetless timestamps
│ ├── contracts/ ch17
│ │ ├── orders.yml
│ │ └── check_contracts.py
│ ├── quality/ ch23
│ │ ├── register.py 22 assertions
│ │ └── quarantine.py ch34 section 34.12
│ ├── layers/ ch34
│ │ ├── layer_check.py 9 rules, in CI
│ │ ├── suppressions.yml expiring, with reasons
│ │ ├── replay.py rebuild + cost
│ │ └── depth_report.py
│ ├── events/ ch36
│ │ ├── outbox_relay.py
│ │ ├── consumer.py idempotent base class
│ │ ├── upcast.py
│ │ └── projections/
│ ├── ml/ ch32
│ │ ├── asof.py ONE implementation
│ │ ├── materialize.py changed-only + weekly full
│ │ ├── skew_check.py daily, by segment
│ │ └── feature_age.py
│ ├── privacy/ ch31
│ │ ├── scan.py
│ │ ├── manifest.py GENERATED from catalog tags
│ │ ├── resolver.py 5 identifier spaces
│ │ └── dags/erasure.py
│ ├── governance/ ch30
│ │ ├── catalog_audit.py
│ │ ├── access_review.py
│ │ └── metric_audit.py the quarterly grep
│ ├── cost/ ch33
│ │ ├── rates.yml ONE source of truth
│ │ ├── estimate.py
│ │ ├── pr_cost_bot.py
│ │ └── waste.py
│ ├── finance/ ch38
│ │ ├── rules.md the four rules, with owners
│ │ └── reconcile.py
│ ├── migration/ ch37
│ │ ├── inventory.yml
│ │ ├── reconcile/
│ │ └── rollback/
│ └── ci/
│ └── purity.py ch38 CS2
├── dbt/ ch 18-20
│ ├── dbt_project.yml
│ └── models/{staging,marts}/
├── dags/ ch24
├── infra/ ch28
└── scripts/
├── validate.py
├── xref_audit.py
└── wordcount.py
I.2 Ingestion (ch 13–16)
load_orders.py — incremental by high-water mark, with the four ways updated_at lies documented
inline and a reconciliation against source row counts.
cdc_replay.py — Debezium-shaped records into bronze, with the (order_id, updated_at, cdc_lsn)
dedup and the deterministic tie-break that Chapter 38 Case Study 2 shows the cost of omitting.
api_client.py — exponential backoff with jitter, cursor pagination, a circuit breaker, idempotency
keys, and terminal-versus-retryable error classification.
timestamp_audit.py — flags any timestamp arriving without an offset. 14 of Kestrel's 41 external
timestamp columns; nine remain unresolved, which is correct.
I.3 Contracts and Quality (ch 17, 23)
contracts/orders.yml — schema, semantics, guarantees, and a deprecation window. Consumer-driven:
the producer's CI fails when a consumer's assertion breaks.
quality/register.py — 22 assertions across validity, completeness, consistency, timeliness, and
uniqueness, each with a severity and an owner. Plus the two added later: an input-volume band
(ch38 §38.13) and a ceiling on every published count (ch30 CS1).
quality/quarantine.py — rejected rows with the assertion that rejected them, a replayable
_batch_id, a paging size limit, and a 30-day retention that forces the drain.
I.4 Transformation (ch 18–22)
models/staging/ stg_orders, stg_order_lines, stg_customers, stg_events
models/marts/core/ dim_customer (SCD2), dim_product, dim_date, fct_order_line
models/marts/finance/ daily_revenue, fin_margin
fct_order_line is incremental with a 90-day lookback, because refunds settle late and a closed
month must be restatable (ch38 §38.5).
dim_customer is SCD Type 2 with valid_from/valid_to/is_current, and it doubles as a
point-in-time-correct feature table (ch32).
I.5 Orchestration and Delivery (ch 24, 27, 28)
dags/kestrel_daily.py — the 6am SLA path: ingest → sessionize → dbt build → quality → reconcile.
Every task keyed on the logical date, max_active_runs=1, deferrable sensors, and an alert on
remaining SLA slack below 45 minutes rather than on the breach.
CI — state:modified+ against a stored production manifest, layer_check, purity.py, the cost
bot, and the sealed-figure check.
infra/ — Terraform with remote state, separated by blast radius, OIDC for CI, and a nightly drift
plan that now includes grants (ch30 CS2).
I.6 Governance, Privacy, Cost (ch 30, 31, 33)
catalog_audit.py — 22 checks; the demo fixture yields 11 findings.
privacy/manifest.py — generated from classification tags, not written. A new table carrying
customer_id joins the deletion manifest automatically and fails verification loudly if it has no
mechanism. This is the highest-leverage single design in the book.
cost/rates.yml — the frozen rate card: $2.400`/node-hour, `$0.023/GB-month, $2.00/credit,
$6.25`/TiB, `$0.09/GB egress.
I.7 The Verification Layer
Four things that produce no data and gate everything:
python platform/layers/layer_check.py --check # 9 rules; must be 0 blocking
python platform/privacy/manifest.py --verify # every customer_id table has a path
python platform/ci/purity.py # no network, now(), or random in a model
python platform/layers/replay.py --from bronze --into scratch_verify
The last one costs $198.96 and four hours, and has failed three times in two years.
I.8 Line Counts
| Area | Files | Lines | Chapters |
|---|---|---|---|
| Ingestion | 9 | ~1,400 | 13–16 |
| Contracts & quality | 6 | ~900 | 17, 23 |
| dbt models | 31 | ~1,900 | 18–20 |
| Orchestration | 7 | ~800 | 24 |
| CI & infra | 14 | ~1,100 | 27, 28 |
| Governance & privacy | 11 | ~1,600 | 30, 31 |
| ML | 8 | ~700 | 32 |
| Cost | 5 | ~600 | 33 |
| Layers & events | 12 | ~1,500 | 34, 36 |
| Migration | 9 | ~700 | 37 |
| Finance & capstone | 4 | ~500 | 38 |
| Total | 116 | ~11,700 |
Under twelve thousand lines for a platform that ingests 2.4M orders and 5.1 billion events a year, reconciles to the cent, and can be rebuilt from raw for $198.96. Most of it is assertions.
I.9 The Capstone Reconciliation
Stop here if you have not computed it yourself. Chapter 38 §38.6.
November 2026, as of 2026-12-01:
lines cents
──────────────────────────────────────────────────────────────
source, all rows 856,117 $24,102,447.18
less R1 test orders 854,705 $24,061,239.18
less R2 cancelled 811,798 $22,856,356.83
less R3 gift cards 781,380 $21,945,202.00
less R4 refunds 781,380 $20,430,983.06
──────────────────────────────────────────────────────────────
GOLD LINES 781,380
GOLD GROSS REVENUE $21,945,202.00
REFUNDS $1,514,218.94
GOLD NET REVENUE $20,430,983.06
The four rules, with owners:
| id | rule | lines | cents | owner |
|---|---|---|---|---|
| R1 | test orders excluded | 1,412 | $41,208.00 | #data-platform |
| R2 | cancelled orders excluded | 42,907 | $1,204,882.35 | #finance |
| R3 | gift card lines excluded | 30,418 | $911,154.83 | #finance |
| R4 | refunds netted, by month sold | — | $1,514,218.94 | #finance |
Verification, and this is the part that matters more than the closing:
781,380 lines / (6,480,000 / 12) = 1.447x
$21,945,202 / ($182,000,000 / 12) = 1.447x
$21,945,202 / 781,380 = $28.085 per line
Chapter 1: $75.83 AOV / 2.70 lines = $28.084 per line
Two independent ratios agreeing to three decimals, and a per-line figure matching Chapter 1's independently-derived one to four significant figures — neither of which the reconciliation forced.
capstone.py --self-check asserts all of it: 38 checks.
I.10 Getting the Code
Every chapter's code/ directory is in the repository alongside its prose. They are standalone,
dependency-free, and deterministic.
# verify everything
python scripts/validate.py
python scripts/xref_audit.py
for f in part-*/chapter-*/code/*.py; do
echo -n "$(basename $f): "; python "$f" --self-check | head -1
done
Expected: 0 errors, 0 broken references, and every self-check passing. A failure on an unmodified file is a bug worth reporting; a failure after you have changed a fixture is the file working as designed.