Commit Graph

4 Commits

Author SHA1 Message Date
5a35ea7776 Revert auto-assigned ids back to letters; only detected ids are numeric
Auto-assignment (no real id known: a manual add, or an accepted
proposal with no confident marker-id read) must stay visually
distinct from a genuinely detected id, or a made-up number could
collide with or be mistaken for a real one. Reverts the previous
commit's switch to numeric auto-assignment (_next_free_numeric_id) --
that was wrong, caught by the user immediately. _next_free_id
(letters, rolling over to "AA"/"AB"/... past 26) is back as the
fallback, still scoped per type (that part of the previous change was
correct and stays). Plain numbers are reserved for an id
_accept_proposal is actually confident was read off the marker itself
(Proposal.detected_id), passed straight through and never touching
auto-assignment.

Also fixes detected_id's own collision pre-check in _accept_proposal,
which wasn't scoped per type either -- same bug as the Change ID
popover fix, just in a second place: a detected id could get
needlessly discarded because an unrelated type already used that
number, not because of a real collision.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 19:49:30 +02:00
d2f70675b8 Auto-ids per type not per group; show detected_id in proposal UI
Auto-assignment (Board.add_target/add_ally with no explicit id_) now
scopes its 1/2/3... sequence per TYPE within each group, not one
sequence shared across every type in the group -- Tank#1/Infantry#1
rather than Tank#A/Infantry#B, matching the game's own numbering.
Reverses the type-scoping half of an earlier fix in this file (see
TODO.md's "Allies and enemies seem to share indices" entry) per
explicit user direction; the targets-vs-allies namespace split that
fix also made is untouched, still correct. _next_free_id (letters,
rolling over to "AA" past 26) is replaced by _next_free_numeric_id --
a plain counter can't run out the way a fixed alphabet could, so
there's no equivalent rollover concern. test_models.py updated to
match (one test asserts the opposite of before, renamed accordingly).

detected_id (map_vision.read_marker_id) was being logged but never
shown anywhere a human could actually check it against the
screenshot before now: added to the proposal popover's heading and
the pending-proposal's own on-map label.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 19:28:01 +02:00
23615a8c92 Fix id-namespace regression, add StrikeRequest type, kill full-panel
rerender on assign/alive/shell, add Windows build tooling

- Board.add_target/add_ally's id auto-assignment used a bare
  next(c for c in string.ascii_uppercase if c not in used), which
  raises StopIteration once 26 entities of a group exist -- a real
  crash confirmed via a live traceback, and a direct regression from
  moving that sequence from per-type to per-group. This was the actual
  cause of "Accept as"/"Accept all" silently doing nothing. Fixed with
  _next_free_id(), which rolls over to two-letter ids instead of
  raising.
- New TargetType.STRIKE_REQUEST: the bearing/distance-offset "taking
  fire" fire-support request (see the earlier two-entity split) now
  creates this instead of reusing STRIKE, so a radioed-in request is
  never confused with a strike the player placed themselves. Same
  crosshair icon, excluded from type pickers/dedupe like STRIKE.
- The "Accept as..." popover on a detected map marker now uses the
  same icon grid the entity-edit "Change type" popover does (was a
  plain unfiltered text list of every TargetType, which also wrongly
  offered STRIKE/STRIKE_REQUEST as pickable).
- Firing panel: _cycle_assignment/_toggle_alive/_pick_shell no longer
  route through app.py's full solver+dedupe+canvas+panel refresh --
  none of the three can affect the solver or dedupe, and none change
  which cards exist or their order (except _toggle_alive in
  hide/sort_later mode). New FiringPanel._rebuild_one() rebuilds just
  the one changed card; on_visual_change is a new, lighter callback
  (just a map redraw) for the two of these three that actually affect
  it. This was a real, confirmed lag source with many units on the
  board: every click on any of these was previously rebuilding every
  card of every target.
- Map right-click entity menu: added "Mark destroyed"/"Mark alive",
  reusing the same cheap-refresh path (new
  FiringPanel.refresh_after_alive_change).
- packaging/windows/: a from-scratch (untested against a real boot)
  MSYS2 + WiX .msi build pipeline for Windows, driven from Linux via
  dockur/windows (KVM-in-container), no Windows machine or GitHub
  required. See its own README for status/caveats.
- New/updated tests: id-namespace sharing + the 26-entity overflow
  regression (tests/test_models.py), StrikeRequest split
  (tests/test_ocr.py), warp_to_map's img_scale param
  (tests/test_map_vision_warp.py). 44/44 passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 20:48:57 +02:00
1ddb532325 Fix ally/target bugs, OCR fire-support parsing, add debug capture
- Board.clear() now also drops allies; the "clear board?" guard checks
  allies too. New Board.clear_units() + Clear button right-click menu
  ("clear enemies, units & flights", keeps Nest/spotters/RPs).
- An Ally with the ad-hoc TargetType.ENEMY showed "Enemy" on the map
  popover/toast instead of "Ally" (icons.target_type_label already had
  the fix for the picker, now reused everywhere else via app.py's
  _display_name).
- Firing panel drag-reorder no longer triggers a full app refresh
  (solver + dedupe + map redraw) on every drop, just a local rebuild.
- "Always show geo" didn't draw for Allies (missing from the overlay
  candidate list); blast radius only respected selection, not the
  show_geo_desc pin.
- ocr.py: added a second fire-support-request grammar ("Infantry#N
  taking fire ... Requesting X Shell on our position at <coord> before
  <time>", plus a bearing/distance-from-position variant), distinct
  from the existing Marine Garrison one.
- New debug_capture.py: saves screenshots (+ metadata) the app handled
  badly, for later tuning of map_vision/ocr against real failures:
  map-read errors, user grid corrections (paired with the auto-detected
  grid), screenshots that read as text but may have been a map, and
  marker-detection ground truth (every proposal's accept/reject verdict
  plus units added with no matching proposal) captured whenever a
  screenshot stops being the active one.
- README: Known issues section (map screenshot reading, grid + unit
  detection, is unreliable and fails often).
- 14 new tests (tests/test_models.py, tests/test_debug_capture.py, +
  additions to tests/test_ocr.py), 38/38 passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 17:35:37 +02:00