Skip to content

feat(recovery): complete lost-key and restored-device recovery #118

Closed

Description

@abruption

Problem

The relay lifecycle correctly treats a restored endpoint as quarantined: new sends, pairing/enrollment and key rotation remain blocked while receipt-status inspection stays available. The current documentation also states that there is no complete lost-key recovery workflow and no one-command override for recovery_required.

That fail-closed boundary is appropriate for Alpha. Stable v1 needs a supported way to either recover safely or determine that the old identity must remain archived. Clearing a marker, restoring an old control database, reusing a principal or treating OAuth login as key possession are not acceptable recovery methods.

Proposed behavior

Implement an explicit recovery workflow with separate inspection, fencing, re-pairing and activation phases.

  • A recovery status/plan command reports the restored identity generation, unresolved outgoing receipts, native effects requiring reconciliation, known peers/routes, control ownership and the exact remaining gates. It must not expose keys, tokens, message bodies or peer certificates.
  • Historical restored state remains read-only for receipt and reconciliation evidence.
  • For a control-managed identity, the owner explicitly revokes/fences the old principal, creates a fresh identity/principal and enrolls it through the normal possession-proof path. OAuth alone never rotates or revives the old key.
  • Every peer explicitly approves the new endpoint identity and pin. No peer pin changes from a control receipt alone.
  • Direct-only identities require the same explicit peer re-pairing; absence of a control authority must not weaken the fence.
  • Activation occurs only after unresolved receipts/native effects are classified and all required peer transitions are committed. Partial completion remains resumable with fixed operation identifiers.
  • Preserve the old identity, tombstone and receipts as audit history rather than merging them into the new active identity.

Acceptance criteria

  • Restore continues to publish a durable quarantine marker before usable state becomes visible.
  • No local-only flag or marker deletion can reactivate an old identity.
  • Recovery status is deterministic, machine-readable and safe to rerun.
  • Managed recovery requires old-principal revocation/fencing, fresh-key possession and explicit peer pin acceptance.
  • Direct recovery requires explicit re-pairing and never trusts copied state as current authority.
  • Crash and response-loss tests cover every phase, fixed-operation reconciliation and repeated status calls.
  • Tests cover already-processed native effects, unknown receipts, offline peers, partial peer commit, lost old key, revoked identity, control rollback and duplicate requests without producing a second effect.
  • Backup/restore documentation gives operators an end-to-end supported outcome: safe activation of a new identity or continued read-only archival quarantine.
  • Public hosted recovery is exercised through the actual Node/Python integration fixture; real provider login remains an operator validation rather than default CI.

Non-goals

  • Recovering the old private key from a backup that does not contain it.
  • Reviving a revoked principal or silently replacing its key.
  • Automatic receipt deletion, native-effect replay or peer-pin acceptance.
  • Treating a control operation receipt as proof that endpoint E2EE commit completed.

This belongs in v1.0.0. It depends on the versioned migration contract in #115 and can proceed alongside #112 after the public compatibility contract in #116 is fixed.

Activity

  1. added this to the v1.0.0 milestone on Sep 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions