## Критерии приёмки задачи

Дословно из `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`
      назван отдельно — его нашло ревью, и без него обзор архитектуры отправлял
      бы следующего читателя чинить уже закрытое
