web-ui: добавлена страница группового удаления загрузок

- выбор → поимённое подтверждение → отчёт: пачка до 20 загрузок, гарды входа
  на обеих границах, потолок времени и остановка после трёх подряд отказов
  внешнего сервиса
- допуск полного удаления сведён в единую точку store.State.CanDelete() —
  worker, страница загрузки и Telegram больше не держат своих перечней
This commit is contained in:
av
2026-08-10 17:43:36 +03:00
parent a7c1efd8eb
commit 288be8ec34
35 changed files with 3185 additions and 31 deletions
+52 -2
View File
@@ -179,8 +179,8 @@ Go-сервиса и что здесь уже проскакивало. Устр
- `requirements`: не завелось ли поведение, которого спека не заказывала — тихий
дефолт, проглоченная ошибка, ретрай «на всякий случай», отброшенное поле?
- `security`: читается ли тело ответа внешнего сервиса целиком без предела —
лимита на размер ответа LLM в проекте нет, и это единственный недоверенный
канал, где предел не стоит ([security.md](security.md) → «Что вне модели»)
у LLM (8 MiB) и метабаз (4 MiB) предел стоит, и новый исходящий вызов обязан
заводить свой ([security.md](security.md) → «Что вне модели»)
- `operations`: гарантия, которую вводит изменение, поставлена на запись или на
чтение — и что будет с данными, записанными до деплоя, которые обычный путь
не перезаписывает? (журнал, 2026-08-10: чистка названия стояла на записи, и
@@ -231,6 +231,13 @@ Go-сервиса и что здесь уже проскакивало. Устр
(`internal/metadata`, `metadata-match`); merge-раскладка при повторном
добавлении раздачи.
- **новая поверхность поверх необратимой операции** — вторая точка входа в
команду, которая удаляет файлы или снимает последнюю копию. Форма решения
здесь нащупывается по ходу: подтверждение, порядок отказов, остаток,
наблюдаемость. Выведено по факту на `bulk-delete-page` (журнал, 2026-08-10):
метка `medium` не дала ни враждебного прохода, ни замера, а именно они нашли
четыре дефекта класса «необратимо».
- «Поведение, видимое снаружи» здесь включает **тексты и карточки Telegram**
для единственного пользователя это и есть интерфейс.
@@ -325,6 +332,49 @@ Go-сервиса и что здесь уже проскакивало. Устр
случаи до этой даты не восстанавливались — восстановленная постфактум причина
непоймания недостоверна, а именно она и нужна.
## 2026-08-10 — метка занижена: новая поверхность поверх необратимой операции прошла как среднее знакомое [пойман]
- **Где:** конвейер, а не код — разметка задачи `bulk-delete-page`
- **Симптом:** прогон по метке `medium` закончился шестью находками, из них ни
одной про необратимое. Сигнал «метка, вероятно, занижена» вернули два прохода
из четырёх — `code` и `basics`, с одинаковым основанием: дифф трогает `store`,
`worker`, `httpapi`, `tgbot` и шаблоны и заводит новую точку входа поверх
команды, удаляющей файлы
- **Причина:** обе оси считались по объёму и по знакомости узлов, и по ним
изменение честно выходило средним и знакомым — цикл над готовым `Delete`. Ни
один триггер `large` не описывал случай «поверхность новая, а операция за ней
необратимая»
- **Чем воспроизведён:** повторная разметка после правок дельта-спек вернула
`large`; догнанные проходы дали четыре находки класса «необратимо», из них три
с прогнанными падающими тестами (`TestAdversaryDoneRowIsLastCopyWithoutWarning`,
`TestAdversaryDeleteWipesSourceOfAnotherActiveDownload`) и одна с замером
удержания общего замка воркера (`280.450631ms` при задержке соседа `300ms`)
- **Что меняем:** в «Триггеры метки», ось «незнакомое», добавлен пункт про новую
поверхность поверх необратимой операции
## 2026-08-10 — три дефекта поштучного удаления жили незамеченными, пока рядом не появилась пачка [проскочил]
- **Где:** `internal/worker/review.go` (`Delete`), `internal/worker/worker.go`
(`Poll`)
- **Симптом:** враждебный и эксплуатационный проходы на задаче
`bulk-delete-page` нашли три дефекта, ни один из которых эта задача не
вносила: удаление сносит раздачу, которой владеет **другая активная** загрузка
с тем же инфохэшем; удаление держит общий замок воркера через сетевой вызов и
останавливает фоновую работу на это время; при недоступном qBittorrent задача остаётся `done` весь простой
соседа, потому что сверка возвращается на первой же ошибке и до коррекции не
доходит
- **Причина:** поштучное удаление ни разу не проверялось меткой `large` — ни
построенного пути, ни замера против него не гонял никто
- **Чем воспроизведён:** тесты и замеры перечислены в
`openspec/changes/archive/2026-08-10-bulk-delete-page/review/report.md`,
находки 24
- **Почему не поймали:** проходы, находящие этот класс, живут в метке `large`, а
задачи, заводившие и правившие `Delete`, шли ниже. Дефект не «пропустил
проход» — проход не запускался
- **Что меняем:** три записи в беклоге со ссылкой на оракулы; триггер метки
дополнен (см. запись выше), чтобы следующая поверхность над необратимой
операцией шла сразу с доказательными проходами
## 2026-08-10 — тест остался зелёным навсегда, потому что проверял снятый атрибут [пойман]
- **Где:** `internal/httpapi/live_test.go``TestFragProgressStopsWhenNotDownloading`