Skip to content

refactor(export): delete re-adopt and the orphan concept entirely (#274, PR B of 2) - #315

Merged
simons-plugins merged 1 commit into
mainfrom
fix/274b-delete-readopt
Aug 26, 2026
Merged

refactor(export): delete re-adopt and the orphan concept entirely (#274, PR B of 2)#315
simons-plugins merged 1 commit into
mainfrom
fix/274b-delete-readopt

Conversation

@simons-plugins

Copy link
Copy Markdown
Owner

Closes #274.

+813 / −3357 across 41 files. PR A made a confirmed deletion destroy the accessory; nothing wants an orphan any more, so the whole concept goes.

Deleted

  • The 14 re-adopt methods and ReadoptOrphansUnavailableexport_recovery_menu_mixin.py 1264 → 744 lines
  • Its MenuItems.xml entry
  • The list_orphans wire command: CMD_LIST_ORPHANS/OrphanRecord/parse_orphans in Python, its handler plus EndpointMapStore.orphans()/noteReadoptableMatch() in TypeScript
  • The orphanedAt field
  • export_store.options_lawful_for_role, dead once _readopt_commit went
  • The permanent flag PR A added. It was scaffolding — an opt-in whose every caller opts in isn't a safety property, it's an unused branch plus a second wire vocabulary. remove_endpoint has one meaning again.

Two near-misses, both caught by a failing test rather than by grep

Worth recording, because a name-based sweep would have taken both:

  • _readopt_device_row is used by migrate. Renamed _migrate_device_row, not deleted.
  • _identity_claimant is used by export_dialog_mixin's collision avoidance. Kept.

Kept, despite the names

supersededBy, orphaned and deviceId survive on endpoint-map.json records. They read as re-adopt leftovers and are not — they serve restorable()'s startup rebuild (#141) and migrate's driving-device rekey detection in check(). Do not delete them on the strength of the name.

Migrate verified end to end

replace()'s literal two-command sequence now destroys and re-adds rather than superseding in place. Accessory numbers come from matter.js's own persisted allocation, not from this witness file, so the number and the identity still move correctly.

Three bridge-node tests that drove the old sequence and asserted the soft bookkeeping were rewritten to assert the new reality. No replacement mechanism was invented. Migrate's 56 tests pass.

mass_removal_refused is untouched, and is now the single guard between a plugin bug that sends a short list and a wiped fabric — the first thing to re-read before changing how the export list is computed.

launch_agent.py/server_process.py "orphan" means orphaned launchd processes. Different word, untouched.

ADR-0016 supersedes ADR-0015's mechanism

ADR-0015 was written against PR A in isolation and recorded permanent as opt-in and replace() as "structurally unable to trigger" destroy. Both are now false.

Its ruling — a confirmed deletion destroys, no retention, no re-adopt — is unchanged and governs. ADR-0015 is not edited, per the repo's immutability rule.

The sequencing error is named in ADR-0016 rather than buried: the ADR was written against a half-finished migration whose second half was already planned and already known to remove the flag. An ADR should be written against the end state, or explicitly marked as describing an interim one.

Numbers

Before After
pytest (3.11 and 3.13) 3891 3804
bridge-node 697 673
pylint 9.48 9.48

Both suites fell because a feature and its tests were removed — the intended direction.

Version 2026.29.1. No [release] marker.

🤖 Generated with Claude Code

…, PR B of 2)

+700/-3355 across 38 files. PR A made a confirmed deletion destroy the
accessory; nothing wants an orphan any more, so the whole concept goes.

Deleted: the 14 re-adopt methods and `ReadoptOrphansUnavailable`
(`export_recovery_menu_mixin.py` 1264 → 744), its MenuItems entry, the
`list_orphans` wire command (`CMD_LIST_ORPHANS`/`OrphanRecord`/`parse_orphans`
in Python, its handler and `EndpointMapStore.orphans()`/`noteReadoptableMatch()`
in TypeScript), the `orphanedAt` field, and `export_store.options_lawful_for_role`
(dead once `_readopt_commit` went).

**And the `permanent` flag PR A added.** It was scaffolding: an opt-in whose
every caller opted in is not a safety property, it is an unused branch plus a
second wire vocabulary. `remove_endpoint` has one meaning again.

Two near-misses, both caught by a failing test rather than by grep — worth
recording because a name-based sweep would have taken them:
- `_readopt_device_row` is used by MIGRATE. Renamed `_migrate_device_row`,
  not deleted.
- `_identity_claimant` is used by `export_dialog_mixin`'s collision
  avoidance. Kept.

`supersededBy`, `orphaned` and `deviceId` survive on `endpoint-map.json`
records. They read as re-adopt leftovers and are not: they serve
`restorable()`'s startup rebuild (#141) and migrate's driving-device rekey
detection in `check()`. Do not delete them on the strength of the name.

**Migrate verified end to end.** `replace()`'s literal two-command sequence now
destroys and re-adds rather than superseding in place; accessory numbers come
from matter.js's own persisted allocation rather than this witness file, so the
number and the identity still move correctly. Three bridge-node tests that drove
the old sequence and asserted the soft bookkeeping were rewritten to assert the
new reality; no replacement mechanism was invented. Migrate's 56 tests pass.

`mass_removal_refused` untouched, and now the single guard between a plugin bug
that sends a short list and a wiped fabric. `launch_agent.py`/`server_process.py`
"orphan" is orphaned launchd PROCESSES — different word, untouched.

**ADR-0016 supersedes ADR-0015's mechanism.** ADR-0015 was written against PR A
in isolation and recorded `permanent` as opt-in and `replace()` as "structurally
unable to trigger" destroy; both are now false. Its RULING — a confirmed
deletion destroys — is unchanged and governs. ADR-0015 is not edited, per the
repo's immutability rule. The sequencing error is named in ADR-0016: the ADR was
written against a half-finished migration whose second half was already planned.

3804 passing on 3.11 and 3.13 (from 3891); bridge-node 673 (from 697). Both fell
because a feature and its tests were removed. pylint 9.48, unchanged.

Closes #274

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 26, 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: deca53e5-0fb2-4292-907a-eb54d7a3c9f6


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 8ae420c into main Aug 26, 2026
7 checks passed
@simons-plugins
simons-plugins deleted the fix/274b-delete-readopt branch August 26, 2026 08:49
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.

export: orphans should be cleared far sooner — and re-adopt may not be worth what it costs

1 participant