fix(quality): an empty frontend-checks list DELETED the job from the run; frontend-tests ignored frontend-path - #150
Merged
Conversation
…ests ignored frontend-path
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.
What was actually wrong
The reported symptom was
quality / Frontend Check (${{ matrix.script }}) skippingon procest(run 30894060736), read as "the matrix did not expand".
That diagnosis was wrong, and the diagnostic rule behind it is wrong. Measured:
frontend-checksexpands and runs correctly wherever a caller supplies the input.petstore run 30897009428:
Frontend Check (test:unit)andFrontend Check (check:specs), both green.frontend-checks, so it defaults to"[]"and the job'sif:is false.That is a correct opt-out.
${{ matrix.x }}in a check list is the signature of a falseif:, not of an emptymatrix. In self-test run 30898711087,
PHP Quality (${{ matrix.tool }}),License (${{ matrix.ecosystem }})andPHPUnit (PHP ${{ matrix.php-version }}, ...)renderedunexpanded in exactly the same way — and all three of those matrices are hard-coded literal lists
that cannot be empty. They were gated off by their
if:, nothing more.So I did not patch the reported symptom. Chasing it did surface two real defects.
Fix 1 —
frontend-checks: the guard disagreed with the matrixif: inputs.frontend-checks != '[]'was a two-character string comparison against a value thematrix consumes through
fromJSON. Every other spelling of empty —'[ ]','[\n]','[""]'—passes that test and then resolves to an empty matrix vector.
An empty matrix vector does not skip. Measured, run 30898927145 with
frontend-checks: '[ ]':Frontend Checkrows'[ ]')'[ ]')skippedNo "skipping" row, no failure, no annotation.
reporthasif: always(), so the run still goesgreen. The gate disappears without a trace — strictly worse than the visible skip a false
if:produces. Routing both sides through
fromJSONmakes that state unreachable.Fix 2 —
frontend-testsignoredfrontend-pathFound by running the self-test with
frontend-path: ci-selftest. This was the only frontend jobwith neither
working-directorynorcache-dependency-path, so it probed the repo root:setup-nodehard-failed, "Dependencies lock file is not found in/home/runner/work/.github/.github" — a falsely RED gate blaming the app for the workflow's own
mislocation;
package.jsonexists: no test script found there, records"skipped", goes GREEN while the frontend's real suite never runs — reopening, for subdirectoryrepos, exactly the hole this job was added to close.
Now mirrors
frontend-build: detect first (including the lockfile), thensetup-nodegated on theresult with
cache-dependency-path.Latent, not live — org-wide code search on 2026-08-04 found no caller setting a non-default
frontend-path; the only hit is this file. Fixed so that adoptingfrontend-pathcannot silentlyswitch the unit gate off.
Evidence
.githubhas no caller ofquality.yml, so I added a temporary self-test caller(
uses: ./.github/workflows/quality.yml) plus a fixture with a deliberately passing and adeliberately failing npm script, ran it, then removed it — this PR touches only
quality.yml.["selftest:pass","selftest:fail"](selftest:pass)✅ ·(selftest:fail)❌ · Quality Report ❌'[ ]', pre-fixFrontend Tests (unit)❌→✅'[ ]', post-fixskippedrow (20 jobs)Red and green in the same run, with a same-run control, and the failure propagated to
Quality Report— so the legs genuinely execute their script and genuinely block.actionlintclean. Positive-controlled first: renaming the matrix key toscriptTYPOmade it emit5 errors, so the clean result is meaningful (this also rules out a key-name mismatch and wrong
nesting as causes).
Left alone deliberately
Features Extractskipping is legitimate.if: ... && github.event_name != 'pull_request',and the run was a PR. Its PR-side twin
Features Checkran and passed. Not the same defect class;no change made.
enable-hydra-gates/enable-axetouched. No suppression baseline added or modified.#148(enable-axe/axe-routes/axe-version,needs: [playwright]onhydra-gates) verifiedintact; branched from
mainat 0d3e589.