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>
This commit is contained in:
2026-08-13 19:49:30 +02:00
co-authored by Claude Sonnet 5
parent 6e18d60eb5
commit 5a35ea7776
5 changed files with 110 additions and 76 deletions
+33 -15
View File
@@ -207,23 +207,41 @@ Status legend: [x] fixed+tested, [~] partially addressed, [ ] open/needs input
(`tests/test_app_accept_proposal.py`).
- Auto-assignment itself (`Board.add_target`/`add_ally` with no
`id_`/no usable detection) changed from one shared letter
sequence per group (targets, or allies) to its own 1/2/3...
sequence per TYPE within each group -- Tank#1/Infantry#1 rather
than Tank#A/Infantry#B, matching the game's own numbering (and
what `detected_id` looks like when it IS read). This directly
reverses an earlier deliberate fix in this same file (see the
"Allies and enemies seem to share indices" entry above, which
moved FROM per-type TO shared-per-group) -- that fix is still
correct for what it fixed (targets-vs-allies must stay separate
namespaces), just not for per-type-vs-shared, which the user has
now clarified the other way. `_next_free_id` (the letter
sequence, with its own StopIteration-safe rollover to "AA" past
26) is gone, 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 to carry forward. Tests in
`test_models.py` updated to match (renamed
sequence per group (targets, or allies) to its own sequence per
TYPE within each group -- Tank#A/Infantry#A rather than
Tank#A/Infantry#B. This directly reverses an earlier deliberate
fix in this same file (see the "Allies and enemies seem to share
indices" entry above, which moved FROM per-type TO
shared-per-group) -- that fix is still correct for what it fixed
(targets-vs-allies must stay separate namespaces), just not for
per-type-vs-shared, which the user has now clarified the other
way. Tests in `test_models.py` updated to match (renamed
`test_auto_id_is_shared_across_types...` ->
`test_auto_id_is_per_type...`, since it now asserts the opposite).
First pass at this ALSO switched auto-assignment from letters to
plain numbers (1/2/3...), reasoning that it should match what
`detected_id` looks like when read successfully. Wrong -- caught
by the user immediately: auto-assignment (no real id known, a
manual add or an accept with no confident read) and a genuinely
detected id need to stay visually distinct, or a made-up
auto-assigned number could collide with, or be mistaken for, a
real one. Reverted back to `_next_free_id` (letters, rolling
over to "AA"/"AB"/... past 26 rather than raising
`StopIteration`) as the auto-assignment fallback, scoped per
type same as above; plain numbers are reserved for an id
`_accept_proposal` is actually confident was read off the
marker itself (`Proposal.detected_id`), passed straight through
as `id_` and never touching auto-assignment at all.
- `_accept_proposal` now actually USES `detected_id` (it was only
being logged before, never applied) -- an accepted proposal's
entity id prefers the detected number over auto-assignment,
falling back on a collision (scoped per type, same bug fixed
in two places: this collision pre-check, and the "Change ID"
popover's own check, which still enforced the OLD shared-per-
group rule after the auto-assignment change above and rejected
valid renames across types). 4 new regression tests
(`tests/test_app_accept_proposal.py`).
- `detected_id` is now shown, not just logged: the proposal
popover's heading (", id #8") and the pending-proposal's own
on-map label (`? #8 G8 5:4`) both show it while there's still a