Files
jellybit/openspec/changes/archive/2026-07-10-refresh-display-name/proposal.md
T
avandClaude Opus 4.8 0c9421f4c1 Имя: восстановление display_name после распознавания + гард пустого входа
Голый magnet без dn/контекста заставлял namer звать LLM на пустом входе,
и модель галлюцинировала мусорное имя («Unknown»), которое писалось и в
display_name, и в rename qBittorrent, а заодно ломало UI-фолбэк на
распознанное название. Верное каноническое имя, вычисляемое позже при
распознавании, никуда не переливалось.

- naming: гард пустого входа в DeriveName (нет контекста и подсказки → ""
  без вызова LLM) + детерминированный форматтер FormatTitleYear.
- qbt: операция RenameTorrent (переименование существующей раздачи).
- store: SetDisplayName — обновление имени постфактум без гарда состояния.
- worker: refreshDisplayNameLocked/RefreshDisplayName — перелив канонического
  имени (эффективный план) в display_name + best-effort rename раздачи по
  реальному t.Hash; авто-триггер при подтверждении матча (choose/manual add).
- web-ui: кнопка «Обновить имя» на странице загрузки (htmx-своп заголовка,
  деградация без JS), видимая при наличии распознавания (вкл. done/orphaned).

Спека: дельты ingest/review/web-ui влиты в openspec/specs; change
refresh-display-name заархивирован.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 16:51:04 +03:00

68 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Why
При бедном первичном приёме (голый magnet без `dn` и без контекста) вывод имени
на шаге добавления зовёт LLM на пустом входе, и модель галлюцинирует мусорное имя
(наблюдалось «Unknown»). Это имя пишется и в `download.display_name`, и в `rename`
qBittorrent, и вдобавок ломает UI-фолбэк на распознанное название (`downloadTitle`
отдаёт непустой `display_name`). Позже распознавание по дереву файлов даёт верное
имя (в наблюдавшемся случае — «Harold and the Purple Crayon», 2024), но это имя
никуда не переливается: и карточка загрузки, и раздача в qBittorrent остаются с
«Unknown».
## What Changes
- **Гард пустого входа при выводе имени.** Если и контекст, и подсказка (`dn`
magnet / имя `.torrent`) пусты, система не зовёт LLM и считает имя не
выведенным (`display_name` остаётся пустым, `rename` не задаётся). Убирает
корень «Unknown» — приём не присваивает имя из пустоты.
- **Обновление имени по подтверждённому распознаванию.** Появляется поведение
«перелить» уже вычисленное каноническое имя (из распознавания / выбранного
кандидата метабазы) в `download.display_name` и в имя раздачи qBittorrent.
Детерминированный формат `Title (Year)` (для сериала — по аналогии с текущим
выводом имени), **без нового вызова LLM** — источник уже сохранён
(`recognition.title/year`, `metadata_candidate.title/year`).
- **Авто:** при подтверждении матча в ревью (выбор кандидата) — согласуется с
инвариантом «авто-действие только при подтверждённом матче».
- **Ручной:** кнопка «Обновить имя» на карточке загрузки.
- **Переименование существующей раздачи в qBittorrent.** Новая операция клиента
qBittorrent `rename` для уже добавленной раздачи (сейчас `rename` действует
только при `add`). Адресация — по infohash своей раздачи.
## Capabilities
### New Capabilities
Нет.
### Modified Capabilities
- `ingest`: требование «Вывод имени через LLM» ужесточается гардом пустого входа
(нет ни контекста, ни подсказки → LLM не вызывается, имя считается не
выведенным). Добавляется требование «Обновление отображаемого имени по
подтверждённому распознаванию» (источник имени, детерминированный формат,
запись `display_name`, переименование раздачи qBittorrent; точки входа — авто
и ручная; политика перезаписи).
- `review`: подтверждение матча (команда выбора/применения кандидата) SHALL
запускать обновление отображаемого имени по подтверждённому распознаванию.
- `web-ui`: на карточке/странице загрузки появляется htmx-действие «Обновить
имя», обновляющее заголовок на месте.
## Impact
- **Код:**
- `internal/naming/naming.go` — гард пустого входа в `DeriveName`.
- `internal/qbt` — новая операция `RenameTorrent(ctx, hash, name)` (`POST
/api/v2/torrents/rename`).
- `internal/store` — метод обновления `download.display_name` пост-фактум.
- `internal/worker` — перелив имени при подтверждении кандидата в ревью.
- `internal/httpapi` — эндпоинт ручного обновления имени + htmx-партиал
заголовка; кнопка в шаблоне карточки/страницы загрузки.
- **Инварианты безопасности данных:** изменение чисто косметическое
(`display_name` + ярлык раздачи в qBittorrent). Пути на диске
(`paths.movies`/`series`), распознавание и раскладка НЕ затрагиваются; rename
адресуется по infohash своей раздачи.
- **БД:** структура не меняется (используется существующий столбец
`download.display_name`); миграция не требуется.
- **Внешние вызовы:** дополнительный вызов qBittorrent `rename` при обновлении
имени (логируется как `ext.service=qbittorrent`). Новых LLM-вызовов нет.