Chapter 02Lesson 05~165 minutes

Checkpoint Lab — Workflow Files, YAML Structure, Jobs, Steps, and Actions

The checkpoint makes Chapter 02 auditable. You will build a two-job workflow, first introduce a structural error that prevents normal execution, then introduce a runner-time filesystem error that produces a failed job, preserve both forms of evidence, and finally restore a verified two-job workflow with explicit checkout/tool setup on each job that needs repository state. The result is a small but production-shaped workflow contract.

CheckpointTwo jobsStructural failureExecution failureEvidence packet

Learning objectives

  • Construct a two-job workflow from first principles with explicit runner, shell, permissions, immutable action references, and stable job names.
  • Predict structural/run/job/runner/action state before each version is committed or dispatched.
  • Capture one pre-run structural failure and one runner-time execution failure without deleting or overwriting first-failure evidence.
  • Restore a final workflow that respects fresh-job filesystems and maps each successful job to the exact source SHA and action/tool versions.
  • Produce a concise evidence packet, verification checklist, cleanup/rollback record, and bridge to Chapter 03 event/trigger semantics.

1. Checkpoint contract and safety boundary

Item Checkpoint value
Repository Disposable repository/branch containing only synthetic Chapter 02 fixture code.
Workflow path .github/workflows/ch02-checkpoint.yml
Runner ubuntu-24.04 standard GitHub-hosted runner.
Permissions contents: read only in executable versions that checkout source.
Checkout actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 — verified v7.0.1.
Python setup actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 — verified v7.0.0; Python 3.13.
Secrets/side effects None. No package, release, deployment, API mutation, cloud credential, environment, or self-hosted runner.
Evidence retention Keep structural-error commit/evidence, failed execution run, repaired run, workflow text, source SHA, and notes through review.

2. Fixture and preflight

Use the same synthetic Python fixture from Lesson 2. Confirm locally that the committed files exist and record the source commit:

git status --short
git rev-parse HEAD
git ls-files src/mathbox.py tests/test_mathbox.py

Write down two predictions before changing the workflow:

  1. A structurally misplaced steps block should fail before a normal job runner can execute.
  2. A file created only in job A should not appear in job B's fresh hosted runner unless it is explicitly transferred or recreated.

3. Version S — deliberate structural failure

name: Chapter 02 checkpoint - structural failure
on:
  workflow_dispatch:
permissions: {}

jobs:
  build:
    runs-on: ubuntu-24.04
  steps:
    - run: echo "misplaced"

Commit this only on the disposable checkpoint branch. Preserve:

  • commit SHA;
  • exact workflow text;
  • GitHub editor/Actions validation evidence;
  • whether a normal workflow run/job was created;
  • the current diagnostic wording, without treating that wording as a permanent API contract.

Then fix only the structure. Do not simultaneously add checkout, Python, or extra permissions because that would obscure which change resolved the structural layer.

4. Version E — deliberate execution failure

After structure is valid, create this two-job version:

name: Chapter 02 checkpoint - execution failure
on:
  workflow_dispatch:
permissions: {}

defaults:
  run:
    shell: bash

jobs:
  build:
    name: Build transient marker
    runs-on: ubuntu-24.04
    steps:
      - name: Create job-local evidence
        run: |
          echo "run=$GITHUB_RUN_ID sha=$GITHUB_SHA" > handoff.txt
          cat handoff.txt

  verify:
    name: Incorrectly expect producer filesystem
    needs: build
    runs-on: ubuntu-24.04
    steps:
      - name: Read nonexistent handoff
        run: cat handoff.txt

Dispatch exactly once. Preserve run ID and attempt. The expected causal pattern is build job success followed by verify job failure on a different hosted runner. Record runner names/metadata from logs. Do not rerun until the first failed run is captured.

5. Version F — final verified two-job workflow

The final design keeps two jobs but removes the implicit filesystem handoff. Each job explicitly acquires the repository state it needs; only the second requires Python setup.

name: Chapter 02 checkpoint

on:
  workflow_dispatch:
  push:
    paths:
      - 'src/**'
      - 'tests/**'
      - '.github/workflows/ch02-checkpoint.yml'

permissions:
  contents: read

defaults:
  run:
    shell: bash

jobs:
  inspect:
    name: Inspect exact source revision
    runs-on: ubuntu-24.04
    steps:
      - name: Prove repository is absent before checkout
        run: test ! -f src/mathbox.py

      - name: Checkout repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false

      - name: Verify checkout identity
        run: |
          echo "run=$GITHUB_RUN_ID attempt=$GITHUB_RUN_ATTEMPT runner=$RUNNER_NAME"
          test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
          git status --short

  test:
    name: Test on a fresh runner
    needs: inspect
    runs-on: ubuntu-24.04
    steps:
      - name: Prove fresh job before checkout
        run: test ! -f src/mathbox.py

      - name: Checkout repository again
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false

      - name: Set up Python 3.13
        uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
        with:
          python-version: '3.13'

      - name: Verify and test
        run: |
          test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
          python --version
          python -m compileall -q src tests
          python -m unittest discover -s tests -v

6. Predict before dispatching Version F

Prediction Independent verification
One run is created for the chosen event and exact source/workflow revision. Record event, ref/SHA, run ID, attempt, workflow path.
inspect runs before test. Inspect job graph/timestamps and needs.
Each job has a fresh runner/workspace. Both pre-checkout test ! -f steps pass; record runner metadata.
Checkout resolves the exact event SHA in both jobs. Compare git rev-parse HEAD with GITHUB_SHA.
Only read permission is needed. Workflow declares contents: read; no mutation API/deployment exists.
Python 3.13 is explicit in the test job. Record setup-python action SHA and python --version.

7. Required evidence packet

Create a local Markdown or text packet outside the repository secrets surface with:

  • Source: final commit SHA, workflow file hash/text, event/ref.
  • Structure: job IDs/names, needs, runs-on, workflow/job defaults, permissions.
  • Dependencies: checkout full SHA ↔ v7.0.1; setup-python full SHA ↔ v7.0.0; Python 3.13.
  • Failure S: invalid structural commit and validation evidence; note that runner evidence is absent/not applicable if no job ran.
  • Failure E: run ID/attempt, build success, verify failure, exact missing-file log and runner identities.
  • Final F: run ID/attempt, both job conclusions, exact checked-out SHA, Python version, passing tests.
  • Limitations: no artifact transfer, cache, secret, environment, cloud deployment, self-hosted runner, matrix, or reusable workflow was tested.

8. Verification checklist

  • Exactly two final job IDs: inspect and test.
  • test depends on inspect but does not expect its filesystem.
  • Both jobs use ubuntu-24.04.
  • All run steps use the explicit Bash default.
  • Checkout/setup actions are full-SHA pinned and release labels are documented.
  • Checkout credentials are not persisted because no authenticated Git mutation follows.
  • Workflow permission is contents: read, not write-all.
  • No real secret, PAT, cloud credential, production URL, registry, or deployment target appears.
  • The original structural and execution failures remain preserved after repair.
  • The final run maps both jobs back to the exact same intended source SHA.

9. Cleanup and rollback

  1. Keep the three checkpoint workflow versions/evidence until review is complete.
  2. If the disposable branch is no longer needed, delete only that branch after preserving the packet.
  3. If using a disposable repository, delete only that explicitly named repository after confirming no other work exists in it.
  4. Do not delete failed runs merely to make the Actions history look green.
  5. No external resource rollback is required because the checkpoint performs no publication or deployment.

10. What Chapter 02 adds to the operating model

Chapter 01 gave you the event-to-run evidence chain. Chapter 02 adds the workflow structure contract: file path and revision, supported schema, stable job IDs/names, runner boundary, ordered step semantics, explicit shell/working-directory scope, run versus uses, immutable action dependencies, narrow permissions, and first-failure separation between pre-run structure and runner-time execution.

Chapter 03 builds on this contract by making trigger semantics precise: events, filters, schedules, manual inputs, repository dispatch, and the subtle difference between event ref/SHA values.

Next lesson

Events, Triggers, Filters, Schedules, Manual Runs, and Repository Dispatch

The workflow graph is now understandable. Next, learn exactly when that graph is selected and which event data it receives.

Knowledge check

Why does the checkpoint preserve Version S even though it never produced a useful job run?

Why is the Version E consumer failure useful instead of merely “broken YAML”?

Why does final Version F checkout twice?

Does final Version F prove cross-job artifact transfer works?

What is the Chapter 03 bridge?

Official references and version notes

Version and compatibility note

Version-sensitive behavior was rechecked against primary GitHub documentation and GitHub-maintained action repositories on 2026-09-09. Executable examples use ubuntu-24.04, actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 (upstream release v7.0.1), and where Python setup is needed actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 (upstream release v7.0.0) with Python 3.13. At verification time both actions declare a Node 24 runtime. Runner images, action releases/runtimes, workflow keys, parser diagnostics, and plan-dependent behavior can change; re-resolve current immutable SHAs before copying these examples into long-lived production workflows. The checkpoint is free/disposable-compatible and has no paid/enterprise/cloud-only prerequisite. It intentionally proves structure and runner isolation without artifacts, caches, protected environments, OIDC, or self-hosted infrastructure.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.