---
key: ci.cancelled-is-not-a-verdict
title: 2026-07-21 — `cancelled` is not `failure`; a cancelled run is no verdict (#542)
status: active
since: '2026-07-21'
supersedes: none
superseded-by: none
rule: Treat a `cancelled` conclusion as "no verdict" — never as pass or fail — and report FAILED and CANCELLED counts separately in any CI monitor.
signals: 'conclusion cancelled · run-level vs job-level conclusion · pre-cancel genuine failure · CI monitor state != pending · phantom failure · paths: n/a · issues: #542'
mechanics: Gitea Actions run/job API; monitor logic, e.g. `fail=[j for j in jobs if j['conclusion']=='failure']; canc=[j for j in jobs if j['conclusion']=='cancelled']`.
---

The operator cancels runs by hand — they are the only party who can (see
`ci.batch-pushes-no-cancel-route`) — and a run-level `conclusion: cancelled` means the run produced
**no verdict** about your diff. Two traps follow. First, a run whose *overall* state is `failure` may
hold a **genuine job failure that happened before the cancel**: check job-level `conclusion` plus
timestamps rather than attributing the red to the cancel. Second, a cancelled run tells you nothing,
so never claim green on one.

A monitor that only asks "is state != pending" will report a cancelled run as a failure and send the
next session debugging a phantom. Split the two counts explicitly.
