Keep the 3.2.3 rollback path readable with agent firearms

Main's generated PlacedAgentAdapter always wrote `weapon` (WeaponType,
typeId 38) at field 7, and StrategyPage legacy slots 4 (agents) and 11
(legacy LineUps) carry PlacedAgents. 3.2.3 has no typeId 38, so it could
not open a page this build had saved.

- PlacedAgentAdapter (typeId 2) is hand-written: it omits field 7 when
  the weapon is none, so an unarmed agent is byte-for-byte the 3.2.3
  record, and still reads field 7 from desktop 4.6 libraries.
- StrategyPageAdapter writes weapon-stripped copies into slots 4 and 11.
  The agents mirror (13) and lineup graph mirror (19) keep the real
  weapons, so this build restores them losslessly.
- Audit of everything reachable from slots 0-11 and 14: only
  PlacedAgent.weapon was newer than 3.2.3. Text, images, utilities,
  settings, filtered drawings, PlacedAbility, LineUp and StrategyData
  write only primitives, Offset, Color, AbilityInfo and 3.2.3's types.
  Newer enum values (e.g. UtilityType) decode to 3.2.3's default rather
  than failing.
- The generator prunes yaml rows for types it does not generate, so the
  hand-written typeIds (2, 3, 9, 11, 12, 17, 20, 24, 31) are now listed
  in @GenerateAdapters(reservedTypeIds:) and can never be reassigned.

Tests: the rollback test decodes pages and a whole StrategyData with a
registry holding exactly 3.2.3's adapters (field bags, byte enums,
Color/TimeOfDay), plus a control proving it rejects an armed agent. The
registry layout test checks weapons survive the round trip through the
mirror while the legacy slots hold none.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
f564c92fcfDara Adedeji committed on 9/24/2026, 8:51:40 PMparentf238037
7 files changedLine totals unavailable