ConventionDetector
Decides which controller convention (see {@see Flavor}) `coa:make controller` should target for a given app root, so the same command "just works" whether it runs inside an existing legacy Milpa host (this monorepo's own `src/app/Providers/BaseController` convention) or a fresh `milpa/runtime` + skeleton app — without the caller having to know which. Detection order (first hit wins): 1. `$override` — an explicit `--flavor=runtime|legacy` always wins outright, no filesystem inspection at all. 2. **Legacy**, if EITHER is true: - `$root/milpa.json` exists (a self-declaring app-level manifest); or - `Milpa\app\Providers\BaseController` resolves to a real file under `$root`'s own `composer.json` `autoload.psr-4` map. Deliberately a pure FILESYSTEM check, not `class_exists()`: this detector must give the same answer whether or not the host has been autoloaded yet (e.g. a `--dry-run` before `composer install`), and `class_exists()` would also give a false positive inside this very package's own test process, where `tests/Fixtures/HostStubs.php` defines that exact FQCN unconditionally for {@see \Milpa\DevTools\Verify\ControllerVerifier}'s own fixtures. 3. **Runtime**, otherwise. This covers every explicit runtime signal (`config/plugins.php` present, `milpa/runtime` required in `composer.json`, an `App\`-style PSR-4 root with no `Milpa\app`) AND the genuinely ambiguous case (a brand new root with none of the above): runtime is the framework's forward default, so the mere absence of an affirmative legacy signal is enough — nothing past step 2 can still produce `Legacy`.
ConventionDetector::detect()
public function detect(string $root, ?string $override = null): Milpa\DevTools\Make\FlavorDetects the {@see Flavor} for the app rooted at `$root`; `$override` short-circuits to that flavor.
Parameters
| Name | Type | Description |
|---|---|---|
| $root | string | |
| $override | ?string |