Commit Graph

832 Commits

Author SHA1 Message Date
root
34393adf7e run.sh: bind backend/frontend to 0.0.0.0; ignore root package.json 2026-07-21 21:12:49 +03:00
456d531a13 feat: harden migration flows and integration coverage 2026-07-21 18:59:26 +03:00
d1d2a0f92e feat: tiered test infrastructure with Makefile + smart selector + OpenCode commands
Root Makefile with timeout-protected test targets:
  - Tier 1 (<30s):   make test, make test-unit, make test-frontend
  - Tier 2 (smart):  make test-related F=file.py (via @RELATION BINDS_TO)
  - Tier 3 (<5min):  make test-integration (Docker, --run-integration)
  - Coverage:        make coverage (backend + frontend)
  - Lint:            make lint (ruff + eslint)

Smart test selector (scripts/find-related-tests.py):
  - Extracts module names from #region anchors, class/function defs
  - Searches 400 BINDS_TO entries across all test files
  - Confidence scoring: exact > case-insensitive > substring > heuristic
  - Fallback: filename-based fuzzy matching

OpenCode commands:
  - /test.all      — full suite + coverage
  - /test.unit     — fast unit tests (<30s)
  - /test.related  — smart selection by file
  - /test.coverage — coverage reports with thresholds

Speckit workflow updated:
  - speckit.test.md:   raw pytest → make targets with timeout safety
  - speckit.plan.md:   quickstart uses make targets
  - speckit.tasks.md:  verification uses make targets
  - speckit.implement.md: default stack uses make targets

Frontend: added 'coverage' script to package.json
2026-07-21 18:24:53 +03:00
8bc805d27b fix(i18n): replace hardcoded UI labels with locale keys
Add missing en/ru translations and wire reports, agent, git, settings,
mapper, and tasks surfaces so UI copy follows the active locale.
2026-07-21 09:15:25 +03:00
7bfc5553cf feat: live app log console, cross-filter, JSONL export
Backend:
- /ws/app-logs — real-time app/cot log stream (raw JSONL)
- /api/logs/recent — REST snapshot of ring buffer
- GET /tasks/{id}/logs/export — streaming JSONL export with CoT parse + redaction
- Thread-safe ring buffer (seq-based polling) replaces unsafe asyncio.Queue
- GIL-friendly multi-row Core insert for log persistence
- task_id ContextVar propagates into CotJsonFormatter for CoT correlation
- Hot-apply logging level on settings update (FR-005)
- Buffer trim under DEBUG floods; drop DEBUG first, preserve ERROR/WARNING
- List projection (include_result=False) keeps reports list slim
- Security event consolidated to single REASON atom

Frontend:
- ReportsLogModel + ReportsLogPanel — full live JSONL console
- Cross-filter pinning: Tasks → Logs tab with task chip badges
- LogEntryRow — CoT-aware rendering (marker icons, expandable payload)
- TaskFilterChip, taskChipMeta — scannable type/id/env chips
- Global drawer push via CSS variable (lg+ padding, not overlay)
- i18n en/ru for all log console strings
- Ctrl+A in log panel selects only log lines (window-level handler)

QA fixes:
- Svelte 5 reactivity: SvelteDate/SvelteSet/SvelteURLSearchParams
- Fix seed_trace_id shadowing (F823) in lifecycle.py
- Remove dead code (selectedEnvironment, goToReportsPage)
- Add @BRIEF to C2 test functions, missing {#each} keys
- Remove unused import json as _json from app.py

All 3200+ frontend tests pass; backend lint clean.
2026-07-20 21:41:34 +03:00
49a566359a feat: translate module — runtime knobs, GRACE anchors, two-layer testing, QA fixes
Implementation:
- Performance knobs: llm_batch_max_rows, llm_concurrency, insert_concurrency,
  multi_lang_mode, batch_aggressiveness, max_in_flight_batches
- Alembic migration f7a8b9c0d1e2 (idempotent, nullable, non-destructive)
- LLM provider capabilities: throughput_class, reasoning_control,
  supports_json_object, default/max_llm_concurrency
- TargetSchemaValidationRequest with conditional validator (sqllab/direct_db)
- Scheduler: background dispatch, local imports for lazy bootstrap

GRACE-Poly compliance:
- Semantic anchors on orchestrator_aggregator, orchestrator_sql, llm_provider
- Shared module _llm_http.py: _apply_reasoning_control extraction (INV_4)
- Alembic migration anchors per C3/C1 template
- Four renamed Svelte components: RunOutcomeSummary, DetectionQualityCard,
  LanguageStatList, SourceLanguageOverride

QA (this session):
- 11 backend test regressions fixed: spec'd MagicMock null fields for new
  columns, _check_translation_cache_bulk retarget, scheduler mock wiring,
  language_detection=auto assertions, token budget constant update
- 4 frontend eslint errors fixed: SvelteSet/SvelteDate imports,
  unused lang parameter, dead isTransientError
- Production bugfix: job_to_response() mapped 6 missing fields
- Pre-existing auth test failure documented (dependencies.py untouched)
- Axiom: 6440 contracts, 0 warnings
2026-07-20 14:19:47 +03:00
31b9a19a0c chore: commit remaining workspace updates
Agent:
- lifecycle: run tracking, middleware hardening, langgraph setup
- tests: agent lifecycle + langgraph setup coverage

Backend:
- async_job_runner: resilience hardening, tests
- agent_conversations: run lifecycle integration
- translate: scheduler + orchestrator SQL adjustments
- schemas/services: agent_lifecycle model extensions

Frontend:
- TaskDrawer: UX improvements
- TaskLogPanel/Viewer: safety hardening, i18n (en/ru)
- FilterBar: report filters contract + tests
- Reports page: layout adjustments

Specs:
- 036-agent-test-stabilization: runs contract, modules, events
- 037-superset-baseline-engine: catalog schema, testing API, modules
- 038-dashboard-scenario-model: scenario schema, capture profile, modules
- 039-dashboard-scenario-ui: screen models, release verification UX, modules
- dashboard-verification-usecases: new cross-cutting spec
2026-07-17 19:11:09 +03:00
fdb6541372 docs(adr): ADR-0019 — механизм импорта дашбордов Superset
Зафиксированы архитектурные решения миграции:
- UUID-трансформация БД через _transform_database_yaml() (вместо strip_databases)
- Cross-filter patching через IdMappingService + mapping_service в dry-run
- Password injection flow: await_input → wait_for_input → retry import
- Разделение dry-run (read-only) и execute (запись)
- Парсинг имён YAML-файлов БД с точками в имени

Задокументированы исправления production-багов 2026-07-16:
- add_log_callback в await_input (менеджер управляет сам)
- mapping_service=None в dry-run (лишал cross-filter patching)
- strip_databases=True → каскадный сбой 1010
2026-07-17 19:08:28 +03:00
8f0d123ff8 fix migration resume and release workflow 2026-07-16 12:31:59 +03:00
45ce585aba chore: commit remaining workspace updates 2026-07-16 07:53:41 +03:00
20105f51c0 feat(translate): add run preflight and focus execution UX 2026-07-16 07:52:52 +03:00
8e2f393267 refactor(frontend): remove addToast bridge — migrate all call sites to notifications API
BREAKING: addToast() removed. Use notify() or notifications facade instead.

- Replace addToast(msg, type, duration?) → notify({ message, type, duration? })
- Introduce notifications.success/info/warning/error/show() semantic facade
- Add dismissAllToasts(), timer management (clearTimeout on remove)
- Unify Toast component: single viewport, a11y (role/aria-live by type)
- Migrate 16 models, 2 stores, 38 components, 23 pages (76 files total)
- 147 test files / 3152 tests pass with updated mocks and assertions
2026-07-16 07:40:54 +03:00
20071b8c7a security: fullstack hardening — task ownership, mapping validation, API-key scoping, test fixes
Backend:
- Add validate_mapping_database_ownership() to verify source/target UUIDs
  belong to declared environments before persisting mappings (mappings.py)
- Add API-key environment scoping to get_mappings (filter) and
  suggest_mappings_api (enforce) (mappings.py)
- Add user_id Column to TaskRecord model + Alembic migration (task.py)
- Persist task.user_id on save, restore on load (persistence.py)
- Wire current_user.id into migrate_dashboards + backup_dashboards
  task creation (_action_routes.py)
- Fix test_migration_routes.py: module-level patch leak → autouse fixture,
  SupersetClient→AsyncSupersetClient, AsyncMock for sync_environment/run
- Fix 7 Pydantic serializer warnings: 'PENDING'→TaskStatus.PENDING
  in test_tasks.py + import TaskStatus

Frontend:
- Deepen isDryRunResult(): validate selection field, risk.items entries
  (all 5 fields), and diff object uuids individually (ExecutorModel.svelte.ts)

Prior work included: task password redaction, resume ownership checks,
canonical dry-run DTO alignment, migration UI callback fixes, credential
exposure reduction, assistant dry-run await fix.
2026-07-15 23:02:23 +03:00
30c8acf7ae fix(translate): handle invalid LLM JSON responses 2026-07-15 20:06:39 +03:00
612cc55911 test(translate): cover required field checklist 2026-07-15 16:53:25 +03:00
9922d7c87a fix(translate,scheduler): language detection, LLM error handling, and scheduler persistence
Translation pipeline fixes (from production error log analysis):

Lang detect:
- Add "ru" to _COMMON_SOURCE_CODES for Cyrillic source detection
- Version detector cache keys (v2:) and include detector version in
  source hash — stale cache entries from old algorithm are invalidated
- Integrate _character_block_fallback into batch_detect() pipeline;
  only assign Cyrillic fallback when exactly one Cyrillic target exists
  (multiple ru/uk/be targets stay undetermined for LLM arbitration)

Batch processing:
- Case-insensitive cache language matching (cached_by_lang lookup)
- Propagate needs_review=True for undetected language rows in pre/cache path

LLM call (critical — fixes silent error hiding):
- Validate LLM row IDs against expected set; log unknown identifiers
- Retry only missing rows on incomplete response (bounded by recursion depth)
- Exhausted retries → FAILED (new _handle_incomplete_response method)
- Parse failures → FAILED instead of SKIPPED (_handle_parse_failure)
- NULL/Empty translations → FAILED via new _add_failed helper
- Source-language identity mapping preserved as TranslationLanguage entry
  (carries source_language_detected metadata that _build_insert_rows
  relies on for detected_src_lang derivation)
- finish_reason propagated to parser for truncation diagnostics

LLM parse:
- Structured incomplete-set logging with expected/received/missing counts

Target schema validation:
- Handle all non-success SQL Lab statuses (failed, timeout, error, stopped)
- Timeout gets explicit message prefix
- Route returns HTTP 502 with correct HTTPException passthrough

Scheduler persistence fix (production pickle error):
- Backup and validation APScheduler jobs now use module-level callbacks
  (execute_scheduled_backup, execute_scheduled_validation) instead of
  bound SchedulerService methods — prevents pickle failure from
  serializing TaskManager + dynamically loaded plugin classes
- Callback func identity verified via pickle round-trip smoke test

Tests:
- Update assertions: FAILED replaces SKIPPED for LLM error paths
- Restore source-language contract tests with identity-mapped values
- Add scheduler callback identity and args verification tests
- Update detector cache key tests for versioned format
- Update target schema error route test: 200→502

Orthogonal code review: MEDIUM finding (empty rec.languages when all
targets match detected source → _build_insert_rows fallback to "und")
fixed by preserving source-language TranslationLanguage entries.
2026-07-15 13:07:41 +03:00
8f4ee25415 fix(alembic): merge three migration heads + add smoke test for chain integrity
- 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
2026-07-14 17:33:16 +03:00
9b3cc54646 feat: add backup integrity verification 0.5.5 2026-07-14 16:05:28 +03:00
c3ad0afc17 refactor: remove rejected dataset review feature 2026-07-14 15:56:31 +03:00
2a56ea5fc9 test: fix backend and frontend test contracts 2026-07-14 10:43:38 +03:00
66497da72b feat(mapper): secure xlsx upload and dataset selection 2026-07-14 00:34:10 +03:00
d630573402 fix(backup): orthogonal code review fixes + UI/UX overhaul
## Critical fixes
- H1: Fix env_id/env/environment_id triple inconsistency in API route
  (_action_routes.py now passes 'environment_id', matches scheduler)
- H2: Decompose BackupPlugin.execute() — CC 13 → 5 methods, CC ≤ 5 each
- H3: Fix unhandled int() ValueError on non-numeric dashboard_ids
- H4: Add concurrent guard test with API-style params (env key fallback)
- H5: Make RetentionPolicy configurable via StorageConfig
  (retention_daily/weekly/monthly in config model + backend plugin)
- Fix: storage DELETE route missing 'await' on async delete_file (bug)

## UI/UX overhaul
- NEW: centralized cron utility (frontend/src/lib/utils/cron.ts)
  - validateCron(), calcNextCronRun(), formatNextRun()
  - Used by BackupManager, BackupDashboardModal
- BackupManager: replace custom BackupList with shared FileList
  - Adds: download, delete, bulk actions, search, sort, pagination
  - Adds: cron next-run preview below schedule input
  - Adds: auto-open TaskDrawer on backup task creation
- BackupDashboardModal: dead 'Cron Help' button removed
  - Adds: live cron validation + next-run preview
- StorageSettings: adds retention daily/weekly/monthly fields
- BackupCreateRequest type fixed to match actual API contract
- i18n: 7 new keys for en/ru (next_run, retention_*)
2026-07-13 20:58:02 +03:00
2819ca3a15 semantic 2026-07-13 17:24:39 +03:00
ed85e0d80a feat(git): clarify dashboard release flow 2026-07-13 16:53:35 +03:00
2eca5b514b docs(specs): complete speckit packages 036-039 2026-07-13 15:10:07 +03:00
c2bd6cb441 feat(git): clarify dashboard release flow 2026-07-13 12:55:24 +03:00
00d2619c86 fix: align DRAFT integration test with removed DRAFT check in validate_job_preconditions
- 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
2026-07-12 19:44:11 +03:00
a39a76c87f feat(agent-centric-logging): consolidate CoT infra in shared, close REASON→REFLECT chains
- shared/cot_logger.py is SSOT; backend/cot_logger.py deleted
- elapsed_ms timing in all REFLECT markers
- Frontend: REASON→REFLECT/EXPLORE in all fetch/post/delete/requestApi
- Dynamic src: route.GET.api.plugins instead of hardcoded api.request_handler
- trace_id generated immediately (no 'no-trace'), X-Trace-ID in both directions
- Global error handlers (window error + unhandledrejection + error.svelte)
- Fixed duplicate logging (shared/logger.py double StreamHandler)
- propagate=False in configure_logger (was in ConfigManager = duplicated startup logs)
- belief_scope: 'Coherence OK' → '{anchor}: completed' + elapsed_ms
- Fixed 28 pre-existing test failures (scheduler sig, DB columns, DRAFT validation, etc)
2026-07-12 19:30:57 +03:00
24d3b7d1f9 refactor(task-manager): implement task resilience and execution lifecycle improvements
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.
2026-07-12 15:31:56 +03:00
0cb1f80cd6 feat(git): implement deployment tracking and enhance lifecycle UX
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.
2026-07-12 14:57:03 +03:00
b39d9991b9 fix(logs): resolve old prod execution issues + full GRACE-Poly compliance
- translate: pure-skip scheduled runs now COMPLETE (not FAILED); extract _compute_final_status
- scheduler: cron validation at update; pre-validate + skip legacy bad expr (/15*) in load
- git: robust get_branch_commits (existence check for 'prod' to avoid fatal)
- health: use explore for network/auth failures (reduces spam)
- Full semantic protocol updates across modules:
  - complete #region/#endregion + @BRIEF/@PRE/@POST/@INVARIANT/@RELATION/@RATIONALE
  - belief_scope + CoT markers (reason/explore/reflect)
  - semantics-testing compliance in tests
- Addresses exact symptoms from container_backend.log and backend/logs/app.*

Related to 039-dashboard-scenario-ui log analysis.
2026-07-10 12:35:07 +03:00
3404967f76 feat(git): add environment timeline visualization and branch commit APIs
Implement a new Git environment timeline component to visualize dashboard
versions across different deployment stages (Development, Pre-production,
and Production). This includes new backend endpoints and frontend
services to support historical data retrieval and version comparison.

- Add `get_branch_commits` and `get_commit_diff` endpoints to backend
  API and Git service.
- Implement `GitEnvironmentTimeline` Svelte component for visual
  representation of deployment history.
- Update `GitManagerModel` to manage timeline state, including
  environment histories and version selection for comparison.
- Add `getBranchCommits` and `getCommitDiff` methods to `gitService`.
- Improve UX by separating the branch selector from the version map.
- Add comprehensive i18n support for the new visualization features.
2026-07-10 10:55:10 +03:00
db07bbb1d5 feat(maintenance): improve store with pending removals + ADR-0006 compliance
- Add pendingRemovals tracking and isEventRemoving() to maintenance store for better in-flight UX in EventsTable.
- Strongly type maintenance API client and store (replace unknown[]).
- Migrate selectedTask/taskLogs to dedicated lib/stores/selectedTask.svelte.ts (proper rune store with separate subscribers).
- Remove legacy central stores.svelte.ts and related dead code (src/pages/, old tests) to comply with ADR-0006 (global stores must be individual files in lib/stores/).
- Update mocks, components, models and tests accordingly.
- Fix related bugs (subscriber decoupling, test mocks).
- Add dedicated test_selectedTask.ts.
- Minor cleanups: semantic tokens, @RATIONALE for model-first, contracts update.
- All key tests (maintenance, selectedTask, store) pass.

Refs: ADR-0006, specs/031-maintenance-banner
2026-07-09 22:14:01 +03:00
fd9218a722 chore(agents): remove deprecated agent definitions and add task CRUD tests
Remove several legacy agent configuration files from the `.kilo/` directory and add new unit tests for task CRUD operations in the backend API routes.

- delete .kilo/agent/swarm-master.md
- delete .kilo/agents/closure-gate.md
- delete .kilo/agents/mcp-backend-coder.md
- delete .kilo/agents/swarm-master.md
- delete .kilo/agents/tester.md
- add backend/src/api/routes/__tests__/test_tasks_crud.py
- update backend/src/api/routes/__tests__/conftest.py to include test database URLs
2026-07-08 21:19:33 +03:00
3b13c67c0d feat(translate): language detection, async HTTP LLM, history model, agent improvements
- Add async HTTP-based LLM transport (_llm_async_http.py)
- Add orthogonal LLM call tests
- Improve language detection (_lang_detect.py) and batch insert
- Update translate schemas, service utils, preview constants/prompts
- Add TranslateHistoryModel with pagination and filtering
- Update agent confirmation, persistence, langgraph setup, run, tools
- Improve LLM health checking in shared module
- Update translate runs API, history route
2026-07-08 19:35:49 +03:00
e6532c8dab refactor(translate): remove DRAFT status from UI, auto-transition via preflight
- Remove DRAFT badge, 'Mark as READY' button, DRAFT filter pill, DRAFT run gate
- Auto-transition DRAFT<->READY based on runReady (all required preflight items)
- Move PreflightChecklist to page top — always visible across tabs
- Remove orchestration DRAFT gate — preflight handles readiness
- Remove 10 dead i18n keys (status_draft, mark_ready, disabled_draft, hint_draft)
- Add reverse transition READY->DRAFT when fields cleared
- Remove unused runComplete prop from RunTabContent
- Add fallback badge styling for unrecognized statuses
2026-07-08 19:35:05 +03:00
2d0fe96a63 chore: add GRACE semantic contracts across agent + backend + build scripts
- Add @RELATION/@RATIONALE/@REJECTED headers to agent modules
- Add GRACE contracts to backend services, models, schemas
- Update build.sh with single-image build commands (build:backend|frontend|agent)
- Update docker entrypoint: openssl rsa → openssl pkey (alg-agnostic)
- Add @RATIONALE to backend core modules (cot_logger, config_manager, ssl)
2026-07-08 11:10:59 +03:00
25643a5656 test(frontend): reach coverage targets — 99.45% stmts, 89.14% branches, 99.71% fns, 99.82% lines
Add 813 new tests (+31.6%) to bring all covered files to thresholds:
- 4 zero-coverage models (KeyRecovery, BulkReplace, TopNavbar,
  TranslationRunResult) → 100% with L1 model-invariant tests
- 8 low-coverage models extended past thresholds
- UI components (Pagination 1→31, Skeleton 20, Badge 27, ConfirmDialog 21)
- API modules (api.ts, cot-logger, maintenance, reports) → 100%
- Utils/stores (dateFormat, timezone, toasts, stores, maintenance)

Production changes:
- Add GRACE contract headers (@RATIONALE/@REJECTED) to 10+ files
- Fix batcheslength→batches.length typo in TranslationRunResult.svelte
- Refactor Badge.svelte || expressions into cls() helper
2026-07-08 11:09:52 +03:00
d0facf4a3a fix(translate): datasource change not persisted on save + preview column cleanup
Root cause: saveJob() used stale sourceDatasourceId (set once on load)
instead of live datasourceId (updated by ConfigTabForm via $bindable).
Since sourceDatasourceId was always truthy, the || fallback to datasourceId
never triggered — the old datasource ID was always sent to PUT.

Fixes:
- Removed dead sourceDatasourceId atom; saveJob() uses datasourceId directly
- Bound sourceTable via $bindable through ConfigTabForm; updated on select
- loadDatasourceColumns() syncs databaseDialect from Superset columns API
- saveJob() sends undefined for database_dialect="unknown" to force re-detect
- Backend: added direct_db+connection_id validation on update (mirroring create)
- Removed redundant "Язык ист." column from TranslationPreview table
- Removed unused getDetectedLang function

Tests:
- TranslationJobModel: datasourceId save mapping, dialect sync, unknown→undefined
- TranslateJobService: reject direct_db without connection_id, preserve existing

Verified: browser — translate_cross datasource persisted after save+reload,
dialect detected as "clickhouse", columns loaded (2), translation column preserved.
2026-07-07 23:50:08 +03:00
34aeeb92a2 fix(backend+frontend): migration deadlock, async pattern, timeout safety, fire-and-forget translations
Backend:
- MigrationPlugin.execute — remove AsyncJobRunner.run() deadlock on post-migration
  ID sync (2 deadlocks total: plugins/migration.py + api/routes/migration.py
  trigger_sync_now). Replace blocking runner.run with direct await.
- MigrationPlugin.execute — fix temp file leak (dry_run=True prevented cleanup).
- MigrationPlugin.execute — IdMappingService(SessionLocal()) now closed in finally.
- MigrationPlugin.execute — wire IdMappingService into MigrationEngine constructor
  so cross-filter patching actually works instead of silently skipping.
- MigrationPlugin.execute — SupersetClient.aclose() in finally to prevent
  httpx connection pool leak.
- TaskManager — _async_tasks dict leak (add_done_callback cleanup).
- JobLifecycle — CancelledError handler (tasks stuck in RUNNING after cancel).
- JobLifecycle — persist_task BEFORE _broadcast_task_status (crash consistency).
- JobLifecycle — wait_for_resolution/wait_for_input now have 3600s timeout.
- AsyncJobRunner.run — 300s timeout on future.result() (APScheduler thread safety).

Translate scheduler:
- execute_scheduled_translation — replace blocking runner.run(orch.execute_run(run))
  with fire-and-forget TranslationOrchestrator.execute_background(). APScheduler
  thread is freed in ms instead of blocking for the full translation duration.
  Translation runs of 10k+ rows (200+ LLM batches, hours) no longer hit the
  300s runner timeout.
- TranslationOrchestrator.execute_background — new static method: opens own DB
  session, dispatches asyncio.create_task, handles errors + notification.
- Scheduler last_run_at updated at dispatch time (not after completion).

Frontend:
- MigrationModel.stepReady[3] now requires dryRunResult != null (was always
  true, allowing UI to reach step 3 without dry-run).
- WizardModel.goToStep gate for step 3 uses stepReady[3].
- +page.svelte  — dryRunResult no longer self-clears via reactive loop.
- Progress bar step 3 indicator gate fixed for new readiness logic.

Tests:
- 2 new regression tests for migration sync (deadlock-free, completes cleanly).
- test_migration_plugin.py — _make_mock_superset_client/_make_mock_mapping_service
  helpers for proper async mock behavior (aclose, sync_environment AsyncMock).
- 10 scheduled-translation tests updated for fire-and-forget pattern.
- MigrationModel.test.ts — step 3 invariant + goToStep block test.
- All affected tests: 104 backend + 79 frontend = 183 passed.
2026-07-07 21:04:23 +03:00
3f6d7222c3 fix(agent): proxy gradio config and reduce translate blocking 2026-07-07 17:37:36 +03:00
cfb95fa3c8 refactor(agent): extract agent+shared into standalone packages with full GRACE semantic markup
- Move agent code from backend/src/agent/ to agent/src/ss_tools/agent/
- Extract shared stdlib-only utilities to shared/src/ss_tools/shared/
- Add #region/#endregion contracts to all ~140 functions (INV_1 compliance)
- Update docker files, entrypoint, build scripts for new package layout
- Backend now imports ss_tools.shared._llm_health (no gradio/langchain deps)
- Add specs for 036-039 feature plans
2026-07-07 15:18:24 +03:00
da6a3f28ad fix(agent): rewrite _llm_health to use openai+httpx instead of langchain
Previous lazy-import fix still required langchain at function call time.
Root cause: langchain_openai/langchain_core are only in requirements-agent.txt,
not requirements-backend.txt. The /api/agent/llm-status endpoint runs in
the backend container which has 'openai' but not 'langchain'.

Rewrite _check_llm_provider_health() to use:
- AsyncOpenAI from 'openai' package (in both containers)
- httpx to call /api/agent/llm-config on localhost (same as agent does)
- system_ssl_context() for SSL (same as LLM test endpoint)
- openai exceptions (APIConnectionError, APITimeoutError, etc.)

No langchain dependency at all — works in both backend and agent containers.

Verified: 977 tests passed, import without langchain succeeds.
2026-07-07 13:34:07 +03:00
ff2f1825a8 fix(agent): lazy imports in _llm_health — langchain_core not in backend container
_llm_health.py imported langchain_core, langchain_openai, and openai at
module level. These packages are only installed in the agent container
(requirements-agent.txt), not the backend container (requirements-backend.txt).

Moved all langchain/openai imports inside _check_llm_provider_health() with
ImportError handled gracefully — returns 'unavailable' status instead of
ModuleNotFoundError 500 error.

Root cause: the /api/agent/llm-status endpoint runs in the backend container,
which has httpx but not langchain. The agent container has all LLM deps.

Verified: import without langchain succeeds, health check returns 'unavailable'.
2026-07-07 13:24:45 +03:00
89cd123dec fix(frontend): dynamic year + git commit hash in APP_VERSION
- Footer.svelte: replace hardcoded '2025' with new Date().getFullYear()
- build.sh: append git short hash to APP_VERSION for all bundle commands
  (bundle, bundle:embeddings, bundle:light). Format: '0.5.2+6f029903'.
  Previously only the tag was passed (e.g. '0.5.2'), and .git was not
  available in Docker context so vite.config.js fell back to '0.0.0'.

Verified: frontend assets contain '0.5.2+6f029903', getFullYear() replaces
hardcoded 2025.
2026-07-07 12:29:46 +03:00
6f02990347 fix(ssl+agent): capath for all HTTP clients + isolate gradio import
SSL fix (ADR-0009 Finding 7):
- Replace ssl.create_default_context() with system_ssl_context(capath)
  in client_registry.py, async_network.py, notifications/providers.py,
  git/_base.py. Previous fix (0.5.1) only covered LLM clients; the
  Superset API client still used ssl.create_default_context() which
  loads cafile (flat bundle) where OpenSSL 3.x ignores intermediate CA
  certificates. system_ssl_context() uses capath only (hash symlinks).

Agent fix:
- Extract _check_llm_provider_health + _llm_status from agent/app.py
  into agent/_llm_health.py. The /api/agent/llm-status endpoint was
  importing from agent/app.py which triggers 'import gradio' at module
  level. Backend container does not have gradio installed, causing
  ModuleNotFoundError (500 error) every 30s on health check polling.

Config:
- Add ALLOWED_ORIGINS to docker-compose.yml + docker-compose.enterprise-clean.yml

ADR-0009 updated: Layer 2 table expanded with 4 missing clients,
Finding 5 reconciled (LLM_CA_CERT_URLS restored in 0.5.1), version 0.5.2.

Verified: 1110 unit tests passed, gradio import isolation confirmed.
2026-07-07 12:18:43 +03:00
1182b29fe0 fix(certs): restore HTTP CA auto-download and test edge matrix
Restore LLM_CA_CERT_URLS support for corporate PKI HTTP cert delivery.
Downloaded certificates are installed into the llm/ CA category and share
the same system trust + NSS import path as CERTS_PATH-mounted certs.

Changes:
- certs.sh: add download_llm_ca_certs with HTTP-only curl policy,
  PEM/DER handling, retries, llm/ storage, hash symlinks for llm+custom
- backend/agent entrypoints: run download before install_all_certs
- compose/env/docs: expose LLM_CA_CERT_URLS again and update ADR-0009
- integration tests: cover PEM/DER/CER, invalid certs, non-HTTP skips,
  query-string filenames, private/server skips, empty inputs, combined
  LLM_CA_CERT_URLS + CERTS_PATH channels, and NSS imports

Verified:
- 194 passed, 1 skipped integration tests
- full backend container smoke passed with testcontainers PostgreSQL
- docker bundle rebuilt for 0.5.0
2026-07-07 10:23:49 +03:00
702ee25ae4 fix(docker): add missing certs.sh COPY to backend/all-in-one Dockerfile
Backend entrypoint sources certs.sh for CA certificate installation,
but the file was never copied into the Docker image — causing
container crash loop on startup (regression in 7f932610).

Changes:
- docker/backend.Dockerfile, docker/all-in-one.Dockerfile: COPY certs.sh
- docker/backend.entrypoint.sh: remove dead install_llm_ca_certs,
  install_certificates (replaced by docker/certs.sh); update @INVARIANT
- backend/src/core/ssl.py: fix describe_context() to report actual
  system cert count (SSLContext.capath attr does not exist in Python 3)
- __tests__: rewrite stale tests asserting LLM_SSL_VERIFY=false →
  verify=False; behaviour is permanently removed — always CERT_REQUIRED
- backend/tests/integration/test_backend_container.py [new]: 5 tests
  verifying certs.sh presence, sourceability, and full-stack smoke
  (testcontainers PG → entrypoint → migrations → health)
- conftest.py: restore health-wait loop and fixtures in superset_container
- ADR-0009, README.md, scripts, .env: align docs with centralized SSL
2026-07-07 00:58:41 +03:00
aafd89f2c7 test(integration): add encrypted key Superset container test with SSL_KEY_PASSPHRASE
conftest.py: superset_container fixture supports {encrypted_key: True}
  - Writes encrypted private key to container
  - Decrypts with openssl rsa -passin env:SSL_KEY_PASSPHRASE
  - Starts Flask/Werkzeug TLS server with decrypted key
  - Falls back to unencrypted key for existing tests

test_superset_tls_custom_ca.py:
  - NEW: TestEncryptedPrivateKeySuperset class
    - test_superset_health_over_tls_with_encrypted_key
    - test_openssl_capath_encrypted_key
  - Uses parametrize({tls: True, encrypted_key: True})

Validates full production flow: encrypted key → SSL_KEY_PASSPHRASE
→ openssl decrypt → TLS handshake → client trust via capath.
2026-07-06 21:21:42 +03:00
7f93261060 refactor(ssl): centralize SSL trust management, remove LLM_SSL_VERIFY
Centralized SSL via one contract: CERTS_PATH=/opt/certs mounted into all containers.

Backend:
  - NEW: backend/src/core/ssl.py — system_ssl_context(), httpx_verify(),
    cert_dir_inventory()
  - LLMClient._get_ssl_verify() → delegates to core.ssl
  - _llm_async_http._get_verify() → delegates to core.ssl
  - Removed LLM_SSL_VERIFY env reading from all runtime code

Docker:
  - NEW: docker/certs.sh — shared cert installer (PEM/DER/cer to .crt conversion,
    update-ca-certificates, hash symlinks, NSS import)
  - NEW: docker/agent.entrypoint.sh — agent entrypoint with cert installation
  - backend.entrypoint.sh → uses certs.sh instead of install_llm_ca_certs
  - Dockerfile.agent → adds ca-certificates, openssl, entrypoint

Compose:
  - Removed LLM_CA_CERT_URLS and LLM_SSL_VERIFY from all compose files
  - Added CERTS_PATH volume mount to agent (dev + enterprise)
  - Added certs volume mount to backend/agent in dev compose

Env examples:
  - Removed LLM_SSL_VERIFY, LLM_CA_CERT_URLS from .env.example,
    .env.enterprise-clean.example, .env.current.example, .env.master.example,
    backend/.env.example
  - Enhanced CERTS_PATH comments with accepted formats

Diagnostics:
  - diag_container.py: removed LLM_* checks, added CERTS_PATH inventory,
    uses core.ssl for context creation

Tests:
  - Updated test_llm_analysis_service, test_llm_async_http,
    test_client_headers to verify centralized ssl context (no env disable)
  - 4/4 SSL tests pass
2026-07-06 21:00:28 +03:00