Chapter 05Lesson 04~175 minutes

Issues, Labels, Milestones, Iterations, Boards, Epics, and Work Planning: Diagnostics, Failure Modes, Security, and Performance

Diagnose misleading board movement, taxonomy sprawl, scope mismatches, unavailable portfolio features, and issue-closing surprises with an evidence-first and least-destructive workflow.

DiagnosticsClosing patternsBoard semanticsTier checksTaxonomy driftRecovery

Learning objectives

  • Use a repeatable diagnostic sequence for planning failures instead of changing labels, boards, roles, or branches at random.
  • Diagnose a board move that is misinterpreted as independent workflow state and a taxonomy that produces contradictory labels.
  • Distinguish milestone/iteration scope errors from permission and tier problems.
  • Interpret closing-pattern behavior when a merge request targets the wrong branch or never reaches the project default branch.
  • Preserve evidence, choose the least destructive repair, and explain security, performance, and API considerations only where they cause the observed failure.
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. The planning diagnostic sequence

Planning failures are dangerous because they often look harmless: a card is in the “wrong” column, a milestone report misses work, or an issue remains open after merge. Random clicking destroys the evidence that explains why.

  1. Preserve evidence: item URL/IID, current labels/state/milestone, board ID/configuration, MR target/default branch, API status/body.
  2. Identify scope: GitLab host → namespace → group/project → work item → board/milestone/iteration → related branch/MR.
  3. Inspect availability and permission: offering/tier/version, role, group/project scope.
  4. Inspect source state: issue/work-item API, board lists, system notes/resource events, MR description/target branch.
  5. Choose the least destructive correction: change one wrong metadata field or configuration rather than delete/recreate planning history.
  6. Verify independently: re-read the item and the view that originally failed.

2. Failure: “the board has its own state”

Symptom: an operator drags issue #12 into a list named “Doing,” then another engineer changes the issue labels directly and the card disappears. The team says the board “lost” the issue.

Diagnosis: inspect the list type. If “Doing” is a label list backed by flow-doing, the board is filtering/projecting metadata. Removing that label makes the card leave that list. The board did not lose a second copy; the source record changed.

ISSUE_IID="12"
BOARD_ID="1"

glab api "projects/$PROJECT_ID/issues/$ISSUE_IID"   --jq '{iid,title,state,labels,milestone:(.milestone.title // null)}'

glab api "projects/$PROJECT_ID/boards/$BOARD_ID"   --jq '{id,name,lists:[.lists[] | {id,label:(.label.name // null),milestone:(.milestone.title // null),iteration:(.iteration.title // null)}]}' 

Repair: restore the intended underlying label only if the work truly belongs there; otherwise change the board or team expectation. Do not create a duplicate issue to “put the card back.”

3. Failure: uncontrolled taxonomy creates contradictory truth

Symptom: one issue has ready, doing, blocked, urgent, P1, priority-high, and three team labels. Different boards show different stories.

On Free, ordinary labels do not enforce mutual exclusion. This is not a GitLab bug. It is a governance failure. Preserve a label inventory, identify semantic duplicates, choose a canonical vocabulary, then migrate items deliberately. On Premium/Ultimate, scoped labels can enforce one label per scope, but only after the team defines the scopes correctly.

# Inventory labels including ancestor-group labels exposed to the project.
glab api "projects/$PROJECT_ID/labels?include_ancestor_groups=true&per_page=100"   --paginate --jq '.[] | {id,name,description}'

# Inventory open issues that carry either of two suspected duplicate labels.
glab api "projects/$PROJECT_ID/issues?state=opened&labels=urgent&per_page=100"   --paginate --jq '.[] | {iid,title,labels}' 

4. Failure: milestone or iteration scope does not match the team

Symptom: a group dashboard is expected to show four projects in one release, but each project created its own milestone with the same title. Or a learner searches for an iteration at project scope and assumes it was deleted.

Diagnosis: names are not identity. Project milestones and group milestones are different resources. Iterations are group-level resources and the project iterations API exposes iterations from ancestor groups rather than creating project-local iteration objects.

Repair: choose the scope that owns the planning goal. Note that GitLab supports promoting a project milestone to a group milestone in some workflows, and that promotion is documented as irreversible; do not use it as a casual lab repair. For a disposable course project, create the correct resource or document the mismatch instead.

5. Failure: “I cannot see epics, so I must need Maintainer”

Symptom: a Free learner keeps escalating their project role because Iteration, Epic, or configurable Status controls are absent.

Diagnosis: authorization and entitlement are separate. More privilege cannot unlock a feature absent from the tier/offering/version. Check official availability first. Epics, iterations, scoped labels, and configurable status are paid capabilities in current documentation.

Repair: restore the least-privilege role and use the free-compatible simulation. Never grant Maintainer/Owner simply to probe whether a feature exists.

6. Intentionally broken example: the issue refuses to close

Setup: issue #17 is open. MR !8 says Closes #17, but the MR targets branch staging. The project default branch is main. The MR is merged into staging, and issue #17 remains open.

This is expected. Current GitLab automatic closing is tied to qualifying commits/MRs reaching the project’s default branch. A closing keyword is a declaration of relationship; the integration event determines when it becomes a close.

# Preserve the important facts.
glab repo view --output json --jq '{default_branch,path_with_namespace}'
glab mr view 8 -R "$REPO" --output json   --jq '{iid,state,source_branch,target_branch,title,description}'
glab issue view 17 -R "$REPO" --output json   --jq '{iid,state,title,labels,milestone}' 

Least-destructive repair: do not rewrite history or force-push. If the intended change still must reach main, create/merge the correct follow-up MR under normal policy. If the issue should have been closed already for business reasons, close it explicitly and record why. The repair depends on delivery intent, not on forcing the automation to fire retroactively.

7. Failure: a closing reference points to the wrong project/item

Cross-project references can be valid, which means a short #17 may not express the intended target in a complex workflow. When automation or documentation crosses projects, prefer explicit full references and inspect the MR’s Work items/closing widget before merge. The user performing the merge is responsible for verifying the targeted items are appropriate to close.

8. Failure: automation sees only the first 20 issues

The Issues API is paginated and defaults to 20 results. An automation that reports “all blockers” after one page can silently undercount work and produce false release confidence.

# Broken: one request, no pagination handling.
glab api "projects/$PROJECT_ID/issues?state=opened&labels=blocked"

# Better for glab: let --paginate follow pages where supported.
glab api --paginate "projects/$PROJECT_ID/issues?state=opened&labels=blocked&per_page=100"   --jq '.[] | {iid,title,labels}' 

For custom clients, also inspect pagination headers/cursors, handle rate limits, and avoid blind retries of issue mutations. A list endpoint returning HTTP 200 does not prove the inventory is complete.

9. Security and destructive-action boundaries

Planning records may contain customer names, incident details, vulnerability context, or confidential issue data. Do not export full issue descriptions into public evidence merely because the API makes it easy. Collect the minimum fields needed for the diagnostic proof.

Issue deletion, milestone deletion, group/project deletion, bulk edits, and history rewriting are unnecessary for the mandatory repair path. Prefer reversible metadata corrections and closing synthetic items. If a real credential ever appears in an issue or MR, credential revocation/rotation comes before editing GitLab history or deleting the planning item.

10. Performance and reliability are causal, not generic warnings

Large group planning can make unfiltered API scans expensive and slow. Use project/group scope, state, label, milestone, and update-time filters intentionally. Prefer keyset pagination on endpoints that support it for large consecutive inventories. Board rendering and API response time are not reasons to discard planning metadata; they are reasons to query the right scope and avoid unbounded automation.

Knowledge check

An issue disappears from a label-list board after someone removes the label. What failed?

A Free user cannot create an iteration. Should an Owner role fix it?

MR !8 says Closes #17 but merges to staging while main is default. Why can #17 remain open?

Why is a one-page API response dangerous for release planning?

When label taxonomy is contradictory, should you delete and recreate all issues?

Summary

Planning failures become tractable when you separate source metadata from views, entitlement from permission, project scope from group scope, and closing declarations from default-branch integration events. Preserve evidence, identify the exact resource, change the smallest cause, and verify from an independent surface.

Official references

Next lesson

Run the integrated planning checkpoint

Lesson 5 creates a lightweight policy, predicts metadata transitions, operates one delivery slice, verifies board/source consistency, captures evidence, and cleans up without touching real planning data.

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.