Files
mantra-kmp/composeApp
Kgothatso Ngako 2fb8d6921b fix(projects): let a membership's foreign key violation out, so the sweep retries
A project's memberships are foreign keys into both the project and the version
they name, so a chronicle page carrying a membership whose project is in a
*later* page cannot apply it yet. `ChronicleManager.applyPage` handles exactly
this: it catches the violation, counts the payload `failed`, and `sweep` re-runs
every page until failures stop falling.

Phase 3 broke that for projects by catching the violation inside the apply arm.
`applyInnerEvent` then returned normally, `applyPage` counted the payload
applied, the sweep saw nothing left to do, and the membership was dropped --
silently, permanently, on the device a chronicle exists for.

The catch was added so that `FrostSigningManager.applySignedEvent` would not
report a succeeded session as failed. That reasoning was already satisfied:
`applySignedEvent` wraps the call in its own try/catch. And no sibling arm
catches -- a translation chapter naming an absent chapter throws today -- so the
catch made projects the only kind a chronicle could not retry. It is gone.

Pages are 128 events or 64 KiB, and projects sort last in APPLY_ORDER, so a
boundary falling between a project and its memberships is the ordinary case for
any room with a chapter's worth of chunks in it.

`pages arriving out of order still converge` already modelled this -- one page
per payload, delivered backwards, comparing every row count on both devices --
and passed anyway, because `rowCounts` did not look at the project tables. It
does now, which is what makes that test the one that would have caught this.
`ProjectApplyJvmTest` asserts the throw rather than the swallow, and adds the
retry in miniature: refused while the project is missing, accepted once it is
there, same event both times.

1404 tests, no failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-02 20:05:28 +02:00
..