Skip to content

fix(quality): re-land axe DOM scoping, with the runner in a file — a 22 KB run: step is what made the workflow unresolvable - #168

Merged
rubenvdlinde merged 1 commit into
mainfrom
fix/axe-scope-to-app-dom-v2
Aug 5, 2026
Merged

fix(quality): re-land axe DOM scoping, with the runner in a file — a 22 KB run: step is what made the workflow unresolvable#168
rubenvdlinde merged 1 commit into
mainfrom
fix/axe-scope-to-app-dom-v2

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Re-lands #161 (reverted by #166) in a shape GitHub resolves, and names the cause instead of guessing at it.

The cause, bisected — it was neither candidate named in the revert

Built a controlled probe: a uses: ./.github/workflows/quality.yml caller inside this repo, so resolution can be tested on a branch without pointing any app repo at unmerged code. Read the JOB COUNT, never the conclusionfailure with jobs>0 means it resolved and something inside failed, which is a pass for this probe. jobs == 0 is the outage signature.

state jobs verdict
baseline (current main) 25 RESOLVES ← positive control
#161 re-applied in full 0 outage reproduced
45 workflow_call inputs, step untouched 25 RESOLVES
whole FILE padded to 226 KB, step untouched 25 RESOLVES
ONE run: step padded to 21 KB with inert JS comments 0 BREAKS

So it is not the input count (43 → 45) and not the file size — the two candidates the revert named, neither of which was proven at the time. It is the size of a single run: step, and because the breaking pad is inert comments, it is size rather than anything in the content.

Bracketed: 18,965 bytes resolves, 21,109 bytes does not. #161's axe step was 22,439.

The fix

The runner is now hydra-gates/scripts/axe-run.cjs — a real file, byte-identical to the one proven under #161 (md5 40ba28f689c8fcc0a056bae3567c0f09) — checked out into the Playwright job exactly the way the hydra-gates job already checks this repo out.

before after
axe run: step 22,439 B 2,162 B
largest run: step in the file 22,439 B 8,533 B
quality.yml 224,420 B 201,108 B

quality.yml is now smaller than the 207,576 it was before #161, because a 500-line Node program moved out of the YAML. That embedding was the real defect: trimming comments to squeak under ~19 KB would have left the next edit one comment away from another fleet outage. A file takes the whole class of failure off the table.

Probe on this exact tree: 25 jobs, name="Resolve probe" — RESOLVES.

Behaviour — unchanged from #161, re-verified against the shipped file

Measured on a live Nextcloud 34, unscoped, every serious/critical violation on a Conduction app page was core's: color-contrast on .unified-search-input__label (unified search, inside #header) and role-img-alt on :root. Scoped, openregister goes 2 → 0 and hermiq 1 → 0.

Selector chosen by measurement, not guess — #app-content and main#content do not exist on NC34 at all, and no single selector covers every page (#content-vue absent on the dashboard, #content absent on /apps/files/), hence the two-selector default.

Three-way proof, run against the shipped axe-run.cjs:

  1. scoped baseline 2 → 0, every removed node provably core's (set-diff of full node lists);
  2. <button></button> injected inside #content-vuestill reported, critical (insideProbeReported: true);
  3. the same violation injected outsidenot reported scoped, reported by an unscoped control on the same injected page (outsideProbeReported: false).

Guard 4 asserts both halves on the live page, every run, and refuses to write a report if either fails — scoping and muting both produce fewer violations, so the third proof is the one that tells them apart. The serious/critical filter is untouched.

A scope matching nothing aborts without writing a report (verified: exit 2, no file), so gate-33 skips loudly rather than reading an absent result as a clean one.

Honest limit, unchanged: on vanilla Nextcloud's own routes scoping removes nothing — those 3 defects live in the Files and Settings apps' content, not the chrome. Removing them would need axe-exclude-selector, which stays empty by default.

Fleet state

Confirmed healthy before opening this: a caller run created after the revert resolves as Code Quality with 19 jobs, against 0 on the run from the #161 window.

🤖 Generated with Claude Code

…22 KB `run:` step is what made the workflow unresolvable

#161 scoped axe to the app's own DOM and was reverted in #166 because every
caller in the fleet started up with ZERO jobs and a run `name` equal to the raw
file path — GitHub never RESOLVED quality.yml. The revert was right. This
re-lands the same measured behaviour in a shape GitHub resolves, and names the
cause rather than guessing at it.

CAUSE, bisected with a controlled probe (a `uses: ./…` caller inside this repo,
so resolution can be tested on a branch without pointing an app repo at unmerged
code). Read the JOB COUNT, never the conclusion — `failure` with jobs>0 means it
resolved and something inside failed, which is a PASS for the probe:

  baseline (current main)                        -> 25 jobs   RESOLVES
  #161 re-applied in full                        ->  0 jobs   outage reproduced
  45 workflow_call inputs, step untouched        -> 25 jobs   RESOLVES
  whole FILE padded to 226 KB, step untouched    -> 25 jobs   RESOLVES
  ONE `run:` step padded to 21 KB with INERT
    JS COMMENTS, nothing else changed            ->  0 jobs   BREAKS

So it is neither the input count (43 -> 45) nor the file size, the two
candidates named in the revert. It is the size of a SINGLE `run:` step, and the
padding control proves it is size rather than anything in the content. Bracketed:
18,965 bytes resolves, 21,109 bytes does not. #161's axe step was 22,439.

FIX: the axe runner is now hydra-gates/scripts/axe-run.cjs — a real file, byte
identical to the one proven under #161 (md5 40ba28f6…) — checked out into the
Playwright job the same way the hydra-gates job already checks this repo out.
The axe step drops 22,439 -> 2,162 bytes, the largest `run:` step in the whole
file is now 8,533 bytes, and quality.yml is 201,108 bytes: SMALLER than the
207,576 it was before #161, because the program moved out of the YAML.

A 500-line Node program embedded in a YAML string was the real defect. Keeping
it in a file takes the entire class of failure off the table instead of leaving
the next comment one edit away from another fleet outage.

The behaviour is unchanged from #161 and re-verified against the shipped file:
openregister 2 serious/critical -> 0 scoped, every violation removed provably
core's; a violation injected INSIDE the container still reported at critical;
the same violation OUTSIDE not reported; a scope matching nothing aborts without
writing a report. Guard 4 asserts both halves on the live page every run.
@rubenvdlinde
rubenvdlinde merged commit 46cc1c8 into main Aug 5, 2026
6 checks passed
@rubenvdlinde
rubenvdlinde deleted the fix/axe-scope-to-app-dom-v2 branch August 5, 2026 17:24
rubenvdlinde added a commit that referenced this pull request Aug 5, 2026
…ed runners — decidesk and doriath went red on gates 4, 24 and 33 (#173)

`hydra-gates-require-full-coverage` was flipped to default TRUE (#164) once the
runner could tell a not-applicable gate from a real gap. But this workflow is
consumed at @main while the gate package is consumed at the caller's own
`hydra-gates-ref`, so the new default was handed to runners that predate the
accounting entirely — and those count EVERY gate they did not run as a gap.

Measured, not inferred, both after the flip and both failing on nothing else:

  decidesk job 92432089644  ref v1.0.1  ALL 61 GATES GREEN
                            COVERAGE: 58 of 61 / DID NOT RUN: 4 24 33 -> exit 98
  doriath  job 92363547732  ref v1.0.1  same three gates, same verdict

Gates 4, 24 and 33 are the exact trio the product owner named as legitimately
not applicable. So the flip was producing the outcome it was made to prevent,
in every repo whose pin had not moved — and pins do not move on in-flight
branches.

The flag is now handed only to a package that can honour it. The probe reads the
package's own accounting (`_NA_GATES` in the runner, the `NOT APPLICABLE`
verdict in the wrapper) rather than comparing versions, because a pin may be a
tag, a branch, a SHA or a fork. Verified against every published tag:
v1.0.0/v1.0.1/v1.1.0/v1.2.0 -> withheld, v1.3.0/v1.4.0 -> applied. A checkout
missing either file is a broken checkout, not an old one, and fails.

Withholding is stated as a `::warning::` naming the pin and the fix. A control
that switches itself off quietly is a control that has stopped existing.

`--axe-enabled` is gated on the same probe. The old wrapper's parser ends in
`*) APP_DIR="$1"`, so an unrecognised flag is swallowed as a POSITIONAL and
clobbers the app dir set moments earlier: a v1.0.1 pin handed it aborts with
`FATAL: --app-dir '--axe-enabled' is not a directory. No gate ran.` — exit 99,
every gate lost, for a flag the caller never typed.

Same ref skew, second instance: axe-run.cjs landed in v1.4.0 and every caller is
pinned v1.3.0, so `enable-axe: true` would die on `Cannot find module` and then
present as "the axe report never arrived" — pointing at Playwright, the one
place the fault is not. Asserted at the checkout with a named error instead.

The two probe literals are a CONTRACT: renaming either would silently disable
coverage enforcement fleet-wide, with a warning blaming the caller's pin. The
package's own suite now asserts both, plus a reverse control proving the probe
does not match the pre-v1.3.0 shape of either file. Positive-controlled: with
both literals renamed in a copy, those assertions go red.

Four-way measurement on one fixture, one variable at a time:

  v1.0.1 + --require-full-coverage        exit 98  <- the observed failure
  v1.0.1, flag withheld (this change)     exit 0
  v1.4.0 + flag, only (a) gaps            exit 0   33 of 33 applicable gates ran
  v1.4.0 + flag + a structural gap        exit 98  [gate-24] SKIPPED (structural)

Also removes a stale comment left by the #161/#166/#168 cycle that instructed
future readers to embed the axe runner inline — the thing that made the whole
workflow unresolvable fleet-wide.

Suite 31 -> 34 tests, 0 failing. actionlint clean (positive-controlled: a
typo'd step id is reported). Largest `run:` step 8,533 B, far below the ~19 KB
that makes a workflow unresolvable.

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
rubenvdlinde added a commit to ConductionNL/openregister that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/opencatalogi that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/docudesk that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/procest that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/hermiq that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/doriath that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/scholiq that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/decidesk that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/openbuild that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/larpingapp that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/pipelinq that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/zaakafhandelapp that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/softwarecatalog that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/nldesign that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/openconnector that referenced this pull request Aug 5, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde pushed a commit that referenced this pull request Aug 5, 2026
Three reconciliations, each caught by an existing assertion rather than by
reading the diff:

* gate-28 — #172 gave this gate a four-way skip taxonomy (`na` for no lib/,
  `na` for no composer.json, `structural` for a composer.json without a
  `license`, `structural` for nothing carrying a tag) and made PASS
  conditional on having actually compared a file. Moving the read into a
  helper collapsed all of that into one `na`, undoing it. The taxonomy is
  restored verbatim; the helper now returns the compared-file count on
  stderr so `_lt_checked` still gates the PASS. The one state that
  short-circuits it is a MISSING HELPER — which #172's chain would have
  called `structural`, i.e. a claim about the REPOSITORY, when the
  repository is fine and the gate is broken. Those must not wear the same
  words.

* gates 40 and 46 — an empty in-scope file set is ordinary ADR-020 diff
  scoping, not "not applicable". tests/test-hydra-gates-bin.sh asserts that
  no src-guarded gate reports NOT APPLICABLE while src/ exists, and gate-40
  was tripping it. Answering differently from every sibling gate drifts the
  applicability table away from the guards it mirrors — the one way that
  table could hide a live gate.

* quality.yml — #173 added a preflight for the FLAG direction of the
  floating-caller / pinned-callee desync (does the pinned runner understand
  the coverage flag?). This branch adds one for the PATH direction (does the
  pinned package contain the files the workflow executes by name?). Both are
  kept: they are different halves of the same interface, and #168 broke the
  half #173 does not cover.

And one contract change, made explicit rather than incidental:

  test-hydra-gates-bin.sh's "empty diff exits 0" fixture set BASE_SHA to
  HEAD, so it was really asserting "scoping a commit against itself exits 0"
  — the shillinq shape. Those are different facts and only one is
  legitimate. The original assertion now runs against a real
  base-behind-HEAD empty diff and still expects 0; a new assertion covers
  base == HEAD, expects 99, and checks that NO gate printed PASS.

Verified on the merged tree:

  hydra-gates entry-point tests: 36 passed, 0 failed  (was 31 passed, 3 failed)
  helper suites:                 23 passed, 0 failed
  gate-46 fleet: 1,995 -> 918    gate-40 fleet: 1,211 -> 517  (unchanged by the merge)
rubenvdlinde added a commit that referenced this pull request Aug 6, 2026
…d its own measurements (#175)

* fix(gates): 46/40/28/9/7 were majority-false, and the runner corrupted its own measurements

Two gates produced more false findings than real ones, which made a
fleet burn-down UN-MERGEABLE: the gates are diff- AND file-scoped, so
touching a file drags in its pre-existing findings, and when the residue
is entirely false there is no honest way to green the PR. Two burn-down
PRs (opencatalogi#808, docudesk#385) are stuck in exactly that state.

Measured across 21 fleet repos at origin/development, against v1.4.0:

  gate-46 spec-anchor-existence   1,995 -> 918   (-54%)
  gate-40 form-label-association  1,211 -> 517   (-57%)
  gate-9  semantic-auth              45 ->  11   (-76%)
  gate-7  no-admin-idor              32 ->  26   (-19%, partial)

Every relaxation ships with the true-positive case it must not swallow.
Four new suites (gate-46, gate-40, gate-28, gate-9) and 8 new gate-7
cases, all discovered automatically by tests/run-helper-suites.sh. Each
was mutation-checked: making the relaxed predicate always-true fails the
suite, and so does making it always-false.

gate-46 — 1,077 findings cleared, none of them evidence about a spec
  * the `:`-tail rule accepted only EQUALITY where the full-heading rule
    accepted a PREFIX, so `### Requirement: REQ-001: List zaken` rejected
    `#REQ-001`
  * a requirement id in trailing parens/brackets was invisible:
    `### Requirement: Payment Provider Adapter Interface (REQ-PAY-001)`
    rejected `#REQ-PAY-001`. Lifted tokens match by EQUALITY only, so
    `#REQ` and `#REQ-PAY` still do not resolve
  * an id before the colon — `#### Scenario REQ-BIE-004-01: Cron triggers`
    — likewise. Only tokens CONTAINING A DIGIT are lifted; without that
    every word of every heading becomes an anchor
  * `- [~]` and `- [-]` checkboxes were invisible to the task rule, which
    ALSO shifted every positional `#task-N` after them. A wrong positional
    resolution reports PASS against a different task — worse than the
    missing anchor it replaced
  * `openspec/specs/x.md` and `openspec/specs/x/spec.md` are the same spec
  * `#scenario`/`#requirement` no longer prefix-match every heading of
    that level; `#webhooks` against `## Webhooks (Task 2.9 of giant)`
    still resolves, by equality against the bracket-stripped heading

gate-40 — 694 cleared, and its advice was an a11y REGRESSION
  The only way to satisfy it on `<NcCheckboxRadioSwitch>Installed apps
  only</NcCheckboxRadioSwitch>` was to add `aria-label`, which OVERRIDES
  the visible label and breaks speech-input users. 463 findings were that
  shape. Also: implicit `<label>` wrapping (268), bound `:id`/`:for`
  pairs matched by expression (56), and markup inside comments and
  <script> blocks (5). Replaces a flatten-the-newlines regex with a real
  tag walker, so nesting and slots are visible. A self-closed switch with
  no slot and no prop — docudesk Settings.vue:41 — is still reported.
  Also ~40x faster: one python process, not one per .vue file.

gate-28 — the NUL byte is worse than filed (#171)
  Depending on the grep implementation, a raw 0x00 makes it either a
  false RED (GNU grep <=3.4 prints "Binary file X matches" on stdout, so
  `awk '{print $3}'` reads the FILE PATH as the licence) or a false GREEN
  (ugrep / GNU grep >=3.5 print nothing to stdout, so the gate `continue`s
  and NEVER CHECKS THE FILE). Verified: an `@license AGPL-3.0-or-later`
  hidden behind a NUL passed silently. Reading bytes in python removes
  the class. Also collects EVERY declaration — `@license` tags and
  `SPDX-License-Identifier:` lines alike — instead of the first `@license`
  only, which is how 174 files carried an AGPL claim behind a green gate.
  Identifiers inside string literals stay test data, not claims.

gate-9 — its remediation would have INTRODUCED the vulnerability
  "remove #[PublicPage] or remove body auth check": the first breaks the
  endpoint (middleware rejects the remote caller before the controller
  runs), the second deletes its only authentication. 34 of 45 findings
  were webhook/portal/federation endpoints that correctly bypass session
  auth and authenticate from the REQUEST. Returning 401/403 is not, on
  its own, evidence of a session dependency. A #[PublicPage] method that
  tests the SESSION still fires, under a rule name that says so.

gate-7 — it was ANTI-CORRELATED with the property it checks (#160)
  On a multi-tenant codebase a tenancy guard refuses with 404 ON PURPOSE,
  because a 403 leaks another tenant's object ids. gate-7 excluded bare
  throws, so it flagged exactly the code that got tenancy right — and
  FlowController::state() reported identically before and after its real
  IDOR was fixed. Adds a tenancy signal requiring BOTH a comparison
  against a session-derived scope AND a refusal. Partial: 6 of the ~17
  openregister false positives clear; the rest need collaborator-hop work.

THE RUNNER CORRUPTED ITS OWN MEASUREMENTS
  61 gates wrote to hardcoded /tmp/hydra-gate-<name>.log and derived
  verdicts by `wc -l` on them. Exactly one used mktemp. Demonstrated with
  two concurrent runs on different repos at v1.4.0: petstore reported
  "gate-46 FAIL - 26 unresolved targets - see /tmp/hydra-gate-spec-anchor-
  existence.log" while that file contained ZERO lines, app-versions having
  truncated it; both repos' gate-40 verdicts (1 and 7) pointed at one file
  holding 7 lines. Had the truncation landed before the `wc -l`, petstore
  would have reported PASS over 26 real findings. Now: one private
  directory per invocation, printed once, TMPDIR honoured, and the run
  REFUSES (exit 97) rather than falling back to a shared path. Same fix in
  tests/run-helper-suites.sh, test_gate_route_auth.sh and
  test_check_manifest.sh, which had the same defect: route-auth reported 7
  failures under the harness and 0 standalone.

A RESOLVING DIFF BASE IS NOT A USABLE ONE
  shillinq's `development` run finished in 22 seconds, all green. Cause:
  on a push to a mainline branch `origin/development` IS HEAD, so the diff
  is empty by construction and every gate passes over nothing. Verified at
  c64e9fe — 52 gates PASS scoped, 18 FAIL unscoped. Now refused with exit
  99, alongside a merge-base check for shallow checkouts, and the diff's
  exit code is read directly rather than through a `||` chain that cannot
  tell "no changes" from "could not run".

  The first draft of that block used `set +e`/`set -e`, which does not
  restore state — it enabled errexit for the remaining 3,700 lines and
  aborted every scoped run right after the scope line. Caught by
  test_gate_route_auth.sh. Replaced with `&& rc=0 || rc=$?`.

ALSO
  * 19 helper lookups re-resolved `dirname "${BASH_SOURCE[0]}"` AFTER the
    `cd "${APP_DIR}"`, against the warning at the top of the file. One of
    them (gate-17) aborted the entire suite when the runner was invoked by
    a relative path — 46 gates never ran.
  * gates 46/40/28 now _skip(wiring) when their helper is missing, rather
    than passing over an unread file set (#147).
  * quality.yml floats on @main while the package it drives is PINNED, and
    it executes paths inside that package BY NAME. That interface broke
    three times in one day (#168). Pinning both halves from one tag is a
    human call; until then a preflight names the desync instead of letting
    it surface as an unexplained gate failure.

* fix(gate-28): know both HTML comment terminators, not just `-->`

CodeQL `py/bad-tag-filter`, high, on the terminator-trimming pattern
introduced in the previous commit. Nothing here sanitises markup — it
trims a comment terminator off a licence identifier — but a half-known
comment syntax is still half-known: `<!--SPDX-License-Identifier:
EUPL-1.2--!>` would have yielded `EUPL-1.2--!` as the licence and
reported drift on a correct header. Tested both ways: the value is
trimmed for `*/`, `-->` and `--!>`, and a genuinely wrong licence is
still wrong after trimming.

* fix(ci): the package's own evidence assertion depended on the shared /tmp path

Two CI failures, both caused by this branch, both worth the detour.

* `hydra-gates-package.yml` asserts that a gate reporting FAIL also WROTE
  the evidence naming the offending file — a good assertion, reading a
  hardcoded /tmp/hydra-gate-<name>.log. That is the defect this branch
  exists to remove, one level up: with a shared path the check could read a
  DIFFERENT run's log and pass, or a truncated one and fail, and neither
  outcome would say anything about the fixture. It now reads the directory
  the run announces on its own first line, and fails loudly if no such line
  appeared — because an unattributable verdict is not a verdict.

  Reproduced locally against the fixed runner: exit 2, both gates named,
  both injected files named in their own run's logs.

* ShellCheck SC2086 x4 on the `${_TCM_LOG}` uses added to
  test_check_manifest.sh. Quoted.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
rubenvdlinde added a commit to ConductionNL/openregister that referenced this pull request Aug 6, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/softwarecatalog that referenced this pull request Aug 6, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/procest that referenced this pull request Aug 6, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit to ConductionNL/scholiq that referenced this pull request Aug 6, 2026
A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.
rubenvdlinde added a commit that referenced this pull request Aug 6, 2026
… on the failure mode that has no red (#177)

* feat(quality): stop pinning the gates package per repo, and gate main on the failure mode that has no red

The fleet pinned `hydra-gates-ref` in 23 repositories. A pin is a silent
expiry date, and it has now cost us twice:

  #159  22 repos sat on v1.0.1, predating a batch of gate fixes. 16 gates
        were dead fleet-wide and every one reported PASS — a gate whose
        helper never runs emits a tick identical to a real one.
  #173  the coverage flag was flipped to default true here, at @main, and
        reached v1.0.1 runners predating the accounting that makes it
        survivable. decidesk and doriath went red (exit 98) on gates 4, 24
        and 33 — the not-applicable gates that must never fail a run.

Both are one defect: this workflow is consumed at @main while the package
was consumed at a pin, so the two sides moved independently and a change on
one reached a runner from the other's past. The fix is no pin. The default
was already `main`; this makes that the documented contract and states the
rollback levers, because "always latest" is only safe with a way back:
revert on main for the whole fleet, or set the input explicitly for one
repo. A moving `v1` tag was considered and rejected — a tag nobody
re-points is indistinguishable from the stale pin being removed.

Unpinning means a broken main now reaches 23 repos at once, so main is
gated on the one failure mode that does not announce itself. An
unresolvable reusable workflow is not a red check: GitHub produces a run
with no jobs, or no run, and every dashboard stays green while every caller
quietly stops being checked. That is what a ~22 KB `run:` step did in #161,
reverted by #166 and re-landed by #168.

  quality-selftest.yml       an in-repo caller of ./.github/workflows/
                             quality.yml. It exists to be RESOLVED, not to
                             pass; its conclusion is not a verdict.
  quality-resolve-probe.yml  counts the JOBS that caller materialised.
                             `jobs == 0` is the outage signature, so the
                             count is the measurement and a conclusion is
                             deliberately not read. Split across two files
                             on purpose: with the call in the probe itself,
                             an unresolvable quality.yml would delete the
                             probe too and the required check would sit
                             PENDING FOREVER rather than go red.

Both guards are positive-controlled on every run. The probe first counts a
workflow that cannot exist and requires the answer to be 0 — a counter
returning a constant would otherwise pass forever. The lint is re-run at a
1-byte limit it cannot meet. The lint also reproduces the real outage:
against quality.yml at d68fb72 it names the 26959-byte block at line 2338.

hydra-gates-package.yml loses its `paths:` filter. It was defensible while
callers pinned; with the fleet on @main the blast radius of any merge here
is the whole fleet, and a required check with a paths filter leaves every
excluded PR pending forever.

Refs #159, #161, #166, #168, #173

* fix(selftest): widen the caller's permissions — a narrow grant is a second silent way to zero jobs

The selftest shipped with `contents: read`. Run 31073908079 came back
startup_failure with ZERO jobs, because quality.yml's journeydoc-capture job
declares `contents: write` + `actions: write` and permissions are validated
when the run is CREATED — `enable-journeydoc-capture: false` never gets a
chance to matter, since the job's `if:` is not reached.

This is a second route into the #161 outage class and it applies to every
caller in the fleet: a permission grant narrower than the shared workflow
requests produces no jobs and no red, indistinguishable from a healthy run
on any dashboard.

The probe caught it on its first execution, which is the evidence that it
works. Run 31073907988 recorded, in order:

  control count = 0
  OK — the counter can return 0, and reports it.
  quality-selftest.yml materialised 0 jobs at 7c3d160
  ##[error]quality.yml produced ZERO jobs. This is the #161 outage signature

So the guard has now been shown to fail on a REAL zero-jobs condition, not
only against its synthetic control.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
rubenvdlinde added a commit to ConductionNL/openconnector that referenced this pull request Aug 6, 2026
* chore(ci): move hydra-gates-ref v1.3.0 -> v1.4.0

A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.

* chore(ci): stop pinning hydra-gates — track the package at @main

Removes `hydra-gates-ref` entirely instead of moving it v1.3.0 -> v1.4.0.
The shared workflow already defaults the input to @main, and this repo
consumes `ConductionNL/.github/.github/workflows/quality.yml@main`, so both
sides now move together: a gate-package fix reaches this repo with no commit
here.

A pin is a silent expiry date. 22 repos sat on v1.0.1 while 16 gates were
dead fleet-wide and every one of them reported PASS (.github#159), and a
default flipped at @main later reached those same old runners and failed them
on gates they had no subject matter for (.github#173). Bumping the pin is a
treadmill that reintroduces the same failure mode on the next release.

The pin-justifying comment block is replaced with a short note saying why
there is no ref here and how to reintroduce one deliberately. The rationale
for `enable-hydra-gates: true` is kept, as is `enable-axe` being left off and
this repo's explicit `hydra-gates-require-full-coverage: false`.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
rubenvdlinde added a commit to ConductionNL/pipelinq that referenced this pull request Aug 6, 2026
* chore(ci): move hydra-gates-ref v1.3.0 -> v1.4.0

A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.

* chore(ci): stop pinning hydra-gates — track the package at @main

Removes `hydra-gates-ref` entirely instead of moving it v1.3.0 -> v1.4.0.
The shared workflow already defaults the input to @main, and this repo
consumes `ConductionNL/.github/.github/workflows/quality.yml@main`, so both
sides now move together: a gate-package fix reaches this repo with no commit
here.

A pin is a silent expiry date. 22 repos sat on v1.0.1 while 16 gates were
dead fleet-wide and every one of them reported PASS (.github#159), and a
default flipped at @main later reached those same old runners and failed them
on gates they had no subject matter for (.github#173). Bumping the pin is a
treadmill that reintroduces the same failure mode on the next release.

The pin-justifying comment block is replaced with a short note saying why
there is no ref here and how to reintroduce one deliberately. The rationale
for `enable-hydra-gates: true` is kept, as is `enable-axe` being left off; the
"no count is written here" note now refers to the package version rather than
to a pin that no longer exists.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
rubenvdlinde added a commit to ConductionNL/opencatalogi that referenced this pull request Aug 6, 2026
* chore(ci): move hydra-gates-ref v1.3.0 -> v1.4.0

A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.

* chore(ci): stop pinning hydra-gates — track the package at @main

Removes `hydra-gates-ref` entirely instead of moving it v1.3.0 -> v1.4.0.
The shared workflow already defaults the input to @main, and this repo
consumes `ConductionNL/.github/.github/workflows/quality.yml@main`, so both
sides now move together: a gate-package fix reaches this repo with no commit
here.

A pin is a silent expiry date. 22 repos sat on v1.0.1 while 16 gates were
dead fleet-wide and every one of them reported PASS (.github#159), and a
default flipped at @main later reached those same old runners and failed them
on gates they had no subject matter for (.github#173). Bumping the pin is a
treadmill that reintroduces the same failure mode on the next release.

The pin-justifying comment block is replaced with a short note saying why
there is no ref here and how to reintroduce one deliberately. The rationale
for `enable-hydra-gates: true` is kept, as is `enable-axe` being left off.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
rubenvdlinde added a commit to ConductionNL/docudesk that referenced this pull request Aug 6, 2026
* chore(ci): move hydra-gates-ref v1.3.0 -> v1.4.0

A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.

* chore(ci): stop pinning hydra-gates — track the package at @main

Removes the `hydra-gates-ref` input from the `quality.yml` caller. The
shared workflow already defaults it to `main`, and this repo consumes
`quality.yml` itself at `@main`, so dropping the override makes both
sides move together: a gate-package fix lands here without a commit here.

A pin is a silent expiry date on every upstream fix, and we have paid for
that twice already:

  - .github#159 — 22 repos sat on v1.0.1, which predated the gate fixes.
    16 gates were dead fleet-wide and every single one reported PASS. A
    gate that never runs emits a tick identical to one that did, so
    nothing in any repo's history showed it.

  - .github#173 — the shared side flipped a default at @main while the
    package stayed pinned per caller. Old runners lacked the coverage
    accounting the new default assumed, so they went red on gates they
    had no subject matter for.

Removing the pin closes both shapes at once. Rolling back is a revert on
ConductionNL/.github main, which reaches the whole fleet in one commit;
holding this one repo still is still possible by setting the input
explicitly, with a reason.

`enable-hydra-gates: true` is unchanged. `enable-axe` remains unset.
The comment block that justified the pin is replaced with a short note
saying why there is no pin.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
rubenvdlinde added a commit to ConductionNL/openbuild that referenced this pull request Aug 6, 2026
* chore(ci): move hydra-gates-ref v1.3.0 -> v1.4.0

A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.

* chore(ci): stop pinning hydra-gates — track the package at @main

Removes `hydra-gates-ref` entirely instead of moving it v1.3.0 -> v1.4.0.
The shared workflow already defaults the input to @main, and this repo
consumes `ConductionNL/.github/.github/workflows/quality.yml@main`, so both
sides now move together: a gate-package fix reaches this repo with no commit
here.

A pin is a silent expiry date. 22 repos sat on v1.0.1 while 16 gates were
dead fleet-wide and every one of them reported PASS (.github#159), and a
default flipped at @main later reached those same old runners and failed them
on gates they had no subject matter for (.github#173). Bumping the pin is a
treadmill that reintroduces the same failure mode on the next release.

The pin-justifying comment block is replaced with a short note saying why
there is no ref here and how to reintroduce one deliberately. The rationale
for `enable-hydra-gates: true` is kept unchanged, as is `enable-axe` being
left off.

---------

Co-authored-by: Ruben van der Linde <juan.claude@conduction.nl>
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
rubenvdlinde added a commit to ConductionNL/decidesk that referenced this pull request Aug 6, 2026
* chore(ci): move hydra-gates-ref v1.3.0 -> v1.4.0

A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.

* chore(ci): stop pinning hydra-gates — track the package at @main

Removes the `hydra-gates-ref` input from the `quality.yml` caller. The
shared workflow already defaults it to `main`, and this repo consumes
`quality.yml` itself at `@main`, so dropping the override makes both
sides move together: a gate-package fix lands here without a commit here.

A pin is a silent expiry date on every upstream fix, and we have paid for
that twice already:

  - .github#159 — 22 repos sat on v1.0.1, which predated the gate fixes.
    16 gates were dead fleet-wide and every single one reported PASS. A
    gate that never runs emits a tick identical to one that did, so
    nothing in any repo's history showed it.

  - .github#173 — the shared side flipped a default at @main while the
    package stayed pinned per caller. Old runners lacked the coverage
    accounting the new default assumed, so they went red on gates they
    had no subject matter for.

Removing the pin closes both shapes at once. Rolling back is a revert on
ConductionNL/.github main, which reaches the whole fleet in one commit;
holding this one repo still is still possible by setting the input
explicitly, with a reason.

`enable-hydra-gates: true` is unchanged. `enable-axe` remains unset.
The comment block that justified the pin is replaced with a short note
saying why there is no pin.

---------

Co-authored-by: Ruben van der Linde <juan.claude@conduction.nl>
rubenvdlinde added a commit to ConductionNL/larpingapp that referenced this pull request Aug 6, 2026
* chore(ci): move hydra-gates-ref v1.3.0 -> v1.4.0

A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.

* chore(ci): stop pinning hydra-gates — track the package at @main

Removes the `hydra-gates-ref` input from the `quality.yml` caller. The
shared workflow already defaults it to `main`, and this repo consumes
`quality.yml` itself at `@main`, so dropping the override makes both
sides move together: a gate-package fix lands here without a commit here.

A pin is a silent expiry date on every upstream fix, and we have paid for
that twice already:

  - .github#159 — 22 repos sat on v1.0.1, which predated the gate fixes.
    16 gates were dead fleet-wide and every single one reported PASS. A
    gate that never runs emits a tick identical to one that did, so
    nothing in any repo's history showed it.

  - .github#173 — the shared side flipped a default at @main while the
    package stayed pinned per caller. Old runners lacked the coverage
    accounting the new default assumed, so they went red on gates they
    had no subject matter for.

Removing the pin closes both shapes at once. Rolling back is a revert on
ConductionNL/.github main, which reaches the whole fleet in one commit;
holding this one repo still is still possible by setting the input
explicitly, with a reason.

`enable-hydra-gates: true` is unchanged. `enable-axe` remains unset.
The comment block that justified the pin is replaced with a short note
saying why there is no pin.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
rubenvdlinde added a commit to ConductionNL/doriath that referenced this pull request Aug 6, 2026
* chore(ci): move hydra-gates-ref v1.3.0 -> v1.4.0

A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.

* chore(ci): stop pinning hydra-gates — track the package at @main

Removes the `hydra-gates-ref` input from the `quality.yml` caller. The
shared workflow already defaults it to `main`, and this repo consumes
`quality.yml` itself at `@main`, so dropping the override makes both
sides move together: a gate-package fix lands here without a commit here.

A pin is a silent expiry date on every upstream fix, and we have paid for
that twice already:

  - .github#159 — 22 repos sat on v1.0.1, which predated the gate fixes.
    16 gates were dead fleet-wide and every single one reported PASS. A
    gate that never runs emits a tick identical to one that did, so
    nothing in any repo's history showed it.

  - .github#173 — the shared side flipped a default at @main while the
    package stayed pinned per caller. Old runners lacked the coverage
    accounting the new default assumed, so they went red on gates they
    had no subject matter for.

Removing the pin closes both shapes at once. Rolling back is a revert on
ConductionNL/.github main, which reaches the whole fleet in one commit;
holding this one repo still is still possible by setting the input
explicitly, with a reason.

`enable-hydra-gates: true` is unchanged. `enable-axe` remains unset.
The comment block that justified the pin is replaced with a short note
saying why there is no pin.
rubenvdlinde added a commit to ConductionNL/nldesign that referenced this pull request Aug 6, 2026
* chore(ci): move hydra-gates-ref v1.3.0 -> v1.4.0

A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.

* chore(ci): stop pinning hydra-gates — track the package at @main

Removes the `hydra-gates-ref` input from the `quality.yml` caller. The
shared workflow already defaults it to `main`, and this repo consumes
`quality.yml` itself at `@main`, so dropping the override makes both
sides move together: a gate-package fix lands here without a commit here.

A pin is a silent expiry date on every upstream fix, and we have paid for
that twice already:

  - .github#159 — 22 repos sat on v1.0.1, which predated the gate fixes.
    16 gates were dead fleet-wide and every single one reported PASS. A
    gate that never runs emits a tick identical to one that did, so
    nothing in any repo's history showed it.

  - .github#173 — the shared side flipped a default at @main while the
    package stayed pinned per caller. Old runners lacked the coverage
    accounting the new default assumed, so they went red on gates they
    had no subject matter for.

Removing the pin closes both shapes at once. Rolling back is a revert on
ConductionNL/.github main, which reaches the whole fleet in one commit;
holding this one repo still is still possible by setting the input
explicitly, with a reason.

`enable-hydra-gates: true` is unchanged. `enable-axe` remains unset.
The comment block that justified the pin is replaced with a short note
saying why there is no pin.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
rubenvdlinde added a commit to ConductionNL/hermiq that referenced this pull request Aug 6, 2026
* chore(ci): move hydra-gates-ref v1.3.0 -> v1.4.0

A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.

* chore(ci): stop pinning hydra-gates — track the package at @main

Removes the `hydra-gates-ref` input from the `quality.yml` caller. The
shared workflow already defaults it to `main`, and this repo consumes
`quality.yml` itself at `@main`, so dropping the override makes both
sides move together: a gate-package fix lands here without a commit here.

A pin is a silent expiry date on every upstream fix, and we have paid for
that twice already:

  - .github#159 — 22 repos sat on v1.0.1, which predated the gate fixes.
    16 gates were dead fleet-wide and every single one reported PASS. A
    gate that never runs emits a tick identical to one that did, so
    nothing in any repo's history showed it.

  - .github#173 — the shared side flipped a default at @main while the
    package stayed pinned per caller. Old runners lacked the coverage
    accounting the new default assumed, so they went red on gates they
    had no subject matter for.

Removing the pin closes both shapes at once. Rolling back is a revert on
ConductionNL/.github main, which reaches the whole fleet in one commit;
holding this one repo still is still possible by setting the input
explicitly, with a reason.

`enable-hydra-gates: true` is unchanged. `enable-axe` remains unset.
The comment block that justified the pin is replaced with a short note
saying why there is no pin.
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.

1 participant