> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentvault.chat/llms.txt
> Use this file to discover all available pages before exploring further.

# Protocol State Machine

> Formal state machine specifications for AgentVault protocol flows.

## Overview

AgentVault defines formal state machines for three core protocol flows: **enrollment**
(device onboarding), **1:1 messaging** (E2E encrypted owner-agent communication), and
**room lifecycle** (multi-participant task rooms). These state machines govern all valid
transitions and enforce security invariants at every step.

<Info>
  The server never sees plaintext. All encryption and decryption happens client-side.
  Protocol messages are opaque blobs to the server.
</Info>

***

## Enrollment

### Invite Token States

Invite tokens are the entry point for device enrollment. Tokens are single-use, short-lived,
and stored as BLAKE2b hashes (never raw).

```mermaid theme={null}
stateDiagram-v2
    [*] --> CREATED: Admin creates invite
    CREATED --> CONSUMED: Device submits valid token
    CREATED --> EXPIRED: TTL exceeded (10 min max)
    CREATED --> REVOKED: Admin revokes
    CONSUMED --> [*]
    EXPIRED --> [*]
    REVOKED --> [*]
```

| Constraint             | Value                                     |
| ---------------------- | ----------------------------------------- |
| Max uses               | 1 (single-use)                            |
| Max TTL                | 10 minutes                                |
| Storage                | BLAKE2b hash only                         |
| Transition to CONSUMED | Immediate on successful device submission |

### Device Lifecycle States

Devices progress through a lifecycle from pending enrollment to active participation,
with administrative controls for suspension and revocation.

```mermaid theme={null}
stateDiagram-v2
    [*] --> PENDING: Device submits enrollment
    PENDING --> APPROVED: Admin approves
    APPROVED --> ACTIVE: Post key-exchange init
    ACTIVE --> SUSPENDED: Admin suspends
    ACTIVE --> REVOKED: Admin revokes
    SUSPENDED --> ACTIVE: Admin reinstates
    REVOKED --> [*]
```

**State rules:**

| State     | Capabilities                                                        |
| --------- | ------------------------------------------------------------------- |
| PENDING   | Cannot communicate. Awaiting admin approval.                        |
| APPROVED  | Eligible for key exchange. Cannot yet send messages.                |
| ACTIVE    | Full participation: messaging, room membership, key exchange.       |
| SUSPENDED | Temporarily blocked. No communication. Reversible.                  |
| REVOKED   | Permanently removed. All room memberships stripped. Triggers rekey. |

<Warning>
  Revoking a device triggers an immediate rekey of all rooms the device belonged to.
  The revoked device cannot decrypt any messages sent after revocation (forward secrecy).
</Warning>

### Enrollment Protocol Flow

The full enrollment sequence from invite creation through device activation:

```mermaid theme={null}
sequenceDiagram
    participant Admin
    participant Server
    participant Device

    Admin->>Server: Create invite token
    Server-->>Admin: Invite token (plaintext, one-time)
    Admin->>Device: Share invite (out-of-band)

    Device->>Device: Generate Ed25519 identity keypair
    Device->>Server: Submit (invite_token, device_public_key, proof_of_possession)
    Server->>Server: Validate token + signature

    alt Token valid
        Server-->>Device: 201 Created (status: PENDING)
        Server->>Admin: Notify new device pending
        Admin->>Admin: Verify device fingerprint
        Admin->>Server: Approve device
        Server-->>Device: Status -> APPROVED
        Device->>Device: Initialize key exchange
        Server-->>Device: Status -> ACTIVE
    else Token expired / reused / invalid signature
        Server-->>Device: 4xx Rejection (generic error)
    end
```

**Failure cases** return generic error messages to prevent information leakage:

| Failure                     | Server Response             |
| --------------------------- | --------------------------- |
| Token expired               | `400 Bad Request` (generic) |
| Token already consumed      | `400 Bad Request` (generic) |
| Invalid proof-of-possession | `400 Bad Request` (generic) |
| Token revoked               | `400 Bad Request` (generic) |

***

## 1:1 Messaging

### Session Establishment

Before two devices can exchange messages, they must establish a shared session
using the X3DH (Extended Triple Diffie-Hellman) key agreement protocol.

```mermaid theme={null}
sequenceDiagram
    participant Owner as Owner Device
    participant Server
    participant Agent as Agent Device

    Owner->>Server: Retrieve agent's public identity key
    Server-->>Owner: Agent identity key bundle
    Owner->>Owner: X3DH key agreement (compute shared secret)
    Owner->>Owner: Initialize Double Ratchet state
    Owner->>Server: Send initial message (ciphertext + X3DH header)
    Server->>Agent: Relay ciphertext
    Agent->>Agent: Complete X3DH, initialize Double Ratchet
    Agent->>Server: Send reply (ciphertext + ratchet header)
    Server->>Owner: Relay ciphertext
```

<Info>
  The owner must send the first message. The agent must not send until it has received
  at least one message from the owner (the `activated` flag). This ensures the Double Ratchet
  is properly initialized from the X3DH shared secret.
</Info>

### Message Send/Receive

Each message advances the Double Ratchet, deriving a unique message key for every
message. Old keys are deleted after decryption (forward secrecy).

```mermaid theme={null}
flowchart LR
    A[Plaintext] --> B[Derive message key via ratchet]
    B --> C[Encrypt with XChaCha20-Poly1305]
    C --> D[Attach header blob]
    D --> E[Upload ciphertext to server]
    E --> F[Server relays to recipient]
    F --> G[Recipient derives message key]
    G --> H[Decrypt ciphertext]
    H --> I[Delete message key]
```

**Message fields uploaded to server:**

| Field              | Type  | Description                               |
| ------------------ | ----- | ----------------------------------------- |
| `conversation_id`  | UUID  | Identifies the 1:1 conversation           |
| `sender_device_id` | UUID  | Sending device identifier                 |
| `ciphertext`       | BYTEA | Encrypted message payload                 |
| `header_blob`      | BYTEA | Ratchet header (public DH key + counters) |

### Replay Protection

* Each message includes a unique **message number** from the ratchet chain.
* The recipient rejects duplicate sequence numbers.
* A **sliding window** handles out-of-order delivery (skipped message keys are cached
  temporarily for later decryption).

### Encryption Details

| Property         | Value                                 |
| ---------------- | ------------------------------------- |
| Key agreement    | X3DH (Extended Triple Diffie-Hellman) |
| Ratchet          | Double Ratchet (Signal Protocol)      |
| Symmetric cipher | XChaCha20-Poly1305                    |
| Key size         | 256-bit                               |
| Nonce size       | 192-bit (eliminates nonce reuse risk) |
| Forward secrecy  | Yes -- old keys deleted after use     |
| Signing          | Ed25519                               |
| Key exchange     | X25519                                |

***

## Room Lifecycle

Each task room is a multi-participant group with its own encryption state.
MLS (RFC 9420) is the primary encryption protocol for rooms, providing scalable group key agreement with per-epoch forward secrecy. Double Ratchet remains as a fallback for legacy 1:1 sessions.

### Room State Machine

```mermaid theme={null}
stateDiagram-v2
    [*] --> CREATED: Admin creates room
    CREATED --> ACTIVE: Initial members added
    ACTIVE --> ACTIVE: Add/remove members
    ACTIVE --> REKEYING: Member removed or device revoked
    REKEYING --> ACTIVE: Rekey complete
    ACTIVE --> ARCHIVED: Admin archives
    ARCHIVED --> [*]
```

### Create Room

<Steps>
  <Step title="Initialize Group State">
    Admin device generates the initial encryption group state for the room.
  </Step>

  <Step title="Upload Encrypted State">
    Admin uploads the encrypted group state blob to the server.
  </Step>

  <Step title="Add Initial Members">
    Admin adds initial members. Each member's device receives the key material
    needed to participate.
  </Step>

  <Step title="Members Sync">
    Members fetch the room state and initialize their local encryption context.
  </Step>
</Steps>

### Add Member

```mermaid theme={null}
sequenceDiagram
    participant Admin
    participant Server
    participant NewMember as New Member
    participant Existing as Existing Members

    Admin->>Server: POST /rooms/{id}/members (new device)
    Server->>Server: Validate device is ACTIVE
    Server->>Existing: Broadcast room_joined event
    Server->>NewMember: Send room state + key material
    NewMember->>NewMember: Initialize local encryption state
```

**Rules:**

* Only **ACTIVE** devices may receive room membership.
* Existing connected members are notified via WebSocket broadcast.
* The new member's device subscribes to the room's Redis pub/sub channels.

### Remove Member / Device Revocation

```mermaid theme={null}
sequenceDiagram
    participant Admin
    participant Server
    participant Removed as Removed Device
    participant Remaining as Remaining Members

    Admin->>Server: Remove member (or revoke device)
    Server->>Removed: Close WebSocket connection
    Server->>Server: Strip all room memberships
    Server->>Remaining: Broadcast member_removed event
    Server->>Server: Trigger rekey
    Remaining->>Remaining: Re-establish encryption state
```

**Guarantees:**

* Forward secrecy preserved -- removed devices cannot decrypt messages from the new epoch.
* WebSocket connections are closed immediately on revocation.
* All room memberships are stripped atomically.

***

## Concurrency Handling

### Simultaneous Admin Changes

When multiple admins issue conflicting changes (e.g., two membership changes at once),
the server enforces ordering:

* The first commit to reach the server is applied.
* Conflicting operations must rebase against the new state and retry.

### Message During Rekey

If a device attempts to send during an epoch transition:

1. The send fails with an epoch mismatch error.
2. The client fetches the latest group state.
3. The client updates local encryption state.
4. The client retries the send under the new epoch.

***

## Error Recovery

<AccordionGroup>
  <Accordion title="Epoch Mismatch">
    1. Fetch latest room state from server.
    2. Verify the commit chain integrity.
    3. Resynchronize local encryption state.
  </Accordion>

  <Accordion title="Corrupt State">
    1. Trigger full state resync from server.
    2. If verification fails, admin can perform a room reset (re-establishes
       all encryption state from scratch).
  </Accordion>

  <Accordion title="Ratchet Desync (1:1)">
    When the Double Ratchet falls out of sync between owner and agent:

    1. Delete the broken session from local storage.
    2. Clear the relevant key material.
    3. Re-establish via fresh X3DH key exchange.
    4. The `device_linked` event triggers a new conversation.
  </Accordion>
</AccordionGroup>

***

## Security Enforcement Rules

These invariants hold across all protocol state machines:

<CardGroup cols={2}>
  <Card title="Zero-Knowledge Server" icon="lock">
    Server never decrypts content. All protocol messages are opaque BYTEA blobs.
  </Card>

  <Card title="RLS Enforcement" icon="database">
    PostgreSQL Row-Level Security enforces membership before read/write on every tenant-scoped table.
  </Card>

  <Card title="Mandatory Rekey" icon="rotate">
    Device revocation triggers mandatory rekey of all affected rooms.
  </Card>

  <Card title="No Content in Push" icon="bell">
    Push notifications contain zero message content. Content is fetched client-side after notification.
  </Card>
</CardGroup>

***

## Non-Goals

The protocol explicitly does **not** protect against:

* Fully compromised operating systems (device-level compromise).
* Screenshot or screen recording prevention.
* Global traffic analysis or metadata obfuscation beyond what TLS provides.

***

## Validation Checklist

For implementers verifying protocol compliance:

<Check>Enrollment tokens are single-use and expire within 10 minutes</Check>
<Check>Device fingerprint is verified by admin before approval</Check>
<Check>All encryption state is validated client-side before use</Check>
<Check>No plaintext columns exist in the database</Check>
<Check>All tenant-scoped tables have RLS policies enabled</Check>
<Check>Revocation automatically triggers rekey of all affected rooms</Check>
<Check>Owner sends first message in every 1:1 conversation</Check>
<Check>Old ratchet keys are deleted after decryption</Check>
