.github#199 ("an AppHost generic the leaf registers itself is not an unreachable route") is merged, and gate-14 still reports 4 false controller-class-not-found findings on procest at hydra-gates@main (756fe89, i.e. after #199).
Measured
$ hydra-gates --app-dir <procest@084fbf03> --full
[gate-14] route-reachability: FAIL — 4 unrouted method(s) or wrong-target route(s)
lib/Controller/HealthController.php route='health#index' rule=controller-class-not-found
lib/Controller/MetricsController.php route='metrics#index' rule=controller-class-not-found
lib/Controller/PreferencesController.php route='preferences#getPreference' rule=controller-class-not-found
lib/Controller/PreferencesController.php route='preferences#setPreference' rule=controller-class-not-found
All four are served. OCA\\OpenRegister\\AppHost\\Bootstrap::registerControllers() binds OCA\\Procest\\Controller\\HealthController etc. to its generics via aliasControllerUnlessLeafDefinesIt(). The absence of the files is deliberate and required — creating them would make the alias skip and break the routes.
Cause
run-hydra-gates.sh L483-488:
_HYDRA_APPHOST=0
if [ -f lib/AppInfo/Application.php ] \
&& grep -qE 'AppHost\\+Bootstrap' lib/AppInfo/Application.php \
&& grep -qE 'Bootstrap::register[[:space:]]*\(' lib/AppInfo/Application.php; then
_HYDRA_APPHOST=1
fi
Both probes are pinned to lib/AppInfo/Application.php. procest does not call Bootstrap::register() there; it delegates Application.php → Registrar/ServiceRegistrar.php → Registrar/AppHostRegistrar.php:121. So _HYDRA_APPHOST=0, _apphost_serves() returns 1 for every slug, and the legitimate-absence branch is unreachable. _di_binds_controller() cannot rescue it either — it is also scoped to Application.php (L534).
Measured, with a positive control so a zero is not mistaken for a broken grep:
$ grep -cE 'AppHost\\+Bootstrap' lib/AppInfo/Application.php -> 0
$ grep -cE 'Bootstrap::register[[:space:]]*\(' lib/AppInfo/Application.php -> 0
# same two greps against a file that DOES contain the patterns:
$ grep -cE 'AppHost\\+Bootstrap' /tmp/probe.php -> 1
$ grep -cE 'Bootstrap::register[[:space:]]*\(' /tmp/probe.php -> 1
$ grep -rn 'Bootstrap::register' lib/AppInfo/
lib/AppInfo/Registrar/AppHostRegistrar.php:121: Bootstrap::register(
Why this matters beyond one repo
The trigger was a quality change. procest#717 ("decompose Application bootstrap", a phpmd remediation) moved the call out of Application.php into a registrar. Decomposing a god-object composition root is exactly what the other gates push apps toward — and doing it silently turns gate-14 red on correct code. Any app that has done, or will do, the same refactor is affected.
Suggested fix
Widen both probes from lib/AppInfo/Application.php to lib/AppInfo/ (recursive), keeping the evidence requirement unchanged — still the literal Bootstrap::register( / the exact fully-qualified class name, never a wildcard, so a genuinely missing controller still fails.
Worth a fixture for the decomposed-registrar shape: the current test suite presumably only covers the inline-in-Application.php shape, which is why #199 read as complete.
Not a duplicate of
.github#199("an AppHost generic the leaf registers itself is not an unreachable route") is merged, and gate-14 still reports 4 falsecontroller-class-not-foundfindings on procest athydra-gates@main(756fe89, i.e. after #199).Measured
All four are served.
OCA\\OpenRegister\\AppHost\\Bootstrap::registerControllers()bindsOCA\\Procest\\Controller\\HealthControlleretc. to its generics viaaliasControllerUnlessLeafDefinesIt(). The absence of the files is deliberate and required — creating them would make the alias skip and break the routes.Cause
run-hydra-gates.shL483-488:Both probes are pinned to
lib/AppInfo/Application.php. procest does not callBootstrap::register()there; it delegatesApplication.php→Registrar/ServiceRegistrar.php→Registrar/AppHostRegistrar.php:121. So_HYDRA_APPHOST=0,_apphost_serves()returns 1 for every slug, and the legitimate-absence branch is unreachable._di_binds_controller()cannot rescue it either — it is also scoped toApplication.php(L534).Measured, with a positive control so a zero is not mistaken for a broken grep:
Why this matters beyond one repo
The trigger was a quality change. procest#717 ("decompose Application bootstrap", a phpmd remediation) moved the call out of
Application.phpinto a registrar. Decomposing a god-object composition root is exactly what the other gates push apps toward — and doing it silently turns gate-14 red on correct code. Any app that has done, or will do, the same refactor is affected.Suggested fix
Widen both probes from
lib/AppInfo/Application.phptolib/AppInfo/(recursive), keeping the evidence requirement unchanged — still the literalBootstrap::register(/ the exact fully-qualified class name, never a wildcard, so a genuinely missing controller still fails.Worth a fixture for the decomposed-registrar shape: the current test suite presumably only covers the inline-in-
Application.phpshape, which is why #199 read as complete.Not a duplicate of
#199— fixed the leaf-registers-the-generic-itself shape (openconnector'sgenericPreferences). This is the delegated-registrar shape; fix(gate-14): an AppHost generic the leaf registers itself is not an unreachable route #199's helper is scoped to the same single file and so cannot see it.#200(closed) — gate-57's attribute-scanner seam, unrelated.