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.
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:
-
A structurally misplaced
stepsblock should fail before a normal job runner can execute. - 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:
inspectandtest. -
testdepends oninspectbut does not expect its filesystem. - Both jobs use
ubuntu-24.04. - All
runsteps 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, notwrite-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
- Keep the three checkpoint workflow versions/evidence until review is complete.
- If the disposable branch is no longer needed, delete only that branch after preserving the packet.
- If using a disposable repository, delete only that explicitly named repository after confirming no other work exists in it.
- Do not delete failed runs merely to make the Actions history look green.
- 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.
Knowledge check
Why does the checkpoint preserve Version S even though it never produced a useful job run?
Because it proves a distinct pre-run structure/schema failure class and records the exact invalid revision/validation evidence rather than conflating it with runner execution.
Why is the Version E consumer failure useful instead of merely “broken YAML”?
It proves a valid job graph can still fail because separate hosted jobs do not share ephemeral filesystems; the run/job logs localize the failure to execution/dataflow.
Why does final Version F checkout twice?
Each job that requires repository source runs on its own fresh hosted runner, so each independently acquires the exact source revision.
Does final Version F prove cross-job artifact transfer works?
No. It deliberately avoids file transfer by recreating required state. Artifacts are a later chapter and are explicitly listed as a checkpoint limitation.
What is the Chapter 03 bridge?
With workflow structure and job boundaries established, Chapter 03 can focus on the event-selection layer: when the workflow is created and what ref/SHA/payload it receives.
Official references and version notes
- Understanding GitHub Actions — current definitions and execution relationships for workflows, jobs, steps, actions, and runners.
- Workflow syntax for GitHub Actions — authoritative workflow structure, jobs, steps, permissions, defaults, runners, and shell behavior.
-
Setting default shell and working directory
— current precedence and restrictions for workflow/job
defaults.run. - Using GitHub-hosted runners — job-to-runner isolation and filesystem sharing within a job.
- Secure use reference — current guidance to pin action dependencies to full-length commit SHAs and minimize privileges.
- actions/checkout v7.0.1 — upstream release recorded for the immutable checkout dependency.
- actions/setup-python v7.0.0 — upstream release recorded for the immutable Python toolchain dependency.
- Events that trigger workflows — bridge reference for Chapter 03 event/ref/SHA semantics.
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.