Skip to content

feat(export): a deleted Indigo device destroys its Matter accessory (#274, PR A of 2) - #314

Merged
simons-plugins merged 1 commit into
mainfrom
fix/274-drop-orphans
Aug 26, 2026
Merged

feat(export): a deleted Indigo device destroys its Matter accessory (#274, PR A of 2)#314
simons-plugins merged 1 commit into
mainfrom
fix/274-drop-orphans

Conversation

@simons-plugins

Copy link
Copy Markdown
Owner

Delete an Indigo device, and the Matter accessory goes with it. Keep one by migrating it to the new device first (menuMigrateExport stays); 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

deviceDeleted already 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_refused is 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.py say "orphan" about orphaned launchd processes. Unrelated, untouched.
  • Migrate stays. It is the "keep the accessory" path and the one that earns its keep.

Known scaffolding — read this before reviewing

This reached the behaviour additively: the node still orphans by default, and a permanent wire flag opts out. That is more machinery than the change deserves.

PR B deletes the re-adopt UI (14 methods / 572 lines, list_orphans, the orphaned/orphanedAt map 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.md and ARCHITECTURE.md updated.

tests/fixtures/bridge_protocol/frames.json gains 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

pytest 3.13 3891 (3882 + 9)
pytest 3.11 3891
bridge-node 697 (686 + 11)
pylint 9.48, unchanged

Version 2026.29.0 — minor, since this is a user-visible behaviour change. No [release] marker.

🤖 Generated with Claude Code

…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>
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: df1d9f23-ef36-4d9e-92e8-1616d57afb44


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@simons-plugins
simons-plugins merged commit 24c5321 into main Aug 26, 2026
7 checks passed
@simons-plugins
simons-plugins deleted the fix/274-drop-orphans branch August 26, 2026 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant