ece487ceee
Layers on the salvaged #88489 (@29206394) and #88341 (@frizikk): - sdk: host.activeConnectionId() — registry id of the LIVE active gateway. The salvaged fix classifies against the registry primary; after the user activates a non-primary source's agent, profiles.list answers from THAT source and primary-based matching would duplicate the active source's agents again. Live id wins, primaryConnectionId is the fallback, the legacy kind==='local' rule covers older desktops. - plugin: roster/chip/picker list keys are botRowKey(bot) — source-qualified (connectionId, name) — so same-named agents on two genuine sources can never collide as duplicate React keys (the render half of the dupe-bots smear: name-keyed rows + duplicate names = repeated blocks every poll). Annotated active-source rows keep the plain-name key, so nothing remounts when a desktop gains the union roster. - tests: live-id-beats-primary regression, botRowKey stability, source-shape anchor refresh.