Skip to content

Call the shared hygiene check beside this board's own gate (#178) - #179

Open
iderex wants to merge 1 commit into
mainfrom
issue-178-shared-hygiene
Open

Call the shared hygiene check beside this board's own gate (#178)#179
iderex wants to merge 1 commit into
mainfrom
issue-178-shared-hygiene

Conversation

@iderex

@iderex iderex commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

The issue this belongs to

Closes #178

What changed

One file is added, .github/workflows/shared-hygiene.yml. It calls
iderex/wache/.github/workflows/pr-hygiene.yml, which holds the half of the
hygiene 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.sh and .github/workflows/pr-hygiene.yml keep
every rule they have, and the shared call runs beside them rather than in place
of them.

Why this is not mergeable as it stands

This pull request stays open and red on purpose. The board's own gate,
Deterministic PR-hygiene checks, is cancelled one second after it is created
every time, with no steps and no verdict, and the cause is this file.

The called workflow declares its concurrency group as
pr-hygiene-<pull request number>. This board's own
.github/workflows/pr-hygiene.yml declares the same string. Both set
cancel-in-progress, so whichever run is created second cancels the other, and
the loser is the local gate.

$ grep -A2 '^concurrency:' .github/workflows/pr-hygiene.yml
concurrency:
  group: pr-hygiene-${{ github.event.pull_request.number }}
  cancel-in-progress: true

$ gh api "repos/iderex/wache/contents/.github/workflows/pr-hygiene.yml?ref=9b311243c2d0d0ced7feb957a20bc178acce6a5d"         --jq .content | base64 -d | grep -A2 '^concurrency:'
concurrency:
  group: pr-hygiene-${{ github.event.pull_request.number }}
  cancel-in-progress: true

Three placements were tried and all three lost the local gate:

  1. no group of my own, the file as the roll out prescribes it. Run 32611192849,
    cancelled, created 01:46:53, cancelled 01:46:54.

  2. a group of my own at workflow level, shared-hygiene-<number>. Run
    32611334638, cancelled, created 01:50:27, cancelled 01:50:28.

  3. the same group on the calling job rather than on the workflow. Run
    32611542281, cancelled, created 01:55:30.

    $ gh api repos/Flowfin/core/actions/runs/32611334638/jobs --jq '.jobs[] | {name,conclusion,started_at,completed_at,steps:[.steps[]?]}'
    {"completed_at":"2026-08-23T01:50:28Z","conclusion":"cancelled",
    "name":"Deterministic PR-hygiene checks","started_at":"2026-08-23T01:50:27Z","steps":[]}

Attempt 2 is the one that settles it. If 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 in pr-hygiene-<number> to cancel the local gate.
The local gate was cancelled anyway, so the called workflow claims that group
independently of the caller, and no caller side declaration can move it.

The fix belongs in iderex/wache, where the group has to be namespaced with the
calling workflow or the calling repository. It cannot be made from this file,
and I am not editing this board's gate to work around a name chosen on another
board. Until that lands, this board can have the shared check or its own
verdict, and its own verdict is worth more.

One thing this turned up on the way. The same collision happened on
iderex/bremsweg#143, which carries the same group name, and that pull request
was merged with the cancelled Deterministic PR hygiene still red on it. It
should be looked at again.

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:

$ git diff --name-only main..HEAD
.github/workflows/shared-hygiene.yml
$ git diff --stat main..HEAD
 .github/workflows/shared-hygiene.yml | 37 ++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

The pin is the commit the tag v1.0.0 points at, dereferenced rather than
trusted:

$ gh api repos/iderex/wache/git/ref/tags/v1.0.0 --jq .object.sha
38510cacf9e10a4ec22d2ac182bf160affca6826
$ gh api repos/iderex/wache/git/tags/38510cacf9e10a4ec22d2ac182bf160affca6826 --jq .object.sha
9b311243c2d0d0ced7feb957a20bc178acce6a5d

The file parses to what its comment claims it says:

$ python -c "import yaml; d=yaml.safe_load(open('.github/workflows/shared-hygiene.yml')); ..."
keys: ['name', 'True', 'permissions', 'jobs']
permissions: {'contents': 'read'}
uses: iderex/wache/.github/workflows/pr-hygiene.yml@9b311243c2d0d0ced7feb957a20bc178acce6a5d
with: {'subject_names_issue': False}

That the subject rule has to be off here was measured, not assumed. 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:

$ gh api "repos/Flowfin/core/commits?per_page=100" \
    --jq '.[] | select(.parents|length==1) | .commit.message | split("\n")[0]'
authored subjects:        52
carrying [#N]:             0
carrying (#N) or any #N:  38
of the last twenty:        8

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 above: 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. I read the logs rather than the
summaries. The deliberately bad pull request on the check's own board,
iderex/wache#2, run 32605656340:

fixture ok     an empty body is refused
fixture ok     one line of body is enough
fixture ok     a placeholder title is refused
fixture ok     a closing keyword mid-paragraph
fixture ok     square brackets count
fixture ok     another board counts
fixture ok     round brackets do not count
fixture ok     a bare number does not count
fixture ok     a colour value is not a mention
##[error]the body is empty
##[error]the title is a placeholder
##[error]418b4efc1 names no issue in its subject. Put it in square brackets,
or name another board as owner/repo#N.

The same rules pass a good pull request, iderex/wache#1, run 32605508804,
which ended in success.

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 hygiene here 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 run
independently 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.

None of the above is evidence that the shared check and the local gate can run
together on this board. They demonstrably cannot at this pin, and the green
Shared hygiene tick on this pull request was bought by cancelling the local
gate, which is worse than not having it.

Nothing here was run on Windows or on any runner other than ubuntu-latest, and
nothing 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#143 and iderex/hoersaal#174, both merged, so the
shape has been through the checks on those boards rather than through a person.

@iderex
iderex force-pushed the issue-178-shared-hygiene branch 3 times, most recently from 78f8da8 to cc02192 Compare August 23, 2026 01:57
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Call the shared pull request hygiene check beside this board's own gate

1 participant