9ae07894c7
For a GroupContextExtensions commit, openmls signs the `FramedContentTBS` over `group.public_group.group_context()` — the UNMUTATED context, before the `diff` applies the GCE proposal. The post-proposal extensions only make it into the HPKE path-encryption context and the subsequent key schedule, not into the TBS / signature / membership_tag. Quartz's `applyProposal` handler for `GroupContextExtensions` mutates `groupContext.extensions` inline — by the time `commit()` captured `preCommitContextBytes`, the extensions were already updated. The signature and membership_tag were then minted over the post-GCE context, and openmls's `verify_membership` recomputed the MAC over the pre-GCE context and reported `ValidationError(InvalidMembershipTag)` on every cross-impl rename / promote / demote / leave. Fix: snapshot `groupContext.extensions` before any proposal is applied, and rebuild `preCommitContextBytes` with those original extensions. The path-encryption context and post-commit key schedule still use the updated extensions, matching openmls. https://claude.ai/code/session_016kAxdp6ubB5CnF9URhCEzP