## Критерии приёмки задачи Дословно из `tasks/items/record-ownership.md`. Файл задачи закрытие удалит — критерии обязаны его пережить. - Запрос чужой записи по её идентификатору возвращает «не найдено», а не содержимое и не «доступ запрещён». Оракул — тест: две сессии, задача первой запрашивается второй, ответ 404 и пустое тело. *Расхождение:* «пустое тело» разошлось с нетронутым сценарием спеки, где ответ по неизвестному идентификатору несёт сообщение о ненайденной задаче. Читается как «то же тело, что и у неизвестного идентификатора, и без состояния и текста расшифровки» — иначе реализация по букве критерия молча снимет действующее требование о сообщении. - Запись, заведённая из веба, принадлежит вошедшему. Оракул — тест приёма по HTTP со сверкой колонки владельца. - Выборка воркера владельцем **не** сужается: конвейер обрабатывает записи всех. Оракул — тест: задачи двух владельцев проходят конвейер одним воркером. - База заводится с чистого листа, колонка владельца обязательна и без умолчания. Оракул — прогон миграций на пустой базе и попытка вставки без владельца. **Четвёртый критерий разошёлся с рамками той же задачи** и правится решением человека на чекпоинте: рамки запрещают назначать владельца записям из Telegram, а обязательная колонка такую запись вставить не даст. Разобрано в `design.md`, «Open Questions»; ниже план написан по рекомендованному способу — колонка без умолчания, допускающая пустое значение, обязательность приёма по HTTP держит код. ## Рубрика ревью дизайна — приёмочные критерии Порождена проходом `rubric` до чтения артефактов. Приёмка судится по одному списку: этот блок и блок выше. 1. Чужая запись неотличима от несуществующей на всех наблюдаемых осях: тот же код, то же тело, та же форма ответа. 2. Сужение живёт в одном месте пути чтения и обязательно к употреблению: второго читающего входа, у которого сужение можно не позвать, нет. 3. Пустой владелец на входе чтения не совпадает ни с одной записью — своей, чужой и ничьей. 4. Записи без владельца недостижимы сужённым путём никому, и недостижимость выведена из правила, а не из того, что таких записей мало. 5. Владелец назначается сервером из сессии: поле владельца, пришедшее запросом, на результат не влияет. 6. Владелец появляется в той же операции, что и запись; отказ по отсутствию владельца не оставляет ни задачи, ни файла, и способ этого назван. 7. Неизменность владельца держит механизм, а не обещание: назван каждый путь, которым владельца можно переписать, и что его удерживает. 8. Колонка прочитана всеми четырьмя местами правки колонок очереди плюс шагом схемы. 9. Воркер владельцем не сужается, и это записано нормой, а не оставлено умолчанию. 10. Судьба записи при исчезновении владельца определена. 11. Шаг схемы: одно представление «владельца нет», откат не требует переписывания применённого шага. 12. Проверка владельца и чтение состояния берутся из одного чтения записи, а не двумя раздельными. 13. Ответ отправителю адресуется по источнику записи, а не по владельцу: запись без владельца получает свой ответ в чат. 14. Ни ответ, ни журнал не выдают того, что прячет разграничение; различение чужой и несуществующей в журнале допустимо. ## 1. Схема хранилища - [x] 1.1 Новый шаг схемы `202608140001_record_owner.go`: колонка `owner` в таблице задач связью с коллекцией `users`, без умолчания, пустое значение допустимо, каскадное удаление выключено. Имя колонки — `owner`, поле сущности — `OwnerID`; имена названы здесь, потому что разойтись им есть где — семь мест плюс подпись метода - [x] 1.2 Тем же шагом — колонка `owner` в таблице файлов, теми же свойствами; правило просмотра коллекции файлов сужается владельцем вместо прежнего «всякий вошедший» - [x] 1.3 Тем же шагом — запрет удаления учётной записи, у которой остались задачи: отказ с причиной, а не снятие ссылки - [x] 1.4 Прежние шаги схемы не тронуты — проверяется шагом гейта `migrations` - [x] 1.5 `docs/database.md`: строки колонок в обеих таблицах, правило выборки по владельцу, новое правило просмотра файлов и запрет удаления учётной записи ## 2. Сущность и контракт - [x] 2.1 `internal/entity`: у задачи расшифровки появляется владелец - [x] 2.2 `internal/contract`: читающий метод репозитория задач принимает владельца; второго читающего метода не заводится ## 3. Хранилище задач - [x] 3.1 `applyToRecord` кладёт владельца при заведении - [x] 3.2 `recordToJob` читает владельца - [x] 3.3 `acquireColumns` и `acquiredRow` читают колонку владельца - [x] 3.4 `applyOwnedByPipeline` владельца **не** трогает - [x] 3.5 Чтение задачи сужено владельцем: задача другого владельца и задача без владельца отдают ту же ошибку, что и несуществующая ## 4. Приём и опрос - [x] 4.1 `internal/service`: метод заведения задачи из веба принимает владельца и отказывает при пустом; метод заведения из Telegram владельца не назначает. Владелец кладётся и на файл, заводимый при приёме - [x] 4.2 `internal/controller/http`: приём берёт владельца из предъявленной сессии - [x] 4.3 `internal/controller/http`: опрос готовности передаёт владельца в хранилище и отвечает `404` с прежним телом на чужую и на ничью задачу ## 5. Проверки - [x] 5.1 Тест: две сессии, задача первой запрашивается второй — `404`, тело без состояния и текста - [x] 5.2 Тест: приём по HTTP заводит задачу с владельцем-предъявителем - [x] 5.3 Тест: приём по HTTP без узнанной учётной записи задачи не заводит - [x] 5.4 Тест: задачи двух владельцев и задача без владельца проходят конвейер одним воркером - [x] 5.5 Тест: шаг конвейера, сохраняющий результат, владельца не затирает - [x] 5.6 Тест: миграции на пустой базе заводят колонку без умолчания - [x] 5.7 Тест: чтение с пустым владельцем не отдаёт ни своей, ни чужой, ни ничьей задачи - [x] 5.8 Тест: сессия без учётной записи пользователя получает `403` на приёме, файла и задачи не заводится — узнан, но не запись коллекции пользователей - [x] 5.9 Тест: вошедший просит токен чужого файла — отказ; своего — успех - [x] 5.10 Тест: удаление учётной записи с задачами отвергается, без задач — проходит - [x] 5.11 `task gate` зелёный ## 6. Архивация - [ ] 6.1 На архивации выправить `## Purpose` спеки `access`: преамбула переживает слияние дельт дословно и сегодня утверждает, что разграничения по владельцу нет. Валидатор преамбулу не судит — вспомнить об этом больше некому - [ ] 6.2 Сверить `docs/security.md`, `docs/passport.md` и **`docs/architecture.md`** (строка «Разграничения записей по владельцу здесь нет»): все три обещают закрытие разграничением именно этой задачей. Адрес в `architecture.md` назван отдельно — его нашло ревью, и без него обзор архитектуры отправлял бы следующего читателя чинить уже закрытое