fix(hydra-gates): stop claiming OCA\OpenRegister\Contract\ as a runtime psr-4 prefix - #547
Merged
Merged
Conversation
…me psr-4 prefix
The package declared
"autoload": { "psr-4": { "OCA\\OpenRegister\\Contract\\": "hydra-gates/contracts/" } }
That prefix is LONGER than openregister's own `OCA\OpenRegister\` -> `lib/`,
PSR-4 is longest-prefix-wins, and the package installs into every consumer's
vendor/ — so whichever app's autoloader registered first defined OpenRegister's
contract FOR THE WHOLE PROCESS. Measured on a real instance: softwarecatalog's
vendored copy was supplying openregister's own interface, and a v1.8.0 copy
without patchObject() broke callers of the real one (#514, #531).
The contracts still ship. A consumer that needs them now requires them from its
own test bootstrap behind interface_exists(), which is order-independent — it
asks whether the interface is RESOLVABLE rather than who registered first.
Appending a fallback autoloader does NOT work: spl_autoload_register appends
relative to registration order, and that order across independently loaded apps
is precisely what nobody controls.
THE MIGRATION IS FOUR APPS, NOT THE FOURTEEN #531 ESTIMATED. Measured by
cloning each of the eighteen and grepping, rather than by code search (which
rate-limits and returns unreliable zeros):
needs the opt-in buildiq, decidiq, filinq, stackiq
ships its own dossiq, pipelinq, shillinq
owns the real one openregister — resolves from lib/Contract/ before AND after
never references the remaining ten
Each of the four is verified both directions — prefix present (guard no-ops) and
prefix removed (guard supplies) — by editing the vendored package's entry in
vendor/composer/installed.json. Editing the vendored composer.json does nothing;
Composer reads installed.json, which cost one invalid experiment before I
noticed.
stackiq turned out not to be preparation at all: its bootstrap-unit.php maps
only `OCA\OpenRegister\Db\` and `...\Service\`, never `...\Contract\`, so its
standalone unit suite was ALREADY failing on this — 131 errors before the guard,
1 after (and that one is an unrelated absent Symfony class).
⚠️ DO NOT MERGE BEFORE THOSE FOUR. This composer.json reaches an app only when
it bumps to a hydra-gates release that contains it, so the guards must be in
first — but merging this before them puts the fleet one `composer update` away
from a bootstrap fatal.
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.
⛔ Blocked on the four consumer guards below. This
composer.jsonreaches an app only when that app bumps to a release containing it — so merging early leaves the fleet onecomposer updatefrom a bootstrap fatal.Closes #531.
The package declared:
That prefix is longer than openregister own
OCA\OpenRegister\tolib/, PSR-4 is longest-prefix-wins, and the package installs into every consumer vendor/ — so whichever app autoloader registered first defined OpenRegister contract for the whole process. Measured on a real instance: softwarecatalog vendored copy was supplying openregister own interface, and a v1.8.0 copy withoutpatchObject()broke callers of the real one (#514).The contracts still ship; consumers opt in from their own test bootstrap behind
interface_exists(), which is order-independent. A fallback autoloader does not work —spl_autoload_registerappends relative to registration order, and that order across independently loaded apps is exactly what nobody controls.The migration is FOUR apps, not the fourteen #531 estimated
Measured by cloning all eighteen and grepping, rather than by code search (which rate-limits and returns unreliable zeros):
lib/Contract/before and afterEach of the four is verified both directions — prefix present (guard no-ops) and prefix removed (guard supplies) — by editing the vendored package entry in
vendor/composer/installed.json. Editing the vendoredcomposer.jsondoes nothing; Composer readsinstalled.json, which cost one invalid experiment before I noticed.stackiq was not preparation at all
Its
bootstrap-unit.phpmaps onlyOCA\OpenRegister\Db\and...\Service\, never...\Contract\— so its standalone unit suite was already failing on this:The remaining error is unrelated (absent
Symfony\Component\HttpFoundation\HeaderUtils).Docs updated:
hydra-gates/README.mdgains the opt-in snippet with the two traps (put it before anything implementing the interface; put it in the bootstrapphpunit.xmlactually loads — several apps ship two or three), anddocs/hydra/operations/app-health.mdrecords that the mechanism is gone.