Commit Graph
116 Commits
Author SHA1 Message Date
av 6001f21a60 docs: вычитка текста, написанного при подъёме канона
- «общий станок» заменён прямым называнием: гейт один на все задачи
- «отсутствие лимита» → «лимита нет», как тот же факт записан в database.md
2026-08-09 19:26:37 +03:00
av 69853a96c9 docs: разобран урожай судей после подъёма канона
- перечень команд пользователя убран из architecture.md в спеки review и
  state-reconciliation, где ему дом: обзор успел разойтись с ними в обе стороны
- README перестал дублировать деплой и статус — теперь ссылается на дом
- статус «заведена ли задача под пробел» сведён в один регистр открытых вопросов
- шаги tasks.py и openspec.py названы в перечне «что красит безусловно»
- из спеки download-tracking сняты числа умолчаний: их дом — database.md
2026-08-09 19:24:59 +03:00
av c5d62d76ee docs: канон поднят с версии 7 до 12
- каталог задач переехал в tasks/ в корне, спринт упразднён — приоритет
  теперь порядок строк в BACKLOG.md, четыре задачи набора вернулись в беклог
- гейт: путь docs.py переведён на av-dev-docs вместо снесённого av-dev-pm,
  добавлены шаги tasks.py check и openspec.py check
- относительные ссылки внутри задач и ссылки из docs/ на задачи починены
2026-08-09 19:09:53 +03:00
av 9a624d4e13 tasks: остаток урожая ревью разнесён по домам
- tests-convention: два кандидата про тесты — один стенд чужого API на пакет,
  интеграционный тест обязан утверждать
- convention-candidates: язык вывода в пяти местах без связывающего правила
- quality-review-agents: четыре прохода не сообщили потолок находок —
  первый замер калибровки
2026-08-07 17:09:52 +03:00
av 397f8aa2c3 tasks: два дефекта из ревью tvdb-title-locale взяты в спринт
- metadata-title-sanitize: название из метабазы подставляется в план мимо
  санитизации и уезжает в имя каталога дословно
- long-title-to-review: имя длиннее ~237 байт роняет раскладку в failed
  вместо отправки на ревью
2026-08-07 17:03:59 +03:00
av 1d375f55ba закрыта задача tvdb-title-locale
- вопрос о неподтверждённой форме ответа TVDB вынесен разведкой
  tvdb-search-response-live-check: закрытие задачи стёрло бы его вместе с файлом
2026-08-07 15:17:29 +03:00
av fdbc781197 metadata: TVDB отдаёт локализованное название и оригинал
- локаль из [general].language применяется при разборе ответа /search, а в
  запрос не уходит: параметр language у TVDB — фильтр выдачи, а не селектор
  перевода (ADR-2026-08-07)
- Title берётся из блока translations с тотальным фолбэком на primary name,
  OriginalTitle — из primary name; форма ответа сверена по документации и
  живым прогоном не подтверждена (docs/research)
- неожиданная форма ответа даёт WARN: признак — отсутствие во всей выдаче
  ключей языка ожидаемого вида, а не неудача разбора блока
2026-08-07 15:17:05 +03:00
av 0c83385098 tasks: заведена задача про конвенцию тестов
- tests-convention: разобрать кандидатов пункта «Тесты» и записать
  docs/conventions/tests.md, четыре критерия приёмки с оракулами
- пункт «Тесты» снят из convention-candidates и заменён ссылкой, чтобы
  не жить вторым домом
2026-08-07 13:48:01 +03:00
av a47a767691 docs: документы дополнены материалом для ревью
- review.md: заведён род узла «вызов LLM и разбор ответа», добавлены вопросы
  тем autotests, security и operations, маршрут к уже механизированному
- architecture.md: «Открытые вопросы» вместо «пока нет» — восемь областей
  знаемо тонкого устройства со ссылкой на задачу
- security.md: снят указатель на несуществующую задачу про лимит ответа LLM
2026-08-07 13:47:52 +03:00
av b879c049ea docs: документы подняты на канон 7
- review.md переведён на словарь меток: вопросы адресованы темам, триггеры
  профиля стали триггерами метки в три списка, quick/standard/wide → small/
  medium/large, профиль deep упразднён
- openspec/config.yaml переписан по канонической форме: адреса passport и
  CLAUDE.md вместо пересказа правил ревью и конвенций
- разобраны находки doc-consistency и doc-code-drift: исключение инварианта
  сверено со спеками, единая точка времени и таблица classifyErr дополнены,
  MaxTorrentSize получил дом в database.md
2026-08-07 13:01:23 +03:00
av b450ab1fd5 закрыта задача ingest-nits 2026-08-06 18:20:12 +03:00
av d081ef1d30 ingest: закрыты мелочи приёма — вырожденное имя, контракт Result, корреляция add
- имя раздачи нормализуется на границе разбора: вырожденное `-`
  (metainfo.NoName) даёт пустое имя, пробельное схлопывается — сентинел больше
  не доходит ни до контекста распознавания, ни до source_ref, ни до подсказки
  вывода имени
- контракт «на любом пути ошибки приёма результат нулевой» объявлен в ingest и
  удерживается структурно; три транспорта перестали обещать идентификатор,
  которого нет, и коррелируют отказ по request_id
- scoped-логгер загрузки ставится до вызова внешнего сервиса в семи командах
  воркера — записи об отказе qBittorrent и метабаз получили download_id
  и infohash; граница разбора bencode записана в docs/research
2026-08-06 18:20:12 +03:00
av 52615e4e49 review: триггеры профиля отвязаны от затронутого узла
- перечни узлов названы картой мест, где живут правила; ступень поднимает
  новое или изменённое правило, а не правка рядом с ним
- заведён закрытый перечень отсекающих условий: исход, названный дельта-спекой
  поимённо, отсутствие новых сценариев, правка сообщений и тестов, сужение
  существующей нормализации
- записан ориентир частоты: deep — исключение на крупной функциональности,
  задача-уборка идёт в quick или standard даже в узле из перечня
2026-08-06 17:55:29 +03:00
av 5c79fdfffe закрыта задача dismiss-marker-lost 2026-08-06 15:51:35 +03:00
av 0b02a8c224 specs: в state-reconciliation разведены Cancel и Dismiss по состояниям
- требование «Ручное закрытие загрузки» приведено к коду: два пути закрытия,
  error_code на каждом, раскладка поверхностей — описательно, а не SHALL
- уборка своего торрента после отмены названа исключением по состоянию, а не
  по команде; убрана ложная гарантия «данных пользователя не касается»
- в docs/review.md записан проскочивший дефект гарда окна после add и новый
  вопрос проходу adversary про асимметрию признака владения
2026-08-06 15:50:41 +03:00
av 5a8c439899 закрыта задача catched-source-type-refresh 2026-08-06 14:45:01 +03:00
av 30ee598547 download-tracking: требование о re-read source_type приведено к коду
- re-read `source_type` перечитывается под блокировкой после тик-снимка, а
  остаточное окно вывода имени названо известным ограничением с ценой и
  достоверным маршрутом восстановления (ручной шаг + `Retry`, не самоисцеление)
- в `ingest` снята парная ложная гарантия «воркер добавит раздачу файлом»,
  добавлены сценарии на оба окна апгрейда и на недоступные байты `.torrent`
- заведён ADR о том, что при разрыве спека↔код двигается тот, чья формулировка
  сильнее рационали
2026-08-06 14:44:21 +03:00
av f42db0a275 sprint: набран спринт 2026-08-06 под цель распознавания
- в наборе шесть задач: локаль TVDB и confidence-гейт под цель, плюс баги и
  техдолг помимо неё
- взятым дописаны разделы своего типа: «Затрагивает», критерии с оракулами,
  воспроизведение
- решены развилки: оба расхождения код↔спека правятся спекой (и потому стали
  chore), опрос qBittorrent тормозится бэкоффом до минутного потолка
2026-08-06 13:57:33 +03:00
av d2d386945e tasks: выкинуты задачи про сбор базы человеком
- закрыты few-shot на правках человека и eval-харнес с размеченным корпусом:
  направление — тюнинг автоматического распознавания без участия человека
- цель распознавания переписана: точность видна по рабочему потоку, а не по
  фиксированному корпусу
- поправлены ссылки на удалённые задачи в CLAUDE.md, review.md,
  research/README.md и в задаче про confidence-гейт
2026-08-06 13:41:49 +03:00
av 66d39297c5 docs: проект переведён на канон документов версии 4
- каталог задач: PLAN.md → ROADMAP.md с каноническими секциями, все 44
  записи получили тип, заголовки приведены к форме своего типа
- расхождения, найденные судьями канона: исключения инварианта «источник
  неприкосновенен», инвариант про один активный infohash, UTC в logging.md,
  поведение из architecture.md заменено ссылками на спеки
- триггеры профиля ревью переписаны под умолчание standard
2026-08-06 13:32:06 +03:00
av 905a1ee4d3 backlog: добавлена задача про локаль названий TVDB
- [general].language доезжает только до TMDB и промпта LLM: клиент TVDB читает
  primary name и отдаёт название на языке оригинала
- в охвате также OriginalTitle, который TVDB не заполняет вовсе
2026-08-06 12:49:45 +03:00
av a4f5faae47 docs: ADR о переезде конвейера ревью в плагины
- Заведена запись ADR-2026-08-04: пайплайн и ревью переехали в
  av-dev-pipeline и av-dev-pm, причина — расхождение копий между
  jellybit и healthlog и переиспользуемость пайплайна.
- Упразднение прохода idiom записано отдельным последствием со ссылкой
  на «Перестали проверять сознательно» в docs/review.md.
2026-08-04 09:32:52 +03:00
av 42d5b73a04 docs: перевод документации на канон av-dev
- Раскладка docs/ приведена к канону 2: заведены passport/architecture/
  database/security/review и research; docs/specs, drafts, backlog, review/
  и BRIEF.md разобраны и удалены, беклог переехал в docs/tasks (34 задачи,
  6 целей, слаги на английский).
- Нарративы specs удалены как дубли openspec-спек после поимённой сверки;
  остаток заведён задачами (редактор маппинга ревью, крайние случаи
  именования), отказ от сущности title промоутнут в ADR.
- Проектные копии агентов и скиллов ревью/пайплайна удалены в пользу
  плагинов av-dev-pm и av-dev-pipeline; в task gate добавлен шаг canon
  вместо er-schema.
2026-08-04 09:27:26 +03:00
av 08bef2cac0 deploy: переход на локальную сборку образа и доставку docker save/load
- task image принимает BUILD_ID и тегает <app>:$BUILD_ID (контракт роли app_image в umbar)
- добавлен ADR-2026-07-24-local-image-build, старый docker-deploy помечен superseded
- README/architecture/roadmap/Dockerfile обновлены под новую схему (без сборки на сервере)
2026-07-24 18:33:51 +03:00
av 8309ce0664 backlog: хуки индекса по правилу «состояние-остаток-боль»
- переписал 21 хук: обрезанные первые абзацы и пустые «ИДЕЯ» → боль/остаток
- убрал дублирующее «ИДЕЯ (…)» в началах тел 5 идей (тип кодирует префикс [idea])
2026-07-24 09:44:38 +03:00
avandClaude Opus 4.8 91db7b8393 backlog: тип задачи — английские ключевые слова idea/epic/task
Тип стал токеном команд скилла (`--type idea|epic|task`, префикс
`[idea]`/`[epic]` в заголовке), поэтому по-честному он английский, как и
прочие идентификаторы. Мигрированы 5 спекулятивных задач с `[идея]` на
`[idea]` (файлы + строки индекса + преамбула). Текст задач остаётся
русским.

Заодно две правки заголовков индекса под согласованность с `backlog.py
check` (catched-source-type, dobavlenie-edinoe-okno).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 21:26:28 +03:00
avandClaude Opus 4.8 2ec952c810 backlog: интеграция скилла ведения беклога
Беклог теперь ведётся пользовательским скиллом `backlog` (заведение из
диалога, разбор находок ревью, груминг, приоритизация, декомпозиция,
штурм). CLAUDE.md делегирует ему формат и держит только проектные
тонкости; добавлены источники задач (диалог, Tududi, находки ревью) и
кладбище `docs/backlog/CLOSED.md` для выкинутого без реализации.

- task-pipeline: шаги 1 и 9 больше не описывают формат сами, ссылаются на
  скилл; шаг 9 гоняет `backlog.py check` после удаления файла задачи.
- review-pipeline: отложенная реальная находка (не для текущего мерджа)
  заводится задачей через скилл с тегом партии review-ГГГГ-ММ-ДД.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 21:26:11 +03:00
avandClaude Opus 4.8 89b3285b5a конвенции: убрать из CLAUDE.md пересказ механизированных правил
Одно и то же жило в трёх местах: docs/conventions, openspec/config.yaml и
CLAUDE.md, который читается каждую сессию. Механизируемое теперь одной строкой
со ссылкой на гейт, прозой — только то, что правилом не выражается.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 18:19:25 +03:00
avandClaude Opus 4.8 534572dc9c доки: ADR о переработке конвейера ревью и обновление беклога
ADR фиксирует «почему»: recall чек-листа равен его длине, ценность верификатора
определяется оракулом и декорреляцией с автором (а не числом ролей), отчёт без
границ покрытия хуже отсутствия отчёта.

В беклоге закрыт открытый вопрос «дробить ли review-code на узкие оптики» — не
дробим; осталась калибровка проходов и ревьювер наименований.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 18:18:23 +03:00
avandClaude Opus 4.8 2fb533e0e6 ревью: скилл review-pipeline — стадии, профили, контракт находок, храповик
Конвейер собран по типу проходов, а не по ролям: гейт (детерминированный,
блокирующий) → сверка с дельта-спеками в обе стороны → generative-проходы →
архитектура → враждебные постановки → обязательный триаж. Профили quick /
standard / deep / design с правилом выбора по факту изменения.

Контракт находок: заголовок через последствие, обязательное поле «Последствие»,
critical без оракула или построенного пути не существует, потолок 7 пунктов и
разметка «инлайн | развилка» — отчёт читает оркестратор и молча реализует
прочитанное, поэтому потолок защищает код от незаказанных правок.

Храповик находка → конвенция → правило → удаление из прозы и промптов; журнал
проскочивших дефектов и калибровка инъекцией с вердиктами keep/retune/drop.
Секция границ покрытия обязательна: отчёт без неё потребляет ощущение
проверенности, ничего не гарантируя.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 18:17:52 +03:00
avandClaude Opus 4.8 612344bab3 конвенции: перенести механизируемое в golangci-lint и internal/archrules
Правило, которое проверяет машина, не должно оставаться прозой: файл конвенций
на сотни строк размазывает внимание по тривиальному — модель добросовестно
проверит именование полей лога и не дойдёт до формы решения.

Включены sloglint (константный msg, стиль ключ-значение), forbidigo (fmt.Print*,
os.Getenv, time.Now мимо store.Now), errorlint (сравнение ошибок), depguard
(сторонние пакеты ошибок). internal/archrules — сканеры на то, что линтером не
выражается: направление зависимостей ядро↔транспорты, AUTOINCREMENT и серверное
время в новых миграциях, матчинг ошибки по тексту.

Код приведён к правилам: logging.StartCall как единая точка отсчёта длительности
внешних вызовов, store.Now вместо time.Now в httpapi и часах воркера,
slog.DiscardHandler в тестах.

Перенесённое вычеркнуто из docs/conventions/* и openspec/config.yaml — прозой
осталось только то, что правилом не выражается.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 18:17:40 +03:00
avandClaude Opus 4.8 1d6f8f3449 review: убрать явный переключатель типа movie↔series из всех транспортов
Кнопка «Тип» была только в Telegram (доменная SetType = жёсткий override
media_type + хинт + перераспознавание), в вебе её нет. Это создавало
расхождение поверхностей и внутреннюю противоречивость спеки review.
Решение: смена типа — редкий случай, для него достаточно «Уточнить»
(перераспознавание с явным указанием типа). Явный переключатель не нужен
ни на одной поверхности.

Снято: Telegram-кнопка и callback type:, worker.SetType, ставший мёртвым
override-плумбинг media_type (ovrMediaType, ветка applyOverrides, хелпер
oppositeType) и стейл-хвосты в тестах httpapi. Спека review — три MODIFIED
требования (запрет на все поверхности, «фиксация типа» убрана из команд и
из быстрых действий Telegram, иллюстрация override заменена на закрепление
источника). Синхронизирован docs/specs/review-ux.md.

Change заархивирован: openspec/changes/archive/2026-07-18-review-remove-type-switch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 16:50:43 +03:00
avandClaude Opus 4.8 f75d6b1f91 tgbot: выбор кандидата метабазы inline-кнопками в карточке ревью
Когда для распознавания сохранены кандидаты метабазы, карточка подтверждения
бота показывает кнопку «🗂 База (N)». По ней двухшагово (как delete/dismiss)
разворачивается список кандидатов inline-кнопками; выбор пиннит источник через
worker.ChooseCandidate (ручной матч, без авто-раскладки) и обновляет карточку.
Веб остаётся точкой точных правок (ручной ввод id/URL, «без базы»).

Безопасность границы: id кандидата из callback_data валидируется как ULID
(ident.Parse) до доменного вызова, как в вебе. Текст inline-кнопок Telegram не
парсится как HTML — название кандидата в подписи не экранируется.

SDD: change telegram-vybor-nahodok — дельта notifications (ADDED «Выбор
кандидата метабазы из карточки подтверждения бота») + review (MODIFIED
«Разделение труда транспортов»: быстрый выбор кандидата — Telegram-действие).
Влито в specs, change заархивирован. Миграций БД нет (кандидаты уже в БД).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 16:02:47 +03:00
avandClaude Opus 4.8 10a6348d39 tgbot: показывать запись матча метабазы (провайдер+id+ссылка)
В карточке подтверждения и уведомлении о готовности бот теперь показывает
запись матча метабазы — провайдер, id и кликабельную ссылку на страницу
записи, — как веб-страница /download/{id} и экран ревью. Так ошибочную
привязку видно и из Telegram.

Билдер URL записи (providerURL/matchURL) вынесен из internal/httpapi в ядро
internal/worker (worker.ProviderURL + метод (*ReviewData).MatchURL()), чтобы
оба транспорта строили ссылку одинаково; httpapi делегирует туда. baseLine
переведён на эффективные provider/id (с учётом ручных правок), URL в href
экранируется escHref (сверх esc закрывает кавычку — иначе изготовленный id
разорвал бы атрибут и Telegram отклонил бы сообщение). При отсутствии матча
карточка ревью показывает «нет матча», уведомление о готовности строку
опускает.

Capability notifications: ADDED «Показ записи матча метабазы» + MODIFIED
требования об экранировании (id матча и URL, контекст href).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 15:41:28 +03:00
avandClaude Opus 4.8 4a58b0bda0 tgbot: download id моноширинным (code) для tap-to-copy
Включён HTML parse mode у всех исходящих сообщений бота (send + edit-путь
refreshCard), download id выводится моноширинным <code> — в клиентах Telegram
по нему работает tap-to-copy (скопировать id для /download/{id} или диагностики).
Префикс # / download_id= остаётся вне <code>, чтобы копировался чистый id.

Parse mode делает разметку значимой для всех текстов, поэтому добавлен
escape-хелпер и экранированы все внешние/недоверенные фрагменты: display name,
распознанное название, источник/контекст, целевой путь, причины, provider,
error_code/error_msg (инвариант «выход LLM недоверенный»). esc применяется
последним шагом, после усечения, чтобы обрез не разрубил HTML-сущность.

Capability notifications: два ADDED-требования (формат id + экранирование).
Беклог: задача закрыта, зонтичный telegram-revyu-uvedomleniy обновлён.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 15:17:26 +03:00
av 85e27b28e2 Добавил задачу про расхождение нумерации в Бибопе 2026-07-18 14:53:12 +03:00
avandClaude Opus 4.8 50f29b56aa Беклог + чистка: две находки аудита в беклог, поправлен устаревший комментарий
Аудит capability после пачки lifecycle-задач вскрыл две пред-существующие
находки (вне scope самих задач) — заведены в беклог:
- catched-source-type-namer-okno (средний): addReq не пересобирается из свежего
  source_type в окне namer'а; самоисцеляется через magnet_timeout→Retry.
- dismiss-cancel-user-dismiss-marker (низкий): веб-UI зовёт Cancel вместо Dismiss
  на не-терминальных, теряется маркер user_dismiss.

Инлайн: finishRecognition — комментарий врал про «Ф3, авто-раскладки нет»;
фактически авто-раскладка идёт при Decision.Auto.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 08:44:36 +03:00
av 659fa5ec44 Слияние: уборка торрента при cancel во время add (T4)
# Conflicts:
#	docs/backlog/README.md
2026-07-17 22:11:53 +03:00
avandClaude Opus 4.8 3a00fde058 Жизненный цикл: уборка торрента при отмене во время добавления (F3/NIT-13)
Отмена задачи (catched→cancelled) в окно, пока worker вне блокировки выводит
имя (LLM) и делает qbt.Add, оставляла добавленный торрент в qBittorrent без
задачи-владельца: PromoteCatched корректно пропускал переход, но источник уже
качался/сидировал вечно, а усыновить его назад нельзя (хеши принадлежат
отменённой задаче). Спека покрывала переход состояния, но не побочный эффект.

Комбинированная защита в processCatched:
- re-read состояния под w.mu прямо перед qbt.Add — при отмене источник не
  добавляется вовсе (сужает окно гонки);
- свежий листинг перед add подтверждает отсутствие infohash — признак «своего»
  торрента; при сбое листинга/присутствии add не делаем (усыновит следующий тик);
- при отмене в окне после add (промах PromoteCatched, подтверждённый re-read'ом
  state != catched) — уборка добавленного нами торрента qbt.Delete(_, true);
- WARN/ERROR-логи по этому пути с корреляцией по download_id, без секретов.

Гарантия «удаляем только своё»: удаление-с-данными достижимо ТОЛЬКО после
подтверждённого отсутствия infohash перед add, поэтому пред-существующий/чужой
торрент с тем же хешем никогда не сносится (негативный инвариант). Обоснование
по инварианту «источник неприкосновенен» — в design.md изменения.

Дельта — download-tracking (требование «Добавление пойманной загрузки в
qBittorrent»): re-read перед add, подтверждение отсутствия, уборка при отмене,
негативный сценарий. Тесты покрывают все ветки (skip-before-add, cleanup после
add, пред-существующий не удаляется, сбой БД не удаляет, сбой листинга не
добавляет).

Change archived: 2026-07-17-cancel-during-add-cleanup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 22:10:21 +03:00
av d02d88f49a Слияние: Defer отклоняет catched, снято мёртвое ребро (T3) 2026-07-17 21:39:41 +03:00
avandClaude Opus 4.8 098695011f Жизненный цикл: Defer запрещён из пре-источникового catched (MAJOR-6)
Команда Defer гардила только IsTerminal() и потому принимала catched
(торрент ещё не добавлен в qBittorrent). Defer из catched уводил задачу
в лимбо → необратимый deleted: processCatched листает только catched и
больше её не подхватывал, а последующие команды через отсутствие
источника выводили deleted (ноль исходящих рёбер), хотя байты .torrent
лежат в download_torrent.

- Worker.Defer отклоняет catched с ErrConflict (транслируется в 409 /
  редирект с сообщением); прочие не-терминальные состояния, где раздача
  уже есть, принимает как раньше.
- Снято мёртвое ребро графа catched → deferred (allowedTransitions);
  инвариант «deferred из каждого не-терминального» уточнён: кроме
  пре-источникового catched. catched — единственное состояние без
  раздачи среди не-терминальных.
- Тесты: Defer из catched отклоняется и не меняет состояние; инвариант
  графа обновлён + негативная проверка ребра.
- OpenSpec: MODIFIED «Команды ревью и их эффекты» (review) с позитивным
  и негативным сценариями; change заархивирован, дельта влита в спеку.
- Беклог: закрыта review-major6-defer-catched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 21:39:01 +03:00
av 91de53b8f1 Слияние: режиссёр в карточке загрузки (T2)
# Conflicts:
#	docs/backlog/README.md
2026-07-17 21:22:35 +03:00
avandClaude Opus 4.8 5948f4d219 Веб-UI: режиссёр в блоке «Распознано как» на странице загрузки
На /download/{id} поле «Режиссёр» было захардкожено прочерком, хотя экран
ревью режиссёра уже выводит: слоистое разрешение полей ярлыка было заперто в
неэкспортируемом worker.effectiveDisplayName. Из-за этого билдеры вью видели
только слой распознавания+матч (rd.Plan.Director) без слоя контекста — то же
на экране ревью.

Вынес разрешение в экспортируемую naming.EffectiveFields(parsedContext, plan)
LabelFields с методом Label(): выбор слоя по сырым значениям (как прежде),
выбранные скаляры возвращаются очищенными (sanitize идемпотентен, display_name
побайтно тот же). effectiveDisplayName стал тонкой обёрткой; страница загрузки
и экран ревью берут режиссёра из той же функции — согласованно с заголовком.

OpenSpec: web-ui (ADDED «Режиссёр в блоке распознавания страницы загрузки»),
review (MODIFIED «Инфо и предпросмотр выбранного источника» — слоистое
разрешение с фолбэком на контекст). Change заархивирован. Беклог: закрыта
rezhisser-v-kartochke-zagruzki.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 21:21:27 +03:00
avandClaude Opus 4.8 1639ebfdd7 Пересканирование Jellyfin: расширить триггер на reverted и deleted
Скан Jellyfin (POST /Library/Refresh) слался только при входе в done.
После Undo (reverted) и Delete (deleted) наши хардлинки сняты, а Jellyfin
держал битые записи до скана по расписанию.

Гейт скана в едином чекпоинте transitionErr переведён с state == done на
предикат triggersScan(state) по множеству {done, reverted, deleted}: гейт по
состоянию-цели естественно ловит пользовательские Undo/Delete и
reconcile-производный deleted, идемпотентно. target_missing/orphaned —
промежуточный рассинхрон (ждём relink/лечения) — исключены.

OpenSpec: заведена и влита дельта file-layout (требование
«Пересканирование Jellyfin после изменения библиотечных ссылок»); change
архивирован. Синк рукописных доков architecture.md/workflow.md. Тесты:
скан стреляет на reverted и deleted, молчит на входе вне множества.
Закрыта задача беклога jellyfin-skan-posle-udaleniya.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 21:14:18 +03:00
avandClaude Opus 4.8 0354a8c96b Беклог: чистка четырёх закрытых задач (mobilnaya-kv, btn-ghost, F7–F10, lifecycle-minor)
Реализованы и влиты; MINOR-9 (I/O под глобальным w.mu) осознанно waived
для one-user home-сервера.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 20:37:58 +03:00
avandClaude Opus 4.8 3e470e3ae6 Беклог: перенос четырёх задач из инбокса Tududi
Инбокс Tududi разгружен: четыре открытые задачи проекта оформлены файлами
в docs/backlog и помечены выполненными в Tududi.

- режиссёр в блоке «Распознано как» на странице загрузки (средний);
- карточка информации о торренте вылезает за экран на мобильном (средний);
- сигнал Jellyfin после отката и удаления файлов (средний);
- кнопки выглядят как кнопки: btn-ghost и рассогласование весов (низкий).

Каждая задача проверена по коду: все четыре актуальны, ни одну не закрыли
прошлые коммиты. В телах — точки правки, развилки и нужные дельты спек.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 21:02:22 +03:00
avandClaude Opus 4.8 02d4ecc2aa display_name: слоистое разрешение полей + сохранение режиссёра из контекста
Единый источник полей отображаемого имени и один рендер полного ярлыка на
всех путях (старт и «Обновить имя»/авто-перелив). Раньше старт давал полный
«Название (режиссёр, год). Сезон N» но выбрасывал структуру, а перелив по
распознаванию — усечённый «Title (Year)».

- Слоистое разрешение скаляров имени: override → recognition(+match) →
  новый базовый слой «контекст» (download.parsed_context, JSON naming.Fields).
- naming: публичные Fields/Label/Derive, вынесен единый рендер; удалён
  FormatTitleYear. Сводка сезонов вынесена в recognize.SeasonSummary.
- Режиссёр из метабазы (решение A2): TMDB/TVDB credits через опциональный
  metadata.DirectorProvider; авто-матч кладёт в plan.Director, ручной выбор
  кандидата тянет credits и пиннит ovrDirector. Метабаза бьёт контекст.
- refreshDisplayNameLocked строит полный ярлык из эффективных полей;
  инфо-панель ревью показывает загруженного режиссёра.
- Миграция 0011_parsed_context + ER-схема. Всё косметика: на пути/раскладку
  не влияет, приём/вывод имени не валятся (best-effort).

Закрывает беклог-задачу «Кнопка „Обновить имя“: полный формат ярлыка».
OpenSpec: archive/2026-07-11-field-resolution-display-name (ingest,
recognition, metadata-match, review).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 11:50:08 +03:00
avandClaude Opus 4.8 9472bfdd83 Спеки+беклог: закрытие батча UI-задач (favicon, cancelled, значок типа, ellipsis, oob-панель)
Реализованное поведение перенесено в openspec/specs:
- web-ui: cancelled скрыт по умолчанию наравне с deleted; значок типа в карточке;
- review: панель действий обновляется oob-фрагментом при свопе источника.
Пять закрытых задач удалены из docs/backlog + индекса.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 09:46:28 +03:00
avandClaude Opus 4.8 c4c0c6bb3f Беклог: груминг трёх задач из Tududi (значок типа, download id code, ревью уведомлений)
Перенос сырых задач проекта jellybit из Tududi в беклог с контекстом и
кросс-ссылками:
- значок типа (фильм/сериал) в списке загрузок;
- download id моноширинным (code) в Telegram — упирается в parse mode + escape;
- зонтичный аудит уведомлений бота.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 09:15:56 +03:00
avandClaude Opus 4.8 e8ce828296 Беклог: полный формат ярлыка «Обновить имя» + скрытие cancelled в списке
- Кнопка «Обновить имя» должна давать формат add-шага (Название (режиссёр,
  год), сезон; всё опц. кроме названия) вместо усечённого «Title (Year)».
- Отменённые (cancelled) скрывать в общем списке наравне с удалёнными;
  тумблер «показать удалённые» раскрывает и cancelled, и deleted.

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