fix(quality): a failed sibling-app install must fail the step, not pass [DRAFT — do not merge] - #484
Draft
rubenvdlinde wants to merge 1 commit into
Draft
fix(quality): a failed sibling-app install must fail the step, not pass [DRAFT — do not merge]#484rubenvdlinde wants to merge 1 commit into
rubenvdlinde wants to merge 1 commit into
Conversation
The "Checkout additional apps" step in the Nextcloud test-matrix job ended
its sibling `composer install` with `2>/dev/null || true` — stderr discarded
AND the exit status thrown away. It was the only `composer install` of the
20+ in this workflow to do either, and the `git clone` on the line directly
above it has always failed loudly, so the asymmetry was not deliberate.
The consequence is the programme's core failure mode in CI plumbing: a step
that did not succeed is indistinguishable from one that did. Worse, the
damage surfaces as the CONSUMING repo's fault, because the missing classes
belong to the sibling.
Measured on decidesk#517 (2026-08-17) — a diff of exactly one `.ts` file and
zero PHP:
* ALL SIX PHPUnit cells hit a transient HTTP 504 while installing
openregister's dependencies. Verified per job that the 504 falls inside
this step, between the "Checking out openregister" line and the next
step group.
* All six reported the step as SUCCESSFUL.
* Three cells then went red with 87 errors, the first being
`Class "Twig\Extension\AbstractExtension" not found` in
server/apps/openregister/lib/Twig/MappingExtension.php.
* Three went green. The only difference was WHICH package the 504 removed
— html5-php and deprecation-contracts broke the autoload chain,
php-http/discovery did not. The green cells were exactly as
half-installed as the red ones.
That last point is the reason this is worth fixing rather than retrying:
the step is producing half-installed sibling apps routinely, and whether
that becomes a red cell is a lottery over which package the network drops.
The fix keeps stderr and fails the step naming the app and its ref. Retrying
becomes an operator's decision taken knowingly rather than a silent default.
Also drops the `cd`/`cd -` dance for a subshell.
Verified with a shell control that the new form propagates correctly out of
the `... | while read` pipeline subshell under `bash -e`:
install succeeds -> step exit 0
install fails -> step exit 1 (old form: step exit 0)
The other three "Checkout additional apps" blocks in this file were checked
and are already loud; they are deliberately left untouched.
DRAFT — do not merge. `.github@main` is consumed live by every repo.
This was referenced Aug 17, 2026
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.
🚧 DRAFT — DO NOT MERGE
.github@mainis consumed live by every repo, so this lands fleet-wide the instant it merges. The flip is Ruben's call.Unlike the companion phpcs PR (#483), this one has no debt precondition — it does not turn any existing green cell red; it only stops a failed step from reporting success. It is deliberately kept separate from #483 so it can be sequenced independently rather than waiting on the 707-error phpcs cleanup.
The defect
.github/workflows/quality.yml, "Checkout additional apps" (Nextcloud test-matrix job):2>/dev/nullhides the error and|| truediscards the exit code. A failed dependency install is therefore invisible, and the suite runs against a half-installed sibling app.This is the only
composer installof the 20+ in this workflow with either its stderr discarded or its status thrown away — and thegit cloneon the line directly above it has always failed loudly. The asymmetry was not a deliberate policy.Worse: the damage surfaces as the consuming repo's fault, because the missing classes belong to the sibling.
Measured evidence — decidesk#517, 2026-08-17
A PR whose diff is exactly one
.tsfile and zero PHP.Every one of its six PHPUnit cells hit a transient HTTP 504 while installing openregister's dependencies. Verified per job that the 504 falls inside this step — between the
Checking out ConductionNL/openregisterline and the next step group — not somewhere else in the log.Masterminds/html5-phpsymfony/deprecation-contractssymfony/deprecation-contractsphp-http/discoveryMasterminds/html5-phpphp-http/discovery6 of 6 installs failed. 6 of 6 steps reported success.
The first error in the red cells:
cascading into ~86 further
UnknownTypeException: Class or interface "OCA\OpenRegister\Service\FileService" does not exist— openregister's autoloader was broken, so all of its classes became unmockable.developmentand the sibling PR #516 ran green in the same window, which is what rules out the PR's own diff.The part that makes this worth fixing rather than retrying
The three green cells were exactly as half-installed as the three red ones. The only difference was which package the network happened to drop —
html5-phpanddeprecation-contractsbroke the autoload chain,php-http/discoverydid not.So this step is producing half-installed sibling apps routinely, and whether that becomes a red cell is a lottery. A retry would have "fixed" #517 and taught us nothing.
The fix
Keep stderr. Fail the step, naming the app and its ref. Retrying becomes an operator's decision taken knowingly rather than a silent default. Also drops the
cd/cd -dance for a subshell.Verified with a shell control that failure propagates correctly out of the
... | while readpipeline subshell underbash -e(how Actions runsrun:blocks) — a check that can say both yes and no:The other three "Checkout additional apps" blocks in this file were checked and are already loud; they are deliberately left untouched. Measure widely, change narrowly.
Relationship to #483
These two defects are the same shape from opposite directions, and they are the reason both were found tonight:
Both produce a green cell over a real failure.
Line ownership — read this before reviewing
#355 (draft, opened 2026-08-11, by @rubenvdlinde) already fixes the sibling line to this one, four lines away in the same step:
php occ app:enable … || echo "::warning::…"composer install … 2>/dev/null || truephpcscase discarding its own verdict#355 and this PR are two halves of one hole — an app that will not enable, and an app whose dependencies never installed. #355's own body already names the second as a cause of the first: "…or its composer install did not complete." They should land together or not at all.
#355's measurement, independently re-verified tonight
Before writing this PR I re-ran #355's evidence rather than restating it. hermiq run
31490144919, six PHPUnit cells:app:enableTests: 1500, Assertions: 4647, Errors: 12Tests: 1500, Assertions: 4657, Errors: 5, Failures: 1Perfect 6/6, same commit, same application code, environment the only variable. It reproduces exactly.
#355 is closer to landing than its metadata suggests
It is 98 commits behind
main, over whichquality.ymlgrew +944/−39. But a local dry-run merge produces exactly one conflict region — everything else auto-merges. It needs a refresh, not a rewrite. (I did not touch the branch: no rebase, no force-push.)The three defects are one story
phpcscasecomposer installfor siblingsapp:enablefor siblingsThree places where the shared workflow reports success over a failure it had already observed. In each case the information existed and was thrown away — #483 threw away a verdict it had computed; #484 and #355 threw away the status of a step that had already failed.
The finding that outlives all three fixes
The
app:enabledefect was found, measured AND fixed on 2026-08-11. The fix never landed. In the five days since, the fleet has spent real effort misattributing environment failures to application debt — including tonight, on decidesk#517, where 87 errors were read as decidesk's.An unmerged fix is indistinguishable from an undiscovered bug — except that the second time, you also pay for the rediscovery. Whatever caused #355 to stall is now itself a finding, and it is the most portable thing in this whole batch.