Files
amethyst/commons
Claude fb31d7e01b fix(cordn): a cancelled subscription really does save, and stop() waits
Two halves of one bug, the second caused by fixing the first.

`CordnGroupManager.subscribe` persisted in a `finally` and its comment
claimed that covered cancellation. It did not: `persistAll` suspends,
and a suspend call in a cancelled coroutine throws before it writes
anything. Cancellation is also the normal way this ends — CordnSyncLoop
cancels the subscription whenever the group set changes — so the case
the `finally` was written for was the one case it never served.
`withContext(NonCancellable)` fixes it.

That alone broke two CordnRuntime tests, and rightly. `CordnSyncLoop.stop()`
was `job?.cancel()` with no join, so it returned while the loop's
`finally` blocks were still running. `importArchive` stops the loops,
deletes the account's directory and restores from the archive — and a
persist that landed a moment late wrote a group back onto disk after the
delete, which the restore then read in again. That is exactly the merge
importArchive exists to prevent, and `adoptMigration` had it too. stop()
is suspend now and does `cancelAndJoin`; CordnRuntime.stop() already
suspended, so nothing else had to change.

Nobody had noticed the missing join because the persist it races was
silently failing. Making the write survive cancellation is what made the
race reachable.

The test needed two goes to be worth anything. The first version passed
against the mutant: `send()` already persists, so the cursor it asserted
on was in the store before the subscription ran, and the fake returned
normally so no cancellation ever landed mid-subscription. The second
still passed, because InMemoryCordnGroupStore's methods are `suspend`
but never reach a suspension point — and cancellation is only observed
at one. It takes a store whose writes actually suspend, like the
file-backed one, and a coordinator that hangs after delivering. With
both, removing NonCancellable fails the test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012BfD4txdnsaPRXmNXbup9n
2026-09-24 04:50:37 +00:00
..