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>
This commit is contained in:
2026-08-13 19:28:01 +02:00
co-authored by Claude Sonnet 5
parent 8109db2f39
commit d2f70675b8
6 changed files with 111 additions and 62 deletions
+6 -4
View File
@@ -1,9 +1,11 @@
"""_accept_proposal: an accepted proposal's entity id should prefer the
marker's own detected "#<N>" id (map_vision.read_marker_id, via
Proposal.detected_id) over an auto-assigned letter, so ids on the board
Proposal.detected_id) over an auto-assigned number, so ids on the board
match what's actually on screen -- falling back to auto-assign only when
there's no detection, or it collides with an id already used in that
group (see _accept_proposal's own docstring).
there's no detection, or it collides with an id already used for that
type in that group (see _accept_proposal's own docstring, and
models.py's _next_free_numeric_id for the per-type auto-assignment
these fall back to).
Needs a real Adw/Gtk init (MainWindow.__new__ skips __init__, so no
window/widgets are actually built, but Adw.init() is still required for
@@ -44,7 +46,7 @@ def test_accept_uses_the_detected_id_when_present():
def test_accept_falls_back_to_auto_id_with_no_detection():
win = _window()
win._accept_proposal(_proposal(detected_id=None))
assert win.board.targets[0].id == "A"
assert win.board.targets[0].id == "1"
def test_accept_falls_back_to_auto_id_on_a_detected_id_collision():