You are W-FACTORY. Repo forge-assets, your own worktree, commit on your branch. Do not push, deploy or ssh. No em dashes.
Goal: two OhMyGames Factory modules (Python 3.12, standard library only + pytest for tests) that attach our new kits to
AI-built 3D games, written exactly in the style of the Factory's Garage module. Read these first, they are your pattern:
omg/factory/ref/games_garage.py (copy of the live Factory module: how a kit is attached, its word regexes, fits(),
the builder contract text), omg/factory/games_library.py and omg/factory/test_ohmygames_library.py (tests style), and
omg/kit/building/SETTLEMENT.md (the town API you will describe to the builder).
1. `omg/factory/games_town.py`: `town_kind(card, prompt) -> 'medieval'|'breton'|None` from the card words (medieval,
   village, hamlet, castle town, fantasy town, kingdom, knights, tavern, blacksmith, smithy, bakery, market town,
   cathedral, abbey, monastery, peasants, feudal, Brittany/Breton/fishing village -> breton, and similar; NOT for
   space, modern city, sci-fi, sports, racing tracks; beware everyday words: "a market for skins", "kingdom hearts"...
   add tests for false positives), `town_tier(card, prompt) -> hamlet|village|town|city` (words: hamlet, village,
   town, city/capital/cathedral/walled), `town_fits(card)` (same lane/stage/view rule as garage_fits), `town_attachments(
   card, first_index, prompt, assets_dir) -> (atts, contract, meta) | None` with attachments `townkit.tar.gz` (code:
   extract into src/lib/town) and `townkit-<style>.tar.gz` (models + textures: extract into public/town), the contract
   text (builder laws: build the world with `settle` + `buildSettlement` from src/lib/town (read TOWN.md), never draw
   houses from boxes, spawn the player on the main square, collide with `colliders`, walk on `heightOf(plan)`, the tier
   from the words, the site from the setting: hill/river/coast/plain/crossroads), and meta {kind, tier, site, sha}.
   Missing tarballs = None (the build goes on as before). Self-contained module (no imports from the Factory), so tests
   run here: `python3 -m pytest omg/factory/test_games_town.py`.
2. `omg/factory/games_city.py` the same for the city kit (`citykit.tar.gz`, code only: extract into src/lib/city, guide
   CITY.md): `city_kind(card, prompt)` -> 'city'|None for GTA-like open modern cities (GTA, grand theft, open city,
   downtown, crime city, gangsters, mafia, heist in the city, taxi driver, city streets, metropolis, skyscrapers, New
   York, Hong Kong, police chase in the city...), never when town_kind() says medieval, never for a racing circuit or a
   board/side view. Contract: build the city with `createCity` from src/lib/city/game.mjs (read CITY.md), never draw
   buildings or roads yourself, spawn at `spawn`, collide with `colliders` and `carPoses()`, player vehicles from the
   Garage kit when it is attached (cars come from the Garage, the city brings streets, buildings and traffic).
3. `tools/pack/pack_townkit.sh`: builds dist/townkit.tar.gz (omg/kit/building/*.mjs, styles/, TOWN.md, SETTLEMENT.md,
   no tests) and dist/townkit-<style>.tar.gz per style family: medieval = browse/kits/{medieval,medieval-trades,
   medieval-church,medieval-cathedral,medieval-walls} (whichever exist), breton = browse/kits/{breton,medieval-church,
   medieval-walls}; each kit dir as town/kits/<kit>/ with kit.glb + extra_files + kit.json + materials.json + style.json
   + the textures it references; prints sizes; writes dist/townkit.sha. Warn when a models tar passes 25 MB.
4. Tests: omg/factory/test_games_town.py, test_games_city.py (words -> kind/tier, false positives, fits rules, missing
   tar -> None, attachment ids numbered from first_index, contract mentions the files). Use a tmp dir of fake tars.
Evidence: pytest output, pack script output (sizes). Report what is NOT done. Time box 60 minutes.
