Remove dead schema left behind by removed features:
- dataset-review family (dataset_review_sessions, dataset_profiles, and
related children) from c3ad0afc — its non-cascading FKs broke environment
deletion with ForeignKeyViolation
- connection_configs from 74e64622
Both are unreachable from the app (no models register them).
Runtime migrations failed with 'Multiple head revisions are present' because
037 T081 (p2q3r4s5t6u7 -> verification_runs.dashboard_id) and a concurrent
session-activity change (a1b2c3d4e5f7) both branched from o1p2q3r4s5t6.
The failed 'upgrade head' left dashboard_id unapplied, causing
'column verification_runs.dashboard_id does not exist' on
GET /verification/history.
Add a no-op merge revision (015281bd7759) collapsing both into a single head
so 'upgrade head' applies the verification_runs.dashboard_id column.
Verified: ScriptDirectory.get_heads() == ['015281bd7759'].
Close the 037 pipeline-automation and read-API gaps found in the audit:
deploy/release hooks did not create VerificationRun, and GET endpoints for
history/detail were absent even though 039 UI and client call them.
T080 - _release_routes.py: create_release now fires best-effort
_trigger_release_verification -> VerificationRun with trigger=release_create
(metric+structure); verification scheduling failures never roll back the
release transaction.
T081 - verification.py: add GET /verification/history (dashboard_id +
environment_id filters, newest-first) and GET /verification/{run_id}
(404 RUN_NOT_FOUND); reuse _record_to_response.
- verification_run.py + alembic migration p2q3r4s5t6u7: nullable indexed
dashboard_id populated from structure/visual/metric category_params.
- verification_service.py: _derive_dashboard_id helper.
Verification: release routes (32) + verification API (8) + persistence (21)
= 53 passed; ruff clean for changed code (pre-existing RUF012/UP017 on old
lines left untouched).
Add auto_end flag to maintenance_events: when set with an end_time, a
60s APScheduler scan dispatches the end task automatically. The scan
survives restarts and is de-duped by task_id; end_time alone stays
informational. Includes alembic migration, route/schema wiring, Svelte
checkbox with validation, examples, and backend + frontend tests.
Systematic rename of all semantic anchors (#region, [DEF], @RELATION)
across 1400+ files — backend Python, frontend Svelte/TS, specs, docs:
- Flat anchors become Namespace.Module.Entity
- @RELATION references updated to match new anchor paths
- Zero business logic changes
- Created merge migration 7eaf84b7f6be joining heads:
- 6b8ca3b7405f (previous merge of c0d1e2f3a4b5 + f2b3c4d5e6f7)
- b4c5d6e7f8a9 (include_source_reference to translation_jobs)
- f4a5b6c7d8e9 (preproduction validation to deployment records)
- Added smoke test (test_smoke_migration_chain.py) that:
- Checks exactly 1 head (catches branch divergence)
- Walks full chain verifying all down_revision links exist
- Confirms all .py files are loaded as revisions
- Runs WITHOUT a database (real ScriptDirectory, no mocks)
- Catches what existing tests missed:
* test_alembic_migrations.py skips on non-PostgreSQL
* test_check_migration_chain.py uses mocks, not real files
- DRAFT validation was removed from orchestrator_validation.py (moved to service layer)
- Integration test expected ValueError for DRAFT jobs — fixed to test actual behavior
- 194/194 integration tests pass, 0 failures
Enhance the reliability and observability of the task execution engine
by introducing retry mechanisms, idempotency, and structured progress
tracking.
- Implement centralized retry logic with exponential backoff support
in `JobLifecycle`.
- Add `retry_task` API endpoint and `TaskManager` method for manual
task restarts.
- Introduce task idempotency using `_idempotency_key` to prevent
duplicate executions.
- Add `retry_count`, `max_retries`, `last_error`, and `progress` fields
to the `Task` model and ensure persistence via `TaskPersistenceService`.
- Upgrade `SchedulerService` to use differential synchronization with
the persistent `SQLAlchemyJobStore` for better job durability.
- Implement structured heartbeat logging to support real-time progress
updates.
- Update project documentation and ADRs to reflect the new plugin
runtime and task resilience patterns.
- Add comprehensive unit and integration tests for the new task
lifecycle features.
Introduce a deployment recording system to track dashboard versions
across environments and improve the Git management user experience.
- Add `Deployment` model and Alembic migration to persist deployment
history.
- Implement `GitDeploymentRecorder` and `GitFingerprint` plugins to
automate deployment logging and content hashing.
- Add `get_deployment_status` API endpoint to retrieve real-time
environment states.
- Refactor `GitLifecycleHeader` to prioritize Call-to-Action (CTA)
buttons and improve visual hierarchy.
- Update `GitWorkspacePanel` to emphasize version saving and
streamline commit workflows.
- Enhance `GitEnvironmentTimeline` with deployment status integration,
collapsible UI, and improved theme consistency.
- Add auto-navigation logic in `GitManagerModel` to guide users to
relevant tabs based on recommended actions.
- Clean up obsolete documentation and update i18n strings for
git visualization features.
- 2df63b7ce038: was checking _column_exists but not _table_exists.
If llm_providers/validation_policies/llm_validation_results don't
exist (fresh DB), _column_exists returns False and add_column crashes.
Now checks _table_exists first.
- a1b2c3d4e5f6 (20260603_add_token_limits_to_llm_providers): no guard
at all. llm_providers is created by create_all() at runtime. Guard
matches pattern used by ed28d34edde7, 9f8e7d6c5b4a and others.
dataset_review_sessions (and potentially other tables in FK_DEFS) are
created at runtime by init_db() → Base.metadata.create_all(), not by
Alembic migrations. On fresh databases, these tables don't exist when
migrations run, causing ALTER TABLE to crash.
Fix: check table existence before operating on each FK. If a table
doesn't exist, create_all() will create it with the correct FK
definition (the model already has ondelete='CASCADE').
This is the same pattern used by other migrations (9f8e7d6c5b4a,
ed28d34edde7, c9d8e7f6a5b4, 86c7b1d6a710) for create_all()-only tables
like llm_providers, roles, validation_policies, llm_validation_results.
- Add e1f2a3b4c5d6 migration: create dataset_review_sessions with FK
ondelete='CASCADE' (matching the model). Previously created at runtime
by init_db() → create_all().
- Update f0e9d8c7b6a5: change down_revision from a5b6c7d8e9f0 to
e1f2a3b4c5d6 so the table exists when this migration runs.
- All other create_all()-only tables (llm_providers, roles,
validation_policies, llm_validation_results) already have guards
(_table_exists()) in their respective migrations.
- Add d1e2f3a4b5c6 migration: create task_records table matching the
TaskRecord model (previously created at runtime by init_db() via
Base.metadata.create_all).
- Update a5b6c7d8e9f0: down_revision now points to d1e2f3a4b5c6, so
task_records exists when this migration runs. Remove the
inspector.has_table() guard (no longer needed).
- create_all() in init_db() becomes a no-op for task_records — the
table is now fully managed by Alembic.
- Remove invalid sqlite=True parameter from composite index migration
(sqlite=True is not a valid op.create_index parameter)
- Fix test_assistant_api assertions for updated response format
- Fix test_git_status_route edge case assertions
- Fix test_audit_service expected value after metric changes
- Fix test_session_repository assertion after store refactor
Add support for regex-based dictionary entries across the full stack:
Backend:
- DictionaryEntry model: add is_regex column (Boolean, default False)
- DictionaryEntryCRUD: validate regex on add_entry(), compile on creation
- _enforce_dictionary: match by regex pattern when is_regex=True
- dictionary_filter: support is_regex in filter/query
- metrics: include is_regex entries in metrics calculations
- Alembic migration: 20260604_add_is_regex_to_dictionary_entries
- Merge migration: 351afb8f961a (merge is_regex + composite index heads)
Frontend:
- DictionaryDetailModel: add is_regex field to DictionaryEntry interface,
EditForm, and addForm; sync edit/add form state with backend schema
- Add composite index ix_translation_records_run_source_hash
for NOT EXISTS dedup subquery performance + Alembic migration
- Remove duplicate #endregion in orchestrator.py (INV_3)
- Replace hardcoded RU fallback 'Статус' with 'Status'
- Add early return guard to loadMoreRecords()
- Show records summary always when recordsTotal > 0
- Removes source_dialect and target_dialect from TerminologyDictionary model,
schemas, routes, helper serialization, and all tests
- Adds allowed_languages config field (BCP-47 language codes) to GlobalSettings
with validation, consolidated settings response, and API endpoint
- Adds alembic migration f1a2b3c4d5e6 to drop the two columns
Backend:
- TranslationRun model: add cache_hits Integer column (default 0)
- TranslationRunResponse schema: add cache_hits field
- _helpers.py/_run_list_routes.py/orchestrator_aggregator.py: include
cache_hits in all run API responses
- _batch_proc.py: count pre_rows served from translation cache per
batch, return cache_hits in batch result
- executor.py: accumulate cache_hits across batches, persist to run
- Alembic migration: dabc9709 — add cache_hits column to translation_runs
Frontend:
- translationRun.svelte.ts: add cacheHits to store state, WS handler,
polling handler
- TranslationRunProgress.svelte: 5-col stats grid with purple Cache card
- TranslationRunGlobalIndicator.svelte: 5-col stats with Cache
- TranslationRunResult.svelte: 5-col detail stats with Cache card
- History page: cache_hits shown in run list row + detail panel
Visual: cache hits shown in purple alongside green/yellow/red metrics
(total/success/failed/skipped). Visible during run + in history.
Tests: backend 69/69 translate tests ✅, frontend 698/698 tests ✅,
frontend build ✅
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