fix(ci): main-red-watchdog skips cancel-cascade entries (mc#1564) #1571
Reference in New Issue
Block a user
Delete Branch "fix/main-red-watchdog-skip-cancel-cascade-mc1564"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Closes #1564.
main-red-watchdogwas filing phantom[main-red]issues because Gitea maps bothaction_run.status=2(Failure) andstatus=3(Cancelled) to commit-status string"failure". On a busymainwithconcurrency: cancel-in-progress: true, every merge burst cancels prior in-flight runs (status=3), inflating the watchdog's red%.This PR implements option B from #1564 (description-string filter, no extra API call):
is_red()excludes per-entry items whosedescription == "Has been cancelled"(the literal Gitea description for cancelled runs; real failures carry"Failing after Ns").Verified empirically against mc#1562 body — that issue contains 3 real failures (
Failing after 8s/1m49s/1m21s) + 1 cancel-cascade (Has been cancelled). With this filter, mc#1562 would have filed with only the 3 real failures (correct), and a pure-cancel-cascade SHA would not file at all.Canonical Gitea 1.22.6 enum
Per
models/actions/status.go:Source: operator memory
reference_gitea_action_status_enum_corrected_2026_05_19+reference_chronic_red_sweep_cancelled_vs_failed_filter(saved during mc#1529 triage).Behaviour change
is_red()now drivesredoff the filtered failed list, not raw combined-state. Combined=failurewith all-cancelled per-entry → not red. Combined=failurewith emptystatuses[]is preserved as red (the CI-emitter-direct edge case fromrender_body's existing fallback).Exact-match (not substring) so a hypothetical real-failure log line containing
"Has been cancelled by ..."still counts as red.Out of scope
ci.yml(18 in 7d, real status=2) remain to file separately once root-caused.Test plan
tests/test_main_red_watchdog.pycovering: cancel-cascade alone (not red), real-failure alone (red), mixed (red, only real in body), all cancelled (not red), combined+empty fallback (still red), exact-match contract.tests/test_main_red_watchdog.pypass locally (Python 3.13).:05) observed on realmain— confirm no new phantom[main-red]issue files when only cancel-cascade present.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
5-axis (core-security):
Secrets: None handled. The watchdog reads Gitea status payloads; description-string match is a literal compare.
Privilege: No new surface — same
combined/statuses[]read shape. The cancel-cascade filter strictly NARROWS what counts as red (fewer issue-files), so least-privilege effect.Input handling: Description-string match uses exact compare after
.strip()— explicitly rejects substring (the over-match test locks this contract:"Has been cancelled by the user unexpectedly"stays red). No regex eval surface.Trust boundary: Test coverage is comprehensive (6 new tests including the empty-statuses fallback edge — preserves the "combined=failure with no per-entry detail" breadcrumb path for the CI-emitter-direct case).
Supply-chain: Pure Python stdlib. No new deps.
APPROVE.
5-axis (core-qa):
Test-driven fix: 6 new tests covering the cancel-cascade filter — exact-match contract, mixed-cancel-and-real, all-cancel green, real-failure preservation, empty-statuses fallback, and the over-match guard. Each test cites the corresponding memory entry.
Canonical alignment: Matches
reference_chronic_red_sweep_cancelled_vs_failed_filter— filter must exclude status=3 from BOTH numerator and denominator. Verified description-string contract"Has been cancelled"(Gitea 1.22.6).Edge coverage:
Forward-compat: Header documents that if Gitea renames the description string in a future release, cancel-cascade entries simply leak back through (visible-not-silent). Option A (resolve action_run.status integer via target_url) documented as escalation path.
Reversibility: Pure filter narrowing; if it over-filters, real failures are still seen via combined-status fallback path.
APPROVE.
/qa-recheck
/security-recheck