Summary
The AppHost route-table detector reads appinfo/routes.php as raw text, so a comment that names Routes::standard() switches it on. Ten canonical route names are then injected into gate-14's route list for an app that does not adopt AppHost, and gate-14 reports them all as unreachable.
Measured on ConductionNL/larpingapp @ 085b36d (origin/development), gate package 651e5c5:
[gate-14] route-reachability: FAIL — 4 unrouted method(s) or wrong-target route(s)
lib/Controller/DashboardController.php route='dashboard#catchAll' rule=method-not-found-on-target-controller
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/SettingsController.php route='settings#load' rule=method-not-found-on-target-controller
None of those four routes exist. appinfo/routes.php is a plain literal array of 20 entries; dashboard#catchAll, health#index, metrics#index and settings#load appear in none of them. larpingapp ships no HealthController and no MetricsController, and does not need to — it never adopted AppHost.
Cause
run-hydra-gates.sh:
_HYDRA_APPHOST_ROUTE_TABLE=0
if [ -f appinfo/routes.php ] \
&& grep -qE 'AppHost\\+Routes::standard[[:space:]]*\(' appinfo/routes.php; then
_HYDRA_APPHOST_ROUTE_TABLE=1
fi
The only thing in larpingapp's routes.php that matches is line 14, a comment:
// Canonical AppHost settings write (OpenRegister\AppHost\Routes::standard()).
Comment-stripped, Routes::standard does not occur in that file at all:
$ php -r '…token_get_all()… strip T_COMMENT/T_DOC_COMMENT…'
NOT PRESENT in code
_HYDRA_APPHOST_ROUTE_TABLE=1 then appends _HYDRA_APPHOST_ROUTE_NAMES (ten names) to the route list gate-14 iterates, and each one is judged against a controller the app does not ship.
The two detectors disagree with each other
The sibling detector for the same subject is already comment-aware — _HYDRA_APPHOST runs each candidate through _php_code_only before grepping:
_ah_code=$(_php_code_only "${_ah_f}")
printf '%s\n' "${_ah_code}" | grep -qE 'Bootstrap::register[[:space:]]*\(' || continue
So on larpingapp _HYDRA_APPHOST=0 (correct — no Bootstrap::register) while _HYDRA_APPHOST_ROUTE_TABLE=1 (incorrect). That split is visible in the findings themselves: _apphost_serves correctly declines to exempt health/metrics because _HYDRA_APPHOST=0, which is precisely why the phantom routes surface as findings instead of being silently exempted. One repo, one question, two answers.
Reproduction — A/B where the only difference is comment text
Same tree, same package, same command. The single edit is to line 14 of appinfo/routes.php, rewording the comment so it no longer spells the call. No code changes; Routes::standard is absent from the code in both arms.
arm A — comment as shipped
code contains Routes::standard: NO
[gate-14] route-reachability: FAIL — 4 unrouted method(s) or wrong-target route(s)
arm B — same sentence, call spelling broken up
code contains Routes::standard: NO
[gate-14] route-reachability: PASS
Four findings appear and disappear on the wording of a comment.
Why this one matters more than an ordinary FP
The cheapest way to clear it is to reword or delete an accurate comment — the comment documents why settings#update exists and what dialect it mirrors. That is the #191 / #184 family again: a gate satisfiable by prose teaches the habit the gate exists to prevent, and here the prose is worth keeping. I have left larpingapp red rather than edit the comment.
It also cuts the other way. Because the detector cannot tell code from comment, an app that genuinely does defer to Routes::standard() but only mentions it in a comment (e.g. a routes.php refactored to a builder that was later reverted, leaving the comment) gets the ten names injected on a false basis — and an app that adopts AppHost through a differently-spelled call gets them injected on no basis at all.
Suggested fix
Route the detection through _php_code_only, as _HYDRA_APPHOST already does:
_HYDRA_APPHOST_ROUTE_TABLE=0
if [ -f appinfo/routes.php ] \
&& _php_code_only appinfo/routes.php | grep -qE 'AppHost\\+Routes::standard[[:space:]]*\('; then
_HYDRA_APPHOST_ROUTE_TABLE=1
fi
A regression test would want both arms: a routes.php that calls Routes::standard() (ten names injected) and one that only mentions it in a comment (none injected). Without the second arm this fix cannot be shown to have changed anything.
Blast radius
Any repo whose appinfo/routes.php names Routes::standard() in a comment while not calling it. larpingapp is one; worth grepping the fleet for routes.php files where the comment-stripped text lacks the call but the raw text has it.
Measured by: gate package 651e5c5bb3ba8764903e5d6fc5bac5a208bd67fc, run-hydra-gates.sh full-repo and --scope-to-diff --base <root-commit>, NODE_PATH set so ajv resolves (/home/rubenlinde/…/node_modules/ajv/dist/ajv.js), .err 0 bytes on every run.
Summary
The AppHost route-table detector reads
appinfo/routes.phpas raw text, so a comment that namesRoutes::standard()switches it on. Ten canonical route names are then injected into gate-14's route list for an app that does not adopt AppHost, and gate-14 reports them all as unreachable.Measured on ConductionNL/larpingapp @
085b36d(origin/development), gate package651e5c5:None of those four routes exist.
appinfo/routes.phpis a plain literal array of 20 entries;dashboard#catchAll,health#index,metrics#indexandsettings#loadappear in none of them. larpingapp ships noHealthControllerand noMetricsController, and does not need to — it never adopted AppHost.Cause
run-hydra-gates.sh:The only thing in larpingapp's
routes.phpthat matches is line 14, a comment:// Canonical AppHost settings write (OpenRegister\AppHost\Routes::standard()).Comment-stripped,
Routes::standarddoes not occur in that file at all:_HYDRA_APPHOST_ROUTE_TABLE=1then appends_HYDRA_APPHOST_ROUTE_NAMES(ten names) to the route list gate-14 iterates, and each one is judged against a controller the app does not ship.The two detectors disagree with each other
The sibling detector for the same subject is already comment-aware —
_HYDRA_APPHOSTruns each candidate through_php_code_onlybefore grepping:So on larpingapp
_HYDRA_APPHOST=0(correct — noBootstrap::register) while_HYDRA_APPHOST_ROUTE_TABLE=1(incorrect). That split is visible in the findings themselves:_apphost_servescorrectly declines to exempthealth/metricsbecause_HYDRA_APPHOST=0, which is precisely why the phantom routes surface as findings instead of being silently exempted. One repo, one question, two answers.Reproduction — A/B where the only difference is comment text
Same tree, same package, same command. The single edit is to line 14 of
appinfo/routes.php, rewording the comment so it no longer spells the call. No code changes;Routes::standardis absent from the code in both arms.Four findings appear and disappear on the wording of a comment.
Why this one matters more than an ordinary FP
The cheapest way to clear it is to reword or delete an accurate comment — the comment documents why
settings#updateexists and what dialect it mirrors. That is the #191 / #184 family again: a gate satisfiable by prose teaches the habit the gate exists to prevent, and here the prose is worth keeping. I have left larpingapp red rather than edit the comment.It also cuts the other way. Because the detector cannot tell code from comment, an app that genuinely does defer to
Routes::standard()but only mentions it in a comment (e.g. a routes.php refactored to a builder that was later reverted, leaving the comment) gets the ten names injected on a false basis — and an app that adopts AppHost through a differently-spelled call gets them injected on no basis at all.Suggested fix
Route the detection through
_php_code_only, as_HYDRA_APPHOSTalready does:A regression test would want both arms: a routes.php that calls
Routes::standard()(ten names injected) and one that only mentions it in a comment (none injected). Without the second arm this fix cannot be shown to have changed anything.Blast radius
Any repo whose
appinfo/routes.phpnamesRoutes::standard()in a comment while not calling it. larpingapp is one; worth grepping the fleet forroutes.phpfiles where the comment-stripped text lacks the call but the raw text has it.Measured by: gate package
651e5c5bb3ba8764903e5d6fc5bac5a208bd67fc,run-hydra-gates.shfull-repo and--scope-to-diff --base <root-commit>,NODE_PATHset so ajv resolves (/home/rubenlinde/…/node_modules/ajv/dist/ajv.js),.err0 bytes on every run.