- предел длины компонента (255 байт) проверяется в BuildLinks до первой операции с ФС: ни каталога, ни ссылки при отказе не создаётся - причина пустого предпросмотра считается на показе (ReviewData.PreviewError) и печатается в панели действий и в карточке Telegram: у задачи без записанной причины взять её больше неоткуда
71 lines
5.2 KiB
Markdown
71 lines
5.2 KiB
Markdown
## ADDED Requirements
|
||
|
||
### Requirement: Непомещающееся целевое имя уходит в review
|
||
|
||
Система SHALL отклонять раскладку целиком, если хотя бы один компонент целевого
|
||
пути (папка тайтла, папка сезона, имя файла с расширением и суффиксами) длиннее
|
||
предела, и SHALL переводить задачу в `review` с доменной причиной, а не в
|
||
`failed`. Проверка SHALL выполняться до первой операции с файловой системой: ни
|
||
каталога, ни ссылки при отказе не создаётся. Причина SHALL нести собственный код,
|
||
отличный и от кода коллизии, и от общего кода отказа построения плана, а
|
||
человекочитаемый текст SHALL называть непомещающийся компонент и НЕ SHALL
|
||
содержать текста системной ошибки.
|
||
|
||
Предел SHALL меряться в **байтах** UTF-8-представления имени, а не в символах:
|
||
кириллическое название упирается вдвое раньше латинского той же длины в знаках.
|
||
Величина — **255 байт** (`NAME_MAX` у ext4/xfs/btrfs); она фиксирована и у ядра не
|
||
выясняется, потому что раскладка обязана отказать до обращения к диску. На
|
||
файловой системе с меньшим пределом остаётся сегодняшний исход — отказ ядра и
|
||
`failed`; это осознанный остаток, а не пробел.
|
||
|
||
Проверка длины SHALL выполняться **после** проверки нахождения пути под корнем
|
||
библиотеки: путь, вышедший за песочницу, SHALL отклоняться как выход за
|
||
библиотеку, иначе находка безопасности спряталась бы за косметической причиной.
|
||
|
||
Самостоятельно обрезать или переименовывать название система НЕ SHALL — это
|
||
решение человека.
|
||
|
||
#### Scenario: Слишком длинное имя файла уходит в review
|
||
|
||
- **GIVEN** распознавание даёт название, из которого имя целевого файла
|
||
складывается длиннее 255 байт
|
||
- **WHEN** выполняется раскладка
|
||
- **THEN** задача переходит в `review` с причиной «имя не помещается», ни один
|
||
каталог и ни одна ссылка не созданы, а текст системной ошибки человеку не
|
||
показан
|
||
|
||
#### Scenario: Предел меряется в байтах
|
||
|
||
- **GIVEN** два названия одинаковой длины в знаках — латинское и кириллическое
|
||
- **WHEN** строятся целевые пути
|
||
- **THEN** кириллическое отклоняется вдвое раньше латинского, а граница
|
||
проходит между 255 и 256 байтами
|
||
|
||
#### Scenario: Слишком длинное имя папки тайтла уходит в review
|
||
|
||
- **GIVEN** название укладывается в имя файла, но папка тайтла с годом и
|
||
provider-тегом длиннее предела
|
||
- **WHEN** выполняется раскладка
|
||
- **THEN** задача переходит в `review` с той же причиной, каталог тайтла не
|
||
создан
|
||
|
||
#### Scenario: Выход за библиотеку важнее длины
|
||
|
||
- **GIVEN** целевой путь одновременно выходит за корень библиотеки и длиннее
|
||
предела
|
||
- **WHEN** строятся целевые пути
|
||
- **THEN** отказ называет выход за библиотеку, а не длину имени
|
||
|
||
#### Scenario: Подсказка человека чинит случай
|
||
|
||
- **GIVEN** задача в `review` с причиной «имя не помещается»
|
||
- **WHEN** человек задаёт название короче и применяет раскладку заново
|
||
- **THEN** раскладка проходит штатно и задача переходит в `done`
|
||
|
||
#### Scenario: Унаследованная база в предел помещается всегда
|
||
|
||
- **GIVEN** база имени унаследована от живой папки-якоря по правилу сходимости
|
||
- **WHEN** строятся имена файлов внутри этой папки
|
||
- **THEN** они помещаются в предел, потому что папка-якорь лежит на диске и уже
|
||
не длиннее предела, а хвост имени файла не длиннее хвоста имени папки
|