Приём/UI: пачка фиксов границ и парсинга (F7–F10, N2)

Пять независимых bugfix'ов из ревью приёма (docs/backlog/review-f7-f10-ingest-ui-fixes.md):

- F7: oversized .torrent через веб отдавал 500. Введён sentinel
  ingest.ErrTorrentTooLarge, classifyErr транслирует его в 400.
- F8: гонка fast-path attach с cancel. Пред-рид
  FindReingestBlockingByInfohash больше не короткозамыкает активную
  запись — авторитетное дедуп-решение принимает CreateDownloadIfNoActive
  под BEGIN IMMEDIATE; короткозамыкание оставлено только для терминальных
  desync-записей (target_missing/orphaned). F6-апгрейд сохранён.
- F9: magnet — регистронезависимый URN-префикс xt (RFC 2141);
  tgbot.ParseMessage срезает хвостовую пунктуацию, приклеенную жадным
  matchем.
- F10: cap контекста до 16 KiB в ingest.Ingest (единственное место
  слияния — покрывает все транспорты), рунобезопасная обрезка + маркер.
- N2: httpapi.shorten режет по рунам, не байтам — кириллица не рвётся в
  U+FFFD.

Добавлены юнит-тесты на каждое исправленное поведение.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
av
2026-07-17 20:35:14 +03:00
co-authored by Claude Opus 4.8
parent 17d9f23630
commit b8017d65eb
9 changed files with 244 additions and 15 deletions
+20
View File
@@ -140,3 +140,23 @@ func TestIndexCardMeta(t *testing.T) {
t.Error("контекст всё ещё показан в карточке списка")
}
}
// N2: shorten режет по рунам, не байтам — кириллица (2 байта/руна) не рвётся
// посреди символа в U+FFFD.
func TestShortenRuneSafe(t *testing.T) {
// 50 кириллических рун (100 байт). Обрезка до 40 рун раньше резала s[:40]
// посреди руны.
s := strings.Repeat("я", 50)
got := shorten(s, 40)
if strings.ContainsRune(got, '') {
t.Errorf("обрезка порвала руну: %q", got)
}
// 40 рун + многоточие.
if want := strings.Repeat("я", 40) + "…"; got != want {
t.Errorf("shorten = %q, want %q", got, want)
}
// Короткая строка (по рунам) возвращается как есть, без многоточия.
if got := shorten("привет", 40); got != "привет" {
t.Errorf("короткая строка изменена: %q", got)
}
}