From a9327eaa2757917fc1d58fb0a2989e98a0e1b07c Mon Sep 17 00:00:00 2001 From: Ku6epXBOCTuK Date: Mon, 5 Oct 2026 07:13:37 +0500 Subject: [PATCH] docs: review backlog --- docs/backlog.md | 384 ++++++++++++++++++++++++------------------------ 1 file changed, 190 insertions(+), 194 deletions(-) diff --git a/docs/backlog.md b/docs/backlog.md index f186e1d..d0712cf 100644 --- a/docs/backlog.md +++ b/docs/backlog.md @@ -3,64 +3,157 @@ > Статус: **active**. Открытые задачи. Подробные планы, разбор решений и сырые > находки — `docs/plan-seo.md`, `docs/plan-platform.md`, > `docs/plan-fields-audit-fixes.md`, `docs/tools-audit.md`, `docs/decisions.md`. +> +> Все пункты — чекбоксы; нумерация «Идея N» в тексте сквозная по документу и +> сохраняется ради перекрёстных ссылок («идея 4 зависит от идеи 3»). Оценки +> (S/M/L) — оценка труда, не приоритет. -## lint и прочие правила +## Pipeline -- [ ] `tseslint.config(...)` deprecated: сигнатура - `(...configs: InfiniteDepthConfigWithExtends[]): ConfigArray` помечена - устаревшей, нужен переход на `defineConfig` из `eslint/config` (ESLint - core, а не `typescript-eslint`) — `web/eslint.config.js`. -- [ ] удалить мёртвые `tools.*.params` из root i18n после проверки потребителей; - до этого действует pattern-based policy-исключение - (`web/eslint-plugins/README.md`, раздел `dict-consistency`) - -## Мелочи всякие - -- [ ] названия инструментов - сейчас в pipeline инструмент называется "обрезать - png", но он работает с любыми картинками, наверное надо убрать. но в - заголовке - возможно надо все форматы указать (SEO задача?) -- [ ] кнопка добавить инструмент в pipeline - обдумать селектор с номальным +- [ ] названия инструментов — в pipeline инструмент называется «обрезать png», + но он работает с любыми картинками, наверное надо убрать; в заголовке + страницы — возможно, надо указать все форматы (связано с SEO) +- [ ] кнопка «добавить инструмент» в pipeline — обдумать селектор с нормальным поиском, фильтром возможных инструментов и т.д. -- [ ] pipeline - промежуточные результаты -- [ ] pipeline - drag-n-drop инструментов +- [ ] **Идея 1. Заменить инструмент шага без удаления** — оценка M. В заголовке + карточки шага кнопка «поменять инструмент»: заменяет инструмент на месте + (любой шаг, не только первый), остальные шаги и их параметры сохраняются, + вход перечитывается. Открытый вопрос: что делать с несовместимыми входами + (text-source ↔ file). +- [ ] **Идея 2. Сворачивать инструменты в chain** — оценка S. Тоггл сворачивания + звена до заголовка «Шаг n: название» (превью скрываются). Состояние + свёрнутости помнить в workspace-pipeline. +- [ ] **Идея 3. Несколько цепочек: сохранение и загрузка** — оценка M. + Именованные цепочки в localStorage (список, создать/переименовать/ + удалить), быстрое переключение. Формат экспортного JSON расширить + опциональным полем имени; обратной совместимости со старыми выгрузками не + делаем — формат не устоялся: он появится вместе с фазой 11 + `docs/roadmap.md` и до её старта может измениться. Плюс отдельная страница + со списком всех цепочек: удалить, переименовать, добавить новую, + «использовать» (переход на страницу инструмента с этой цепочкой). На + странице — упрощённый вид: только список инструментов цепочки, без + реального выполнения и параметров. +- [ ] **Идея 4. Batch-обработка архивов выбранным chain** — оценка L. Вход — + zip-архив картинок (распаковка в браузере), прогон текущего или выбранного + сохранённого chain по каждому файлу, сборка результата обратно в zip для + скачивания. Зависит от идеи 3 (выбор цепочки) и от экспортного формата + pipeline JSON; прогресс и ошибки — пофайлово. +- [ ] **Идея 15. Набор файлов в пайплайне: 1 → many не должен быть + терминальным** — оценка L. **Сейчас** `execute` принимает один + `source: PixelImage | undefined` и возвращает один `ToolResult`, а + `SchemaToolView` раскладывает вывод в `result` / `fileResult` / + `textResult` по `resultKind` — поэтому шаг с `result: "files"` упирается в + конец цепочки. **Направление:** следующий инструмент применяется **ко всем + картинкам** предыдущего результата (fan-out), а many → 1 (вход = архив или + несколько файлов) — обратная сторона того же контракта. Терминальными + остаются только результаты, которые не картинка (text, verdict). Что + обдумать: - где проходит граница: один вызов `run(ctx)` на файл (имя части + склеивается в `FileResult.files`) или батч целиком на стороне исполнителя; + `executor/protocol.ts` `files` уже сериализуются, но при батче нужен + прогресс и отмена; - частичные ошибки: один битый файл не должен ронять + весь шаг — нужен per-file отчёт, а не один `ToolError` на шаг; - имена + частей на каждом шаге и Download для набора (сейчас zip по `page.slug`, + `SchemaToolView.download()`); - обратная сторона: распаковка zip в + браузере, порядок файлов, поведение many → 1 → many в одной цепочке. + Зависит от идеи 10 (остальные потребители 1 → many) и идеи 4 (batch по + архиву), `docs/roadmap.md` фаза 8 «batch-страница». +- [ ] **Идея 17. Промежуточные результаты шагов + выравнивание рядов** — оценка + M. Два режима просмотра цепочки: - **без выравнивания (по умолчанию):** в + панели просмотра цепочка изображений по 2 в колонку «исходник → результат + 1 → результат 2 → … → конечный результат»; - **с выравниванием (галочка + «выровнять инструменты и просмотр»):** у каждого инструмента показаны его + исходник и результат построчно «параметры — исходник — результат»; + промежуточные картинки при этом осознанно дублируются на экране — + результат шага является исходником следующего. + +## Инструменты + +- [ ] qr code to text, text to qr code +- [ ] bar code to text, text to bar code - [ ] split-into-parts-png - увеличить максимальные значения, плохо работает для нарезки ассетов - [ ] split-into-parts-png — режим «по размеру тайла»: указываешь размер тайла (16×16, 32×32…, список `SIZE_PRESETS`), инструмент сам считает сетку — сценарий «режу спрайтшит, знаю размер тайла, не знаю сетку» (новый режим: схема + core, из задачи C3) -- [ ] e2e: `i18n.spec.ts` и `text-and-verdicts.spec.ts` дублируют локаторы из - `helpers/page.ts` вместо вызова — правило «спека зовёт helpers» - (`docs/testing-strategy.md`, раздел 5) -- [ ] e2e webkit: случайные падения по таймауту 5с (элемент не появляется), - каждый прогон падают разные тесты — webkit под Windows слишком медленный. - Рассмотреть увеличение timeout/expectTimeout для webkit-проекта в - `playwright.config.ts`. После фикса перепроверить `tool-flows.spec.ts` - «chain: remove step» — на webkit удаление шага не успевает за 5с (на - остальных движках стабильно) -- [ ] мёртвый i18n-ключ `noParams` («нет параметров — результат готов»): его - ничем не читают. Либо показывать подсказку для инструментов с пустой - схемой (FA-E1), либо удалить ключ из обеих локалей -- [ ] Пересмотреть тесты — убрать точные совпадения текстов и любые селекторы, - привязанные к разметке или svelte-классам (сейчас остались: - `tool-flows.spec.ts`, `schema-tool-strings.test.ts`) -- [ ] можно ли в тестах получать i18n ключ вместо текста? можно ли написать lint - правило такое (запретить toContain без i18n) - [ ] нужен инструмент для удаления фона по выбранной точке - удалять внутри выделенной области - [ ] сделать конвертацию в смайлики\награды для твитча (6 размеров или выбор какой размер - 112\56\28px или 72\36\18) - [ ] сделать несколько проходное сжатие png для получения необходимого размера файлов, посмотреть реализацию в - [https://github.com/tma02/twitch-emote-resizer](https://github.com/tma02/twitch-emote-resizer) -- [ ] неудобно настраивать ползунками, некоторые инструменты удобнее настроить - через drag-n-drop. звучит сложно, но надо придумать процесс -- [ ] убрать в тестах все нестандартные символы `→`, длинные тире, русский язык - и т.д., сделать lint правило -- [ ] комментарии на английском, lint правило -- [ ] уменьшить количество и многословность комментариев (lint правило?) + [twitch-emote-resizer](https://github.com/tma02/twitch-emote-resizer) - [ ] Пересмотреть прозрачность в инструментах - Create empty PNG - прозрачность должны быть настраиваемой 0-100%, а не переключателем +- [ ] Font Style - обдумать выбор шрифта (google fonts???) как организовать + шрифты с кириллицей? сделать галочку "только с кириллицей"??? (решение о + наборе и лицензиях: `docs/plan-platform.md` §4 — только OFL/Apache с + паспортом, семейства с кириллицей) +- [ ] проверить настройки range slider на crop-png - слишком большие значения +- [ ] Свести convert-страницы (`convert-png-to-jpg`, `convert-png-to-webp`, + `png-to-bmp`) на один инструмент `convert` — зависит от S1f + (`docs/plan-seo.md` §4). Мешает не только `quality` (он живёт в схеме + инструмента), а сама модель: `output` с mime/ext — свойство `Tool`, а + `PageStep` умеет только `{ id, params? }`, поэтому страницы на общий `id` + получат одинаковый формат вывода. Нужно научить шаг переопределять формат + вывода +- [ ] **Идея 6. Конвертация формата — НЕ отдельный инструмент, а выбор в кнопке + Download** — оценка M/L. Решение и продуктовое обоснование: + `docs/plan-seo.md` §0 и задача **S1f**; почему селектор не заменяет + существующие convert-страницы — `docs/plan-seo.md` §5. Механическая часть + уже есть: `Tool.output` (`OutputFormat`: mime/ext/qualityParamId) и + кодирование по нему в `SchemaToolView.download()` — + `docs/architecture.md`, раздел 3. Что осталось сверх S1f: - экспорт с + лимитом размера → «сжатие до целевого КБ»: для lossy это quality в + селекторе формата, для PNG — бинарный поиск по k из квантования. Нужна ли + отдельная страница под этот интент — открытый вопрос с вордстатом, имя не + выбрано (`docs/plan-seo.md` §5). Проработать вместе с достройкой + download-флоу. +- [ ] **Идея 7. Страница `watermark-image-png` (водяной знак картинкой)** — + оценка M. Нужна overlay-механика: второй источник изображения + (getOverlay/store), параметры scale/opacity/position/margin/aspect. + Решается вместе с вопросом, как второй источник картинки вписывается в + schema-driven preview (`SchemaToolView`). +- [ ] **Идея 8. `png-info` (детальная информация о PNG)** — оценка M/L. + Отдельный райз: exif-теги, редактирование, структурированный вывод; нужен + свой отдельный случай в UI, не «ещё один text/verdict». Возможно нужна + вообще отдельная страница, несовместимая с другими инструментами: 1) она + работает не с изображением, а с метаданными из файла, 2) она не может быть + частью цепочки, т.к. результат не является изображением, 3) если надо + изменить теги, никакого форматирования и изменения в изображение вносить + не надо, только в метаинформацию. +- [ ] **Идея 9. Region-инструменты** (censor/erase/pixelate-area/blur-area/ + sharpen-area/reverse-area) — ждут UI выделения области на превью. Вне + очереди. +- [ ] **Идея 10. Мультифайловые инструменты-потребители** (gif-to-frames, + separate-colors) — механизм «результат = набор файлов» (1 → many) уже есть + (`docs/architecture.md`, раздел 7), первый потребитель — + `split-into-parts-png`. Остальные подключаются по мере нужды. +- [ ] **Идея 11. Анимационные** (slow-reveal/fade/scrolling) — выход не PNG; + отдельное решение о формате. +- [ ] **Идея 12. HARD-серия** (glitch, barcode, signature-extract, + handwritten-digital). +- [ ] **Идея 14. Отображение маски для инструментов (`runMask`)** — придумать и + реализовать процесс показа маски результата. **Контекст:** удалённый UI-v1 + умел показывать ч/б превью-маску «что будет вырезано» отдельным полем; при + переходе на единый `run(ctx)` этого поля не осталось — executor и + schema-превью зовут `run()` напрямую, маска не возвращается. **Идея 1:** + дать каждому `run` возможность вернуть (или инструмент — объявить) + `runMask` — ч/б изображение маски изменений либо иной подход (отдельное + поле `mask` + функция маски, второй результат, overlay). Оценка — на + усмотрение при проработке (S/M). Пока живём без неё. **Идея 2:** каждый + `run` возвращает два изображения — для отображения (показывает маску или + сам результат) и для передачи в следующий инструмент (всегда результат). + Оценка — на усмотрение при проработке (S/M). Пока живём без неё. Первые + кандидаты на маску: `remove-color-from-png`, `remove-background-png`. + +## UI и качество + +- [ ] мёртвый i18n-ключ `noParams` («нет параметров — результат готов»): его + ничем не читают. Либо показывать подсказку для инструментов с пустой + схемой (FA-E1), либо удалить ключ из обеих локалей +- [ ] неудобно настраивать ползунками, некоторые инструменты удобнее настроить + через drag-n-drop. звучит сложно, но надо придумать процесс - [ ] обдумать объединение пар `inputMode + source` и `resultKind + result` в единую структуру, позволит упростить некоторые вещи - например `sourceValue` \ `resultValue` в `SchemaPreview.svelte` @@ -70,23 +163,11 @@ - [ ] Переделать внешний вид инструментов без настроек, например Remove alpha channel PNG "remove-alpha-channel-png". Сейчас выглядит слишком пустым. - [ ] Пересмотреть поля - Plate, Position, Font Style - сейчас второй label -- [ ] Font Style - обдумать выбор шрифта (google fonts???) как организовать - шрифты с кириллицей? сделать галочку "только с кириллицей"??? (решение о - наборе и лицензиях: `docs/plan-platform.md` §4 — только OFL/Apache с - паспортом, семейства с кириллицей) - [ ] поле ввода текста - сделать по умолчанию нормального размера, а не одну строку для svg - форматирование или подсветку синтаксиса??? для bin\hex - форматирование по колонкам??? для hex\bytes\rgba - пример в placeholder - [ ] прикрутить кастомный color picker, добавить прозрачность (range?) -- [ ] проверить настройки range slider на crop-png - слишком большие значения - [ ] обновить страницу kit или сделать storybook -- [ ] Свести convert-страницы (`convert-png-to-jpg`, `convert-png-to-webp`, - `png-to-bmp`) на один инструмент `convert` — зависит от S1f - (`docs/plan-seo.md` §4). Мешает не только `quality` (он живёт в схеме - инструмента), а сама модель: `output` с mime/ext — свойство `Tool`, а - `PageStep` умеет только `{ id, params? }`, поэтому страницы на общий `id` - получат одинаковый формат вывода. Нужно научить шаг переопределять формат - вывода - [ ] `PreviewTile`: высота плитки задана только `min-height: clamp(...)`, поэтому она не следует за пропорциями результата — широкий результат уезжает в узкую полосу, а высокий упирается в `max-height: 100vh`. Нужно, @@ -95,20 +176,57 @@ - [ ] Радиусы бордеров: `--radius-m` ненулевой и применён ко всем бордерам (`app.css`, `SchemaToolView.svelte`). Решить, где скругления реально есть в дизайне, а где должен быть 0 +- [ ] Component-тесты `SchemaToolView`/`SchemaPreview` требуют отдельного + решения: node Vitest не имеет DOM/canvas, а e2e уже покрывает поведение. +- [ ] Ошибка декодирования изображения из `createImageBitmap` пока показывается + сырым сообщением браузера; нужен `ToolError`-маппер и i18n-ключ. +- [ ] **Идея 5. Избранные инструменты (fav tools)** — оценка S/M. + Тоггл-звёздочка на карточках каталога, результатах поиска и в шапке + страницы инструмента; список slug в localStorage. Избранное показывается + отдельной секцией сверху каталога и поднимается в выдаче поиска (бонус к + popularity при скоринге). +- [ ] **Идея 13. Контраст текста на акцентных кнопках — частично закрыт**. Тона + `--color-main`/`--color-accent` подняты под текущий порог + `palette.test.ts`; targeted-тест проходит. Light-тема всё ещё ниже AA 4.5 + для обычного текста, а `--color-danger` в light-теме на границе: после + завершения редизайна вернуть порог 4.5 и перепроверить оба токена. +- [ ] **Идея 16. Главная должна отличаться от каталога** — оценка S. Сейчас + `src/routes/+page.svelte` и `src/routes/list-tools/+page.svelte` побайтово + идентичны (совпадают script, шаблон и стили), при этом `/list-tools` — + рабочий маршрут: на него ссылается крошка в `+layout.svelte` и он открыт + e2e-сценариями `catalog.spec.ts`, `i18n.spec.ts`, `navigation.spec.ts`. + Замысел: главная — крупнее и с более простым поиском, без категорий; + каталог остаётся группировкой с фильтрами. Детектор дублирования разметки + сознательно не вводим — `docs/decisions.md`, раздел 1, поэтому расхождение + ловится на ревью. -## Инструменты +## Тесты и lint -- [ ] qr code to text, text to qr code -- [ ] bar code to text, text to bar code - -## Переезд - -- [ ] множественные числа (часть/части/частей; «N параметров», счётчики) — - функция `tPlural(path, n)` и форма `PluralForms` (обязательное `other`, - опциональные `one`/`few`/`many`); первые потребители — `part`/`parts` в - подписи результата и счётчики параметров. **Критерий приёмки:** у ключа с - plurals есть все формы, для которых нужен перевод, `other` никогда не - пустой, число подставляется в текст без склейки +- [ ] `tseslint.config(...)` deprecated: сигнатура + `(...configs: InfiniteDepthConfigWithExtends[]): ConfigArray` помечена + устаревшей, нужен переход на `defineConfig` из `eslint/config` (ESLint + core, а не `typescript-eslint`) — `web/eslint.config.js`. +- [ ] удалить мёртвые `tools.*.params` из root i18n после проверки потребителей; + до этого действует pattern-based policy-исключение + (`web/eslint-plugins/README.md`, раздел `dict-consistency`) +- [ ] e2e: `i18n.spec.ts` и `text-and-verdicts.spec.ts` дублируют локаторы из + `helpers/page.ts` вместо вызова — правило «спека зовёт helpers» + (`docs/testing-strategy.md`, раздел 5) +- [ ] e2e webkit: случайные падения по таймауту 5с (элемент не появляется), + каждый прогон падают разные тесты — webkit под Windows слишком медленный. + Рассмотреть увеличение timeout/expectTimeout для webkit-проекта в + `playwright.config.ts`. После фикса перепроверить `tool-flows.spec.ts` + «chain: remove step» — на webkit удаление шага не успевает за 5с (на + остальных движках стабильно) +- [ ] Пересмотреть тесты — убрать точные совпадения текстов и любые селекторы, + привязанные к разметке или svelte-классам (сейчас остались: + `tool-flows.spec.ts`, `schema-tool-strings.test.ts`) +- [ ] можно ли в тестах получать i18n ключ вместо текста? можно ли написать lint + правило такое (запретить toContain без i18n) +- [ ] убрать в тестах все нестандартные символы `→`, длинные тире, русский язык + и т.д., сделать lint правило +- [ ] комментарии на английском, lint правило +- [ ] уменьшить количество и многословность комментариев (lint правило?) ## SEO/GEO @@ -139,133 +257,11 @@ - [ ] Шрифты: лицензирование (F1–F4) и DOM-free рендер (F5–F6) — до фазы 8 (`docs/plan-platform.md` §4) -## Качество production UI +## Переезд -- [ ] Component-тесты `SchemaToolView`/`SchemaPreview` требуют отдельного - решения: node Vitest не имеет DOM/canvas, а e2e уже покрывает поведение. -- [ ] Ошибка декодирования изображения из `createImageBitmap` пока показывается - сырым сообщением браузера; нужен `ToolError`-маппер и i18n-ключ. - -## Идеи - -Идеи 1–5 и 15 — про пайплайн (фаза 11 `docs/roadmap.md`). Идеи 6–14 и 16 — про -существующие инструменты и UI. Оценки (S/M/L) — оценка труда, не приоритет. - -1. **Менять первый инструмент цепочки** — оценка M. Сейчас базовый инструмент - зафиксирован при открытии страницы; хочется заменить его на другой без - разборки цепочки: шаги и их параметры сохраняются, вход перечитывается. - Открытый вопрос: что делать с несовместимыми параметрами (text-source ↔ - file). - -2. **Сворачивать инструменты в chain** — оценка S. Тоггл сворачивания звена до - заголовка «Шаг n: название» (превью скрываются). Состояние свёрнутости - помнить в workspace-pipeline. - -3. **Несколько цепочек: сохранение и загрузка** — оценка M. Именованные цепочки - в localStorage (список, создать/переименовать/удалить), быстрое переключение. - Формат экспортного JSON расширить опциональным полем имени; обратной - совместимости со старыми выгрузками не делаем — формат не устоялся: он - появится вместе с фазой 11 `docs/roadmap.md` и до её старта может измениться. - -4. **Batch-обработка архивов выбранным chain** — оценка L. Вход — zip-архив - картинок (распаковка в браузере), прогон текущего или выбранного сохранённого - chain по каждому файлу, сборка результата обратно в zip для скачивания. - Зависит от идеи 3 (выбор цепочки) и от экспортного формата pipeline JSON; - прогресс и ошибки — пофайлово. - -5. **Избранные инструменты (fav tools)** — оценка S/M. Тоггл-звёздочка на - карточках каталога, результатах поиска и в шапке страницы инструмента; список - slug в localStorage. Избранное показывается отдельной секцией сверху каталога - и поднимается в выдаче поиска (бонус к popularity при скоринге). - -6. **Конвертация формата — НЕ отдельный инструмент, а выбор в кнопке Download** - — оценка M/L. Решение и продуктовое обоснование: `docs/plan-seo.md` §0 и - задача **S1f**; почему селектор не заменяет существующие convert-страницы — - `docs/plan-seo.md` §5. Механическая часть уже есть: `Tool.output` - (`OutputFormat`: mime/ext/qualityParamId) и кодирование по нему в - `SchemaToolView.download()` — `docs/architecture.md`, раздел 3. Что осталось - сверх S1f: - - экспорт с лимитом размера → «сжатие до целевого КБ»: для lossy это quality - в селекторе формата, для PNG — бинарный поиск по k из квантования. Нужна ли - отдельная страница под этот интент — открытый вопрос с вордстатом, имя не - выбрано (`docs/plan-seo.md` §5). Проработать вместе с достройкой - download-флоу. - -7. **Страница `watermark-image-png` (водяной знак картинкой)** — оценка M. Нужна - overlay-механика: второй источник изображения (getOverlay/store), параметры - scale/opacity/position/margin/aspect. Решается вместе с вопросом, как второй - источник картинки вписывается в schema-driven preview (`SchemaToolView`). - -8. **`png-info` (детальная информация о PNG)** — оценка M/L. Отдельный райз: - exif-теги, редактирование, структурированный вывод; нужен свой отдельный - случай в UI, не «ещё один text/verdict». Возможно нужна вообще отдельная - страница, несовместимая с другими инструментами: 1) она работает не с - изображением, а с метаданными из файла, 2) она не может быть частью цепочки, - т.к. результат не является изображением, 3) если надо изменить теги, никакого - форматирования и изменения в изображение вносить не надо, только в - метаинформацию. - -9. **Region-инструменты** (censor/erase/pixelate-area/blur-area/sharpen-area/ - reverse-area) — ждут UI выделения области на превью. Вне очереди. - -10. **Мультифайловые инструменты-потребители** (gif-to-frames, separate-colors) - — механизм «результат = набор файлов» (1 → many) уже есть - (`docs/architecture.md`, раздел 7), первый потребитель — - `split-into-parts-png`. Остальные подключаются по мере нужды. - -11. **Анимационные** (slow-reveal/fade/scrolling) — выход не PNG; отдельное - решение о формате. - -12. **HARD-серия** (glitch, barcode, signature-extract, handwritten-digital). - -13. **Контраст текста на акцентных кнопках — частично закрыт**. Тона - `--color-main`/`--color-accent` подняты под текущий порог `palette.test.ts`; - targeted-тест проходит. Light-тема всё ещё ниже AA 4.5 для обычного текста, - а `--color-danger` в light-теме на границе: после завершения редизайна - вернуть порог 4.5 и перепроверить оба токена. - -14. **Отображение маски для инструментов (`runMask`)** — придумать и реализовать - процесс показа маски результата. **Контекст:** удалённый UI-v1 умел - показывать ч/б превью-маску «что будет вырезано» отдельным полем; при - переходе на единый `run(ctx)` этого поля не осталось — executor и - schema-превью зовут `run()` напрямую, маска не возвращается. **Идея 1:** - дать каждому `run` возможность вернуть (или инструмент — объявить) `runMask` - — ч/б изображение маски изменений либо иной подход (отдельное поле `mask` + - функция маски, второй результат, overlay). Оценка — на усмотрение при - проработке (S/M). Пока живём без неё. **Идея 2:** каждый `run` возвращает - два изображения — для отображения (показывает маску или сам результат) и для - передачи в следующий инструмент (всегда результат). Оценка — на усмотрение - при проработке (S/M). Пока живём без неё. Первые кандидаты на маску: - `remove-color-from-png`, `remove-background-png`. - -15. **Набор файлов в пайплайне: 1 → many не должен быть терминальным** — оценка - L. **Сейчас** `execute` принимает один `source: PixelImage | undefined` и - возвращает один `ToolResult`, а `SchemaToolView` раскладывает вывод в - `result` / `fileResult` / `textResult` по `resultKind` — поэтому шаг с - `result: "files"` упирается в конец цепочки. **Направление:** следующий - инструмент применяется **ко всем картинкам** предыдущего результата - (fan-out), а many → 1 (вход = архив или несколько файлов) — обратная сторона - того же контракта. Терминальными остаются только результаты, которые не - картинка (text, verdict). Что обдумать: - - где проходит граница: один вызов `run(ctx)` на файл (имя части склеивается - в `FileResult.files`) или батч целиком на стороне исполнителя; - `executor/protocol.ts` `files` уже сериализуются, но при батче нужен - прогресс и отмена; - - частичные ошибки: один битый файл не должен ронять весь шаг — нужен - per-file отчёт, а не один `ToolError` на шаг; - - имена частей на каждом шаге и Download для набора (сейчас zip по - `page.slug`, `SchemaToolView.download()`); - - обратная сторона: распаковка zip в браузере, порядок файлов, поведение - many → 1 → many в одной цепочке. Зависит от идеи 10 (остальные потребители - 1 → many) и идеи 4 (batch по архиву), `docs/roadmap.md` фаза 8 - «batch-страница». - -16. **Главная должна отличаться от каталога** — оценка S. Сейчас - `src/routes/+page.svelte` и `src/routes/list-tools/+page.svelte` побайтово - идентичны (совпадают script, шаблон и стили), при этом `/list-tools` — - рабочий маршрут: на него ссылается крошка в `+layout.svelte` и он открыт - e2e-сценариями `catalog.spec.ts`, `i18n.spec.ts`, `navigation.spec.ts`. - Замысел: главная — крупнее и с более простым поиском, без категорий; каталог - остаётся группировкой с фильтрами. Детектор дублирования разметки - сознательно не вводим — `docs/decisions.md`, раздел 1, поэтому расхождение - ловится на ревью. +- [ ] множественные числа (часть/части/частей; «N параметров», счётчики) — + функция `tPlural(path, n)` и форма `PluralForms` (обязательное `other`, + опциональные `one`/`few`/`many`); первые потребители — `part`/`parts` в + подписи результата и счётчики параметров. **Критерий приёмки:** у ключа с + plurals есть все формы, для которых нужен перевод, `other` никогда не + пустой, число подставляется в текст без склейки