downloadSkippedCsv and downloadFailedCsv call api.fetchApiBlob()
but it was not exposed on the api object — causing
"o.fetchApiBlob is not a function" at runtime.
Deleted stale .js files (taskService, toolsService, report_page.contract.test)
7 .svelte.js test files intentionally preserved (Svelte 5 convention)
Final metrics:
- Production JS files: 0
- Production TS/TSX/Svelte files: all
- npm run build ✅
- npm run test ✅ (645 passed, 6 pre-existing)
API returns 'screenshot_paths' but frontend template reads 'screenshots'.
Without field mapping, screenshots are never displayed.
Fix: map screenshot_paths -> screenshots and logs_sent_to_llm -> logs_sent
in the +page.js load function.
Also verifies that /api/storage/file endpoint exists (mounted at /api/storage)
and the frontend API_BASE_URL='/api' correctly prefixes /storage/file.
Svelte each block key used , but when
two issues share the same message text (e.g. 'Main content area
is completely blank') and have no id, the key collides.
Fix: use composite key
as fallback when issue.id is missing.
Delete deprecated code that has been fully replaced by v2:
- backend: validation.py routes, validation_run_service.py
- frontend: validation.js API module, validation/ pages
Add binary-search probe endpoint POST /providers/{id}/probe-max-images
that discovers the per-request image limit by sending incrementally
more 1x1 JPEGs via the provider's own API. Result is cached in the
new max_images column on the provider config.
- LLMProviderConfig: add max_images: int | None
- LLMProvider (SQLAlchemy): add max_images column
- Migration ed28d34edde7: clean ADD COLUMN
- LLMProviderService: create/update/set_max_images
- POST /providers/{id}/probe-max-images: binary search + error parsing
- ProviderConfig.svelte: 'Detect' button in edit modal + HelpTooltip
- i18n (en/ru): 11 new keys for probe UI
Fixes:
- Move batch size, upsert strategy, include source reference
from Config tab to Target Config tab (Write Settings section)
- Fix 'Dataset #26' fallback — look up real datasource name
via API when source_table is not saved in job data
- Persist include_source_reference in save payload and
restore from job data on load (was a pre-existing gap)
QA review fixes:
- Update @BRIEF contracts for both tabs
- Fix import indentation in +page.svelte
Other: help tooltips on translate pages, flow hint on list page,
git migration manager components, dashboard hub pages,
migration settings pages
1. Remove get_config_manager() call from translate_run_websocket
(@app.websocket /ws/translate/run/{run_id}) — was not imported
and unused. Also remove unused from sqlalchemy.orm import Session.
2. Fix prop name mismatch: showBulkReplace -> showPageBulkReplace
in RunTabContent. Use () for reactive two-way binding.
3. Add ('DRAFT') for status prop in RunTabContent.
Backend:
- Add /ws/translate/run/{run_id} WebSocket endpoint in app.py
- Streams structured run status every second (total_records,
successful_records, failed_records, progressPct, batch_count, etc.)
- Auto-detects terminal states (COMPLETED, FAILED, CANCELLED) and closes
- Authenticated via JWT/API key token query param
Frontend:
- Add getTranslateRunWsUrl() URL builder in api.js
- Update translationRunStore to use WebSocket instead of log stream
- WebSocket receives structured status JSON, updates store reactively
- Falls back to polling silently if WebSocket fails
- Keep polling as fallback for insert phase
Clean up remaining orphaned references after tab extraction:
- Remove loadColumnsForDatasource, searchDatasources, selectDatasource
etc. from page (moved to ConfigTabForm)
- Add on datasourceId in ConfigTabForm for auto-loading
columns when parent sets datasourceId (loadJob)
- Fix stray braces, remove dead isVirtual function
- Page now 779 lines (down from 1519, -49%)
Remove loadColumnsForDatasource, searchDatasources, selectDatasource,
toggleContextColumn, toggleSourceKeyCol, updateTargetKeyCol, isVirtual
from page — all moved to ConfigTabForm.svelte.
Add on datasourceId in ConfigTabForm to auto-load columns
when parent sets datasourceId (loadJob) or user selects a datasource.
Add comprehensive UX contract header documenting:
- @UX_STATE: all states of the page-level state machine (idle, loading,
configured, saving, validation_error, datasource_unavailable, error)
- @UX_STEP: 5 logically separated steps/tabs (Config, Preview, Target, Run, Schedule)
- @UX_FEEDBACK: toasts, modals, inline progress, schema validation
- @UX_RECOVERY: retry paths for save/preview/run failures
- @UX_REACTIVITY: props, local state, derived, effects, store bindings
- @UX_DEPENDENCY: data flow between datasource selection, env switching,
config validity, and tab availability
- @UX_TEST: test scenarios for the automated Judge Agent
Also remove leftover sourceDialect/targetDialect selects from UI
(now sent as sensible defaults in save payload).
Sub-components (TargetSchemaHint, TranslationPreview, TranslationRunProgress,
ScheduleConfig, BulkReplaceModal) already have UX contracts.
These fields were showing database types (PostgreSQL, ClickHouse)
as human language options for the LLM prompt, which was confusing.
Now sending sensible defaults (source='SQL', target='en') directly
in the save payload without exposing them in the UI.
The backend already has fallbacks:
_llm_call.py: source_language = job.source_dialect or 'SQL'
_batch_proc.py: target_langs = or [job.target_dialect or 'en']
sourceDialect/targetDialect select options contained database types
(PostgreSQL, ClickHouse, MySQL...) while these fields are used as
human language indicators for the LLM prompt:
_llm_call.py: source_language = job.source_dialect or 'SQL'
Changed to use the existing LANGUAGES list (from LANGUAGE_LABELS:
ru, en, de, fr, es, etc.) plus 'SQL' option for source dialect.
Defaults updated: source='SQL' (SQL-like expressions), target='en'.
Bug: loadDatabases() was called at line 374 while environmentId still
held the FIRST environment from initialization (line 259), because
environmentId = j.environment_id was not set until line 391 (inside
the datasource block). Only after that was environmentId correct.
This caused the database dropdown to show databases from a different
environment than the job's actual environment. For example, db_id=2
is DEV Greenplum in 'dev' but Prod Clickhouse in 'preprod'. The user
would select Greenplum from the dev list, but the job would use
preprod where db_id=2 is ClickHouse.
Fix: set environmentId from the job's stored environment BEFORE
calling loadDatabases(), and outside the datasource conditional
so it runs for all existing jobs.
Root cause: fetch_available_datasources did not return database_id,
so frontend could not auto-set target_database_id when user selected
a datasource. User then had to manually pick a database on Target Config
tab — and could accidentally select the wrong one.
Backend changes:
- Add 'database_id' field to datasources response (from db_info.get('id'))
- Add _database_name tracking in SupersetSqlLabExecutor with getter
- Add database_name + database_backend to TargetSchemaValidationResponse
- Enrich resolve_database_id logging with database_name and all_keys
Frontend changes:
- In selectDatasource(), auto-set targetDatabaseId from ds.database_id
when present, so the correct target DB is used for schema checks.
Introduce a centralized tool registry system for the assistant to manage
executable operations, permissions, and tool catalogs. This refactors
the assistant dispatch logic from a monolithic approach to a modular,
decorator-based registry.
Key changes:
- Implement `AssistantToolRegistry` to handle tool registration,
permission checks, and safe operation identification.
- Add a suite of new assistant tools: backup, commit, branch creation,
deployment, health summary, environment listing, LLM operations,
maintenance, migration, and dashboard searching.
- Refactor `_dispatch.py` and `_llm_planner.py` to utilize the new
registry for intent resolution and tool catalog building.
- Enhance the LLM planner to support more descriptive clarification
responses in Russian when intents are ambiguous.
- Update the frontend to support the new tool-based workflow, including
improved i18n labels for assistant operations and a new step-by-step
wizard for the migration page.
- Add ADR-0008 to document the architectural decision for the tool
registry.
Introduce a new API key authentication mechanism to support service-to-service
communication (e.g., Airflow, CI/CD) without browser-based JWT login.
- Add `APIKey` model and `APIKeyPrincipal` dependency for RBAC.
- Implement `require_api_key_or_jwt` dependency with environment scoping.
- Add admin CRUD endpoints for API key lifecycle management.
- Add API key management UI in System Settings.
- Update maintenance API to support explicit `environment_id` and API key auth.
- Add i18n support for API keys and connection settings.
- Include Python and Bash usage examples in the `examples/` directory.
- Update technical specifications and documentation.
Как на maintenance с шаблоном баннера — добавил чипсы-шаблоны
SQL-запросов над textarea в модалке маппинга колонок:
- information_schema — вставляет запрос к information_schema
с JOIN pg_description для получения описаний колонок
- Custom table — вставляет запрос к кастомной таблице маппинга
- Clear — очищает поле
Чипсы в стиле rounded-full с hover-эффектами, подпись
"Шаблоны:" и title-tooltip на каждой кнопке.
i18n: 6 новых ключей (sql_templates, sql_template_*).
Использует существующий компонент /ui/HelpTooltip.svelte
(ⓘ иконка со стилизованным попапом при наведении) — тот же
паттерн, что на Maintenance и Settings страницах.
Добавлен HelpTooltip рядом с лейблами:
- Модалка маппинга: Тип источника, База данных, SQL-запрос, XLSX-файл
- Модалка генерации docs: LLM-провайдер
Native title сохранён как fallback на самих элементах форм.
StatsBar — title-подсказки на все кнопки-фильтры.
DatasetList — action-кнопки заменены на SVG-иконки с tooltip
(title="map_columns_tip" / "generate_docs_tip"), title на
select/deselect и пагинацию.
+page.svelte — title на refresh, bulk-панель, обе модалки
(маппинг колонок и генерация docs): source_type_tip,
database_tip, sql_query_tip, file_input_tip, llm_provider_tip
и текстовые хинты. Добавлены id на form-элементы для a11y.
i18n: 20 новых tooltip-ключей в ru/en.
StatsBar — переделаны огромные карточки-кнопки в компактные пилюли
(rounded-full px-3 py-1 text-sm вместо p-3 grid grid-cols-4).
DatasetList — экшн-кнопки из bg-primary в outline-стиль, карточки
плотнее (p-2.5, py-0.5), ESLint-фиксы (#each key).
Backend — linked_dashboard_count теперь заполняется в списке датасетов
через /dataset/{id}/related_objects (конкурентно, Semaphore=3, timeout=10s).
Ранее поле было только в get_dataset_detail и StatsBar показывал 0.
- Add ondelete=CASCADE/SET NULL to all environment and translate FK constraints
- Add is_multimodal to GET /api/settings/consolidated response
- Fix toggleActive to not overwrite is_multimodal with false
- New SearchableMultiSelect component for dashboard search with multi-select
- Fix validation task page: task data unwrapping, date formatting, dashboard multi-select
- Fix infinite effect loop on dashboards page via queueMicrotask guard
- 3 new Alembic migrations (merge f0e9d8c7b6a5, translate b0c1d2e3f4a5)
Backend:
- /api/validation/ CRUD for validation tasks (policies)
- Run history with 6 filters + pagination
- Alembic migrations (provider_id, policy_id)
- 28 pytest tests
Frontend:
- /validation — task list page with status filters + CRUD
- /validation/[id] — task config (Config + History tabs)
- /validation/history — run history with metrics
- Sidebar nav entry under Operations
- i18n en/ru
Playwright (ScreenshotService):
- Removed 25s hardcoded sleeps → conditional waits
- CDP fallback to full_page screenshot
- Total timeout enforcement (120s)
- Debug screenshots → temp dir with cleanup
QA fixes:
- Debug screenshot accumulation in production (tempdir + rmtree)
- Frontend API payload field name mismatch
- History issues field reference fix
- delete_runs scoped by policy_id
Belief protocol:
- @RATIONALE/@REJECTED on 27 C4+ contracts
Closes: VALIDATION-REWORK-2026