Capstone — build a pipeline end to end
You’ve learned every piece. This capstone puts them together into one real pipeline: no new features, just the whole track working as a unit. You’ll build it, validate it before it runs, and run it.
The brief
Section titled “The brief”Build a customer pipeline that:
- Reads
customers.csvwith a declared schema (status,lifetime_value). - Keeps only active customers and computes a
tier:"gold"whenlifetime_valueis over a threshold, else"standard". The threshold must be a pipeline variable so a channel can change it per tenant. - Routes gold customers down one branch and everyone else down another.
- Writes two outputs:
gold.csvandstandard.csv. - Summarizes per tier (a count of customers and their total lifetime value) with an
aggregate, written to
summary.csv. - Continues past bad rows, sending failures to a dead-letter queue.
Each requirement is something the track already taught:
| Requirement | From lesson |
|---|---|
| Source + declared schema | 01: Sources & schema |
filter + emit + the if/then/else tier | 02: Transforms & CXL |
route with a condition and a default | 03: Composition |
Per-tier summary with an aggregate (count + sum) | 05: Groups & windows |
Threshold as a $vars value a channel can override | 04: Channels |
error_handling + dlq | 07: Errors & the DLQ |
Confirm it with --dry-run / --explain | 08: Validate before you run |
Build it
Section titled “Build it”Start from this scaffold (the source is given) and add the transform, the route, the
aggregate, the three output nodes, and the error_handling block. Then check yourself
against the reference below.
pipeline: name: customer_capstone vars: gold_threshold: { type: int, default: 10000 }nodes: - type: source name: customers config: name: customers type: csv path: ./data/customers.csv options: { has_header: true } schema: - { name: status, type: string } - { name: lifetime_value, type: string } # TODO: classify (filter active; emit tier from $vars.gold_threshold) # TODO: route by_tier (gold vs default standard) # TODO: aggregate tier_summary (group_by tier; count + sum), also reading from classify # TODO: two outputs — gold.csv and standard.csv # TODO: summary output — summary.csv from tier_summary# TODO: error_handling with a dlqRun the reference
Section titled “Run the reference”Here is the complete pipeline. Predict what lands in each output, then run it.
> output appears here — predict, then run
The inactive customer was dropped by filter status == "active", so it appears in neither
output. Of the two active customers, 80000 clears the 10000 threshold (gold) and 4000 does
not (standard), and each is routed to its own file. The same classified rows also fan out to
the aggregate, which groups by tier and reports one customer and the matching total in each
group, so summary.csv counts the two tiers without the dropped inactive row ever appearing.
Validate before you ship it
Section titled “Validate before you ship it”The habit from lesson 08: never ship a pipeline you haven’t validated. Before a real run,
clinker run customer_capstone.yaml --dry-run # config + schema valid?clinker run customer_capstone.yaml --explain # the plan: nodes, wiring, outputs--dry-run catches a misspelled input:, an undeclared schema type, or a CXL compile error
in a second; --explain shows the shape (source → classify → route + aggregate → three
outputs) so you can confirm the wiring matches the brief, including that classify fans out to
both the route and the aggregate.