Chapter 05Lesson 05~215 minutes

Checkpoint Lab — Issues, Labels, Milestones, Iterations, Boards, Epics, and Work Planning

Plan and execute a miniature delivery slice from issue to branch and merge request, prove that planning views reflect underlying metadata, collect evidence, and clean up synthetic work safely.

CheckpointDelivery sliceEvidencePredictionsCleanupChapter 06 bridge

Learning objectives

  • Define a lightweight planning policy before creating work and record Free/tier/version assumptions explicitly.
  • Create a miniature delivery slice with issues, labels, a milestone, a board, a branch, and a merge request while predicting key state transitions first.
  • Prove from independent surfaces that board columns reflect underlying work-item metadata and that merge-request closing behavior depends on the default-branch event.
  • Produce a compact evidence packet that distinguishes observed GitLab state from paid-feature simulations and does not contain credentials or unnecessary private content.
  • Clean up synthetic work safely and state how Chapter 05 strengthens the production GitLab operating model before moving to collaboration utilities in Chapter 06.
Availability baseline (verified 2026-08-21). Issues/work items, ordinary project/group labels, milestones, and basic issue boards are documented for Free, Premium, and Ultimate on GitLab.com, Self-Managed, and Dedicated. Scoped labels, iterations, configurable work-item status, and epics are Premium/Ultimate. Iterations are group-level timeboxes. Epics are now exposed through the work-item model in current GitLab; the legacy Epics REST API is deprecated and GitLab 18.1+ documentation directs integrations to the Work Items API/GraphQL path. Board list/scope capabilities vary by tier. Always verify the current GitLab version/tier before relying on a planning field or API.

1. Checkpoint mission and safety preflight

You are the maintainer of a disposable project preparing a tiny “CH05 Demo” delivery slice. Your job is not to build a feature-rich planning system. Your job is to prove the invariants behind one: metadata has defined meaning, board views reflect that metadata, Git objects and planning records remain distinct, and work-to-MR relationships behave as predicted.

  • Offering/tier: GitLab.com Free or equivalent Free Self-Managed/Dedicated access where the documented Free features are available.
  • Role: enough project permission to create/edit issues, labels, milestones, board configuration, branches, and a draft MR in a disposable project you control.
  • Tools: Git, glab, and jq.
  • Not required: runner/CI minutes, Premium/Ultimate, Dedicated tenancy, Self-Managed admin, cloud, Kubernetes, AI/Duo, registry, or second account.
  • Safety: all titles use [CH05 LAB]; no real backlog, secrets, customer data, or production repository.

2. Write the policy before the first issue

Record this contract in a local ch05-policy.md file or your lab notes:

# CH05 planning policy
- type labels: exactly one of type-bug | type-docs | type-feature (team convention)
- flow labels: at most one of flow-ready | flow-doing (team convention)
- delivery goal: one project milestone named CH05 Demo
- board: projects flow labels; it does not own separate work state
- ownership: assignee means current accountable person
- closure: only a deliberate closing pattern reaching the default branch may auto-close
- paid fields: scoped labels, iteration, status, epic are optional/fixture only on Free

Prediction 1: moving an issue from the Ready label list to Doing will replace the team-convention flow label in the source issue (assuming the board is configured with those label lists).

Prediction 2: creating a draft MR containing Closes #IID will not immediately close the issue; the issue should remain open until a qualifying merge/commit reaches the project default branch.

3. Capture target and current state

glab auth status

glab repo view --output json   --jq '{path_with_namespace,visibility,default_branch,web_url}'   | tee ch05-project-before.json

git status --short --branch
git remote -v

glab issue list --all --output json   --jq '[.[] | select(.title | startswith("[CH05 LAB]")) | {iid,title,state}]' 

If synthetic items from a prior attempt exist, reuse or clean them deliberately instead of creating duplicates. Record the current default branch; the checkpoint later compares it with the MR target.

4. Create the planning resources

Use the same metadata policy as Lesson 2. Inspect before each create in a real run; the commands below show the intended mutations.

PROJECT_ID="123456"        # disposable project numeric ID
REPO="group/example-project" # disposable full path

# Labels (create only when absent).
for spec in   'type-bug|#D9534F|CH05 lab defect'   'type-docs|#428BCA|CH05 lab docs'   'type-feature|#5CB85C|CH05 lab feature'   'flow-ready|#F0AD4E|CH05 lab ready'   'flow-doing|#8E44AD|CH05 lab active'; do
  IFS='|' read -r name color desc <<EOF
$spec
EOF
  if ! glab api "projects/$PROJECT_ID/labels?search=$name" --jq '.[].name' | grep -Fxq "$name"; then
    glab api "projects/$PROJECT_ID/labels" -X POST -f name="$name" -f color="$color" -f description="$desc" >/dev/null
  fi
done

# Milestone (create only when absent).
MILESTONE_ID="$(glab api "projects/$PROJECT_ID/milestones?state=active&search=CH05%20Demo" --jq '.[] | select(.title=="CH05 Demo") | .id' | head -n1)"
if [ -z "$MILESTONE_ID" ]; then
  MILESTONE_ID="$(glab api "projects/$PROJECT_ID/milestones" -X POST -f title='CH05 Demo' -f description='Disposable Chapter 05 milestone' --jq '.id')"
fi
printf 'milestone_id=%s
' "$MILESTONE_ID"

# Three synthetic issues.
glab issue create -R "$REPO" -t '[CH05 LAB] Fix parser edge case' -d 'Synthetic checkpoint defect.' -l type-bug,flow-ready -m 'CH05 Demo' --yes
glab issue create -R "$REPO" -t '[CH05 LAB] Add operator note' -d 'Synthetic checkpoint docs.' -l type-docs,flow-ready -m 'CH05 Demo' --yes
glab issue create -R "$REPO" -t '[CH05 LAB] Add dry-run option' -d 'Synthetic checkpoint feature.' -l type-feature,flow-ready -m 'CH05 Demo' --yes

# Capture the three IIDs.
glab api "projects/$PROJECT_ID/issues?scope=all&state=opened&per_page=100" --paginate   --jq '.[] | select(.title | startswith("[CH05 LAB]")) | {iid,title,labels,milestone:(.milestone.title // null)}'   | tee ch05-issues-created.ndjson 

5. Build the board and prove Prediction 1

Create CH05 Flow if needed and add label lists for flow-ready and flow-doing. Use the current issue-board UI or Boards API. Then move only the parser issue from Ready to Doing.

# Current glab supports creating a project issue board.
glab issue board create 'CH05 Flow' -R "$REPO"

# Read board structure; identify the intended board/list types.
glab api "projects/$PROJECT_ID/boards" --paginate   --jq '.[] | {id,name,lists:[.lists[]? | {id,label:(.label.name // null)}]}'   | tee ch05-boards.json

# After the drag in the UI, verify the source issue independently.
PARSER_IID="1"  # replace with actual IID
glab api "projects/$PROJECT_ID/issues/$PARSER_IID"   --jq '{iid,title,state,labels,milestone:(.milestone.title // null)}'   | tee ch05-parser-after-board.json 

Pass condition: the issue contains flow-doing and no longer carries the lab’s flow-ready workflow label. If both remain, inspect the board configuration and remember that Free ordinary labels rely on team convention rather than scoped-label exclusivity.

6. Create the branch/MR and prove Prediction 2

Use a harmless documentation change. This proves traceability without introducing CI or deployment complexity.

DEFAULT_BRANCH="$(glab repo view -R "$REPO" --output json --jq '.default_branch')"
BRANCH="$PARSER_IID-ch05-checkpoint"

git switch "$DEFAULT_BRANCH"
git pull --ff-only
git switch -c "$BRANCH"
printf '
CH05 checkpoint marker.
' >> CH05_LAB.md
git add CH05_LAB.md
git commit -m "docs: chapter 05 checkpoint marker"
git push -u origin "$BRANCH"

glab mr create -R "$REPO"   --source-branch "$BRANCH" --target-branch "$DEFAULT_BRANCH"   --title '[CH05 LAB] Parser delivery slice'   --description "Closes #$PARSER_IID

Synthetic checkpoint MR; do not merge into a valuable branch."   --draft --yes

MR_IID="$(glab mr list -R "$REPO" --source-branch "$BRANCH" --output json --jq '.[0].iid')"
glab mr view "$MR_IID" -R "$REPO" --output json   --jq '{iid,state,title,source_branch,target_branch,description}'   | tee ch05-mr.json

glab issue view "$PARSER_IID" -R "$REPO" --output json   --jq '{iid,state,title,labels,milestone}'   | tee ch05-parser-before-merge.json 

Pass condition: the issue is still open. The MR has a closing relationship, but it has not been integrated into the default branch.

Optional live close proof: only in this disposable project, remove Draft status and merge the MR through the normal project policy if you want to observe automatic closure. No force push, bypass, or admin override is needed. Then verify the issue changed to closed. The mandatory checkpoint can instead stop at the predicted pre-merge state and use the official documented behavior as the final event model.

7. Compare UI, glab, API, and Git evidence

Invariant UI evidence CLI/API/Git evidence
Correct work record Issue/work-item page Issues API iid/title/state
Workflow move changed metadata Board + issue sidebar Issues API labels
Delivery goal is attached Milestone on item Issues API milestone.title
Branch is separate Git state Repository branch view git branch -vv, commit SHA
MR links delivery to planning MR Work items/description glab mr view + issue state
Board is a view Card appears in label list Boards API list type + issue labels

9. Evidence packet and verification checklist

Collect only planning fields needed to prove the checkpoint. Avoid full confidential descriptions or user email addresses.

mkdir -p ch05-evidence
cp ch05-project-before.json ch05-evidence/
cp ch05-issues-created.ndjson ch05-evidence/
cp ch05-boards.json ch05-evidence/
cp ch05-parser-after-board.json ch05-evidence/
cp ch05-mr.json ch05-evidence/
cp ch05-parser-before-merge.json ch05-evidence/
[ -f ch05-paid-fixture.json ] && cp ch05-paid-fixture.json ch05-evidence/

python - <<'PY'
from pathlib import Path
import hashlib, json, datetime
root=Path('ch05-evidence')
items=[]
for f in sorted(root.iterdir()):
    if f.is_file():
        items.append({'file':f.name,'sha256':hashlib.sha256(f.read_bytes()).hexdigest(),'bytes':f.stat().st_size})
out={'captured_at_utc':datetime.datetime.now(datetime.timezone.utc).isoformat(),'files':items}
(root/'manifest.json').write_text(json.dumps(out,indent=2)+'
')
PY
cat ch05-evidence/manifest.json
  • Three synthetic issues have one type label and the CH05 Demo milestone.
  • The parser issue’s flow metadata matches the board column.
  • The board API proves the relevant list is label-backed.
  • The branch and MR are identifiable separately from the issue.
  • The MR target equals the recorded default branch.
  • The issue state before merge matches Prediction 2.
  • Any paid-feature data is clearly marked live or simulated.

10. Cleanup / rollback

Cleanup should preserve useful evidence and avoid destructive shortcuts. The safest mandatory cleanup is to close synthetic work and remove the temporary branch/MR without deleting the whole project.

# If the draft MR was not merged, close it explicitly.
glab mr close "$MR_IID" -R "$REPO" || true

# Close only synthetic Chapter 05 issues.
glab issue list -R "$REPO" --all --output json   --jq '.[] | select(.title | startswith("[CH05 LAB]")) | .iid'   | while read -r iid; do
      glab issue close "$iid" -R "$REPO" || true
    done

# Remove local branch after switching away. Delete remote branch only if it is the synthetic lab branch.
git switch "$DEFAULT_BRANCH"
git branch -D "$BRANCH" || true
git push origin --delete "$BRANCH" || true

# Verify no synthetic open issues/MRs remain.
glab issue list -R "$REPO" --opened --output json   --jq '[.[] | select(.title | startswith("[CH05 LAB]")) | {iid,title}]'
glab mr list -R "$REPO" --state opened --output json   --jq '[.[] | select(.title | startswith("[CH05 LAB]")) | {iid,title}]' 
Do not delete a real project, group, milestone, board, or planning history merely to satisfy cleanup. Labels, milestone, and the disposable board may be kept for later chapters or removed only after verifying they are synthetic and unused. Project/group deletion is not required.

11. What this chapter adds to a production GitLab operating model

Chapter 01 established platform boundaries, Chapter 02 identities, Chapter 03 project governance, and Chapter 04 authorization inheritance. Chapter 05 adds the work-control plane: a small taxonomy, explicit delivery goals, traceable ownership, view/source separation, API-readable evidence, and a clear bridge from planned work to code change.

The production invariant is: every planning view must be explainable from source work-item metadata, every automation must have an explicit state-transition contract, and every paid/portfolio assumption must be labeled before it becomes a dependency.

Knowledge check

You drag the parser issue to Doing, but the API still shows flow-ready. What should you do first?

The draft MR contains Closes #12. Why is issue #12 expected to remain open?

A teammate wants iterations and epics in the mandatory Free checkpoint. What is the correct response?

Why capture board configuration as well as issue labels?

What does the evidence manifest hash prove?

What is the safest cleanup if the project will be reused in Chapter 06?

Checkpoint summary

You defined policy before data, created a Free-compatible backlog, predicted two state transitions, proved board/source consistency, connected one issue to Git and a merge request, distinguished closing intent from the default-branch close event, and captured auditable evidence without requiring paid features. That planning discipline now supports collaboration rather than replacing it.

Official references

Chapter 06

Wikis, snippets, discussions, Service Desk, notifications, and collaboration utilities

The next chapter expands beyond structured planning into the collaboration surfaces teams use to document, discuss, receive, and route work while preserving the same namespace, permission, and evidence discipline.

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.