Commit Graph

385 Commits

Author SHA1 Message Date
21794465f4 lang detect 2026-05-20 17:15:31 +03:00
b455e1a16b refactor(semantics): make complexity tiers descriptive, not gatekeeping
Why: tier rules forbidding @PRE/@POST on C2 cause agents to either
remove useful documentation or generate audit noise. Both outcomes are
worse than having slightly richer metadata.

Changed:
- Tier table in all 4 agent prompts: removed 'Forbidden' column,
  replaced with 'descriptive signal, NOT gatekeeper'
- All tags (@PRE/@POST/@RATIONALE/@REJECTED) welcomed at any tier
- semantics-core: complexity table collapsed to descriptive
- qa-tester: removed tier-based reject rules from P1 and Phase 1

Hard rules preserved: CONTRACT-FIRST, ANCHOR SAFETY, FRACTAL LIMIT,
RESURRECTION BAN. Everything else is descriptive intent.
2026-05-20 15:15:52 +03:00
2205c41ff0 refactor(agents): inject CONTRACT MANDATE into all coder agent prompts
Why: agents kept forgetting #region contracts because the rationale
was hidden in loadable skills, not active in their system prompt.

Changed agent prompts (+RATIONALE-first):
- python-coder: +55 lines — 4 failure modes + operational rules
- fullstack-coder: +40 lines — same, with cross-stack emphasis
- svelte-coder: replaced PHYSICS OF ATTENTION with unified mandate
- qa-tester: +15 lines — QA-specific contract mandate

Compressed skills (reference-only):
- semantics-core: 174→110 lines (-37%) — rationale removed, syntax+tables kept
- semantics-contracts: 103→79 lines (-23%) — duplicates removed, methodology kept

Verification: 320 tests pass, 0 parse warnings, 0 semantic audit warnings
2026-05-20 15:02:29 +03:00
0b8c68f6ee fix(semantics): add function-level GRACE contracts to _lang_detect.py
All 5 functions now have proper #region/#endregion contracts:
- _detector_cache_key [C:1] — private helper
- build_detector [C:2] — public API
- get_detector [C:2] — public API with caching
- detect_language [C:2] — public API, @RAISES for safety
- batch_detect [C:3] — public API with @RELATION edges

Clean audit: 0 warnings on _lang_detect.py
2026-05-20 14:39:06 +03:00
83dde3550d fix(semantics): upgrade complexity tiers, add missing relation edge
- LanguageDetectService: C2→C3 (has @RELATION, requires C3)
- LanguageDetectServiceTests: C2→C3 (has @RELATION, requires C3)
- preview.py: add @RELATION DEPENDS_ON -> [LanguageDetectService]
2026-05-20 14:34:43 +03:00
c334b1b0ca feat(translate): replace LLM-based language detection with local lingua-detector
- Add _lang_detect.py module wrapping lingua-language-detector (pure Python, 0.076ms/call)
- Add batch_detect() with detector caching for performance
- Pre-filter rows where detected source language matches target (same-language skip)
- Remove detected_source_language from LLM prompt templates (token savings)
- Use local detection for cached rows (was always 'und')
- Preserve backward compat: LLM detected_source_language as fallback when lingua returns 'und'
- Add 24 unit tests for detection, edge cases, caching, and mapping
2026-05-20 14:31:37 +03:00
81f3b4cc7f tasks 2026-05-20 09:59:11 +03:00
d48e6c0d83 semantics 2026-05-20 09:59:03 +03:00
82c1b92a51 semantics 2026-05-19 18:36:15 +03:00
75d01aa28f refactor(log-viewer): replace dark terminal theme with light app design system
- Rewrote LogFilterBar: terminal-bg → white, terminal-surface → white/gray-50
- Rewrote LogEntryRow: terminal backgrounds → gray-50 hover, gray-100 border
- Rewrote TaskLogPanel: terminal-bg → white panel with border+shadow, gray-50 footer
- Rewrote TaskLogViewer: spinners/errors → primary/red-50, modals → white/gray
- All 4 components now use: bg-white, text-gray-700/900, border-gray-200
- Kept log level colors (log-* tokens) and source colors (source-* tokens) intact
- Kept all functionality: filters, auto-scroll, progress bars, inline/modal modes
- All 8 existing tests pass
2026-05-19 11:48:57 +03:00
de5410dc14 feat(sidebar): redesign with sections, new navigation items, profile footer
- Split sidebar into 3 groups: Resources / Operations / System
- Added Migration section (Overview + Mappings) - was hidden in routes
- Added Git section (Repository Status) - was hidden in routes
- Added Tools section (Mapper, Debug, Storage, Backups) - was hidden in routes
- Moved Settings gear icon to footer (quick link to /settings)
- Moved Profile to footer (avatar + username)
- Moved Collapse button to header (always visible)
- Organized Admin with all sub-items (Users, Roles, ADFS, LLM)
- Reduced visual noise: section labels collapse independently
- Kept existing features: RBAC filtering, health badges, mobile overlay, collapse animation
- Updated tests to match new structure
- Updated i18n (en/ru) with new keys
2026-05-19 11:34:58 +03:00
6af74984e5 refactor(frontend): unify Tailwind classes — replace hardcoded colors with semantic design tokens
- Replace all bg-blue-600/hover:bg-blue-700 → bg-primary/hover:bg-primary-hover
- Replace all bg-red-600/hover:bg-red-700 → bg-destructive/hover:bg-destructive-hover
- Replace all focus:ring-blue-500 → focus-visible:ring-primary-ring
- Replace all text-blue-600 → text-primary on interactive elements
- Replace all bg-blue-50 → bg-primary-light on UI surfaces
- Replace all bg-red-50 → bg-destructive-light on error surfaces
- Replace all border-blue-200/300 → border-primary-ring
- Replace all border-red-200 → border-destructive-light
- Replace peer-checked:bg-blue-600 → peer-checked:bg-primary (toggles)
- Replace focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 patterns
- Keep status badge patterns (bg-*-100 text-*-700) and hover:bg-blue-50 intact

82 files changed, ~400 changes. Build passes.
2026-05-19 10:46:00 +03:00
cd668b9405 agents 2026-05-18 23:58:42 +03:00
d690601813 fix(translate): replace fromStore+ with +subscribe to prevent reactive loop, add runComplete flag, show error_message, collapsible run results
- TranslationRunGlobalIndicator: replace fromStore + 6x  with
  (() => store.subscribe()) to prevent accumulating render_effect
  instances via createSubscriber that caused infinite Svelte reactive flush
- translate/[id]/+page.svelte: add runComplete flag to hide progress bar
  after completion without touching the store; add collapsible run detail
  cards with status badge, counts, and error_message; filter invalid runs
- translationRun.js: remove stale guard (no longer needed)
- Sidebar.svelte: fix mobile overlay close on route change
- docs/adr/ADR-0007-rejected-fromStore-derived.md: document REJECTED pattern
2026-05-18 11:43:27 +03:00
48c0756d6d fix(translate): fix job creation tab navigation and preview validation
- frontend: add  to reload job data on param change after goto
- frontend: set existingJob from createJob response for immediate tabs
- frontend: suppress error toasts for schedule 404 (normal state)
- frontend: conditional ScheduleConfig mount to avoid 'new' job loading
- backend: skip preview check for jobs with direct Superset datasource
- backend: add orthogonal test for datasource+no-preview success case
2026-05-18 10:56:21 +03:00
b58cb8b5e7 fix(translate): handle row lock timeout in cancel, add flush fallback, migrate progress to store
- Extract _fallback_cancel_request for row lock timeout recovery in orchestrator_cancel
- Add flush lock timeout fallback in cancel_run
- Set error_message when all records fail in executor
- Track insert_failed state in scheduler and frontend store
- Migrate TranslationRunProgress from local polling to centralized store
- Fix nginx resolver for Docker variable-based proxy_pass
- Add FRONTEND_HOST_PORT env var to docker-compose
2026-05-18 10:36:58 +03:00
64bd5c43b2 fix: update Kilo default base URL to api.kilo.ai/api/gateway 2026-05-18 10:36:23 +03:00
bc6c3f366b e2e 2026-05-17 23:34:58 +03:00
8212f8d8c6 fix(translate): fix batch sizing — use real available input budget, respect job.batch_size, lazy playwright in docker
- _batch_sizer.py: compute per_batch_budget from actual available_input_budget
  (context_window - max_output_tokens) instead of sum of first N rows
- _batch_sizer.py: cap max_rows_hard_cap with job.batch_size (user config)
- _token_budget.py: add available_input_budget and max_output_tokens to return
- preview.py: validate required config fields before preview
- requirements-docker.txt: add playwright pip package (~5 MB)
- backend.entrypoint.sh: lazy playwright install chromium on first start
- build.sh: switch tar to tar.xz (-T0 -9), 5.5x smaller bundles
- README.md: add offline bundle deployment instructions
- playwright.config.js: add testMatch for *.e2e.js files
- frontend: preview tab config validation, i18n keys, translationRun store
2026-05-17 23:32:00 +03:00
2b93692070 chore: commit remaining pre-existing changes
- Agent configs (.opencode/agents/)
- Backend: alembic, routes, app, utils, scripts
- Frontend: package.json, vite, components, e2e infra
- Specs: 028-llm-datasource-supeset updates
- Docker e2e config and Playwright setup
2026-05-17 19:23:07 +03:00
ac468121f5 chore: cleanup tracked junk + commit remaining test fixes
.gitignore:
- Add .duckdb semantic index binaries
- Add .axiom/temp/ pytest artifacts
- Add e2e_*.png screenshots
- Remove tracked package-lock.json (already in gitignore)

Untrack junk (git rm --cached):
- 3 duckdb binary index files
- 18 pytest temp artifacts
- 12 e2e screenshots
- package-lock.json

Test fixes (decomposition follow-up):
- executor test mock paths
- orchestrator test mock paths
- preview test mock paths
- orthogonal fixes test mock paths
- git_manager integration test
- settings_page integration test
- settings-utils fix
2026-05-17 19:22:09 +03:00
3379985ef8 refactor: decompose oversized contracts to satisfy INV_7 fractal limit
Break monolithic modules >400 lines into focused sub-modules while
preserving backward-compatible imports and all test coverage:

Backend (Python):
- TranslationExecutor: 1974→241 lines, split into 9 sub-modules
- Translate plugin: orchestrator (1137→148), preview (1303→244),
  service (1052→275), dictionary (1007→68)
- ProfileService: 857→172 with 4 extracted sub-modules
- TaskManager: 708→322 with graph/event_bus/lifecycle extracted
- Test dictionary: 1199→split into 6 focused test files

Frontend (Svelte):
- SettingsPage: 1451→291 with 6 extracted tab components
- GitManager: 1220→228 with 5 extracted panels
- DatasetReviewWorkspace: 1202→314
- translate.js API: 664→28 barrel with 6 domain modules

Protocol:
- Remove single-contract 150-line limit from INV_7 (keep CC≤10)
- Fix unclosed #endregion tags across 11 files
- Fix 19 test regressions from stale mock paths
- All 294 tests passing
2026-05-17 19:18:32 +03:00
571768fff5 fix(health): suppress 404 when health monitor disabled + fix audit test assertion
- Sidebar.svelte: defer healthStore.refresh() until feature flags confirm
  health_monitor is enabled; skip entirely when disabled
- health.js: remove throw error from catch block — log and return null
  instead, preventing 'Uncaught (in promise)' on expected 404
- test_report_audit_immutability.py: fix mock assertions —
  audit_service uses logger.reason/reflect/explore, not logger.info
- HealthStore and Sidebar now produce zero network noise when
  FEATURES__HEALTH_MONITOR=false
2026-05-17 14:18:02 +03:00
0a4088188b fix(translate): token budget overhaul + truncation retry + smart batch sizing + LLM provider fixes
Token Budget (_token_budget.py):
- DEFAULT_MAX_OUTPUT_TOKENS 8192→16384 (adequate for 50 rows×4 langs)
- Add PROVIDER_DEFAULTS with per-model context_window/max_output_tokens
- OUTPUT_PER_ROW_PER_LANG 60→120, add JSON_OVERHEAD_PER_ROW=50
- PROMPT_BASE_TOKENS 300→600, MAX_OUTPUT_HEADROOM 1000→3000
- CJK-aware token estimator (_estimate_tokens_for_text: 1.5 chars/tok for CJK)
- Output-aware batch sizing (_apply_output_aware_batch_sizing)
- Warn on dictionary cap mismatch

Executor (executor.py):
- Return finish_reason from _call_openai_compatible→_call_llm
- Truncation detection + batch splitting on finish_reason=length
- Smart batch sizing (_auto_size_batches): greedily split by row token budget
- Fix disable_reasoning hardcoded 8192→use calculated max_tokens
- TypeError guard on choices[0] access, base_url validation
- Broadened response_format fallback (matches response_format|structured|json_object)
- Remove invalid extra_body, fix partial-recovery regex for integer row_id
- 18 new tests for estimate_row_tokens and _auto_size_batches

Preview (preview.py):
- Align token constants with _token_budget.py (CHARS_PER_TOKEN=2.2, OUTPUT=120)
- Return finish_reason, broadened response_format fallback
- Fix hardcoded 8192, base_url validation

LLM Services:
- render_prompt: detect unfilled {placeholders}, log WARNING
- llm_provider: distinguish crypto exceptions (InvalidTag vs ValueError vs generic)
- Respect Retry-After header on HTTP 429
2026-05-16 09:58:31 +03:00
8d7ff06f01 fix(translate): exclude key columns from cache hash — only text + context fields
- _compute_source_hash now accepts context_keys parameter
- source_data is filtered to only include context-relevant fields (not row_id, primary keys)
- If no context_columns configured, hash is based on source_text + dict_hash + config_hash
- This ensures identical text in different rows produces a cache hit
2026-05-16 09:33:15 +03:00
9c5f763646 feat(translate): add translation cache with source_hash dedup + enforce dictionary post-processing
- Add source_hash column (SHA256 of source_text+source_data+dict_hash+config_hash) to TranslationRecord for cache dedup
- Add Alembic migration b1c2d3e4f5a6 for the new column and composite index (source_hash, status)
- Implement _compute_source_hash / _check_translation_cache in executor.py — before LLM call, check if same source+dict+config combo was already translated successfully
- Implement cache-aware routing in _process_batch: full cache hit → skip LLM, partial hit → route to LLM
- Store source_hash on all new TranslationRecord rows for future cache hits
- Strengthen dictionary prompt instructions from 'use when applicable' to 'MUST use — mandatory'
- Add _enforce_dictionary() post-processing: force-replace dictionary terms in LLM output if LLM ignored them
- Fix CRITICAL: use run.dict_snapshot_hash/config_hash (exist on TranslationRun, not TranslationJob)
- Fix MAJOR: verify cached languages cover ALL target_languages before accepting cache hit
- Fix MAJOR: prevent regex back-reference injection in dictionary enforcement (use lambda)
- Fix: add joinedload to cache lookup to avoid N+1 queries
- Fix: remove redundant single-column index (composite index is sufficient)
- Fix(frontend): parse paginated /translate/dictionaries response correctly (result.items)
2026-05-16 00:42:07 +03:00
8797c28958 feat(llm): mask API keys in UI responses and prevent masked-key leakage in fetch/test/save payloads
- Add mask_api_key() and is_masked_or_placeholder() to llm_provider service
- Return masked keys in all provider CRUD endpoints
- Reject masked/placeholder keys in fetch_models and test_provider_config
- Show masked key with Change button in ProviderConfig.svelte edit form
- Exclude masked keys from fetch-models, test, and submit payloads on frontend
- Update semantics-core skill with clarified complexity tier rules
- Switch agent modes from subagent to all
2026-05-15 23:34:09 +03:00
174bf54618 fix(ui): upgrade global indicator from thin bar to rich progress panel
- Show full stats grid (total/success/fail/skip) + progress bar + cancel button during active run
- Compact colored banner for terminal states (completed/partial/failed/cancelled) with auto-dismiss
- Import cancelRun from translate API for functional cancel button
- fromStore() reactivity confirmed working — no store changes needed
- Hide on /translate/[id] to avoid duplication (existing behavior preserved)
2026-05-15 22:37:25 +03:00
0919258716 fix(ui): global indicator no longer disappears on run complete — stop resetting store on handleRunComplete
- Remove resetTranslationRun() from handleRunComplete so the store keeps its terminal state
- Global indicator (TranslationRunGlobalIndicator) now shows 'Completed' for 5s then auto-dismisses
- Page navigation while run is active keeps the indicator visible until terminal state
2026-05-15 22:19:36 +03:00
df7e78b4d1 fix(translate): log RUN_CANCELLED event on flag cancel, skip source-lang TranslationLanguage entries
- Add RUN_CANCELLED event logging in orchestrator when executor returns CANCELLED (cancel flag path)
- Skip TranslationLanguage creation for languages matching detected source language (no ru in stats)
- Update tests for new behavior (3 entries instead of 4, no fr entry for source-match)
- Fix clickhouse insert test mocks for .options(joinedload()) chain
- All 208 translate tests pass
2026-05-15 22:15:53 +03:00
e0cfa3c18f feat(llm): add LiteLLM provider — enum, client, tests, QA follow-ups
- Add LITELLM = "litellm" to LLMProviderType enum (already in HEAD from prev commit)
- Add comment in LLMClient.__init__ explaining standard Bearer auth for LiteLLM
- Add regression test test_provider_type_enum_values — guard against value drift
- Add test_litellm_client_uses_default_bearer_auth — verify no extra headers
- Clean up duplicate @RELATION lines in models.py
- All 20 backend + 4 frontend tests pass
2026-05-15 22:11:55 +03:00
eadb3a75fc fix(translate): normalize Unix timestamps to YYYY-MM-DD for ClickHouse Date columns
- Add _normalize_timestamp_value to key column values in orchestrator.py and executor.py before SQL generation
- Fix test mocks for .options(joinedload()) chain, explicit None attrs for mock job
- Add global translation run progress indicator (TranslationRunGlobalIndicator + store)
- Fix translate page import missing translationRunStore
- All 208 translate tests pass
2026-05-15 22:06:27 +03:00
ecb3b11f22 fix(translate): Kilo API response_format, reasoning_effort skip, structured_outputs fallback, refusal handling
- Enable response_format (json_object) for all providers including Kilo/OpenRouter
- Skip reasoning_effort for Kilo/OpenRouter (returns 400 — mandatory reasoning)
- Add structured_outputs fallback: retry once without response_format if upstream
  provider (e.g. StepFun) rejects it with 'structured_outputs is not supported'
- Handle model refusal field (refusal) instead of treating as empty content
- Fix None-handling guards for message/finish_reason/content fields
- Apply same fixes to both preview.py and executor.py _call_openai_compatible
- Connect orphaned TermCorrectionPopup, BulkReplaceModal, BulkCorrectionSidebar
2026-05-15 18:12:29 +03:00
dcf9298962 fix(ui): responsive parent layout - remove max-w-4xl constraint
The job config page was capped at 896px (max-w-4xl), making the
10×4 translation preview table extremely squished. Changed to
max-w-full xl:max-w-7xl — full width on all screens, 1280px max
on ultrawide.
2026-05-15 10:45:33 +03:00
59f867b2e7 fix(ui): dynamically resizable TranslationPreview table for 100-10000 char texts
- Removed max-w-[200px] compression on source text column → now
  gets proportional space
- Scrollable containers (max-h-32 overflow-y-auto) for long text cells
- Language columns: min-w-[200px]→[250px] with whitespace-pre-wrap
- Source language badge and status columns remain narrow (w-28, w-24)
2026-05-15 10:40:57 +03:00
e2bea37d4d fix(translate): partial JSON recovery for truncated LLM responses when DeepSeek runs out of tokens
DeepSeek v4 Flash returns finish_reason=length when reasoning uses
all output tokens. Partial row extraction via regex recovers complete
rows from truncated JSON instead of failing with 400 error.

Also: extra_body reasoning_effort for Kilo/OpenRouter proxied providers
2026-05-15 10:31:51 +03:00
2ba7fa0db2 feat(translate): universal reasoning suppression for DeepSeek/Qwen/MiniMax/Kimi
Added disable_reasoning toggle that works via:
1. API parameter: reasoning_effort: 'none' (DeepSeek, Qwen)
2. System prompt instruction: 'Respond directly with ONLY the JSON.
   Do NOT include any reasoning, thinking, or chain-of-thought'
   (works for ALL models universally)

Backend: model column, schema, preview+executor payload
Frontend: checkbox in LLM settings, i18n en+ru
2026-05-15 10:13:37 +03:00
6144d94f24 feat(translate): auto batch_size estimator for LLM token budget
New _token_budget.py calculates safe batch_size and max_tokens based on source text length, target languages, dictionary size, and model context window (64K DeepSeek v4 Flash). preview.py: auto-reduces sample_size when texts are long. executor.py: per-batch dynamic max_tokens. 12 new tests.
2026-05-15 09:53:54 +03:00
4acf8f774f fix(translate): increase max_tokens 4096→8192 for DeepSeek multi-language output
finish_reason=length from DeepSeek v4 Flash — model runs out of
output tokens due to reasoning_content (CoT) + multi-language (4 langs).
8192 tokens ensures complete JSON response for preview and execution.
2026-05-15 09:46:37 +03:00
d89e053462 fix(translate): add detailed LLM response logging for empty content debug
Preview + executor now log finish_reason, message_keys, and raw
response structure when LLM returns empty content, enabling
diagnosis of DeepSeek API issues (empty content with finish_reason=length)
2026-05-15 09:28:21 +03:00
99006e5e07 fix(translate): add EXPLORE logging for LLM JSON parse failures
Preview + executor now log the raw LLM response (first 1000 chars)
when JSON parsing fails, enabling debugging of malformed LLM output.

Previously ValueErrors from JSON parse failures were silently returned
as 400 without any diagnostic data in logs.
2026-05-15 09:15:36 +03:00
a1d4604806 feat(translate): enhanced target table column mapping + fix multi-language save
Multi-language save fix:
- MultiSelect.svelte: selected prop changed to $bindable([])
  (without $bindable, bind:selected never propagated to parent component,
  so target_languages always stayed as default ['en'])

Target table column mapping (INSERT enhancement):
- target_language_column — stores language code (e.g. 'ru', 'en')
- target_source_column — stores original source text
- target_source_language_column — stores detected BCP-47 source language
- SQL generator includes these columns in INSERT when configured
- Frontend: 4 input fields under 'Target Column Mapping' section
  with clear labels, placeholders, and i18n hints

Backend: model, schema, service, orchestrator
Frontend: job config page, i18n en+ru
DB: 3 new columns added to production
2026-05-15 09:09:39 +03:00
8eae4258c1 feat(i18n): localize all translate components (spec 028)
P0 — Wired i18n to 4 previously-unlocalized surfaces:
- BulkReplaceModal (~25 strings → translate.bulk_replace.*)
- CorrectionCell (~20 strings → translate.corrections.cell_*)
- TermCorrectionPopup (~30 strings → translate.term_correction.*)
- history/+page.svelte (~50 strings → translate.history.*)

P1 — Added 85+ keys to en.json + ru.json (identical structures):
- 11 previously-missing keys (common.close, config.status, etc.)
- bulk_replace.*, corrections.*, term_correction.*, history.*, dictionaries.*

P2 — Dictionary detail page: import form, filter-by-language, context display
P3 — Russian hardcoded strings in job config replaced with i18n

Tests: 280 pass, build succeeds
2026-05-15 09:00:33 +03:00
4af6a2719e refactor(translate): remove all deprecated columns from model + DB
Removed 6 legacy columns replaced by Phase 11 multi-language models:
- TranslationJob.target_language → target_languages (JSON)
- TranslationRecord.{llm_translation, user_edit, final_value} → TranslationLanguage
- TerminologyDictionary.{source_language, target_language} → DictionaryEntry per-entry

Affected files: model, schemas, 5 plugins, 4 test files
Alembic migration: aa1b2c3d4e5f (DROP COLUMN IF EXISTS)
Production DB: columns dropped via ALTER TABLE

Tests: 234 passed, 0 failed
2026-05-15 00:06:41 +03:00
3e8aec9335 fix(translate): add missing target_languages column to production DB
Migration 2a7b8c9d0e1f adds target_languages (JSON) to translation_jobs.
Uses ADD COLUMN IF NOT EXISTS for idempotent PostgreSQL deployment.

Fixes 500 error on GET /api/translate/jobs:
  column translation_jobs.target_languages does not exist

Migration chain is now clean: 5 linear revisions, no orphans.
2026-05-14 23:51:25 +03:00
de5bf1a3f7 chore: remove legacy SQLite migration script + fix stale comments
- Delete migrate_sqlite_to_postgres.py (one-time script, no longer needed)
- Fix @INVARIANT in mappings.py: SQLite → PostgreSQL
- Remove deprecated source_language column from TranslationJob model
  + Alembic migration 8dd0a93af539 to drop column if exists
- Remove source_language from TranslateJobResponse schema

Fixes recurring 'source_language does not exist' scheduler error
2026-05-14 23:48:13 +03:00
0946f4a72d feat(docker): add all-in-one Dockerfile without Playwright (<200MB target)
Multi-stage build:
- Stage 1: node:20-alpine builds frontend (discarded)
- Stage 2: python:3.11-slim runs backend + serves SPA static files
- Playwright removed from deps (saves ~350MB)
- Uvicorn serves both API and frontend on :8000
- Healthcheck via curl
- Entrypoint with admin bootstrap support

Estimated image size: ~190MB (vs ~550MB with playwright)
2026-05-14 21:37:08 +03:00
db18348ab1 chore: update semantic index, agent configs, and app startup 2026-05-14 21:33:26 +03:00
7113e16d9b feat(translate): complete Phase 10-11 — full spec 028 closure (T075-T134)
Phase 10 closure:
- T075: NotificationService wiring for scheduled-run failures
- T077: Semantic audit via axiom MCP (0 warnings)
- T078: Quickstart validation — all 165+280 tests pass

Phase 11 completion:
- T083-T086: Multi-language models/schemas/Alembic migration
- T087-T090: Auto-detect source language (BCP-47) + tests
- T091-T095: Multilingual dictionaries with language-pair filtering
- T096-T108: Multi-language job config → preview → execution pipeline
- T109-T118: Inline correction + BulkReplaceModal + CorrectionCell + tests
- T119-T122: Per-language history and MetricSnapshot
- T123-T134: Context-aware corrections (Jaccard similarity, priority flagging, context_data)

New files: Alembic migration, test_scheduler, test_inline_correction,
BulkReplaceModal, vitest for CorrectionCell + BulkReplaceModal

Total: 134/134 tasks complete. Backend 165p, Frontend 280p.
2026-05-14 21:14:04 +03:00
4d6493793d fix(translate): M1-M3 medium + L1-L2 low bugs from QA review
M1: ReDoS guard — 500 char max + try/except on re.compile
M2: Performance note — O(n×m) regex documented for future optimization
M3: Verified test key names correct (metrics.py transforms cumulative_* → short)
L1: Removed @staticmethod no-op from module-level function
L2: Added aria-label to emoji indicators in CorrectionCell
2026-05-14 17:44:50 +03:00