layout: непомещающееся целевое имя уводит задачу в review вместо failed
- предел длины компонента (255 байт) проверяется в BuildLinks до первой операции с ФС: ни каталога, ни ссылки при отказе не создаётся - причина пустого предпросмотра считается на показе (ReviewData.PreviewError) и печатается в панели действий и в карточке Telegram: у задачи без записанной причины взять её больше неоткуда
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
# Ревью изменения `long-title-to-review` — триаж
|
||||
|
||||
Отчёт агента `review-triage`. Записан оркестратором: харнесс блокирует запись
|
||||
файлов подагентами.
|
||||
|
||||
## Сводка
|
||||
|
||||
- **Размер:** 9 изменённых файлов (+180/−5) плюс новый
|
||||
`internal/layout/name_length_test.go`. Продуктового кода ~47 строк.
|
||||
- **Метка:** `medium`, назначена человеком; разметчик дал `small`. Режим — по графу.
|
||||
- **Сигнал о заниженной метке:** от `review-code` — «`medium` адекватна, `small`
|
||||
был бы занижен: дифф трогает четыре слоя». Триаж поддержал основанием, которого
|
||||
сам сигнал не назвал: код причины `name_too_long` оседает в
|
||||
`downloads.error_code` и обратной правкой после мерджа не откатывается.
|
||||
- **Гейт:** зелёный целиком, подтверждён `autotests` независимо; ни одного `SKIP`,
|
||||
`-race` реально прогонялся.
|
||||
- **Находок на вход:** 14 плюс 1 promote-кандидат. **Осталось:** 5 (2 блокируют,
|
||||
3 к исправлению), 3 понижены в гипотезы, 2 promote.
|
||||
|
||||
### План разметки с исходом
|
||||
|
||||
| тема | дом | глубина | кто закрывает | исход |
|
||||
|---|---|---|---|---|
|
||||
| requirements | `openspec/specs/` + дельты | разбор | specs | закрыта, 3 находки |
|
||||
| autotests | `CLAUDE.md` → «Гейт» | — | autotests | закрыта, находок нет |
|
||||
| conventions | `docs/conventions/` | разбор | code | закрыта, 5 находок (склеены в 3) |
|
||||
| architecture | `docs/architecture.md` | разбор | basics | закрыта, 1 находка |
|
||||
| security | `docs/security.md` | разбор | basics | закрыта, находок нет |
|
||||
| operations | `docs/architecture.md` → «Эксплуатация» | разбор | basics | закрыта, 3 находки |
|
||||
| темы проекта | — | — | — | своих тем нет |
|
||||
|
||||
Тем без отчёта нет.
|
||||
|
||||
## Блокирует мердж
|
||||
|
||||
### 1. На самом вероятном входе экран ревью не называет причину и теряет «Применить»
|
||||
|
||||
- Файл: `internal/worker/review.go:1085-1095`, `:240`,
|
||||
`web/templates/partials/review_main.html:79`
|
||||
- Severity: major. Confidence: high.
|
||||
- Оракул: два дерева (`git archive HEAD` против того же среза с наложенным
|
||||
`git diff HEAD`), один вход — задача в `review` без записанной причины,
|
||||
название `strings.Repeat("ы", 200)`:
|
||||
|
||||
```
|
||||
HEAD: preview_links=2 (HasLinks=true) → «Применить» показана
|
||||
Apply → failed, msg=970 байт "…file name too long"
|
||||
рабочее дерево: preview_links=0 (HasLinks=false) → формы /apply нет
|
||||
StateError="" → «Подтверди источник…»
|
||||
```
|
||||
|
||||
- Последствие: путь «распознавание без подтверждённого матча → `review`» —
|
||||
штатный и самый частый вход в ревью. На нём экран советует подтвердить
|
||||
источник, который ни при чём. Изменение, чья цель «человек узнаёт причину», на
|
||||
этом входе делает диагностируемость хуже, чем была.
|
||||
- **Действие: развилка.** Сюда же сняты два спутника той же причины: текст
|
||||
печатается дважды (баннер + панель) и после смены источника в панели остаётся
|
||||
причина от плана, которого больше нет.
|
||||
- Найдено проходами: `specs`, `basics`; склеено триажем.
|
||||
|
||||
**Отработано:** причина пустого предпросмотра считается на показе и приезжает
|
||||
отдельным полем (`ReviewData.PreviewError`), панель предпочитает её записанной.
|
||||
Человек выбрал вариант (а) на повторном чекпоинте.
|
||||
|
||||
### 2. Карточка Telegram в `review` не называет причину вовсе
|
||||
|
||||
- Файл: `internal/tgbot/render.go:70-95`, `internal/tgbot/bot.go:396-415`
|
||||
- Severity: major. Confidence: high.
|
||||
- Оракул: рендер карточки на рабочем дереве, задача в `review` с записанной
|
||||
причиной `name_too_long` и пустым предпросмотром — упоминает причину `false`,
|
||||
кнопки «Применить» нет. Контроль: та же причина в состоянии `failed` (исход до
|
||||
изменения) печатала текст и давала кнопку «Повтор».
|
||||
- Последствие: владелец видит «Нужно подтверждение» без плана, без кнопки и без
|
||||
слова о длине имени. `proposal.md` обещал обратное; `docs/architecture.md` →
|
||||
«Единые точки» называет обе границы трансляции, обновлена была одна.
|
||||
- **Действие: развилка.**
|
||||
|
||||
**Отработано:** карточка печатает причину для любого случая (вариант (а)), плюс
|
||||
своя ветка ответа в колбэке, как у коллизии.
|
||||
|
||||
## Стоит исправить сейчас
|
||||
|
||||
### 3. Штатный отказ краснит логи как сбой, и три предписанных реестра о новой ветке не знают
|
||||
|
||||
- Файл: `internal/worker/worker.go:962-968`, `docs/conventions/errors.md:81-97`,
|
||||
`docs/database.md:210-214`
|
||||
- Severity: minor. Confidence: high.
|
||||
- Оракул: прогон ручного `Apply` с логгером Debug — `level=ERROR msg="command
|
||||
failed"`. `docs/conventions/logging.md:154` относит штатный конфликт к `DEBUG`
|
||||
и ставит `layout.ErrCollision` поимённо.
|
||||
- **Действие: инлайн.** **Отработано** целиком: `logCmd`, таблица `errors.md`,
|
||||
блок констант `database.md`, клауза 409 в дельте `review`.
|
||||
|
||||
### 4. Текст причины несёт непомещающееся имя целиком — 494 байта
|
||||
|
||||
- Файл: `internal/layout/name.go:29-31`
|
||||
- Severity: minor. Confidence: high.
|
||||
- Оракул: `Apply` с названием `strings.Repeat("ы", 200)` → `msg_len_bytes=494`.
|
||||
- **Действие: инлайн.** **Отработано:** имя усекается серединой (`shorten`, 40
|
||||
рун), точная длина остаётся числом.
|
||||
|
||||
### 5. Два сценария дельты не проверены ничем; комментарий у теста границы описывает не тот вход
|
||||
|
||||
- Файл: дельта `file-layout`, `internal/layout/name_length_test.go:109-113`
|
||||
- Severity: minor. Confidence: high.
|
||||
- **Действие: инлайн.** **Отработано, и по одному из сценариев — не так, как
|
||||
предлагал триаж.** Попытка написать тест на «унаследованную базу» показала, что
|
||||
случай **недостижим**: папка-якорь лежит на диске и потому ≤ предела, а хвост
|
||||
имени файла (11 байт) не длиннее хвоста имени папки (≥ 11 байт). Сценарий
|
||||
переписан на верное утверждение, свойство закреплено тестом
|
||||
`TestApply_InheritedBaseAtLimitStillFits`. Комментарий у границы исправлен,
|
||||
кириллическая граница добита.
|
||||
|
||||
## Гипотезы без доказательства
|
||||
|
||||
- Тупик с унаследованной базой не назван в тексте причины (`basics`, B-4).
|
||||
**Снято разбором:** случай недостижим, см. находку 5.
|
||||
- Рубрика R6 в `tasks.md` противоречит сценарию S6 дельты. **Снято:** после
|
||||
переписывания сценария противоречия нет.
|
||||
- Панель печатает любой `error_msg` без разбора кода, включая сырые тексты ошибок
|
||||
хранилища. Не отработано: тот же текст уже печатал баннер до изменения, нового
|
||||
канала не появилось.
|
||||
|
||||
## Promote candidates
|
||||
|
||||
- **Язык текстов sentinel-ошибок:** русский у тех, что уходят на операторскую
|
||||
поверхность, английский у прочих; правила в `docs/conventions/errors.md` нет.
|
||||
- **Внешний текст в персистентной диагностике — только усечённым.** В проекте
|
||||
есть и `shorten`, и `naming.truncate`, но правила «то, что уезжает в
|
||||
`error_msg`, усекается на границе» нет; отсюда находка 4.
|
||||
|
||||
## Границы покрытия
|
||||
|
||||
**Что запускалось.** Метка `medium`, режим по графу: `autotests`, `specs`,
|
||||
`code`, `basics`, `triage`. Ревью дизайна (`specs` + `rubric`) отработало
|
||||
отдельным чекпоинтом до кода.
|
||||
|
||||
**Что не запускалось и почему.** Всё, что требует запуска — построенные пути
|
||||
атаки, замеры под нагрузкой, эксплуатационный постмортем, — даёт только метка
|
||||
`large`. Живые qBittorrent, LLM, метабазы и Telegram не трогались; рабочая БД не
|
||||
трогалась.
|
||||
|
||||
**Чего не мог каждый проход.** `autotests` — отличить исполнение строки от её
|
||||
проверки. `specs` — судить о качестве распознавания. `basics` на `medium` —
|
||||
строить пути и снимать замеры. `code` — сверять с руководствами по стилю языка.
|
||||
Триаж — находить новое: он работает с чужими выводами.
|
||||
|
||||
**Потолки проходов.** Ни один проход не сообщил ни своего потолка, ни числа
|
||||
находок за срезом. Это находка о прогоне: по молчанию нельзя отличить «показал
|
||||
всё» от «показал верхушку».
|
||||
|
||||
**Не проверялось никем.** Решения проекта (`docs/adr/`) и записанные наблюдения
|
||||
(`docs/research/`) — процессные документы, прогон их не открывает; расхождение с
|
||||
записанным решением ловит `av-dev-docs:healthcheck`. Поимённая сверка с
|
||||
руководствами по стилю Go никем не задавалась. Альтернативной реализации, с
|
||||
которой можно сдиффить решения, у конвейера нет.
|
||||
|
||||
**Осталось на человеке.** История инцидентов на umbar; поведение SQLite под
|
||||
реальным объёмом; завязка внешних потребителей на текущее поведение; суждение
|
||||
«этой функциональности не должно существовать»; качество распознавания;
|
||||
идиоматичность Go (проход упразднён 2026-08-04).
|
||||
Reference in New Issue
Block a user