Files
ss-tools/specs/034-task-status-center/spec.md
busya 3133e50645 perf: fix translate deadlock, speed, trace_id, UI bugs — fullstack patch
## Backend (7 production files + 6 test files)

### P0-2: LLM output truncation cascade fix
- _token_budget.py: OUTPUT_PER_ROW_PER_LANG 120→200, OUTPUT_SAFETY_FACTOR 0.70→0.55
- Prevents finish_reason=length → split → retry cascade (3 calls → 1 call per batch)
- P2-8: added qwen-flash/qwen-plus/qwen-max/qwen-coder to PROVIDER_DEFAULTS

### P1-4/P1-5: EncryptionManager singleton
- encryption.py: get_encryption_manager() process-wide singleton
- llm_provider.py: use singleton instead of new EncryptionManager() per batch
- Eliminates ~90 redundant Fernet key validations per translation run

### P1-6: Cache-hit log aggregation
- _batch_proc.py: one log per batch (batch_rows + cache_hits) instead of per-row
- 1076 log lines → ~30 per run

### P1-7: Timezone-aware datetime fix
- scheduler.py: _ensure_aware() helper for naive DB datetime → UTC-aware
- Fixes TypeError in scheduled translation concurrency check

### P2-9: Connection test timeout
- connection_service.py: asyncio.wait_for(15s) on all dialect tests
- Prevents 2-minute UI hangs from DNS/TCP stalls

### Trace ID propagation
- middleware/trace.py: inject x-trace-id response header via ASGI send wrapper

### Test fixes & integration tests
- test_scheduler.py: AsyncMock for execute_run, mock get_async_job_runner
- test_sql_insert_service.py: AsyncMock for execute_sql
- test_token_budget.py: batch_size 50→45 for new OUTPUT_PER_ROW_PER_LANG=200
- test_encryption.py: +2 singleton tests
- test_scheduler_ensure_aware.py: +4 (naive→aware, passthrough, None, subtraction)
- test_batch_classify_persist.py: +2 cache-hit aggregation tests
- test_connection_service_edge.py: +2 timeout tests
- test_trace_middleware.py: +4 x-trace-id header tests
- test_token_budget.py: +4 qwen-flash/O200 tests

## Frontend (7 production files + 5 test files)

### Trace ID propagation
- api.ts: _captureTraceId() reads x-trace-id → setTraceId() in fetchApi/requestApi/postApi/deleteApi

### Duplicate datasource columns fetch
- ConfigTabForm.svelte: guard availableColumns.length === 0 before fetch

### Admin pages Svelte 5 runes fix
- admin/users/+page.svelte: plain let → () for all template-bound vars
- admin/roles/+page.svelte: same fix
- Both pages were stuck on «Загрузка...» due to mixed reactivity models

### Validation popover positioning
- +page.svelte: pass trigger HTMLElement instead of event
- DashboardHubModel.svelte.ts: toggleValidationPopover(HTMLElement), closeValidationPopover()
- Added X close button + click-outside overlay + i18n

### Test fixes & integration tests
- api.test.ts: mock setTraceId/getTraceId, +3 _captureTraceId tests
- provider_config.integration.test.ts: handleDelete→promptDeleteProvider
- DatasetPreview.test.ts: dashboards/ → ROUTES.dashboards
- test_config_tab_form.svelte.js: +2 columns fetch guard tests (NEW)
- admin-users.test.ts: +3 loading→table tests (NEW)
- admin-roles.test.ts: +2 loading→table tests (NEW)

## Semantic curation
- Removed @COMPLEXITY N from 6 route files + metrics.py (duplicate of [C:N])
- Added [C:N] to 2 orphan child contracts in metrics.py
- Added [C:N] + @BRIEF to 4 frontend anchors
- Fixed #region → # #region consistency in validation_tasks.py

## Verification
- Backend: 608 pytest passed (0 failures)
- Frontend: 2472 vitest passed (128 files, 0 failures)
- Frontend build: ✓ built in 18s
- Browser: dashboards, admin/users, admin/roles, validation popover — all green
2026-06-18 23:54:57 +03:00

16 KiB
Raw Blame History

#region FeatureSpec [C:3] [TYPE ADR] [SEMANTICS spec,requirements,feature,task,status,monitoring] @BRIEF Feature specification — единый центр просмотра статусов всех фоновых задач superset-tools: переводы, миграции, бекапы, валидации, документация и прочие. Без привязки к реализации Python/Svelte.

Navigation (DSA Indexer keywords)

@SEMANTICS: spec, requirements, feature, task, status, monitoring, dashboard

Feature Branch: 034-task-status-center
Created: 2026-06-18 | Status: Draft
Input: "я хочу единый центр просмотра статусов всех задач - переводов миграций бекапов валидаций и прочих."

Clarifications

Session 2026-06-18

  • Q: Центр статусов — новая страница или переработка существующей /reports? → A: Переработка /reports — добавляем сводную панель, real-time обновления и интеграцию с Task Drawer на существующей странице. Новый роут /tasks не создаётся. Старый режим «только история» остаётся доступным через фильтр.
  • Q: Какие задачи видит каждая роль (admin, analyst, viewer) на /reports? → A: Admin — все задачи всех пользователей; analyst — свои задачи + задачи без владельца (системные); viewer — только задачи, запущенные им лично.
  • Q: Показывать ли в сводке и списке задачи, удалённые retention-политиками? → A: Нет. Сводка и список — оперативная панель, показывающая только незаархивированные задачи. Архивные задачи исключены из выборки.

User Scenarios

Each story is an independently testable unit. Prioritized P1 (MVP) → P2 → P3. All stories share @SEMANTICS domain keywords from the feature header.

Story 1 — Сводный обзор всех задач (P1)

Why P1: Существующая страница /reports показывает только исторические отчёты завершённых задач. Оператору нужна сводная картина «прямо сейчас»: сколько задач выполняется, ожидает, требует ввода — без переключения между страницами. Сводная панель добавляется поверх существующего списка отчётов на /reports.

Independent Test: Открыть страницу /reports → над списком отчётов появилась сводная панель с агрегированными счётчиками задач по статусам (pending, running, awaiting_input, success, failed) для каждого типа.

Acceptance:

  1. Given в системе есть задачи разных типов (миграция выполняется, перевод ожидает, бекап завершён с ошибкой) When оператор открывает /reports Then он видит сводную панель над списком отчётов с агрегированными счётчиками по статусам и типам задач.
  2. Given оператор находится на /reports When запускается новая задача или меняется статус существующей Then сводка обновляется в реальном времени (без ручной перезагрузки страницы).
  3. Given в системе нет ни одной задачи When оператор открывает /reports Then сводная панель показывает нули по всем категориям, список отчётов пуст с пояснением «Нет задач».

Story 2 — Детальный список задач с фильтрацией (P2)

Why P2: Сводка даёт общую картину, но оператору нужно найти конкретную задачу: «что там с миграцией дашборда X?», «какие переводы упали сегодня?», «показать только бекапы за последние сутки».

Independent Test: На странице /reports кликнуть по карточке сводки «Миграция / Выполняется (3)» → список отчётов фильтруется: только миграции в статусе running.

Acceptance:

  1. Given в системе есть задачи всех типов When оператор применяет фильтр по типу задачи Then список обновляется и показывает только задачи выбранного типа.
  2. Given в системе есть задачи в разных статусах When оператор применяет фильтр по статусу (только running + pending) Then список показывает только активные задачи.
  3. Given оператор ввёл текст в строку поиска When текст совпадает с названием задачи или идентификатором дашборда/конфигурации Then список фильтруется по совпадению.
  4. Given оператор выбрал временной диапазон «последний час» When задачи созданы более часа назад Then они не отображаются в списке.

Story 3 — Быстрый переход к логам и результатам задачи (P3)

Why P3: Увидев, что задача упала или выполняется, оператор хочет немедленно посмотреть логи или результат — без поиска задачи на другой странице.

Independent Test: На странице /reports кликнуть на строку задачи со статусом FAILED → открывается Task Drawer с логами этой задачи.

Acceptance:

  1. Given оператор на /reports видит задачу со статусом FAILED When он кликает по задаче Then открывается Task Drawer с логами задачи, курсор прокручивается к последней ошибке.
  2. Given оператор на /reports видит задачу со статусом RUNNING When он кликает по задаче Then открывается Task Drawer и начинает показывать live-логи через WebSocket.
  3. Given оператор навёлся на строку задачи When курсор находится над строкой Then появляется тултип с краткой информацией: тип, время запуска, длительность, ключевой параметр (например, название дашборда).

Edge Cases

  • Массовое завершение задач: Одновременно завершаются десятки задач (например, batch-перевод) → сводка и список должны корректно отобразить все изменения без зависания UI (debounce обновлений, batch-обработка WebSocket-событий).
  • Потеря WebSocket-соединения: Соединение разрывается → индикатор состояния соединения в интерфейсе; автоматический reconnect с экспоненциальной задержкой; на время разрыва показывается «данные могут быть неактуальны».
  • Длительная загрузка истории: В системе тысячи завершённых задач → пагинация и серверная фильтрация предотвращают загрузку полного списка; активные задачи всегда показываются первыми.
  • Задача с типом UNKNOWN: Плагин не сопоставлен ни с одним известным типом → отображается с меткой «Неизвестный тип», не ломает фильтрацию.
  • Задача в статусе AWAITING_INPUT: Задача ожидает ввода пользователя → отображается в сводке отдельной категорией «Ожидает ввода»; в списке — с визуальным индикатором и кнопкой «Ответить».
  • Отсутствие прав: Пользователь с ролью viewer видит только свои задачи в списке и сводке; задачи других пользователей не отображаются. Попытка прямого доступа к чужой задаче через URL — 403.
  • Переключение между страницами: Оператор уходит с /reports и возвращается → восстанавливается последний набор фильтров (из URL query params), сводка перезапрашивается.
  • Задачи, удалённые retention-политикой: Задача очищена из БД → исчезает из сводки и списка при следующем обновлении данных. Оператору не нужно видеть «призраки» удалённых задач.

Requirements

Functional (IDs survive HCA 128× via hierarchical naming)

  • TSC-FR-001: Страница /reports отображает сводную панель над списком отчётов с агрегированными счётчиками задач по статусам (pending, running, awaiting_input, success, failed) для каждого типа задач (перевод, миграция, бекап, валидация, документация, прочие).
  • TSC-FR-002: Сводная панель обновляется в реальном времени через WebSocket без перезагрузки страницы.
  • TSC-FR-003: Список отчётов (задач) отображается с пагинацией, сортировкой по времени создания (свежие сверху) и возможностью изменить сортировку.
  • TSC-FR-004: Оператор может фильтровать список отчётов по: типу задачи, статусу, текстовому поиску (по названию задачи, идентификатору ресурса), временному диапазону. Клик по карточке сводки автоматически устанавливает соответствующий фильтр.
  • TSC-FR-005: Каждая задача в списке показывает: тип (с иконкой), название/идентификатор, статус (с цветовой индикацией), время запуска, длительность, связанный ресурс (дашборд, датасет, конфигурация перевода).
  • TSC-FR-006: Клик по задаче открывает Task Drawer с логами этой задачи через WebSocket (/ws/logs/{task_id}). Для завершённых задач — загружает архивные логи.
  • TSC-FR-007: Задачи в статусе AWAITING_INPUT отображаются с визуальным индикатором и кнопкой «Ответить», открывающей форму ввода в Task Drawer.
  • TSC-FR-008: Статус WebSocket-соединения отображается индикатором; при разрыве — автоматический reconnect с уведомлением оператора.
  • TSC-FR-009: Страница /reports соблюдает RBAC: admin видит задачи всех пользователей; analyst видит свои задачи и системные задачи (без владельца); viewer видит только задачи, запущенные им лично. Сводная панель отражает только видимые пользователю задачи.
  • TSC-FR-010: Активные задачи (running, pending, awaiting_input) всегда показываются в начале списка, независимо от выбранной сортировки.

Key Entities

  • Task: Фоновая задача, запущенная через любой плагин superset-tools. Ключевые атрибуты: идентификатор, тип (translate, migration, backup, validation, documentation, git, storage, debug, search, mapper, maintenance, clean_release, unknown), статус (PENDING, RUNNING, SUCCESS, FAILED, AWAITING_INPUT, AWAITING_MAPPING), время создания/запуска/завершения, связанный ресурс, идентификатор пользователя. Архивные задачи (удалённые retention-политикой) исключаются из сводки и списка.
  • TaskSummary: Агрегированная сводка — срез количества задач по каждой комбинации (тип × статус). Обновляется в реальном времени.
  • TaskFilter: Набор параметров фильтрации, применяемых к списку задач: типы, статусы, поисковый запрос, временной диапазон.

Success Criteria

  • SC-001: Оператор получает сводку по всем задачам не более чем за 1 секунду после открытия /reports.
  • SC-002: Изменение статуса задачи отражается в сводке и списке не более чем через 2 секунды после события на backend (измеряется от отправки WebSocket-события до обновления DOM).
  • SC-003: Оператор находит нужную задачу (фильтрация + поиск или клик по карточке сводки) не более чем за 2 действия после открытия /reports.
  • SC-004: При 100+ одновременно активных задачах интерфейс остаётся отзывчивым (частота кадров не падает ниже 30 fps при прокрутке списка).
  • SC-005: Восстановление WebSocket-соединения после разрыва происходит автоматически в течение 5 секунд с экспоненциальной задержкой.

#endregion FeatureSpec