# Known Limitations

## Authentication

- **DID method support**: Only `did:plc` and `did:web` are supported.
  Other DID methods (e.g. `did:key`, `did:ion`) are not implemented.
- **Key rotation**: If a user rotates their DID document keys, existing
  sessions are not invalidated. The server does not poll for key changes.
- **Handle verification**: The server resolves handles to DIDs at auth time
  but does not re-verify handles periodically. If a handle changes ownership,
  the server won't notice until the next authentication.
- **DPoP nonce rotation**: PDS nonce rotation during SASL is handled via
  automatic retry (server signals nonce, client retries). If the PDS rotates
  nonces again during the retry, authentication will fail (requires reconnect).

## IRC Protocol

- **No user limits (+l)**: Channel user limits are not implemented.
- **No secret/private channels (+s/+p)**: Channels always appear in LIST.
- **No WALLOPS, LINKS, STATS**: Server-to-server informational commands
  are not implemented.
- **USERHOST is simplified**: Returns `nick@host` with a cloaked hostname
  rather than the real connected host.
- **No services integration (NickServ/ChanServ)**: Identity is DID-based,
  not services-based.
- **Multiline messages degrade for clients that don't negotiate
  `draft/multiline`**: those clients see N separate PRIVMSGs (one per
  chunk), and only the first carries the message's msgid. Editing the
  message replaces only that first row in their UI — the trailing rows
  of the original chain stay around as orphans. Deletes have the same
  shape (only row 1 disappears; rows 2-N remain). Reactions are
  correctly attributed to the right logical message but visually attach
  to the first row only. Workaround: client negotiates `draft/multiline`
  during CAP REQ. See [MULTILINE-CLIENT-COMPATIBILITY.md](MULTILINE-CLIENT-COMPATIBILITY.md)
  for the full wire-shape comparison.
- **Multiline in `+E` channels requires the receiver to negotiate
  `draft/multiline` for messages larger than a single line of
  ciphertext** (~5.6 KB plaintext / ~7.5 KB ciphertext). Smaller
  messages ride in a single `+encrypted` PRIVMSG and are unaffected.
  Larger messages are sent as ciphertext-chunked across a multiline
  BATCH with `draft/multiline-concat`; fallback receivers see the
  fragments as separate PRIVMSGs, none of which decrypt individually
  (they're slices of one AES-GCM ciphertext). Note that vanilla IRC
  clients in `+E` channels have no useful UX regardless — they can't
  decrypt any `ENC1` blob, multiline or not. See
  [MULTILINE-CLIENT-COMPATIBILITY.md](MULTILINE-CLIENT-COMPATIBILITY.md#multiline-in-e-encrypted-channels).

## S2S Federation

- **Channel key removal**: `-k` cannot propagate via SyncResponse (additive
  only). Needs a protocol change or CRDT-backed key state.
- **Outgoing peer enforcement**: `--s2s-allowed-peers` only checks incoming
  connections. Outgoing connections go to whatever `--s2s-peers` specifies.
  Ensure both flags are consistent for mutual authorization.
- **Founder race condition**: If two servers simultaneously create the
  same channel, both may assign different founders. The CRDT resolves
  this deterministically after sync (first-write-wins), but there is a
  brief inconsistency window.
- **Topic merge strategy**: SyncResponse ignores remote topic if local is set,
  but CRDT reconciliation uses last-write-wins. The two merge strategies can
  cause flapping in edge cases.
- **Federated identity is peer-vouched, not verified**: a relayed message
  carries the sender's DID (`account`) and a `+freeq.at/origin` tag, but the
  receiving server does not verify it — it trusts the origin peer (the same
  trust the message body already rides on). The signature (`+freeq.at/sig`) is
  not verifiable across servers (its canonical inputs don't survive S2S), so
  clients render federated messages as "via {origin}" rather than locally
  verified. End-to-end verification is future work.

## Persistence

- **No message retention by age**: Message pruning is count-based only
  (`--max-messages-per-channel`). There is no `--message-retention-days`.
- **No full-text search**: SQLite FTS5 is not wired up. Message search
  would require a separate index.
- **Single-server SQLite**: The database is a single SQLite file. There
  is no replication or multi-server persistence (state sync happens at
  the CRDT/S2S layer instead).

## E2EE

- **No forward secrecy for channels**: Channel encryption keys are derived
  from a static passphrase. There is no ratcheting or key rotation.
  (DMs use X3DH + Double Ratchet and do have forward secrecy.)
- **Key distribution is manual**: Users must share the channel passphrase
  out-of-band. There is no key exchange protocol for channels.
- **ENC2 group size**: DID-based group encryption requires all members'
  DIDs to derive the group key. Very large groups would have slow key
  derivation.

## Transports

- **WebSocket is uncompressed**: No per-message compression.
- **iroh relay dependency**: iroh uses relay servers for NAT traversal.
  If iroh's relay infrastructure is unavailable, direct connections may
  fail for users behind restrictive NATs.

## Web Client

- **No offline mode**: Requires active WebSocket connection. No service
  worker message caching.
- **No push notifications**: Desktop notifications only work while the
  tab is open.

## TUI Client

- **No auto-reconnection**: If the connection drops, you must restart.
- **Not a full IRC client**: The TUI is a reference implementation. It
  lacks DCC, scripts, multiple networks, etc.
- **No mouse support**: Terminal mouse events are not handled.

## Plugin System

- **Compiled-in only**: Plugins must be compiled into the server binary.
  There is no dynamic loading. New plugins require a rebuild.
- **No async hooks**: Plugin hooks are synchronous. Long-running plugin
  logic should spawn tasks rather than blocking the hook.
- **Limited hook set**: Currently only `on_connect`, `on_auth`, `on_join`,
  `on_message`, and `on_nick_change` are available.

## Resolved (no longer limitations)

The following were previously listed as limitations and have been fixed:

- ~~No server operators (OPER)~~ → OPER command + `--oper-dids` auto-oper
- ~~No hostname cloaking~~ → `freeq/plc/xxxxxxxx` for DID users, `freeq/guest` for guests
- ~~No S2S ban enforcement~~ → Bans sync via S2S, enforced on join (nick + DID)
- ~~No S2S authorization~~ → Mode/kick/topic/join all verified server-side
- ~~No S2S invite sync~~ → Invites sync via S2S, consumed on join
- ~~No CHATHISTORY~~ → IRCv3 CHATHISTORY with batch support
- ~~No account-notify~~ → IRCv3 account-notify + extended-join
- ~~Open federation by default~~ → `--s2s-allowed-peers` for allowlist mode
- ~~Per-IP connection limits~~ → 20 connections/IP on TCP + WebSocket
