Call the shared hygiene check beside this board's own gate (#178) - #179
Merged
Conversation
iderex
force-pushed
the
issue-178-shared-hygiene
branch
3 times, most recently
from
August 23, 2026 01:57
78f8da8 to
cc02192
Compare
One workflow file, which calls iderex/wache/.github/workflows/pr-hygiene.yml with the subject rule off. .github/pr-hygiene/hygiene.sh is untouched and keeps every rule it has, including the two the shared check has no equivalent for: the scope comparison against the Scope: line a named issue declares, and the qualifier aware reading that leaves another repository's issue number alone. This does not merge as it stands and the file says why. The called workflow declares pr-hygiene-<pull request number> as its concurrency group and this board's own gate declares the same string, so the run created second cancels the other. The local gate is the one that dies, one second after creation, with no steps and no verdict. A group declared here does not help, at workflow level or on the calling job: the called workflow claims the group independently of the caller. Three attempts are on the pull request. The reference is pinned by commit hash with the version beside it, because a moving reference would let the called repository change what executes here without anybody reviewing it. Closes #178 Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
iderex
force-pushed
the
issue-178-shared-hygiene
branch
from
August 23, 2026 01:57
cc02192 to
41e930d
Compare
At v1.0.0 the called workflow claimed `pr-hygiene-<pull request number>` as its concurrency group, which is the string .github/workflows/pr-hygiene.yml on this board already claims. Both cancel in progress, so the run created second cancelled the other and the local gate was the one that died: cancelled one second after creation, no steps, no verdict. This pull request has been open and red in that state since it was created on 2026-08-23. What was wrong was the pin rather than anything in this tree, and it was found by re-reading the blocker it was waiting on rather than by a new run here. iderex/wache#4 closed as completed and namespaced the group. At the commit pinned now the shared run sits in `wache-pr-hygiene-<number>` while this board's gate keeps `pr-hygiene-<number>`, so the two no longer meet: gh api repos/iderex/wache/git/ref/tags/v1.2.0 --jq '.object.sha' ea26725f1acaa2616c9810b955230c40ba548e98 gh api repos/iderex/wache/git/tags/ea26725f1acaa2616c9810b955230c40ba548e98 --jq '.object.sha' 113085b269d3437a3f96ff9e7060b64b0af88ab1 gh api "repos/iderex/wache/contents/.github/workflows/pr-hygiene.yml?ref=113085b269d3437a3f96ff9e7060b64b0af88ab1" \ --jq .content | base64 -d | grep -A2 '^concurrency:' concurrency: group: wache-pr-hygiene-${{ github.event.pull_request.number }} cancel-in-progress: true The failure this prevents is a gate that reads as present and judges nothing. A cancelled check blocks no merge here, because the ruleset on main requires no status check: gh api repos/Flowfin/core/rulesets/20572113 \ --jq '{enforcement, bypass: .bypass_actors, required: [.rules[].type]}' {"bypass":[],"enforcement":"active","required":["deletion","non_fast_forward","pull_request"]} so this board's own rules stopped being judged while the tick beside them stayed green, which is worse than not calling the shared check at all. Nothing else changes. `.github/pr-hygiene/hygiene.sh` and `.github/workflows/pr-hygiene.yml` are untouched, and the subject rule stays off. Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The issue this belongs to
Closes #178
What changed
One file is added,
.github/workflows/shared-hygiene.yml. It callsiderex/wache/.github/workflows/pr-hygiene.yml, which holds the half of thehygiene rules every board in this fleet has in common, with
subject_names_issue: false. Nothing else in the tree is touched:.github/pr-hygiene/hygiene.shand.github/workflows/pr-hygiene.ymlkeepevery rule they have, and the shared call runs beside them rather than in place
of them.
The pin is
113085b269d3437a3f96ff9e7060b64b0af88ab1, which isv1.2.0. It was9b311243c2d0d0ced7feb957a20bc178acce6a5d,v1.0.0, and the section below iswhy it moved.
Why this was red for a day, and what moved
This pull request was open and red on purpose from 2026-08-23 until the pin
moved. At
v1.0.0the called workflow declared its concurrency group aspr-hygiene-<pull request number>, and this board's own.github/workflows/pr-hygiene.ymldeclares that same string. Both setcancel-in-progress, so whichever run was created second cancelled the other,and the loser was the local gate.
Three placements of a group on the caller were tried and all three lost the
local gate:
cancelled, created 01:46:53, cancelled 01:46:54.shared-hygiene-<number>. Run32611334638,
cancelled, created 01:50:27, cancelled 01:50:28.32611542281,
cancelled, created 01:55:30.Attempt 2 is the one that settles where the claim comes from. Had the caller's
own block decided the run's group, the shared call would have sat in
shared-hygiene-<number>and nothing would have been left inpr-hygiene-<number>to cancel the local gate. It was cancelled anyway, so thecalled workflow claims that group independently of its caller, and no caller
side declaration can move it.
The fix belonged in
iderex/wacheand was filed there asiderex/wache#4. Ithas landed, and the group is namespaced:
So the shared run now sits in
wache-pr-hygiene-<number>and this board's gatekeeps
pr-hygiene-<number>. The two no longer name one group, and both report averdict on this pull request, which is the measurement
iderex/wache#4named asits own condition of done.
What made the collision cost a verdict rather than a red tick is local and has
not changed. A cancelled check blocks no merge here, because the ruleset on
mainrequires no status check:so a board's own rules can stop being judged while the tick beside them stays
green. #26 is where that is held open, and nothing here answers it.
What failure it prevents
A failure that has already happened rather than one that could. The count is in
iderex/operations#1556: nineteen boards carried nineteen implementations of the
same three or four rules, in four languages, no two alike, so a two line change
to a rule they share cost nineteen edits and failed in nineteen different ways.
A recent change across the fleet took six attempts, because each board refused
it for a different reason. Every board that calls the shared half instead of
copying it is one board that stops contributing a new way to fail.
It prevents nothing this board's own gate already prevents. That gate still
runs, still reads the body, and still compares the changed paths against the
scope the named issue declares.
Evidence
The change is one added file and no other line:
The pin is the commit the tag
v1.2.0points at, dereferenced rather thantrusted:
The file parses to what its comment claims it says:
That the subject rule has to be off here was measured, not assumed, and the
measurement was re-run at this head rather than quoted from the earlier one. Not
one authored subject on this board is in the square brackets the fleet rule
wants, and the twelve most recent carry no reference in the subject at all,
because this board puts it in the body, which is what its own gate reads:
What a guard here refuses, and the proof it bites
The guard this change adds to the board is the shared check itself, and what it
refuses is listed on #178: an empty body, a closing keyword buried in a
paragraph, a placeholder title, and, where the rule is on, a commit subject that
names no issue. Here the subject rule is off, so this call refuses the first
three and says in its own log that it read no commit subject.
I did not have to construct a violation to watch it bite, because the check
constructs its own on every run: nine fixtures, one line that passes and one
line that bites per rule, judged before the change is judged, and a failed
fixture makes the run refuse to judge at all. Read out of this pull request's
own run at this pin, rather than out of a run on the board the check lives on:
Nine fixture lines and the line saying the subject rule is off, which is what
#178 asks to be visible in that log. The refusal direction is proved by the
fixtures rather than by a violation of mine: each of the four rules has a line
the check must refuse and a line it must pass, and
fixture okon the refusingline is that refusal executed. What is not shown here is the check refusing THIS
pull request, because this pull request does not violate it, and the fixtures
are the reason that is not a gap.
Both gates reported on this head, which is the collision being gone rather than
being worked around. The listing is deduplicated on purpose: this board's own
gate also runs on
edited, so every edit to this body adds another run of itunder the same name, and a raw paste stops reproducing the moment the body
carrying it is saved.
The reading that does not move when a run is added is the count of everything
that concluded as something else:
Deterministic PR-hygiene checksis this board's own gate and it carries averdict rather than a cancellation. Every other check is the colour it was
before this branch existed.
The two files #178 says must not move did not:
Same blobs, so byte for byte rather than line for line.
No guard on this board is added, edited or deleted by this change, so there is
nothing here whose deletion could be shown to redden a suite.
What this does not cover
A green
Shared hygienehere is not evidence that the shared rules are right,only that they run across a repository boundary and that this board passes them.
It is no evidence at all about the subject rule, because that rule is off on
this call and no commit subject is read. The log line says so in as many words,
and a reader should take the green tick as covering three rules rather than
four.
It measures nothing about
.github/pr-hygiene/hygiene.sh. The two runindependently and neither covers the other's gaps. The scope comparison, the
qualifier aware reference reading, and this board's stricter sense of an empty
body exist only in the local gate and are not touched, retested or replaced
here.
It is also not evidence that any local rule is now redundant. Nothing was
removed, and nothing should be until the shared check is shown, rule by rule, to
cover it.
The collision is settled at this pin and not in general. Nothing here stops a
later version of the called workflow from claiming the bare pattern again, and
nothing on this board reads the group a pin claims before the pin is moved. The
comment in the file names the string to check by hand, and that is a sentence
rather than a mechanism.
Nothing here was run on Windows or on any runner other than
ubuntu-latest, andnothing here reads the called workflow's behaviour on a fork pull request.
Who has read it
Nobody other than me. This is the third board of a fleet wide roll out and
follows
iderex/bremsweg#143andiderex/hoersaal#174, both merged, so theshape has been through the checks on those boards rather than through a person.
That is not a second reader, and this pull request does not have one.