chore(openspec): архивировать fix-album-sync-churn-and-degradation и синхронизировать спеки

В спеку phone-album-sync добавлены требования о роли локального файла,
подтверждении новой версии до удаления устаревшей и разгрузке без
незавершённой загрузки; уточнены синхронизация изменений, провенанс и
возврат оригиналов.
This commit is contained in:
iu
2026-10-20 20:35:52 +03:00
parent 2e3728d83d
commit 3a44844ff9
6 changed files with 89 additions and 4 deletions
+89 -4
View File
@@ -74,8 +74,9 @@
Для каждого отслеженного изменения приложение SHALL применить его к целевому Для каждого отслеженного изменения приложение SHALL применить его к целевому
серверному альбому: загрузить новое содержимое, переименовать и перенести через серверному альбому: загрузить новое содержимое, переименовать и перенести через
API, а изменение содержимого SHALL трактовать как новую загрузку с удалением API. Изменение содержимого SHALL трактоваться как новая загрузка, а устаревшая
устаревшей собственной загрузки. собственная загрузка SHALL удаляться после подтверждения новой версии и SHALL NOT
удаляться из-за смены локальной роли файла (оригинал ↔ превью).
#### Scenario: Новое содержимое #### Scenario: Новое содержимое
@@ -90,7 +91,36 @@ API, а изменение содержимого SHALL трактовать к
#### Scenario: Изменение содержимого #### Scenario: Изменение содержимого
- **WHEN** содержимое медиа изменено на устройстве - **WHEN** содержимое медиа изменено на устройстве
- **THEN** приложение загружает новую версию, а устаревшую собственную загрузку удаляет - **THEN** приложение загружает новую версию и после её подтверждения удаляет устаревшую собственную загрузку
### Requirement: Подтверждение новой версии до удаления устаревшей
Устаревшая собственная загрузка элемента SHALL удаляться только после подтверждения новой
версии: сообщённая сервером контрольная сумма принятого объекта SHALL совпадать с
отправленной. При расхождении приложение SHALL отклонить загрузку, удалив принятую копию, и
SHALL NOT считать элемент загруженным. Если сервер контрольную сумму не сообщил, загрузка
SHALL считаться состоявшейся, но устаревшая копия SHALL NOT удаляться, а замена SHALL
повториться при следующей синхронизации.
#### Scenario: Новая версия подтверждена
- **WHEN** новая версия загружена, а сообщённая сервером контрольная сумма совпала с отправленной
- **THEN** приложение удаляет устаревшую собственную загрузку (мягко, в корзину)
#### Scenario: Контрольная сумма не совпала
- **WHEN** сервер сообщил для принятого объекта контрольную сумму, отличную от отправленной
- **THEN** приложение удаляет принятую копию, не считает элемент загруженным и оставляет прежнюю серверную копию в альбоме
#### Scenario: Контрольная сумма не сообщена
- **WHEN** сервер не сообщил контрольную сумму принятого объекта
- **THEN** загрузка считается состоявшейся, прежняя серверная копия остаётся в альбоме, а замена повторяется при следующей синхронизации
#### Scenario: Загрузка не удалась
- **WHEN** загрузка новой версии завершилась ошибкой
- **THEN** прежняя серверная копия остаётся в альбоме
### Requirement: Идентичность по контрольной сумме ### Requirement: Идентичность по контрольной сумме
@@ -154,12 +184,29 @@ API, а изменение содержимого SHALL трактовать к
- **WHEN** пользователь включает режим переноса - **WHEN** пользователь включает режим переноса
- **THEN** приложение запрашивает широкий доступ к файлам, и разгрузка выполняется без системного диалога согласия - **THEN** приложение запрашивает широкий доступ к файлам, и разгрузка выполняется без системного диалога согласия
### Requirement: Разгрузка без незавершённой загрузки
Приложение SHALL NOT заменять оригинал превью, пока для этого элемента есть незавершённая
загрузка (в очереди или выполняющаяся), чтобы загрузка не отправила превью вместо оригинала.
#### Scenario: Загрузка в очереди
- **WHEN** для элемента есть задание загрузки в очереди или выполняющееся
- **THEN** оригинал на устройстве не заменяется превью
#### Scenario: Загрузка подтверждена
- **WHEN** загрузка элемента подтверждена сервером
- **THEN** приложение выполняет обычную разгрузку в режиме переноса
### Requirement: Провенанс разгруженных превью ### Requirement: Провенанс разгруженных превью
Разгруженные превью, постеры видео и скачанные с сервера элементы SHALL содержать Разгруженные превью, постеры видео и скачанные с сервера элементы SHALL содержать
метаданные провенанса, включая признак происхождения (загружено клиентом или скачано с метаданные провенанса, включая признак происхождения (загружено клиентом или скачано с
сервера), достаточные для восстановления связи с серверным альбомом и принадлежности сервера), достаточные для восстановления связи с серверным альбомом и принадлежности
загрузок после переустановки приложения. загрузок после переустановки приложения. Метка SHALL также служить признаком того, что
локальный файл является созданным приложением превью: элемент с такой меткой SHALL NOT
считаться содержащим оригинал, даже если состояние локального индекса утверждает обратное.
#### Scenario: Восстановление после переустановки #### Scenario: Восстановление после переустановки
@@ -176,6 +223,39 @@ API, а изменение содержимого SHALL трактовать к
- **WHEN** метаданные провенанса недоступны (например, файл перезаписан сторонним редактором) - **WHEN** метаданные провенанса недоступны (например, файл перезаписан сторонним редактором)
- **THEN** элемент считается неопознанным, не удаляется и не загружается повторно - **THEN** элемент считается неопознанным, не удаляется и не загружается повторно
#### Scenario: Метка против состояния индекса
- **WHEN** файл несёт метку созданного приложением превью, а состояние индекса указывает оригинал
- **THEN** элемент считается разгруженным, а не новым оригиналом
### Requirement: Роль локального файла не является содержимым
Приложение SHALL отличать превью, созданное им самим при разгрузке (в том числе по метке
провенанса), от новой версии оригинала: разгруженный элемент SHALL NOT загружаться повторно
и SHALL NOT вызывать удаление серверной копии, а расхождение состояния в локальном индексе
SHALL выправляться. Это SHALL относиться и к постеру, которым в режиме переноса заменяется
видео.
#### Scenario: Разгруженный элемент не создаёт новую версию
- **WHEN** серверная копия элемента есть в целевом альбоме, а на устройстве лежит созданное приложением превью, в том числе если состояние локального индекса ошибочно указывает оригинал
- **THEN** приложение не ставит загрузку и не удаляет серверную копию
#### Scenario: Состояние выправляется
- **WHEN** файл на устройстве является созданным приложением превью, а индекс считает его оригиналом
- **THEN** приложение помечает элемент как разгруженный и последующие проходы не создают загрузок
#### Scenario: Постер разгруженного видео
- **WHEN** видео разгружено (заменено постером под новым элементом MediaStore), а его метка указывает на исходное видео
- **THEN** приложение связывает элемент с серверным фото видео и не удаляет это фото на сервере, а постер не загружается как новое фото
#### Scenario: Настоящее изменение содержимого
- **WHEN** содержимое медиа заменено содержимым, не созданным приложением при разгрузке
- **THEN** приложение загружает новую версию элемента
### Requirement: Возврат оригиналов и отвязка ### Requirement: Возврат оригиналов и отвязка
При выходе из режима C приложение SHALL предложить вернуть оригиналы на устройство При выходе из режима C приложение SHALL предложить вернуть оригиналы на устройство
@@ -215,6 +295,11 @@ API, а изменение содержимого SHALL трактовать к
- **WHEN** пользователь снова включает синхронизацию после выключения - **WHEN** пользователь снова включает синхронизацию после выключения
- **THEN** связь создаётся заново, а восстановление происхождения снова действует по обычным правилам - **THEN** связь создаётся заново, а восстановление происхождения снова действует по обычным правилам
#### Scenario: Возврат устойчив
- **WHEN** оригиналы возвращены на устройство после выхода из режима переноса
- **THEN** приложение не разгружает их повторно, пока альбом не переведён в режим переноса снова
### Requirement: Автоматическая фоновая синхронизация ### Requirement: Автоматическая фоновая синхронизация
Синхронизация SHALL выполняться автоматически в обе стороны: при открытом приложении — Синхронизация SHALL выполняться автоматически в обе стороны: при открытом приложении —