fix(quality): quality.yml resolved to ZERO jobs — and the three Nextcloud legs could not block a merge - #389
Conversation
…loud legs could not block a merge TWO DEFECTS. The second is the one that was asked for; the first is the one that made the second academic. quality.yml PRODUCED ZERO JOBS ------------------------------ #383 (info-xml) merged at 11:19:40Z. #385 (app:check-code + REUSE) merged at 11:26:16Z from a branch written against a tree that did not contain info-xml. Its hunks anchored on the context lines - name: Checkout uses: actions/checkout@v4 with: which by then belonged to info-xml's checkout. Git merged it textually, cleanly, and spliced two jobs into a third: * app-check-code lost its `steps:` entirely — the job header ran straight into the info.xml comment block. * info-xml's body became app-check-code's steps. * reuse swallowed info-xml's steps, and a stray `sparse-checkout: appinfo/` landed inside a `run: |` block where it would have executed as a shell line. * the final upload-artifact carried TWO `name:` keys, which is what actually makes the file unparseable. Every core app consumes this file at @main, so since 11:26 the whole fleet's Code Quality workflow has resolved to nothing. Both apps that pushed after that point produced a run with ZERO jobs: openconnector 31592994170 and larpingapp 31592027242. The other sixteen have not pushed since; their green is stale evidence about a workflow that no longer exists. An unresolvable reusable workflow never goes red on its own. The only thing that noticed was this repo's own resolve probe, which said so in words. Note for anyone linting this file in future: PyYAML's safe_load PARSES the broken version happily — last duplicate key wins — and reports twenty jobs. A generic YAML lint would have called it clean. Proven both ways with a duplicate-rejecting loader on one tree: before, a duplicate `name` at line 799; after, none. THE THREE LEGS COULD NOT BLOCK A MERGE -------------------------------------- Neither #383 nor #385 added its job to the Quality Report's `needs:` list, and that job is the only meaningful required check on main and beta across the fleet. scripts/assert-quality-report-gates-every-leg.py named all three. It fails on the parent commit and passes here, and its own positive control passes in both states, so the clean pass is a verdict rather than an instrument that cannot fail. FIVE CHECKS, THREE JOBS ----------------------- #385's own message names five Nextcloud checks. Only three are jobs in this file. Multi-database PHPUnit is a matrix dimension of `phpunit`, which was already in `needs:`, and `occ integrity:sign-app` lives in release.yml, which has no Quality Report to gate. So `needs:` goes 16 -> 19, not 16 -> 21. WHAT LISTING THEM ACTUALLY DOES, PER LEG ---------------------------------------- app-check-code and reuse are internally non-blocking by default — the first swallows a non-zero occ exit and warns, the second carries continue-on-error: ${{ !inputs.reuse-blocking }}. Both conclude success with findings, so listing them changes nothing today. That is the point: the wiring has to exist first, or flipping the per-app input later would be a no-op nobody notices. Their `*-blocking` inputs are NOT flipped here; that is a separate decision. info-xml has no such flag and is blocking on arrival. #383 measured it before merging across all 18 core apps: five pass, thirteen fail, twelve of those on xs:sequence element ORDER and one on a summary over the schema's length cap. Confirmed live in the six-minute window in which this job both existed and resolved — openregister run 31591669849, `Element 'documentation': This element is not expected`. So this commit will red thirteen apps and block their merges until their manifests are reordered. That is the authorised trade: the App Store rejects the same files at upload time, after the release has been built, tagged and published. Every one of the thirteen is a reorder away from passing. THE REPORT WAS SILENT ABOUT ALL THREE ------------------------------------- They upload result artifacts nobody read. That is the same silence the Hydra-gates row three lines below exists to correct, and it would have been reintroduced the day these landed. Three rows added — with a comment saying to read them differently, because reuse.txt records the RAW step outcome (so it goes red on findings while the job is green) and app-check-code.txt records job.status (so it reads green with findings, and its cell means "a verdict was produced", not "no private API usage"). Narrowing that one to its own finding count is left as a separate change rather than smuggled in here.
#383's 5/13 was measured before it merged. Re-measured against every repo's live development tip with the same App Store XSD: 6 pass, 12 fail. The one-app difference is larpingapp, whose manifest was reordered by efa6aead at 11:28:48Z; validating that single file at both refs gives FAIL then PASS, so the difference is the world moving rather than the instrument drifting. Also records that the local validator reproduces the live CI message on openregister byte for byte, and that the count decays.
Correction to the framing this PR was opened underIt was described to me as "the Shared-workflow guard is red and that is blocking the gate-fix merge queue — six PRs." Measured against the open PRs, that is not the shape of the queue.
The break landed at 11:26:16Z. Every one of those greens predates it — they are stale verdicts about a Exactly one PR is measurably blocked by the two defects this fixes, and it is blocked by both. #378's resolve-probe run So the accurate claim for this PR is: it unblocks #378 outright, and it stops the other six going red on their next re-run. The queue was not held by a red light; six of its seven were holding a green one that had expired.
Also re-measured rather than quoted
|
…efault it off This job cannot pass in any repo in this fleet, and merging it into the Quality Report's `needs:` would have hard-failed every PHP app on a check that no longer exists. MEASURED, not inferred. Extracting the registered App-namespace commands from `core/register_command.php` at each tag — same expression, same file, only the tag varying: v20.0.0 Disable Enable GetPath Install ListApps Remove Update + CheckCode v34.0.0 Disable Enable GetPath Install ListApps Remove Update CheckCode appearing at v20 is the control: the extraction CAN produce it, so its absence at v34 is a result rather than a failed lookup. Corroborated independently against a second artefact — `core/Command/App/CheckCode.php` answers 200 at v20 and v21 and 404 at v25, v31, v32, v33 and v34, while `core/Command/App/ListApps.php` answers 200 at every one of those tags, so the 404s are a removal and not a wrong path. Every app here declares a Nextcloud min-version of 31, 32 or 34, and the job fetches the server at the version the app DECLARES. So occ would be asked for a command around eleven majors dead, print no recognisable verdict, and trip the job's own positive control — whose `exit 1` is UNCONDITIONAL. It sits above the check-code-blocking branch and is not covered by it, so "non-blocking by default" was never true of this job's failure path. The positive control behaved exactly as designed: it refused to report an absence of private API usage from a run that inspected nothing. The job is what is wrong, not the control. LEFT WIRED AND STILL IN `needs:`. A skipped job's result is `skipped`, not `failure`, so this blocks nothing while it is off, and the wiring stays correct for whoever rebuilds the check on tooling that still exists. Deleting it would quietly re-open the gap #385 was written to close. check-code-blocking is untouched. Nobody asked for it to move, and it is irrelevant while the job does not run.
|
Two defects. The second is what was asked for; the first is what makes the second matter.
1.
quality.ymlhas produced ZERO jobs since 11:26Z, fleet-wide#383(info-xml) merged at 11:19:40Z.#385(app:check-code + REUSE) merged at 11:26:16Z from a branch written against a tree that did not yet contain info-xml. Its hunks anchored on- name: Checkout/uses: actions/checkout@v4/with:— context lines that by then belonged to info-xml's checkout. Git merged it textually and cleanly, and spliced two jobs into a third:app-check-codelost itssteps:entirely — the job header ran straight into the info.xml comment block.reuseswallowed info-xml's steps, and a straysparse-checkout: appinfo/landed inside arun: |block, where it would have executed as a shell command.upload-artifactended up with twoname:keys, which is what actually makes the file unparseable.Every core app consumes this file at
@main. Both apps that pushed after 11:26 produced a run with zero jobs — openconnector31592994170and larpingapp31592027242. The other sixteen have not pushed since; their green describes a workflow that no longer exists. The next push in any of them gets zero jobs.An unresolvable reusable workflow never goes red on its own. The only thing that noticed was this repo's own
Quality resolve probe, which said so in words.2. The three Nextcloud legs could not block a merge in any of the 18 apps
Neither
#383nor#385added its job to the Quality Report'sneeds:list, and that job is the only meaningful required check onmainandbetaacross the fleet.scripts/assert-quality-report-gates-every-leg.pynamed all three. It fails on the parent commit and passes on this branch, and its own positive control passes in both states, so the clean pass is a verdict rather than an instrument that cannot fail.Five checks, three jobs
#385's message names five Nextcloud checks. Only three of them are jobs in this file:needs:info-xmlenable-php— no dedicated flagocc app:check-codeapp-check-codeenable-php&&enable-check-codereuseenable-reusephpunitdatabase-test-matrixphpunitocc integrity:sign-apprelease.ymlSo
needs:goes 16 → 19, not 16 → 21.What listing them actually does, per leg
app-check-codeandreuseare internally non-blocking by default — the first swallows a non-zerooccexit and warns, the second carriescontinue-on-error: ${{ !inputs.reuse-blocking }}. Both concludesuccesswith findings, so listing them changes nothing today. That is the point: the wiring has to exist first, or flipping the per-app input later would be a no-op nobody notices. Their*-blockinginputs are deliberately not flipped here — that is a separate decision.info-xmlhas no such flag and is blocking on arrival.#383measured it before merging across all 18 core apps: five pass, thirteen fail — twelve onxs:sequenceelement order, one on a summary over the schema's length cap. Confirmed live in the six-minute window in which this job both existed and resolved (openregister run31591669849, complaining that adocumentationelement is not expected in that position).So merging this reds thirteen apps and blocks their merges until their manifests are reordered. That is the authorised trade: the App Store rejects the same files at upload time, after the release has been built, tagged and published. Every one of the thirteen is a reorder away from passing, and none of them needs a code change.
The report was silent about all three
They upload result artifacts nobody reads — the same silence the Hydra-gates row three lines below exists to correct, reintroduced the day these landed. Three rows added, with a comment saying to read them differently:
reuse.txtrecords the raw step outcome (so it goes red on findings while the job is green), whileapp-check-code.txtrecordsjob.status(so it reads green with findings — its cell means a verdict was produced, not no private API usage). Narrowing that one to its own finding count is left as a separate change rather than smuggled in here.Verification
assert-quality-report-gates-every-leg.py— fails onmainnaming exactly the three jobs, passes here over nineteen legs; positive control clean in both states.assert-run-steps-resolvable.pyover all sixteen workflows, with its--limit 1positive control.assert-no-producer-deletes-a-verdict.py,test-spec-coverage-gate.py,assert-seed-step-fails-loudly.py— all clean, controls clean.app-check-codesix steps,reusefive,info-xmleight.The one assertion that cannot be run locally is
quality.yml resolves (job count > 0), which dispatches a real run and counts its jobs. That is the assertion that caught the outage, and only this PR's ownQuality resolve probecan close it.