Collapse the legend, tap a pin, then close the detail: the legend comes back
open, though nothing asked it to. Reported against the leaf research map;
reproduced at 1440 in en, collapsed-first.
selectPeopleGroup saved the pre-detail legend state on every call that carried
a group, not only on the call that entered detail. The second call therefore
saved the 'open' the first call had just forced, on top of the 'collapsed' it
correctly saved on entry, and closing the detail restored that 'open'.
The measured part is why a second call happens at all. The pin click handler is
registered per map layer, and every visible pin has an invisible hitbox twin at
the same point -- same source, larger radius, added alongside it so taps are
easier to land. A layer-scoped click fires once per layer with a feature under
the point, so a single pin click calls selectPeopleGroup exactly twice, 3ms
apart. Measured on two different pins, both reporting both layers at the click
point; never more than twice. So ONE pick was already enough to lose the
collapsed state -- it never needed two, which is why this reproduced every time
rather than intermittently.
The fix is to make the method idempotent: save only when entering detail (no
group was selected before), restore only what was actually saved, then clear it
so a later detail cannot inherit a stale value. The duplicate binding is a real
defect in its own right and is tracked separately; this method should not have
depended on being called exactly once.
Verified two-sided against the shipped source, driving the real method body
rather than a copy: seven scenarios pass on the fix and four fail with the
previous body restored, while the scenarios that must be insensitive stay green
both ways. The poisoned run reproduces the browser measurement value for value
-- saved collapsed, overwritten to open by the second call, restored open.
Trace in _qa-cycle so the next reader can re-run it.
Three stores, one responsibility each. Created fresh per <doxa-map> element and provided to
descendants from ProfileLoader.vue — reach them via inject(), never a direct useXxxStore()
import (LL-010, LL-023).