mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-09 16:14:40 +00:00
`ConcordRefounding.compactControlPlane` re-wraps one edition per entity when a community rotates epoch, and the ROTATOR chooses which one survives. The receiving side had no memory: `refold()` folds only the wraps at the current epoch's Control-Plane address and discards the prior epoch's buffer, and `EditionFold` accepts whatever it is handed (its no-genesis fallback anchors at the lowest version present). So a rotator could publish only version 1 of a chain and omit version 2 — restoring a revoked role, clearing a banlist, reverting metadata. Every signature is genuine; this is rollback by omission, not forgery. Adds a per-entity floor: the version AND hash last successfully folded. - **No floor (fresh joiner)** — unchanged: genesis anchor, else the lowest-version edition as the legitimate compaction bootstrap. - **With a floor** — the walk is anchored AT the floor: the offered set must contain the exact edition already folded (version and hash; a same-version sibling is a fork, not our chain), then walks up. A head below the floor is structurally unreachable. - **Gap** (the floor edition is absent) — refuse, and keep the known head. Refusing by *retaining* matters here: this fold is recomputed from scratch each time, so letting an entity vanish would itself be a rollback — a dropped banlist is an unban. The floor needs no new persistence. It is derived from `heldRoots`, the rotated-out access roots already persisted in the NIP-44 self-encrypted kind-13302 list: the session derives each prior epoch's Control-Plane address from them, folds oldest-first, and takes the resulting heads as the floor. That survives both a process restart and the session rebuild `ConcordSessionRegistry.sync` performs at exactly the moment of a Refounding — which would have destroyed any in-session floor. If the old planes are not served, there is no floor and behaviour is as before. Floors are built from AUTHORITY-GATED heads, not raw ones. Without that, any ex-member still holding a rotated-out root could mint a high-version edition on the old plane and freeze the entity for every honest client — a denial of service this change would otherwise have introduced. Covered by a test. Verified by disabling both enforcement points: 7 of 12 quartz tests and the end-to-end commons test fail, and the ones that still pass are exactly the non-regression cases (fresh joiner, honest compaction, pass-through without floors). Known limit: `AuthorityResolver.resolve` folds authorized SUBSETS of the edition pool and does not carry floors itself; gating happens at the pool level before the resolver sees anything. Sound, but connectivity checked on the full set is a weaker precondition than on each subset — passing floors into the resolver's three folds is worth a follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>