(medium) BulkGeoPanel/handleSubmit: очистка поля Parallelism шлёт parallelism=0 → 422, запуск молча проваливается #1428

Closed
opened 2026-06-15 05:54:43 +00:00 by bot-backend · 1 comment
Collaborator

Severity: medium · Категория: frontend · Файл: frontend/src/components/admin/BulkGeoPanel.tsx:169-176

BulkGeoPanel.tsx:174 onChange={(e)=>setParallelism(Number(e.target.value))} — при очистке инпута Number('')===0 (а при мусоре/некорректном вводе можно получить и NaN, который JSON.stringify сериализует в null). Атрибуты min={1} max={10} (строки 172-173) ограничивают только стрелочки/нативную форму, но не программное значение state. В mutationFn (строка 58) parallelism уходит в body как есть. Backend BulkGeoEnqueueRequest объявляет parallelism: int = Field(default=5, ge=1, le=10) (backend/app/api/v1/admin_scrape.py:754) — значение 0 / null / вне [1..10] отвергается с 422. Кнопка «Запустить» блокируется только bulkMutation.isPending (строка 181), не по валидности, поэтому валидный сценарий (очистил поле, чтобы перенабрать, кликнул) ведёт к невнятной ошибке 422 вместо запуска backfill. Импакт: операция backfill молча проваливается с непонятной серверной ошибкой. Чинить: клампить/валидировать parallelism перед mutate (например Number.isFinite + clamp в [1,10], при пустом — дефолт 5) и/или disable кнопки при невалидном значении.

Почему баг: В mutationFn body отправляется parallelism: напрямую (строки 56-62). Backend BulkGeoEnqueueRequest объявляет parallelism: int = Field(default=5, ge=1, le=10) (admin_scrape.py:754) — значение 0 или вне диапазона отвергается с 422. NaN при JSON.stringify сериализуется в null → тоже 422. Кнопка при этом показывает '~N на job' и не блокируется по валидности, пользователь жмёт «Запустить» и получает невнятную ошибку вместо запуска backfill. То есть валидный сценарий (очистил поле чтобы перенабрать, кликнул) ведёт к провалу операции.

Как чинить: Хранить parallelism как строку и парсить при submit с clamp в [1..10], либо в onChange: const n = Number(e.target.value); setParallelism(Number.isFinite(n) ? Math.min(10, Math.max(1, n)) : 1). И дизейблить submit если значение невалидно.


deep-audit «армия ботов 2» · verify+harden, confidence 0.9 · unit U85

**Severity:** medium · **Категория:** frontend · **Файл:** `frontend/src/components/admin/BulkGeoPanel.tsx:169-176` BulkGeoPanel.tsx:174 onChange={(e)=>setParallelism(Number(e.target.value))} — при очистке инпута Number('')===0 (а при мусоре/некорректном вводе можно получить и NaN, который JSON.stringify сериализует в null). Атрибуты min={1} max={10} (строки 172-173) ограничивают только стрелочки/нативную форму, но не программное значение state. В mutationFn (строка 58) parallelism уходит в body как есть. Backend BulkGeoEnqueueRequest объявляет parallelism: int = Field(default=5, ge=1, le=10) (backend/app/api/v1/admin_scrape.py:754) — значение 0 / null / вне [1..10] отвергается с 422. Кнопка «Запустить» блокируется только bulkMutation.isPending (строка 181), не по валидности, поэтому валидный сценарий (очистил поле, чтобы перенабрать, кликнул) ведёт к невнятной ошибке 422 вместо запуска backfill. Импакт: операция backfill молча проваливается с непонятной серверной ошибкой. Чинить: клампить/валидировать parallelism перед mutate (например Number.isFinite + clamp в [1,10], при пустом — дефолт 5) и/или disable кнопки при невалидном значении. **Почему баг:** В mutationFn body отправляется parallelism: <state> напрямую (строки 56-62). Backend BulkGeoEnqueueRequest объявляет parallelism: int = Field(default=5, ge=1, le=10) (admin_scrape.py:754) — значение 0 или вне диапазона отвергается с 422. NaN при JSON.stringify сериализуется в null → тоже 422. Кнопка при этом показывает '~N на job' и не блокируется по валидности, пользователь жмёт «Запустить» и получает невнятную ошибку вместо запуска backfill. То есть валидный сценарий (очистил поле чтобы перенабрать, кликнул) ведёт к провалу операции. **Как чинить:** Хранить parallelism как строку и парсить при submit с clamp в [1..10], либо в onChange: const n = Number(e.target.value); setParallelism(Number.isFinite(n) ? Math.min(10, Math.max(1, n)) : 1). И дизейблить submit если значение невалидно. --- <sub>deep-audit «армия ботов 2» · verify+harden, confidence 0.9 · unit U85</sub>
bot-backend added the
week ревью 1
label 2026-06-15 05:54:43 +00:00
bot-backend added the
scope/backend
label 2026-06-15 11:02:03 +00:00
Owner

🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)

Текущее состояние кода: frontend/src/components/admin/BulkGeoPanel.tsx:

  • Инпут (169-176): value={parallelism} min={1} max={10} onChange={(e) => setParallelism(Number(e.target.value))} (174). При очистке Number("") === 0; мусорный ввод → NaN. min/max ограничивают только нативную форму, не программный state.
  • mutationFn (55-59): parallelism уходит в body как есть (58), без клампа.
  • Кнопка submit (179-186): disabled={bulkMutation.isPending} (181) — блокируется только по pending, не по валидности значения.

Backend BulkGeoEnqueueRequest.parallelism: int = Field(default=5, ge=1, le=10) (admin_scrape.py:754 по issue) → значение 0 / вне [1..10] / null (NaN после JSON.stringify) отвергается с 422.

Корень: Очистка поля Parallelism шлёт parallelism=0 (или NaN→null) → backend 422 → запуск backfill молча проваливается невнятной серверной ошибкой вместо запуска.

Что править:

  • Клампить/валидировать перед mutate: в onChange const n = Number(e.target.value); setParallelism(Number.isFinite(n) ? Math.min(10, Math.max(1, n)) : 5); либо хранить как строку и парсить с clamp при submit.
  • Дизейблить submit при невалидном значении.

Что посмотреть:

  • Код: frontend/src/components/admin/BulkGeoPanel.tsx:55-59, 169-176, 179-186. Backend backend/app/api/v1/admin_scrape.py (BulkGeoEnqueueRequest.parallelism Field ge=1 le=10).
  • Vault: релевантных заметок не найдено.
**🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)** **Текущее состояние кода:** `frontend/src/components/admin/BulkGeoPanel.tsx`: - Инпут (169-176): `value={parallelism} min={1} max={10} onChange={(e) => setParallelism(Number(e.target.value))}` (174). При очистке `Number("") === 0`; мусорный ввод → `NaN`. `min`/`max` ограничивают только нативную форму, не программный state. - mutationFn (55-59): `parallelism` уходит в body как есть (58), без клампа. - Кнопка submit (179-186): `disabled={bulkMutation.isPending}` (181) — блокируется только по pending, не по валидности значения. Backend `BulkGeoEnqueueRequest.parallelism: int = Field(default=5, ge=1, le=10)` (admin_scrape.py:754 по issue) → значение 0 / вне [1..10] / null (NaN после JSON.stringify) отвергается с 422. **Корень:** Очистка поля Parallelism шлёт `parallelism=0` (или NaN→null) → backend 422 → запуск backfill молча проваливается невнятной серверной ошибкой вместо запуска. **Что править:** - Клампить/валидировать перед mutate: в onChange `const n = Number(e.target.value); setParallelism(Number.isFinite(n) ? Math.min(10, Math.max(1, n)) : 5)`; либо хранить как строку и парсить с clamp при submit. - Дизейблить submit при невалидном значении. **Что посмотреть:** - Код: `frontend/src/components/admin/BulkGeoPanel.tsx:55-59, 169-176, 179-186`. Backend `backend/app/api/v1/admin_scrape.py` (`BulkGeoEnqueueRequest.parallelism` Field ge=1 le=10). - Vault: релевантных заметок не найдено.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1428
No description provided.