Skip to content

fix(gate-28): an empty diff scope is not a structural gap — it is ADR-020 working - #182

Merged
rubenvdlinde merged 1 commit into
mainfrom
fix/gate-28-empty-scope-is-not-a-gap
Aug 6, 2026
Merged

fix(gate-28): an empty diff scope is not a structural gap — it is ADR-020 working#182
rubenvdlinde merged 1 commit into
mainfrom
fix/gate-28-empty-scope-is-not-a-gap

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

gate-28 goes RED on every PR whose diff does not touch lib/**/*.php — which is most of them. It reports the diff's shape as the repository's defect.

Found while unpinning nldesign to main per #177: with the pin removed both capability probes pass, all 58 applicable gates go green, and the only failure is gate-28 not running. It does not exist at v1.3.0, so unpinning is what surfaced it — and it would have turned the whole fleet red as the sweep landed.

The conflation

_lt_files empty had two causes, and the final else stated them as one:

  • (a) the repo has lib/**/*.php but this diff touches none — ADR-020 diff-scoping working, the same state gate-4 reports NOT APPLICABLE for the same diff;
  • (b) lib/ exists but holds no tracked .php at all.

Neither is (c) "files were in scope and none carried a declaration" — the genuine structural gap that branch describes. All three printed (c), and for (a) that message is simply false: with zero files in scope, "0 in-scope file carried a declaration" is true only vacuously.

Not cosmetic: hydra-gates-require-full-coverage defaults TRUE (#164) and a structural gap exits 98. This is a fleet-wide falsely-RED gate — the mirror of the falsely-GREEN shape #172 built this taxonomy to kill.

Three arms, measured on nldesign against the real runner

diff before after
.github/workflows/code-quality.yml SKIPPED (structural) → exit 98 NOT APPLICABLE
3 files under lib/ PASS PASS
one lib/*.php declaring AGPL while composer.json declares EUPL-1.2 FAIL — 1 file(s)

The third arm is the one that matters. Turning a red into a not-applicable is exactly how a gate gets muted, so the mismatch gate-28 exists to catch was injected on a throwaway branch and confirmed still caught.

The (c) message now also reports the in-scope file count, so a reader can tell it apart from the case it used to be conflated with.

…-020 working

gate-28 turned RED on every PR in the fleet whose diff does not touch
lib/**/*.php, which is most of them. It reported the DIFF's shape as the
REPOSITORY's defect.

`_lt_files` empty had two causes, and the final `else` stated them as one:

  a) the repo has lib/**/*.php but this diff touches none of them — ADR-020
     diff-scoping working, the same state gate-4 reports NOT APPLICABLE for
     the same diff;
  b) lib/ exists but holds no tracked .php at all.

Neither is (c) "files WERE in scope and none carried a declaration", the
genuine structural gap that branch describes. All three printed (c), and for
(a) that message is FALSE: with zero files in scope, "0 in-scope file carried
a declaration" is true only vacuously.

Not cosmetic. hydra-gates-require-full-coverage defaults to TRUE (#164) and a
structural gap fails the run with exit 98, so this was a fleet-wide falsely-RED
gate — the mirror of the falsely-GREEN shape #172 built this taxonomy to kill.
It surfaced the moment a repo unpinned to main, because gate-28 does not exist
at v1.3.0.

Measured on nldesign against the real runner, three arms, before and after:

  diff = .github/workflows/code-quality.yml   before SKIPPED(structural) -> exit 98
                                              after  NOT APPLICABLE
  diff = 3 files under lib/                   before PASS   after PASS
  diff = one lib/*.php declaring AGPL while
         composer.json declares EUPL-1.2      after  FAIL — 1 file(s)

The third arm is the one that matters: turning a red into a not-applicable is
exactly how a gate gets muted, so the mismatch it exists to catch was injected
and confirmed still caught.

The (c) message now also states the in-scope count, so a reader can tell it
apart from the case it used to be conflated with.
@rubenvdlinde
rubenvdlinde merged commit da23b92 into main Aug 6, 2026
29 checks passed
rubenvdlinde pushed a commit to ConductionNL/nldesign that referenced this pull request Aug 6, 2026
…it was cut

development moved from v1.3.0 to v1.5.0 while this branch was open, which
fixes the symptom that opened it: v1.5.0 satisfies #177's capability probe,
so Hydra Gates no longer fails before a gate runs. Unpinning entirely still
matters, and the reason is now sharper than when this branch started.

v1.5.0 carries a fleet-wide falsely-RED gate. gate-28 license-triangle
reported a `structural` coverage gap whenever the diff scope was empty —
that is, on every PR that does not touch lib/**/*.php, which is most of
them — because "no file in scope" and "files in scope, none carried a
licence declaration" reached the same branch. With
hydra-gates-require-full-coverage defaulting TRUE, that is exit 98.

It is fixed in ConductionNL/.github#182, on main. A repo pinned to v1.5.0
cannot see that fix, and the tag will not move. Measured here against the
real runner, three arms:

    diff = .github/workflows/code-quality.yml   before SKIPPED(structural)
                                                after  NOT APPLICABLE
    diff = 3 files under lib/                   PASS, both
    diff = a lib/*.php declaring AGPL while
           composer.json declares EUPL-1.2      FAIL — 1 file(s)

That is the whole argument for #177's contract in one branch: this repo was
pinned at v1.3.0, bumped to v1.5.0 to clear one breakage, and would have
needed a third commit to clear the next one. A pin is a silent expiry date
on every upstream fix.

Verified on this PR's own run after the unpin: Hydra Gates PASS in 20s,
58 applicable gates green, 5 correctly NOT APPLICABLE.

Rollback for this repo alone stays available: set hydra-gates-ref
explicitly. An escape hatch, not a resting state.
rubenvdlinde pushed a commit to ConductionNL/nldesign that referenced this pull request Aug 6, 2026
…it was cut

development moved from v1.3.0 to v1.5.0 while this branch was open, which
fixes the symptom that opened it: v1.5.0 satisfies #177's capability probe,
so Hydra Gates no longer fails before a gate runs. Unpinning entirely still
matters, and the reason is now sharper than when this branch started.

v1.5.0 carries a fleet-wide falsely-RED gate. gate-28 license-triangle
reported a `structural` coverage gap whenever the diff scope was empty —
that is, on every PR that does not touch lib/**/*.php, which is most of
them — because "no file in scope" and "files in scope, none carried a
licence declaration" reached the same branch. With
hydra-gates-require-full-coverage defaulting TRUE, that is exit 98.

It is fixed in ConductionNL/.github#182, on main. A repo pinned to v1.5.0
cannot see that fix, and the tag will not move. Measured here against the
real runner, three arms:

    diff = .github/workflows/code-quality.yml   before SKIPPED(structural)
                                                after  NOT APPLICABLE
    diff = 3 files under lib/                   PASS, both
    diff = a lib/*.php declaring AGPL while
           composer.json declares EUPL-1.2      FAIL — 1 file(s)

That is the whole argument for #177's contract in one branch: this repo was
pinned at v1.3.0, bumped to v1.5.0 to clear one breakage, and would have
needed a third commit to clear the next one. A pin is a silent expiry date
on every upstream fix.

Verified on this PR's own run after the unpin: Hydra Gates PASS in 20s,
58 applicable gates green, 5 correctly NOT APPLICABLE.

Rollback for this repo alone stays available: set hydra-gates-ref
explicitly. An escape hatch, not a resting state.
rubenvdlinde added a commit to ConductionNL/zaakafhandelapp that referenced this pull request Aug 6, 2026
…it was cut (#331)

This repo has been bumped twice already (v1.0.1 -> v1.3.0 -> v1.5.0), each
time to clear a breakage the pin itself caused, and a third was queued.

v1.5.0 ships gate-28 reporting a `structural` coverage gap whenever the diff
scope is empty — i.e. on every PR that does not touch lib/**/*.php, which is
most of them. With hydra-gates-require-full-coverage defaulting TRUE that is
exit 98. It is fixed in ConductionNL/.github#182, on main, and a pinned repo
cannot see that fix because the tag will not move.

Tracking main is the fleet contract as of ConductionNL/.github#177, which
also added the guard that makes it safe: an unresolvable reusable workflow
produces no red check at all, just zero jobs, so quality-resolve-probe.yml
counts the jobs a caller materialises and asserts > 0.

Supersedes #329, which set v1.4.0 — a DOWNGRADE from what development now
carries, and to a ref that fails #177's capability probe outright (v1.4.0
ships none of check_spec_anchors.py, check_form_labels.py or
check_license_triangle.py).

Rollback for this repo alone stays available: set hydra-gates-ref explicitly.

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
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