# Proposal ## Why Режим переноса (C) может залить на сервер **превью вместо оригинала** и тут же удалить устаревшую серверную копию, то есть молча уничтожить оригинал. Причина — планировщик не отличает содержимое от роли локального файла: когда состояние элемента в локальном индексе расходится с фактической ролью (в индексе «оригинал», на диске превью), смена роли читается как «содержимое изменилось» и запускается цикл «удалил → залил → удалил». Реальный инцидент: альбом устройства U2, режим переноса, серверный альбом `N2`. Из 20 фото пять перезаливались по кругу (20:03 → 20:08 → 20:42 → 21:24), а два потеряли оригиналы — `IMG_20261004_163151.jpg` (3 437 694 Б, 3072x4096 → 259 282 Б, 1200x1600) и `IMG_20261009_153136.jpg` (2 226 043 Б → 192 651 Б). Лечиться это будет только сейчас: у первого уцелевший оригинал лежит в корзине сервера, у второго — в корзине и в альбоме «Первый». Побочно тот же цикл оставляет на телефоне элементы, которых на сервере уже нет: в приложении альбом `N2` показывает 26 плиток вместо 20, шесть из них пустые. ## What Changes - **Роль не является содержимым.** Приложение SHALL отличать созданное им превью (в том числе по метке провенанса) от нового оригинала: превью никогда не загружается как новая версия и не влечёт удаления серверной копии, а расхождение состояния в индексе выправляется. Настоящее изменение содержимого, как и раньше, синхронизируется новой версией. - **Удаление только после подтверждения.** Устаревшая собственная загрузка удаляется только после того, как новая версия подтверждена сервером: сообщённая им контрольная сумма принятого объекта совпала с отправленной. При расхождении загрузка отклоняется вместе с принятой копией, прежняя серверная копия остаётся в альбоме, а замена повторяется при следующей синхронизации. Если сервер контрольную сумму не сообщил (например, старая версия инстанса), загрузка остаётся состоявшейся, но прежняя копия не удаляется. - **Контрольная сумма в ответе на загрузку.** Сервер SHALL отдавать контрольную сумму оригинала в данных созданного фото — как требует существующее требование способности `photos`; сегодня ответ на загрузку её не содержит (дефект сервера, а не изменение API). - **Разгрузка не гоняется с загрузкой.** Оригинал не заменяется превью, пока по этому элементу есть незавершённая загрузка. - **Возврат оригинала устойчив.** После возврата оригиналов на устройство элемент не разгружается превью повторно, пока альбом снова не переведён в режим переноса. - **Разовое восстановление двух пострадавших фото** из корзины сервера (и альбома «Первый» для второго) с удалением деградировавших копий. - **BREAKING**: нет. Успешные сценарии (загрузка нового, разгрузка, повторная синхронизация, настоящее изменение содержимого) сохраняют поведение; меняются только защитные условия. ## Capabilities ### New Capabilities _Нет — поведение относится к существующей способности синхронизации альбома устройства._ ### Modified Capabilities - `phone-album-sync`: различение роли и содержимого (метка превью против нового оригинала), разгрузка только без незавершённой загрузки, удаление устаревшей загрузки только после подтверждения новой версии, устойчивый возврат оригиналов. ## Impact - **Код (Android):** `data/sync/SyncPlan` (различение роли и содержимого, отложенная замена), `data/sync/SyncCoordinator` (выправление состояния, разгрузка без незавершённых загрузок, постановка замены), `data/sync/LocalAssetProvider` (метка превью рядом с хешем), `data/upload/UploadWorker` (сверка принятой контрольной суммы, удаление устаревшей копии после подтверждения, без разгрузки вне координатора), `data/sync/RestoreManager` (состояние после возврата оригинала), `data/db` (поле «заменяемое фото» в задании загрузки). - **Схема Room:** версия 8 → 9, `ALTER TABLE upload_jobs ADD COLUMN replacesPhotoId TEXT`. - **API и бэкенд:** не затрагиваются — используются существующие `DELETE /api/photos/{id}` (мягко, в корзину), `POST /api/photos/{id}/restore` и `original_checksum` в ответе загрузки. - **Данные инстанса:** разовое восстановление двух оригиналов и удаление деградировавших копий (операция, а не постоянное поведение). - **Не затрагивается:** серверная модель версий/идентичности, дедупликация вложения, чистка кэша альбома на телефоне (пустые плитки удалённых фото — отдельная задача), доверие к метаданным MediaStore при кэшировании хешей (сверка контрольной суммы закрывает риск).