There was no way to ask "will this mod load on FireRed?". `validate`, `lint`
and `pack` only reason about Gen 1, and `gen2check` refuses a Gen 3 mod at the
manifest gate. `gen3check` is the Gen 3 counterpart of `gen2check`:
python3 tools/modkit.py gen3check mods/<id> [--notes] [--json] [--strict]
- Factor the shared compat analysis behind a `Generation` descriptor, with
`GEN2`/`GEN3` module-level singletons holding everything that differs: the
compat facade name, the generation's own directory (`gen2` vs `game3`), the
legacy manifest flag, the screen-twin prefix, and the sibling spelling. Every
compat helper now takes a trailing `gen`.
- MK400-MK410 stay shared by design -- they are the same questions asked of a
different facade -- and the verdict line (`on gen 3: ...`) disambiguates.
- Gen 3 sibling spelling: `src/ui/game3/` is snake_case while
`src/world/game3/WorldAPI.lua` is not, so MK403 tries both spellings and
stops at the first sibling that exists. Only 8 Gen 1 modules are reachable
this way (`BattleAPI`, `BagMenu`, `HallOfFame`, `IntroMovie`, `OptionRows`,
`ShopMenu`, `SummaryMenu`, `TrainerCard`), so MK403 on Gen 3 is live but
narrow.
- MK409's screen-twin half is switched off on Gen 3 -- there is no
`Screens.GEN2_IDS` equivalent -- while its version-string half still runs,
since a Gen 1 version id in a mod that declares only FireRed is a real bug.
- Rename `GEN2_IDS_DUMP` to `VERSION_IDS_DUMP`, now parameterized by
generation.
Gen 2 behaviour is unchanged: `diff -r` of `gen2check --notes` and
`gen2check --notes --json` output over all 10 shipped mods, captured before and
after this change, is empty.
Tests: `tests/modkit/cases/gen3check.lua` grows from 504 to 542 checks. Every
fixture is derived from the engine at run time -- the coverage table,
`GEN1_ONLY_MODULES`, and the `game3/` directory listings -- so the suite cannot
drift away from the tables it is asserting against. It covers MK400's Gen 3
wording, MK402 naming `Gen3Compat` and never `Gen2Compat`, MK403 naming the
snake_case path, MK404 quoting the member, MK409's version-string half, MK410
counted once at file scope, the `--json` verdict shape, and that no adapted
module is ever MK402.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>