Files
ds-galo/Отчёты об изменениях/2026-10-21-изменения-без-спецификаций.md
T

13 KiB
Raw Permalink Blame History

Отчёт: изменения, сделанные без спецификаций

  • Дата: 2026-10-21
  • Диапазон: 45a953f^..eb2d478 — 21 коммит, 2026-10-20 — 2026-10-21
  • Ветка: develop
  • Предмет: правки веб-интерфейса просмотра и нового инструмента «Свет» (редактирование фото), сделанные без обновления спецификаций OpenSpec
  • Результат: спеки дописаны (748143c), заведено изменение fix-copy-edit-variant-sharing

1. Метод

  1. Разобран диапазон коммитов 45a953f^..eb2d478: для каждого проверено, затронул ли он openspec/specs.
  2. Для коммитов без спек — прочитаны затронутые участки кода (frontend/src/lib/components/Viewer.svelte, PhotoEditPanel.svelte, PhotoPanel.svelte, frontend/src/lib/edit.ts, backend/internal/photos/worker.go, store.go, sqlite_store.go).
  3. Сопоставлено фактическое поведение с текстом существующих требований ui-workspace, media-objects, photos, dev-make-workflow.
  4. Каждое найденное расхождение зафиксировано как требование (SHALL) со сценариями WHEN/THEN; после правок спеки проверены openspec validate --specs.

2. Сводка

Показатель Значение
Коммитов в диапазоне 21
Из них со спеками 11
Из них без спек 10
Затронутых спецификаций 4 (ui-workspace, media-objects, photos, dev-make-workflow)
Новых требований 3 («График тональной кривой», «Навигация в зуме», «Сборка WASM-модуля фильтров»)
Уточнённых требований 6
Новых сценариев 12
Ошибок валидации 0 (23 passed, 0 failed)

3. Покрытие по коммитам

Коммит Изменение Где описано
45a953f скрытие боковых панелей, хоткеи размера миниатюр ui-workspace → «Скрытие боковых панелей» (уже было)
50b9983 размер миниатюр не меняется при скрытых панелях там же, сценарий «Размер миниатюр при скрытых панелях»
35f8439 зум клавишами + / - ui-workspace → «Зум в просмотре» (уже было)
0a9e527 лента миниатюр следует за текущим фото уже было
961dff1 Ctrl+F — полноэкранный режим приложения уже было
afaaaab офлайн-режим с кешем эскизов и превью ui-workspace → «Офлайн-режим веб-приложения» (уже было)
0548b1a вкладка «Редактирование», инструмент «Свет» ui-workspace → «Вкладка «Редактирование»» (уточнено)
cd3d17c правки применяются сразу; вкладка не сбрасывается при обновлении фото уточнено: «Обновление фото SHALL сохранять открытую вкладку панели»
6d3d7cb ускорение рендера правок в 9 раз сознательно не специфицировано (внутренняя оптимизация)
4d2069d, 520886a клиентский рендер правок, WASM-фильтры «Фильтры считаются в браузере» (уже было)
2adcb13 предпросмотр правок работает и без зума уточнено: «Правки видны сразу — и во вписанном виде, и в зуме»
500ec10, f8ee937 починка зума, центрирование «Зум в просмотре»: Space = 100% от оригинала по центру кадра
b2a509f в зуме стрелки панорамируют фото новое требование «Навигация в зуме»
2668d87 искажение цветов в предпросмотре уже было (сценарий про сверку с эталоном)
d904b2f невидимая линия тональной кривой сознательно не специфицировано (багфикс)
b64574b гистограммы каналов в редакторе кривой новое требование «График тональной кривой»
48ed0bb гистограмма пересчитывается при правке там же, сценарий «Живая гистограмма»
332f35b, eb2d478 сворачивание блока «Кривая», свёрнут по умолчанию там же, сценарий «Сворачивание кривой»
520886a сборка WASM-модуля фильтров (npm run wasm, cargo) dev-make-workflow → новое требование «Сборка WASM-модуля фильтров»
520886a, worker.go роли объектов edit, edit_thumb, edit_medium, edit_preview media-objects → «Журнал объектов» + сценарий «Привязка отредактированной версии»
worker.go отдельная очередь рендера правок (edit_jobs) media-objects → «Генерация вариантов» + «Рендер правок не блокирует варианты»
worker.go рендер правок по исходному объекту photos → «Неразрушающее редактирование фотографии» + «Рендер по оригиналу»

4. Новые и уточнённые требования

Новые требования:

  • ui-workspace → «График тональной кривой»: гистограмма каналов, живой пересчёт, добавление и перетаскивание точек, сворачиваемый блок «Кривая» (по умолчанию свёрнут, кнопки выбора канала остаются доступными).
  • ui-workspace → «Навигация в зуме»: клавиши-стрелки панорамируют фото и не переключают соседние снимки, переключение остаётся за мышью и кнопками у краёв.
  • dev-make-workflow → «Сборка WASM-модуля фильтров»: Rust-исходники в frontend/wasm/light, обновление модуля перед сборкой статики, откат на готовый модуль из репозитория, если cargo недоступен.

Уточнённые требования:

  • ui-workspace → «Вкладка «Редактирование»»: добавлено сохранение вкладки при обновлении фото; предпросмотр правок работает в любом режиме просмотра.
  • ui-workspace → «Зум в просмотре»: Space показывает 100% от оригинала по центру кадра.
  • media-objects → «Журнал объектов»: перечислены роли edit, edit_thumb, edit_medium, edit_preview.
  • media-objects → «Совместные объекты»: уточнено, что отредактированная версия создаётся и привязывается только к фото, чьи правки её породили.
  • media-objects → «Генерация вариантов»: рендер правок идёт в отдельной очереди.
  • photos → «Неразрушающее редактирование фотографии»: рендер идёт по исходному объекту, а не по уменьшенной копии.

5. Что сознательно осталось без спецификаций

Изменение Почему
6d3d7cb — ускорение рендера в 9 раз внутренняя оптимизация, внешнее поведение не изменилось
d904b2f — видимость линии кривой багфикс: требование «кривая показывается» уже было
500ec10 — контейнер прокрутки зума деталь вёрстки, покрыта требованием «Панорамирование»
правки переноса/центрирования внутри f8ee937 описаны пользовательские последствия, а не механизм

6. Найденное расхождение кода и замысла

Store.Clone и SQLiteStore.Clone копируют все привязки photo_objects, включая роли edit*, хотя воркер создаёт edit-объекты с владельцем []string{photoID} и комментирует это так: «The edit belongs to this photo only, so the variants are not shared with the copies of the same original».

Последствия:

Сценарий Фактическое поведение Ожидаемое
Копия до правки копия в исходном виде так и должно быть
Копия после рендера копия показывает отредактированную картинку, но edit_params пусты: в панели правок параметров нет, первая же новая правка перезаписывает обработку с нуля копия в исходном виде

Оформлено как изменение fix-copy-edit-variant-sharing (openspec/changes/fix-copy-edit-variant-sharing/):

  • proposal.md — зачем;
  • design.md — фильтр ролей в Clone вместо правки выдачи URL, единый список edit-ролей, разовая чистка существующих копий миграцией в обоих диалектах;
  • specs/media-objects/spec.md — дельта требования «Совместные объекты»;
  • tasks.md — 4 группы задач (список ролей → копирование → миграции → проверки).

7. Проверка

openspec validate --specs      → 23 passed, 0 failed
openspec validate fix-copy-edit-variant-sharing --type change → valid

8. Реализация fix-copy-edit-variant-sharing

Изменение реализовано полностью (9/9 задач):

Что Где
Общий список edit-ролей EditRoles() и предикат IsEditRole() backend/internal/photos/edit_render.go
Clone не переносит edit-привязки (Postgres: role <> ALL($3::text[])) backend/internal/photos/store.go
То же для SQLite (role NOT IN (...)) backend/internal/photos/sqlite_store.go
Сброс правок использует общий список ролей backend/internal/photos/edit_service.go
Разовая чистка копий, созданных до фикса backend/migrations/000016_*.sql, backend/migrations/sqlite/000008_*.sql
Контрактная проверка копирования (оба хранилища) backend/internal/repo/contract/contract.go, кейс Clone
Сервисные тесты: копия и миграция backend/internal/photos/copy_test.go, backend/internal/e2e/copy_edit_test.go

Проверки:

  • make test (с Postgres) — весь бэкенд зелёный;
  • контрактный кейс Clone проходит на SQLite и Postgres; без фикса он падает («clone shares the edited version»);
  • e2e на SQLite: копия показывает исходник, edit_params пусты, миграция убирает «чужие» привязки, не трогая привязки владельца;
  • ручная проверка через HTTP и браузер: в просмотре копии грузится thumb.webp (не edit_preview), все ползунки панели «Редактирование» в нуле.

9. Что дальше

  • Ревью и архивация изменения /opsx-archive — дельта media-objects переедет в основную спеку.
  • Изменение требует Postgres для полного прогона: в этом окружении поднимался временный контейнер postgres:16-alpine на порту 55432 (TEST_DATABASE_URL='postgres://postgres:postgres@127.0.0.1:55432/galo?sslmode=disable').