All five PR-only jobs are dispatched on a tag push even though if: github.event_name == 'pull_request' should skip them — Gitea dispatches a job as a runner task even when its if skips it, evaluating the skip only after dispatch. On the v26.12.0 tag, api-docs/format (ubuntu-latest, identicalif:) resolved to skipped cleanly, while the three small-lane git-diff gates (ci-image-pin, docs-reminder, decisions-guard) wedged in act's setup phase and were killed by a runner restart mid-setup → failure (no logs) → red overall commit status on a release that built, scanned, and deployed fine. #508 (already in the tag) widened the lane but did not prevent it. The kill lands in the dispatch window before any step or if:-skip runs, so tweaking the if:/step logic (the issue's options 2/3) could not fix it.
Fix
Relocate exactly those three pure git-diff gates (no container:, no image pin) verbatim into a dedicated .gitea/workflows/pr-checks.yml that triggers on: pull_requestonly. Gitea evaluates a workflow's trigger before creating any job, so on a tag/main push this workflow produces zero jobs: no dispatch, no kill, no spurious red — for the whole class, permanently.
Why it's safe
ci-image-pin integrity: it carries no pin and still greps docker-build.yml, where all five pin-bearing jobs (test/migrations/functional-e2e/api-docs/format) remain → validation unchanged.
Merges unaffected: none of the three are required checks (only Build & test (.NET) + EF migration integrity are), and the merge-consent hook reads the prefix-agnostic combined status, so the context-prefix change (Build ErsatzTV Image / … → PR Gates / …) doesn't matter.
Fixes #535.
## Root cause (run-952 forensics)
All five PR-only jobs are **dispatched** on a tag push even though `if: github.event_name == 'pull_request'` should skip them — Gitea dispatches a job as a runner task *even when its `if` skips it*, evaluating the skip only after dispatch. On the v26.12.0 tag, `api-docs`/`format` (ubuntu-latest, **identical** `if:`) resolved to `skipped` cleanly, while the three `small`-lane git-diff gates (`ci-image-pin`, `docs-reminder`, `decisions-guard`) wedged in act's setup phase and were killed by a runner restart mid-setup → `failure` (no logs) → red overall commit status on a release that built, scanned, and deployed fine. #508 (already in the tag) widened the lane but did not prevent it. The kill lands in the dispatch window **before** any step or `if:`-skip runs, so tweaking the `if:`/step logic (the issue's options 2/3) could not fix it.
## Fix
Relocate exactly those three pure git-diff gates (no `container:`, no image pin) **verbatim** into a dedicated `.gitea/workflows/pr-checks.yml` that triggers `on: pull_request` **only**. Gitea evaluates a workflow's trigger *before* creating any job, so on a tag/main push this workflow produces **zero** jobs: no dispatch, no kill, no spurious red — for the whole class, permanently.
## Why it's safe
- **`ci-image-pin` integrity**: it carries no pin and still greps `docker-build.yml`, where all five pin-bearing jobs (`test`/`migrations`/`functional-e2e`/`api-docs`/`format`) remain → validation unchanged.
- **Merges unaffected**: none of the three are required checks (only `Build & test (.NET)` + `EF migration integrity` are), and the merge-consent hook reads the prefix-agnostic **combined** status, so the context-prefix change (`Build ErsatzTV Image / …` → `PR Gates / …`) doesn't matter.
- **Bashisms**: `pr-checks.yml` declares `defaults: run: shell: bash` (`ci-image-pin` uses `mapfile`/`set -o pipefail`).
- **Faithful relocation**: byte-identical job bodies (only intentional diff: a comment `in this file` → `in docker-build.yml`).
- **Live proof**: this PR itself runs the three gates under the new `PR Gates /` context.
## Docs
`docs/ci-cd.md`: new **PR gates workflow** section + cross-references (same PR).
## Review
Cold adversarial review over the diff: **MERGEABLE**, no Blocker/High/Medium/Low findings.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Three PR-only git-diff gates (ci-image-pin, docs-reminder, decisions-guard)
lived in docker-build.yml, which also triggers on push to main and v* tags.
Gitea dispatches a job as a runner task even when its `if` skips it, so on
every tag/main push these three were dispatched to the `small` lane just to
evaluate the skip. On the v26.12.0 tag those dispatched skip-tasks wedged in
act's setup phase and were killed by a runner restart mid-setup, reporting
`failure` (no logs) and reddening the tag's overall commit status even though
the release built, scanned, and deployed fine. The two identical-`if:` jobs on
ubuntu-latest (api-docs, format) skipped cleanly — the job logic was never the
problem; the kill lands in the dispatch window before any step or skip runs, so
tweaking the `if:`/step logic could not fix it.
Relocate exactly those three (pure checkout + git-diff, no container:, no image
pin) verbatim into a dedicated pr-checks.yml that triggers `on: pull_request`
only. Gitea evaluates a workflow's trigger before creating any job, so on a
tag/main push this workflow produces zero jobs: no dispatch, no kill, no
spurious red — for the whole class, permanently.
- ci-image-pin carries no pin and still greps docker-build.yml, where all five
pin-bearing jobs (test/migrations/functional-e2e/api-docs/format) remain, so
its validation is unchanged.
- None of the three are required checks (only Build & test + EF migration
integrity are), so the status-context prefix change (Build ErsatzTV Image / ...
-> PR Gates / ...) does not affect merges; the merge-consent hook reads the
prefix-agnostic combined status.
- pr-checks.yml declares `defaults: run: shell: bash` (ci-image-pin uses
mapfile / set -o pipefail).
docs/ci-cd.md: new "PR gates workflow" section + cross-references.
fixes#535
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cold adversarial review over the diff returned MERGEABLE with zero Blocker/High/Medium/Low findings (only a pre-existing informational nit on the pin grep, unchanged by this PR). CI green on this head, including the three relocated gates running under the new PR Gates / context (live proof the split works).
Review-verdict: MERGEABLE @ b4ac46fce188496c17fb25f1e00872264dad2c89
Cold adversarial review over the diff returned MERGEABLE with zero Blocker/High/Medium/Low findings (only a pre-existing informational nit on the pin grep, unchanged by this PR). CI green on this head, including the three relocated gates running under the new `PR Gates /` context (live proof the split works).
timothy
merged commit c21d227132 into main2026-07-21 18:31:42 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes #535.
Root cause (run-952 forensics)
All five PR-only jobs are dispatched on a tag push even though
if: github.event_name == 'pull_request'should skip them — Gitea dispatches a job as a runner task even when itsifskips it, evaluating the skip only after dispatch. On the v26.12.0 tag,api-docs/format(ubuntu-latest, identicalif:) resolved toskippedcleanly, while the threesmall-lane git-diff gates (ci-image-pin,docs-reminder,decisions-guard) wedged in act's setup phase and were killed by a runner restart mid-setup →failure(no logs) → red overall commit status on a release that built, scanned, and deployed fine. #508 (already in the tag) widened the lane but did not prevent it. The kill lands in the dispatch window before any step orif:-skip runs, so tweaking theif:/step logic (the issue's options 2/3) could not fix it.Fix
Relocate exactly those three pure git-diff gates (no
container:, no image pin) verbatim into a dedicated.gitea/workflows/pr-checks.ymlthat triggerson: pull_requestonly. Gitea evaluates a workflow's trigger before creating any job, so on a tag/main push this workflow produces zero jobs: no dispatch, no kill, no spurious red — for the whole class, permanently.Why it's safe
ci-image-pinintegrity: it carries no pin and still grepsdocker-build.yml, where all five pin-bearing jobs (test/migrations/functional-e2e/api-docs/format) remain → validation unchanged.Build & test (.NET)+EF migration integrityare), and the merge-consent hook reads the prefix-agnostic combined status, so the context-prefix change (Build ErsatzTV Image / …→PR Gates / …) doesn't matter.pr-checks.ymldeclaresdefaults: run: shell: bash(ci-image-pinusesmapfile/set -o pipefail).in this file→in docker-build.yml).PR Gates /context.Docs
docs/ci-cd.md: new PR gates workflow section + cross-references (same PR).Review
Cold adversarial review over the diff: MERGEABLE, no Blocker/High/Medium/Low findings.
🤖 Generated with Claude Code
Review-verdict: MERGEABLE @
b4ac46fce1Cold adversarial review over the diff returned MERGEABLE with zero Blocker/High/Medium/Low findings (only a pre-existing informational nit on the pin grep, unchanged by this PR). CI green on this head, including the three relocated gates running under the new
PR Gates /context (live proof the split works).