fix(apphost): the class_exists guard has been answering false — Bootstrap::register() has never run - #139
fix(apphost): the class_exists guard has been answering false — Bootstrap::register() has never run#139rubenvdlinde wants to merge 1 commit into
Conversation
ADR-040's load-order hazard, caught by gate-64 once the gate package was
actually reaching this repo.
OC_App::getEnabledApps() sort()s the app list, and Coordinator::registerApps()
walks THAT sorted list calling OC_App::registerAutoloading($appId, $path) and
then $app->register() for ONE APP AT A TIME. So every app's register() runs
BEFORE the PSR-4 prefix of every alphabetically-later app exists — on a
completely healthy instance, with OpenRegister enabled.
The fix is to put OpenRegister's prefix on the autoloader ourselves, which is
exactly what Nextcloud does a few iterations later. Two properties make this
the right call: registerAutoloading() touches ONLY the autoloader and is
idempotent (it early-returns on an $alreadyRegistered key), and it does NOT
boot the app. IAppManager::loadApp('openregister') would be wrong here — it
sets loadedApps['openregister']=true and calls Coordinator::bootApp(), booting
OpenRegister BEFORE its own register() has run.
Verified both directions with the gate itself, against this tree:
without the prelude rc=1 FAIL — AppHost adoption with no prelude
with the prelude rc=0 PASS
and under BOTH matcher versions (the one on .github main and the named-constant
fix in .github#185), so this is not a repo change chasing a gate change.
Quality Report — ConductionNL/openbuild @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| test-l10n | ✅ | ||||
| composer | ✅ | ✅ 101/101 | |||
| npm | ✅ | ✅ 654/654 | |||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-06 08:25 UTC
Download the full PDF report from the workflow artifacts.
|
Superseded by #138. Both PRs add the ADR-040 prelude, but this one adds it inline in #138 also carries the spec delta (REQ-OBS-006), the e2e regression guard on the Bootstrap-aliased routes, and the gate-2/gate-46 fixes that touching this method pulls into diff scope. Matches the shape already merged in procest (#752) and scholiq (#288). Closing without merging; nothing here is lost. |
This is the acute one
lib/AppInfo/Application.phpguards its AppHost adoption:That probe answers false on a perfectly healthy instance.
OC_App::getEnabledApps()sort()s the app list andCoordinator::registerApps()callsregisterAutoloading()thenregister()one app at a time — andopenbuildsorts beforeopenregister, soOCA\OpenRegister\is not autoloadable at this point.So
Bootstrap::register()has apparently never run in this app. Everything it wires is silently absent:DeepLinkRegistrationListener)The guard was not wrong to exist — it is what stopped the
\Errorfrom aborting the wholeregister()and taking the per-Application RBAC guards and the hybrid metadata-lock with it. It was just guarding against a condition the app itself creates by not registering the autoloader first. Theelsebranch'serror_logshould be in every instance's log today.The fix
Add the prelude before the probe.
registerAutoloading()touches only the autoloader and is idempotent ($alreadyRegisteredkey guard); it does not boot the app.IAppManager::loadApp('openregister')would be wrong — it marks OpenRegister loaded and callsCoordinator::bootApp(), booting it before its ownregister()has run.The
class_existsguard is deliberately kept: it is still the correct behaviour when OpenRegister is genuinely absent or disabled.Verified both directions, against this tree
rc=1FAIL — AppHost adoption with no preluderc=0PASSChecked under both matcher versions (
.githubmainand the named-constant fix in.github#185).class_existsanswers true andBootstrap::register()runs for the first time, registering the generics listed above. The domain overrides that follow are expected to win over the generic aliases — that expectation has never actually been exercised, so it is worth a look at the first CI run rather than assuming.php -lclean.🤖 Generated with Claude Code