# ADR-034: Входящее сообщение с известным id не перезаписывает запись ## Контекст `docs/storage.md` описывал повтор доставки одной строкой: «`put` с тем же `id`, без дублей». Подразумевался тот же самый конверт — сервер выдаёт очередь заново при каждом подключении и вправе прислать конверт дважды (ADR-017). Клиент так и делал: писал `put` по `id` безусловно. `id` — открытое поле конверта, собеседник видит его сразу, как получает сообщение. Истории идентификаторов сервер не хранит: это противоречило бы ADR-008, — поэтому `POST /api/messages` с чужим `id` он принимает и раскладывает по очередям как любой другой. AAD сходится: в него входят `id`, `chat`, `from` и `keyId`, а `from` сервер ставит из сессии — конверт собеседника валиден и расшифровывается. Дальше `put` перезаписывал мою строку: в ленте вместо моего сообщения оказывался чужой текст, исходное исчезало, и фан-аут разносил подмену на остальные мои устройства. Тем же приёмом собеседник стирал и то, что прислал сам, — это прямо противоречит модели угроз: «„Удалить у всех“ после доставки не существует». Вторая половина того же места — счётчик. Все чтения `messages` выпускались до первого `put`, поэтому две копии одного конверта в одной пачке обе считались новыми и `unread` рос дважды. Такая пачка — не гипотеза: конверт, попавший в очередь в момент подключения, приходит и выдачей очереди, и живым событием. ## Решение - Входящее сообщение с уже известным `id` игнорируется целиком: ни записи, ни счётчика непрочитанных. Строку, которая уже лежит на устройстве, входящий конверт не трогает. - Повторный `id` внутри одной пачки учитывается один раз. - Перезапись по `id` остаётся у исходящего: переход `pending → sent/failed`, где `id` свой и запись своя. - Правило записано строкой в `docs/storage.md`. ## Следствия - Знание `id` не даёт собеседнику ничего: подменяющий конверт у получателя молча пропадает. - Нерасшифрованное чинится не повторной доставкой, а полем `raw` — оно для этого и хранится (`docs/storage.md`). - Дубль доставки, разрешённый ADR-017, больше не двигает счётчик непрочитанных.