Skip to content

Bug: old incomplete revocations can poison status reads after switching Space #19

Description

@mkdir700

Summary

Switching to a new Space can succeed, yet a later query_current_member_revocation fails with Engine error 1387 and hides otherwise valid Space state in consumers.

1387 maps to MEMBER_GROUP_REVOCATION_FAILED_CODE. This is not a join failure: in the observed mobile flow, the new Space and device roster were already available and the new device was visible online to other members.

Suspected Cause

SwitchSpaceUseCase clears encrypted_relationship through RelationshipStateResetPort::clear_all_relationships(), but durable key-epoch and member-revocation data remain in member_revocation_log / space_key_epoch_state.

DefaultSpaceAccessAdapter::current_group_revocation() calls list_incomplete_revocations(), which currently decrypts and validates every incomplete row before selecting the record for the active Space. Therefore an unreadable incomplete record from a previous Space can fail the whole query before the active-Space filter is applied. The operation is surfaced as error 1387.

The exact unreadable-row cause is not yet observable: the current error mapping preserves the stable code but does not record the underlying safe failure reason.

Expected Behavior

A member-removal record from a previous Space must not prevent reading the active Space state or the active Space removal status after a successful switch.

Proposed Direction

  • Scope the storage query for incomplete revocations to the active Space lookup token before decrypting rows.
  • Review whether old-Space key-epoch / revocation records need explicit lifecycle handling on a Space switch; do not delete security records without a defined retention and recovery policy.
  • Add redacted Engine-side diagnostics for failures of query_current_member_revocation so the underlying reason is captured without recording device IDs, keys, tokens, or payloads.

Acceptance Criteria

  • Given an unreadable incomplete revocation record for Space A and an active Space B, query_current_member_revocation for Space B returns its own status (or no status) instead of error 1387.
  • A successful Space switch remains readable even when old-Space revocation data cannot be decoded.
  • The affected query emits a redacted failure reason that can distinguish repository, decryption, integrity, and state-transition failures.
  • Tests cover the cross-Space case and preserve encrypted-at-rest requirements.

Consumer Impact

Mobile now treats this removal-status query as optional so its failure no longer hides an active Space and its devices. That is a consumer safeguard; the Engine query should still be isolated from unrelated old-Space records.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions