Skip to content

L01 CI/CD pipeline anatomy

Lesson 00 named the current delivery paths. This lesson teaches how to read a workflow file as a delivery graph: a trigger starts a run, jobs form the graph, steps do the work, gates decide whether the graph can advance, artifacts carry evidence forward, environments receive promoted output, and feedback tells the operator what happened.

The examples stay anchored in the lab. fos-workbench uses .github/workflows/ci.yml to validate tutorial/docs changes and publish the docs surface. The sibling fos shape uses pr.yml, staging.yml, and release.yml to validate an app, promote it to Cloudflare Pages staging, and then release production behind a GitHub environment gate.

Azure is not part of the current delivery-platform operating model. The Azure workflow remains deployment-target validation and historical context, not the pipeline used to ship the tutorial/docs site or sibling fos app.

TermHow to read it in YAMLLab example
TriggerThe on: block that decides when the graph starts.fos-workbench starts CI on pull requests and pushes to main; sibling fos starts production release on a v* tag or manual dispatch.
JobA named node under jobs: with its own runner, permissions, timeout, and steps.editor, serving, and deploy-docs are separate fos-workbench jobs.
StepOne action or command inside a job.npm run typecheck, uv run ... dbt test, actions/upload-artifact@v4, and wrangler pages deploy are steps.
GateA condition that must pass before later work matters.Tests, generated-reference drift checks, needs: [editor, serving], branch/tag filters, and the sibling fos production environment approval gate.
ArtifactA generated file or bundle kept for a later job, deployment, or reader.Generated OpenAPI/dbt references, the evaluation snapshot, the serving DuckDB warehouse, the Astro docs bundle, the Observable dashboard bundle, and sibling fos SvelteKit build output.
SecretA credential supplied by GitHub at runtime, not committed to the repo.deploy-docs uses secrets.CLOUDFLARE_API_TOKEN and secrets.CLOUDFLARE_ACCOUNT_ID for Cloudflare Pages publishing.
EnvironmentA named runtime place or protected release target.dataplatform.kodeklaus.dk, Cloudflare Pages staging for sibling fos, Cloudflare Pages production, and the GitHub production environment gate.
Deployment jobA job that publishes or promotes output after validation.deploy-docs publishes docs-site/dist; sibling staging.yml and release.yml deploy the app.
Smoke checkA post-deploy runtime check that proves the environment behaves.fos-workbench checks public analytical-surface routes; sibling fos checks login reachability and private API authorization boundaries.
Failure modeThe reason a graph stops or a release is unsafe.Typecheck failure, reference drift, missing uploaded artifacts, failed dbt or pytest runs, missing Cloudflare credentials, a blocked production approval, or a failed smoke check.

Start with the YAML shape instead of the shell commands.

  1. Read on: first. This tells you whether the run is a pull-request validation path, a push-to-main publish path, a tag release path, a manual run, or scheduled automation.
  2. Read the job names next. Job names usually reveal the graph: validation jobs first, deployment and publishing jobs after them.
  3. Look for needs, if, path filters, branch filters, tag filters, and GitHub environments. Those are gates.
  4. Look for upload/download artifact steps. Those show what one job proves or produces for the next job.
  5. Look for credentials under env: and secrets.*. Those mark the boundary where CI can become CD without storing secrets in the repo.
  6. Look for smoke checks after deploy commands. Those are feedback from the runtime environment, not just from the build.

In fos-workbench, editor and serving are validation gates. They prove that generated references are current, TypeScript checks pass, Evalite passes, dbt compiles and tests, Python tests pass, Dagster definitions validate, and the streaming marker e2e still works. deploy-docs is a deployment and publishing job. It runs only after those gates pass and only on main.

That separation matters: validation gates answer “is this change trustworthy?” Deployment and publishing jobs answer “can we put the trusted output in an environment and prove it works there?”

The main file is .github/workflows/ci.yml.

TriggerGateArtifactEnvironmentFeedback
Pull request to maineditor typecheck/test/eval and serving dbt/pytest/Dagster/streaming checksGenerated references and snapshots are checked for drift or produced inside CI, but nothing is publishedNonePull request status checks show whether the change can merge
Push to maindeploy-docs waits for needs: [editor, serving]Generated OpenAPI/dbt references, evaluation snapshot, serving DuckDB warehouse, Astro docs bundle, Observable dashboard bundleCloudflare Pages docs site at dataplatform.kodeklaus.dkPublic analytical-surface route checks after deploy

The artifact flow is the promotion clue. serving uploads generated docs references and the serving DuckDB warehouse. editor uploads the evaluation snapshot. deploy-docs downloads those artifacts, builds docs-site/dist, adds the Observable dashboard bundle under docs-site/dist/dashboard, and publishes the combined site to Cloudflare Pages.

Promotion here is not a separate release ceremony. It is the movement from validated artifacts on a main push into the public docs environment.

The sibling fos workflow shape uses the same anatomy but different environments because it ships an application.

In that shape, promotion means moving from pull-request CI proof to Cloudflare Pages staging, then from an approved release request to production. Promotion path: Cloudflare Pages staging, then production.

TriggerGateArtifactEnvironmentFeedback
Pull request to main in pr.ymlBuild, Svelte typecheck, unit tests, and advisory high-severity auditApp build evidence inside CINonePull request status checks
Push to main in staging.ymlApp build and branch/path conditionsSvelteKit build output deployed by WranglerCloudflare Pages staging/login reachability and private workspace API auth failure check
v* tag or manual dispatch in release.ymlApp build plus GitHub production environment approvalSvelteKit build output promoted to productionCloudflare Pages productionBetter Auth provider boundary and private API authorization smoke checks

This is why pr.yml is CI, while staging.yml and release.yml are CD. pr.yml proves the app. staging.yml and release.yml place a built app into named environments and then check runtime behavior.

Production promotion has an explicit gate. A tag or manual dispatch can request release, but the GitHub production environment approval decides whether the deployment may proceed.

Secrets sit at the moment a trusted graph needs external authority. The repo can build a docs bundle without Cloudflare credentials. It cannot publish that bundle to Cloudflare Pages without credentials supplied at runtime.

That split is the platform contract:

  • source code and workflow logic are reviewable in the repo;
  • credentials live in GitHub Actions secrets or environment configuration;
  • deployment jobs receive the credentials only when their gates allow them to run;
  • smoke checks report whether the target environment accepted the change.

For fos-workbench, the visible example is deploy-docs: Cloudflare account and API token secrets are used only in the publishing job. For sibling fos, the staging and production deploy jobs use the same idea around separate Cloudflare Pages environments, with production also protected by the GitHub production environment gate.

Every pipeline graph should make failure modes visible. In these repos, common failure modes are:

  • trigger mismatch: a workflow does not run because the branch, tag, or path filter does not match;
  • validation failure: typecheck, unit tests, Evalite, dbt, pytest, Dagster, or streaming e2e fails;
  • drift failure: generated OpenAPI or docs reference output differs from what is checked in;
  • artifact failure: a downstream job cannot download the references, snapshot, warehouse, or build output it expects;
  • secret failure: Cloudflare credentials or environment variables are missing or invalid;
  • environment gate failure: production approval is not granted;
  • smoke-check failure: deployment completed, but runtime behavior does not match the expected public routes or auth boundaries.

The important delivery-platform habit is to ask which category failed. “The pipeline is red” is too vague. “The validation gate failed before artifact promotion” or “the deploy succeeded but the smoke check failed” tells the operator where to look.

  1. A pull request changes only tutorial prose in fos-workbench. Which part of the graph gives feedback, and why is there no environment?

    Expected reasoning: the pull request trigger starts CI. The editor and serving validation gates report status checks. deploy-docs does not run because publishing is limited to pushes to main, so no environment is changed.

  2. serving passes tests and uploads the serving DuckDB warehouse, but editor fails the generated OpenAPI drift check. Should deploy-docs publish?

    Expected reasoning: no. deploy-docs needs both editor and serving, so one failed validation gate blocks artifact promotion to Cloudflare Pages.

  3. Why is the sibling fos staging workflow CD even if it also builds and tests the app?

    Expected reasoning: a workflow can contain validation steps and still be CD when its purpose is to place a built artifact into an environment. The staging workflow deploys to Cloudflare Pages staging and then smoke-checks runtime behavior.

  4. A production release tag is pushed in sibling fos, but the GitHub production environment is not approved. What kind of failure is that?

    Expected reasoning: it is an environment gate failure, not a build failure. The release request exists, but promotion to production is intentionally blocked until approval is granted.

  5. A deploy step finishes, but the public auth smoke check says a private API returns data without authorization. Did CI or CD fail?

    Expected reasoning: CD failed after deployment. The build artifact was promoted, but runtime feedback proved the environment is unsafe.