From 33e17dba0ee2160c0b711c5a47e4b091d34021a4 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Sat, 19 Sep 2026 15:53:01 +0200 Subject: [PATCH 1/3] CI-9 follow-up: the summary said "mechanically", the blind spots say otherwise The residual-risk paragraph at the top of checks.yml claims the `guard the trigger` step "keeps it that way mechanically rather than by asking the next editor to read this comment". For blind spots 1 and 3 that is not true: the guard lives inside the workflow a filter makes Gitea skip, so for those cases the defence IS the comment. That paragraph is the preamble someone reads at the exact moment they are editing the trigger, so a summary running ahead of its detail is worse here than elsewhere. It now points at the blind spots and states spot 3 plainly: a filter naming a branch nothing targets is itself skipped, lands green and untested, and then skips every subsequent pull request - the gate off for everything, silently. Flagged by the reviewer on PR #95 (issuecomment-1424) as non-blocking. This PR is also the first real test of CI-9's fix on release/1.0 itself. Run 806 was a workflow_dispatch and posts no commit status at all, so it verified content but never the gate. This one has to post `checks / unit (pull_request)` as success rather than skipped. Verified before push: the guard passes against this edited file (whose new prose quotes `branches: [main]` and `master`) and still refuses a genuine filter added to the `on:` block. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- .gitea/workflows/checks.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.gitea/workflows/checks.yml b/.gitea/workflows/checks.yml index 425738e..0d7d692 100644 --- a/.gitea/workflows/checks.yml +++ b/.gitea/workflows/checks.yml @@ -110,6 +110,18 @@ name: checks # trigger` step below then keeps it that way mechanically rather than by asking # the next editor to read this comment. # +# ⚠️ READ THE BLIND SPOTS ON THAT STEP BEFORE TRUSTING THE SENTENCE ABOVE. +# "Mechanically" holds only for a reintroduced filter that still names the +# PR's own base. For blind spots 1 and 3 the defence IS this comment, because +# the guard lives inside the workflow that a filter makes Gitea skip. Blind +# spot 3 is the one that matters: a filter naming a branch nothing targets +# (`branches: [main]` from a template - this repo has no `main`, and no pull +# request in 99 has ever targeted `master`) is itself skipped, lands green and +# untested, and then every subsequent pull request is skipped too. That is the +# gate off for everything, silently. Closing it needs a SECOND permanently +# unfiltered workflow posting its own context, with that context added to +# `release/1.0`'s `status_check_contexts` - a forge change, with the owner. +# # THE MEASUREMENT, because the obvious guess is wrong and was nearly written # here as fact. A skip-ci keyword in a commit message (`[skip ci]`, `[ci skip]`, # `[no ci]`, `[skip actions]`, `[actions skip]`) does NOT behave like a filter -- 2.54.0 From 628279a68aca8d9197e0951b91f4d455f98b6d24 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Wed, 23 Sep 2026 20:18:50 +0200 Subject: [PATCH 2/3] CI-9 follow-up: name the filter that actually gets written, not the one that looks wrong Three sentences in the blind-spot clause went stale between writing and review. `no pull request in 99 has ever targeted master` is no longer true: SEC-2 made `release/1.0` -> `master` the mandated release path and protected `master` with the same required context, and a PR against that base has run for real. The census it came from also erases its own evidence - PR #102 was itself opened against `master` before retargeting, which the /pulls listing no longer shows, exactly as the caveat 25 lines above this clause warns. The clause also named `branches: [main]` as the hazard. That is the version that looks wrong. The one someone would actually write is `branches: [release/1.0]` - it reads as tightening onto the protected branch, every day-to-day PR keeps running green, and the only thing it switches off is the release PR whose content reaches an installed system. And the prescribed fix named only `release/1.0`'s status_check_contexts. Since SEC-2 `master` carries the same rule, so a reader following it literally would half-close the hole and believe it shut. Guard re-verified against the edited bytes: passes on this file (whose new prose quotes `branches: [release/1.0]` in a comment) and still refuses a real filter added to the `on:` block. Comment-only: 0 non-comment lines changed. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- .gitea/workflows/checks.yml | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/.gitea/workflows/checks.yml b/.gitea/workflows/checks.yml index 0d7d692..a7c3155 100644 --- a/.gitea/workflows/checks.yml +++ b/.gitea/workflows/checks.yml @@ -114,13 +114,25 @@ name: checks # "Mechanically" holds only for a reintroduced filter that still names the # PR's own base. For blind spots 1 and 3 the defence IS this comment, because # the guard lives inside the workflow that a filter makes Gitea skip. Blind -# spot 3 is the one that matters: a filter naming a branch nothing targets -# (`branches: [main]` from a template - this repo has no `main`, and no pull -# request in 99 has ever targeted `master`) is itself skipped, lands green and -# untested, and then every subsequent pull request is skipped too. That is the -# gate off for everything, silently. Closing it needs a SECOND permanently -# unfiltered workflow posting its own context, with that context added to -# `release/1.0`'s `status_check_contexts` - a forge change, with the owner. +# spot 3 is the one that matters: a filter naming a branch THIS pull request +# does not target is itself skipped, lands green and untested, and then every +# subsequent pull request matching it is skipped too. That is the gate off, +# silently. +# +# ⚠️ AND THE DANGEROUS ONE IS NOT `branches: [main]`, WHICH AT LEAST LOOKS +# WRONG. It is `branches: [release/1.0]`, which looks like tightening onto the +# protected branch and is what a careful person would write. Every day-to-day +# pull request still runs and still goes green, so nothing appears broken - +# and the only thing switched off is the `release/1.0` -> `master` release +# PR, i.e. the one whose content reaches an installed system. SEC-2 made that +# PR the mandated release path (docs/RELEASE.md), so this is now a live route +# rather than a hypothetical one. +# +# Closing it needs a SECOND permanently unfiltered workflow posting its own +# context, with that context added to the `status_check_contexts` of BOTH +# `release/1.0` AND `master` - both carry the rule since SEC-2, and adding it +# to one alone leaves the hole open on the other. A forge change, with the +# owner. # # THE MEASUREMENT, because the obvious guess is wrong and was nearly written # here as fact. A skip-ci keyword in a commit message (`[skip ci]`, `[ci skip]`, -- 2.54.0 From 8f9c2cad5781e90240de6179c4427a5895507895 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Thu, 24 Sep 2026 14:27:19 +0200 Subject: [PATCH 3/3] CI-9 follow-up: the skip direction, written the right way round `every subsequent pull request matching it is skipped too` is the inverse of the behaviour. A pull request that MATCHES a `branches:` filter still RUNS; the one the filter EXCLUDES is what Gitea sits out, reports `skipped`, and the rollup launders into `success`. The error arrived with the generalisation in the previous commit: `33e17db` said "every subsequent pull request is skipped too", which was unqualified and true for the `[main]` case it described. Naming the wider hazard made a qualifier necessary, and the wrong one went in - contradicting the paragraph directly below it, which describes `[release/1.0]` correctly as leaving every day-to-day PR running and green. Corrected, and the direction is now stated explicitly with the failed draft recorded, because this file already carries one instance of the same shape: "That was wrong, it contradicted the checkout step's own note a few lines below, and the error was not cosmetic." Guard re-verified on the edited bytes: passes here, still refuses `branches: [release/1.0]` added to the `on:` block. Comment-only, 0 non-comment lines changed. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- .gitea/workflows/checks.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/checks.yml b/.gitea/workflows/checks.yml index a7c3155..44709c0 100644 --- a/.gitea/workflows/checks.yml +++ b/.gitea/workflows/checks.yml @@ -116,8 +116,15 @@ name: checks # the guard lives inside the workflow that a filter makes Gitea skip. Blind # spot 3 is the one that matters: a filter naming a branch THIS pull request # does not target is itself skipped, lands green and untested, and then every -# subsequent pull request matching it is skipped too. That is the gate off, -# silently. +# subsequent pull request the filter DOES NOT NAME is skipped too. That is the +# gate off, silently. +# +# ⚠️ THAT DIRECTION IS THE WHOLE POINT AND IT IS EASY TO WRITE BACKWARDS. A +# pull request that MATCHES the filter still runs; it is the one the filter +# excludes that Gitea sits out, reports `skipped`, and the rollup launders +# into `success`. An earlier draft of this very clause said "matching it is +# skipped", which is the inverse of the measurement and contradicted the +# paragraph directly below. # # ⚠️ AND THE DANGEROUS ONE IS NOT `branches: [main]`, WHICH AT LEAST LOOKS # WRONG. It is `branches: [release/1.0]`, which looks like tightening onto the -- 2.54.0