feat(export): a deleted Indigo device destroys its Matter accessory (#274, PR A of 2) - #314
Merged
Merged
Conversation
…274, PR A of 2) Simon's decision, 2026-08-25: when a user deletes an Indigo device, the Matter accessory goes with it. Keep an accessory by migrating it to the new device first (`menuMigrateExport`, which stays); delete it and you re-pair in Apple/Alexa, which takes a few minutes. #274 records that Simon proposed exactly this when orphan retention was designed and was argued down on "an orphan costs nothing to keep". #273 then measured what it costs: NINE live published endpoints on the reference rig, duplicate names, dead accessories and inflated endpoint counts in every ecosystem. An orphan is not free — it is an accessory every controller still sees. `deviceDeleted` already removed the allow-list entry and the endpoint, so a deletion Indigo witnessed was already handled. The gap this closes is a deletion Indigo reported to nobody because the plugin was not running: on the next attach, the endpoint whose device is gone is now destroyed rather than retained for re-adopt. **The existence check is the whole rule.** A device is gone when it is not in `indigo.devices` — nothing else. A device whose owning plugin is disabled, restarting or still loading STILL EXISTS, so it is never a delete; there is no transient-vs-permanent distinction to draw, no grace period and no retry bookkeeping, and none is implemented. `mass_removal_refused` is untouched and matters more now than it did: it is the only thing between a plugin bug that sends a short list and a wiped fabric, and removal is no longer reversible. `launch_agent.py`/`server_process.py` say "orphan" about orphaned launchd PROCESSES — unrelated, untouched. ADR-0015 records the decision and supersedes the retention rationale. BRIDGE_PROTOCOL and ARCHITECTURE updated. The shared golden fixture `tests/fixtures/bridge_protocol/frames.json` gains the permanent-removal frames; both suites read it and both pass, which is the point of that file. **Known scaffolding, deliberate:** this reached the behaviour additively — the node still orphans by default and a `permanent` wire flag opts out. PR B deletes the re-adopt UI, at which point orphaning has no consumer at all and comes out wholesale, taking the flag with it. Shipping it this way because the end state is identical and it gets the fix in today. 3891 passing on 3.11 and 3.13 (3882 + 9); bridge-node 697 (686 + 11); pylint 9.48, unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Delete an Indigo device, and the Matter accessory goes with it. Keep one by migrating it to the new device first (
menuMigrateExportstays); delete it and you re-pair in Apple/Alexa — a few minutes.Why
#274 records that this was proposed when orphan retention was designed, and argued down on "an orphan costs nothing to keep".
#273 measured what it costs: nine live published endpoints on the reference rig, duplicate names, dead accessories, inflated endpoint counts in every ecosystem. An orphan is not a dormant record — it is an accessory every controller still sees.
What changed
deviceDeletedalready removed the allow-list entry and the endpoint, so a deletion Indigo witnessed was handled. The gap was a deletion Indigo reported to nobody, because the plugin wasn't running to hear it. On the next attach, an endpoint whose device is gone is now destroyed rather than retained for re-adopt.The existence check is the whole rule
A device is gone when it is not in
indigo.devices. Nothing else.A device whose owning plugin is disabled, restarting, or still loading still exists — so it is never a delete. There is no transient-vs-permanent distinction to draw, no grace period, no retry bookkeeping, and none is implemented.
What deliberately did not change
mass_removal_refusedis untouched, and matters more than before: it is the only thing between a plugin bug that sends a short list and a wiped fabric, now that removal is not reversible.launch_agent.py/server_process.pysay "orphan" about orphaned launchd processes. Unrelated, untouched.Known scaffolding — read this before reviewing
This reached the behaviour additively: the node still orphans by default, and a
permanentwire flag opts out. That is more machinery than the change deserves.PR B deletes the re-adopt UI (14 methods / 572 lines,
list_orphans, theorphaned/orphanedAtmap markers) — at which point orphaning has no consumer at all and comes out wholesale, taking the flag with it.Shipping it this way because the end state is identical and it gets the fix in now rather than after a subtractive rewrite that nobody would see the intermediate of.
Docs
ADR-0015 records the decision and supersedes the retention rationale — not edited, per the repo's immutability rule.
BRIDGE_PROTOCOL.mdandARCHITECTURE.mdupdated.tests/fixtures/bridge_protocol/frames.jsongains the permanent-removal frames. It is the one shared golden fixture — the Python suite reads it directly and the TS suite copies it in at build. Both pass, which is exactly what that file exists to prove.Numbers
Version 2026.29.0 — minor, since this is a user-visible behaviour change. No
[release]marker.🤖 Generated with Claude Code