Skip to content

gate-14: a COMMENT naming Routes::standard() injects ten phantom AppHost routes — 4 false findings on larpingapp, and the sibling detector for the same fact is already comment-aware #296

Description

@rubenvdlinde

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions