Commit Graph

435 Commits

Author SHA1 Message Date
614bf9123a log fix 2026-05-27 10:49:06 +03:00
c9d720f29a fix: bypass broken logger.isEnabledFor in log_requests middleware
After configure_logger() runs, logger.isEnabledFor(logging.INFO)
returns False despite level=10 (DEBUG). This is a CPython logging
framework anomaly that makes logger.info() silently drop messages.

Workaround: check isEnabledFor first; if False, write JSON directly
to sys.stderr bypassing the logging system entirely.
2026-05-27 10:32:42 +03:00
7aa3bd52ef fix: add PYTHONUNBUFFERED=1 to run.sh to prevent stderr buffering
Without PYTHONUNBUFFERED, when stderr is piped through '2>&1 | sed',
Python fully buffers stderr output. JSON log lines are small and never
fill the buffer, so they never appear in real time (or at all for
sporadic HTTP request logs). Startup logs appeared because the buffer
flushed on process exit during Alembic migration.

Also kept --reload removed as it breaks stderr capture from child process.
2026-05-27 10:19:16 +03:00
bc1179722e fix: remove --reload from run.sh (breaks stderr capture), fix reason/reflect level to INFO
- run.sh: removed --reload flag from uvicorn — reload subprocess breaks
  the 2>&1 pipe and all JSON logs from superset_tools_app are lost.
  Added comment with alternative for hot-reload.
- core/logger.py: reason() and reflect() now use self.info() instead of
  self.debug() — per molecular CoT protocol these are INFO-level bonds.
  DEBUG is reserved for high-frequency loops only.
2026-05-27 10:11:36 +03:00
073a7da9ec fix: change reason() and reflect() from DEBUG to INFO level
Per molecular CoT protocol: REASON and REFLECT are primary reasoning
bonds and must be visible at INFO level in production. DEBUG is
reserved for high-frequency loops.

- reason(): self.debug()  → self.info()
- reflect(): self.debug() → self.info()
- explore(): stays at warning() (WARNING level)
- Also removed redundant logger.info() calls in lifespan (now reason()
  itself provides visible startup logging)
2026-05-27 10:09:12 +03:00
11bb4c1e26 fix: add visible startup progress logs to lifespan
- Added logger.info() calls before each startup step (encryption key,
  Alembic, init_db, admin bootstrap, scheduler, app complete)
- Previously only logger.reason() was used which logs at DEBUG level
  and is invisible in production/development at INFO log level
- This fixes 'no backend logs visible' when running via ./run.sh
2026-05-27 10:05:51 +03:00
20d8ea4d35 fix: logging audit fixes from QA
- Added missing from fastapi import status (global_exception_handler crashed)
- Moved TraceContextMiddleware to outermost (trace_id now available in log_requests)
- Enhanced global_exception_handler with query_params, client host
- Added logger.explore() in WebSocket auth except blocks (was silent pass)
- Fixed middleware registration order
2026-05-27 09:55:12 +03:00
0b55647941 fix: add global exception handler to log 500 errors
- Added @app.exception_handler(Exception) that logs full traceback via
  logger.exception() into superset_tools_app logger (visible in docker logs)
- Previously FastAPI/Starlette wrote unhandled exceptions to uvicorn.error
  logger, making 500 errors invisible in docker logs
- Added JSONResponse import for the handler
2026-05-27 09:46:14 +03:00
21e32ac4cc fix: legacy DB support + QA audit fixes
- Entrypoint: for legacy DBs, add is_admin via raw SQL then stamp head
  (instead of running full migration chain which fails on existing tables)
- Fixed admin_api_keys.py Pydantic config (dict → ConfigDict)
- Added tests/test_alembic_migrations.py (PostgreSQL-only integration tests)
- Fixed infinite recursion in _create_table_if_not_exists (QA catch)
2026-05-26 20:35:36 +03:00
e2a473aa98 fix: prevent set -e from killing entrypoint on DB detection
The python3 DB detection script exits with code 1 (empty) or 2 (legacy),
but entrypoint has set -e which kills the script on any non-zero exit.
Fixed by using '|| _db_state=$?' pattern to safely capture exit code
without triggering set -e.
2026-05-26 20:15:32 +03:00
1a57f33606 fix: handle legacy databases in entrypoint Alembic migration
Three-way detection in entrypoint:
  - alembic_version exists → normal incremental upgrade
  - no tables → fresh upgrade from scratch
  - tables exist but no alembic_version → stamp head (legacy DB created
    by create_all(), mark all migrations as current without running them)

This fixes 'relation already exists' errors when Alembic tries to CREATE
TABLE on databases that already have tables from previous deployments.
2026-05-26 19:58:31 +03:00
d870fe18d3 fix: run Alembic migrations in entrypoint before bootstrap_admin
The entrypoint was calling init_auth_db.py → init_db() + seed_permissions()
before the FastAPI startup_event (where run_alembic_migrations() lived).
Since the _ensure_*() safety net was removed, seed_permissions() failed
with 'column roles.is_admin does not exist' on databases with old schema.

Now alembic upgrade head runs directly in the entrypoint, ensuring all
migrations are applied before any DB queries.
2026-05-26 19:41:45 +03:00
7af5311449 chore: remove bundle artifact from git, add to .gitignore 2026-05-26 19:18:32 +03:00
4205618ee6 chore: eliminate all deprecation warnings from tests and linter
Warnings fixed:
- datetime.utcnow() → datetime.now(UTC) across 48+ files (src/ + tests/)
- datetime.utcnow (callback ref) → lambda: datetime.now(UTC) in model fields (18 files)
- Pydantic class Config → model_config = ConfigDict(...) (16 files)
- Pydantic .dict() → .model_dump() (8 files)
- ConfigDict(allow_population_by_field_name=True) → validate_by_name=True
- SQLAlchemy declarative_base() import path updated
- FastAPI on_event → lifespan context manager (app.py)
- Import sorting (ruff I001) auto-fixed across all files
- Fixed broken re-export chains that ruff F401 cleanup broke:
  _validate_bcp47: service.py now imports from dictionary_validation directly
  job_to_response: _job_routes.py and test imports from service_utils directly
  fetch_datasource_metadata: restored re-export in service.py
- Added missing TranslateJobService import in _job_routes.py (was deleted by F401)
- Added ConfigDict(protected_namespaces=()) for DashboardDatasetItem schema field
- pytest.ini: replaced deprecated importmode with asyncio_mode

All 440 tests pass with zero deprecation warnings.
2026-05-26 19:18:28 +03:00
eda346979b refactor: remove _ensure_*() safety net, keep only Alembic
- Simplified init_db() to only call Base.metadata.create_all() on all
  three engines — no more _ensure_*() inline additive migrations
- run_alembic_migrations() now raises on failure (no safety net to
  fall back to)
- All schema changes (add/drop/rename columns, data migrations) must
  go through Alembic. create_all() handles new tables only.

@REJECTED _ensure_*() inline migrations removed because they:
  - Duplicated Alembic logic without versioning
  - Created hidden schema drift (columns existed in DB but had no
    corresponding Alembic migration)
  - Made audits and fresh DB provisioning unreliable
2026-05-26 19:02:59 +03:00
9337a4cecd fix: add missing schema columns and Alembic model imports
- Added 4 missing columns to _ensure_translation_jobs_columns() inline
  migration: target_language_column, target_source_column,
  target_source_language_column, disable_reasoning — these were in the
  SQLAlchemy model but had no Alembic migration or _ensure_*() coverage
- Added missing api_key, assistant, clean_release model imports to
  alembic/env.py so autogenerate can see all tables
2026-05-26 19:00:04 +03:00
81fc7e0902 feat: run Alembic migrations automatically on startup
- Added alembic==1.18.4 to requirements.txt (was missing, transitive only)
- Added run_alembic_migrations() to startup_event in app.py — runs
   before init_db() to apply all pending migrations
- Combined approach: Alembic for complex migrations first, then inline
  _ensure_*() additive safety net in init_db()
- This ensures DB schema is always up to date on container startup
  without manual intervention
2026-05-26 18:56:29 +03:00
ce0c0cf235 fix: add missing call to _ensure_roles_is_admin_column() in init_db()
The inline migration _ensure_roles_is_admin_column() was defined but
never called from init_db(). This caused 'column roles.is_admin does
not exist' errors when logging in against databases with an older
schema. Added the missing call to ensure the column is created during
startup.
2026-05-26 18:50:48 +03:00
ee08e2f3dd fix 2026-05-26 18:15:37 +03:00
0b6f61623e fix: _ensure_roles_is_admin_column also sets is_admin=true for Admin 2026-05-26 15:29:49 +03:00
2fa8edfa03 fix: is_admin fallback for legacy Admin roles + migration data fix
Migration now sets is_admin=true for existing Admin roles.
has_permission falls back to role.name == 'Admin' check if
is_admin flag is missing (backward compat for pre-migration roles).
2026-05-26 15:29:14 +03:00
6b960b0eb3 fix: add is_admin column migration + additive safety net
Alembic migration 86c7b1d6a710 adds is_admin BOOLEAN DEFAULT FALSE
to the roles table. Fixes login crash after M-3 change:

  psycopg2.errors.UndefinedColumn: column roles.is_admin does not exist

Also adds _ensure_roles_is_admin_column() as an additive migration
safety net for environments that don't run alembic automatically.

To apply: cd backend && source .venv/bin/activate && alembic upgrade head
2026-05-26 15:28:03 +03:00
8dcc0f86f8 fix: conditional HSTS via FORCE_HTTPS, safe for enterprise without certs
HSTS (Strict-Transport-Security) is now opt-in via FORCE_HTTPS=true.
Without it enabled, no HSTS header is sent — safe for dev environments
and enterprise deployments behind HTTP-only proxies without HTTPS certs.

When FORCE_HTTPS=true, sends 'max-age=31536000; includeSubDomains'.
Enterprise recommendation: set HSTS at nginx/ingress level instead.

.env.example documents the risk: enabling without certs breaks site access.
2026-05-26 15:25:55 +03:00
10cdb8a81a fix: replace TrustedHostMiddleware with proper HSTS middleware
TrustedHostMiddleware blocked Vite proxied requests (Host: localhost:5173
vs allowed_hosts list). Replaced with simple HSTSMiddleware that adds
Strict-Transport-Security header without blocking any requests.
2026-05-26 15:24:40 +03:00
a2786ad713 docs: add .env.example with required PostgreSQL env vars
Template documents all required env vars:
- AUTH_SECRET_KEY and ENCRYPTION_KEY (secrets)
- DATABASE_URL, AUTH_DATABASE_URL, TASKS_DATABASE_URL (PostgreSQL)
- ALLOWED_ORIGINS, SESSION_SECRET_KEY (optional)

After [SEC:C-4] removed DEV_MODE fallback, the .env must have
AUTH_DATABASE_URL set explicitly or the app crashes at startup.
2026-05-26 15:22:58 +03:00
ee4ca3cdf6 security: HSTS, AD group validation, INITIAL_ADMIN_PASSWORD warning
L-2: HSTS middleware via TrustedHostMiddleware — restricts allowed hosts
  to ALLOWED_ORIGINS list, prevents Host header injection.

L-4: AD group name validation — ADGroupMappingCreate.ad_group validated
  with regex: DOMAIN\groupname or CN=...,DC=... format. Empty or
  invalid characters rejected.

L-5: INITIAL_ADMIN_PASSWORD warning — log warning that env-var password
  is visible via /proc to other processes on the same host.
2026-05-26 15:20:29 +03:00
2bc8ad87e1 security: rate limiter, is_admin flag, password policy, log masking
M-3: Role.name == 'Admin' string comparison → Role.is_admin boolean flag.
  Admin role created with is_admin=True. has_permission checks getattr(role,
  'is_admin', False) instead of comparing role names.

M-2: In-memory rate limiter on /api/auth/login. Tracks failed attempts
  per IP (10 in 5 min window, 15 min ban). Thread-safe via threading.Lock.

M-5: Password policy — UserCreate.password: min_length=8, must include
  uppercase, lowercase, and digit.

L-1: log_security_event details dict now masks sensitive fields:
  password, secret, token, api_key, authorization. Recursive masking
  for nested dicts. Sensitive field names matched via regex.

OTHER:
- 4 rate limiter tests (under limit, ban, success clears, IP isolation)
- 4 password policy tests (too short, no upper, no digit, valid)
- 2 log masking tests (flat keys, nested)
2026-05-26 15:17:19 +03:00
23719ecfbc security: JWT aud/iss validation, token blacklist, encryption key crash-early
C-2 (CRITICAL): JWT decode_token now validates aud, iss, iat, jti claims.
  Tokens without these claims are rejected. Audience 'ss-tools-api' and
  issuer 'ss-tools' prevent cross-service token reuse.

H-2 (HIGH): Server-side JWT revocation via token_blacklist table.
  - New TokenBlacklist model (SHA-256 hash only, never raw token)
  - blacklist_token() on logout — revokes current session
  - is_token_blacklisted() check in get_current_user
  - Expired entries auto-pruned via _prune_blacklist()

H-3 (HIGH): Encryption key auto-generation removed — crash-early instead.
  Previously, ensure_encryption_key() would auto-generate a Fernet key
  on first run and write it to .env. This made encrypted data unrecoverable
  when the key changed between deployments. Now raises RuntimeError with
  a clear command to generate the key explicitly.

Also: update orthogonal security test for crash-early behavior.
2026-05-26 15:08:55 +03:00
a9a453109c security: critical auth fixes, test migration to SQLite+FK, 44 test fixes
CRITICAL (CVE-class):
- C-4: Remove DEV_MODE fallback with hardcoded postgres:postgres credentials
- C-3: WebSocket endpoints now require JWT or API key token (?token=) auth
- C-1: Superset environment passwords encrypted via Fernet at rest in DB
- H-4: SESSION_SECRET_KEY separated from JWT AUTH_SECRET_KEY
- H-1: Log injection via %s-formatting instead of f-strings
- H-5: X-Trace-ID header validated as UUID4 to prevent trace poisoning

INFRASTRUCTURE:
- New src/core/encryption.py — EncryptionManager extracted from llm_provider
- Test DB: per-module sqlite:///:memory: with PRAGMA foreign_keys=ON
- testcontainers PostgreSQL via TEST_DB=postgres env var
- conftest temp-file global engine (no 10GB shared-cache leak)

TEST FIXES (44 pre-existing → 0):
- test_smoke_plugins: module-level sys.modules mock isolated to per-test fixture
- test_migration_engine: EXT:Python:uuid → uuid syntax fix
- test_dashboards_api: mock env attributes + correct patch target
- test_constants_audit_fixes: sync expected constant names with actual
- test_defensive_guards: patch.object instead of module-level Repo mock
- test_clean_release_cli: removed empty config.json directory
- FK violations: TaskRecord parents in log_persistence, Environment in
  mapping_service, ReleaseCandidate in candidate_manifest_services

ORTHOGONAL TESTS (18 new):
- test_security_orthogonal.py: bcrypt 72-byte limit, unicode, API key
  format invariants, Fernet robustness, encryption key lifecycle,
  log injection protection, JWT edge cases

MODEL FIXES:
- MetricSnapshot.job_id: nullable with SET NULL (was broken FK for
  aggregate prune snapshots, hidden by SQLite)

CLEANUP:
- Removed stale :memory:test_main/test_auth/test_tasks file databases
- Removed duplicate #endregion in encryption_key.py
2026-05-26 14:58:49 +03:00
f49b7d909e feat: GRACE-Poly protocol optimization — ~3200→10 warnings (↓99.7%)
Full optimization cycle:

Protocol (15 files):
- 4-layer SSOT architecture for agent prompts & skills
- Anti-Corruption Protocol consolidated from 5 duplicates
- Tag-to-tier permissiveness matrix (all @tags allowed at all tiers)

Axiom config:
- complexity_rules: all 22+ tags available on C1-C5
- contract_type_overrides: removed (was narrowing per-type)
- 18 new tags added, LAYER enum expanded (Infra, Frontend, Atom, etc.)
- RELATION predicates expanded (USES, CONTAINS, BELONGS_TO, etc.)

Code fixes:
- 2216 @TAG: normalized to @TAG (colon→space)
- 518 [DEF] blocks migrated to #region/#endregion (37 files)
- VERIFIES→BINDS_TO, :Class/:Function suffixes removed, paths→IDs
- 1173-line _external_stubs.py deleted (EXT: handled natively)
- Batch EXT: reference audit (240 targets: 132 external, 99 internal, 9 fix)
- QA regression check: 0 regressions across all checks

Infrastructure:
- DuckDB rebuild stabilized (appender API, INSERT OR IGNORE)
- Anchor regex fix (parent-child BINDS_TO now resolves)
- EXT:*/DTO:/NEED_CONTEXT: regex fixed in validator
- 34MB Doxygen API portal (3194 contract pages)
2026-05-26 11:14:25 +03:00
9ffa8af1dc semantics 2026-05-26 09:30:41 +03:00
1e7bcecaea agents 2026-05-25 16:35:00 +03:00
4b6c47837f agents skills 2026-05-25 13:25:35 +03:00
320f82ab95 feat(auth): implement API key authentication and management
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.
2026-05-25 11:35:27 +03:00
31680a1bc9 fix(maintenance): auto-expiry + adaptive markdown height + tests
- Auto-expiry: expired events auto-end on GET /events via task manager
- Height: _estimate_markdown_height adapted to unit=8px scale with padding detection
- CRITICAL-1: removed dead import remove_chart_from_position (QA finding)
- CRITICAL-2: added chart alive check in ensure_banner_chart (QA finding)
- CRITICAL-3: fixed test assertions update_markdown_chart → update_banner_on_dashboard
- @POST contract: fixed return range [2,12] → [19,200]
- Tests: 8 new tests (auto-expiry + layout height)
2026-05-25 08:36:33 +03:00
2bf686674e feat(datasets): add SQL template chips for column mapping modal
Как на maintenance с шаблоном баннера — добавил чипсы-шаблоны
SQL-запросов над textarea в модалке маппинга колонок:

- information_schema — вставляет запрос к information_schema
  с JOIN pg_description для получения описаний колонок
- Custom table — вставляет запрос к кастомной таблице маппинга
- Clear — очищает поле

Чипсы в стиле rounded-full с hover-эффектами, подпись
"Шаблоны:" и title-tooltip на каждой кнопке.

i18n: 6 новых ключей (sql_templates, sql_template_*).
2026-05-24 09:51:31 +03:00
8acd2666b9 feat(datasets): add HelpTooltip ⓘ popups in mapping/docs modals
Использует существующий компонент /ui/HelpTooltip.svelte
(ⓘ иконка со стилизованным попапом при наведении) — тот же
паттерн, что на Maintenance и Settings страницах.

Добавлен HelpTooltip рядом с лейблами:
- Модалка маппинга: Тип источника, База данных, SQL-запрос, XLSX-файл
- Модалка генерации docs: LLM-провайдер

Native title сохранён как fallback на самих элементах форм.
2026-05-24 09:49:59 +03:00
edc500c3e4 feat(datasets): add tooltips, text hints and icon-only action buttons
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.
2026-05-24 09:44:18 +03:00
7219c47357 fix(datasets): fix oversized buttons UI + populate linked_dashboard_count in list endpoint
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.
2026-05-24 09:38:21 +03:00
d9669698b8 feat(031): Maintenance Banner for Dashboards — full spec→plan→tasks package
Spec: 5 user stories (P1-P3), 17 FRs, 7 SCs, 12 edge cases, RBAC matrix
Plan: 7 research decisions, 15 semantic contracts (C1-C4)
Data: 4 SQLAlchemy models (Banner entity enforces one-chart-per-dashboard)
UX: async-only API, banner template with optional variables, admin settings UI
Tasks: 64 tasks across 8 phases, 12 reused frontend components
Workflow: component reuse scan mandated in speckit.plan/tasks + semantics-svelte
Constitution: filled with 7 architecture principles from ADRs
2026-05-22 16:20:39 +03:00
7f62e87b4c tasks 2026-05-22 11:22:19 +03:00
0653a75ee7 fix(db): add ondelete cascade to all FK constraints, fix multimodal flag persistence
- 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)
2026-05-22 09:21:24 +03:00
48cc02ea0b feat: LLM Validation section — 9 API endpoints + 3 Svelte pages + Playwright optimization
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
2026-05-21 20:29:36 +03:00
36643024cf refactor(connections): remove ConnectionConfig, migrate mapper to SQL Lab
Backend:
- Remove ConnectionConfig model, CRUD routes (connections.py), and tests
- Remove ensure_connection_configs_table from database.py
- Migrate MapperPlugin from psycopg2 direct PostgreSQL to SupersetSqlLabExecutor
- Add DatasetMapper.get_sqllab_mappings() with default information_schema query
- Update MapColumnsRequest: connection_id → database_id + sql_query
- Fix pydantic_settings v2 deprecation (Field(env=...) → validation_alias)
- Clean up app.py, routes/__init__.py, database.py imports

Frontend:
- Remove DatabaseConnectionsTab, ConnectionForm, ConnectionList components
- Remove /settings/connections route page and Navbar link
- Remove connectionService.js, connections i18n files
- Update MapperTool.svelte: postgres → sqllab source
- Update Map Columns modal: database selector + SQL query instead of connection_id
- Clean up settings page tabs, nav links, test mocks
- Clean up i18n keys (settings, nav, mapper)

Tests: 25/25 pass (14 030-feature + 11 route tests)
Build: succeeds
2026-05-21 18:47:41 +03:00
b529e8082a feat(030): Dataset Lifecycle Workspace — Stats Bar, split-view, inline-edit, bulk actions
Backend:
- Add MetricItem, StatsCounts, ColumnDescriptionUpdate, MetricDescriptionUpdate DTOs
- Add metric_count to DatasetItem and DatasetDetailResponse
- Add server-side filtering via ?filter=unmapped|mapped|linked|all
- Add PUT endpoints for column/metric description inline-edit
- Add HTML stripping validation (max 2000 chars, plain text)
- Add WebSocket dataset.updated event on task completion
- RBAC: plugin:migration:WRITE for mutations, READ for reads
- 14 pytest tests (stats, filter, metrics, inline-edit, validation, 502/503)

Frontend:
- Rewrite +page.svelte as split-view orchestrator (387 lines)
- StatsBar.svelte — 4 metric tiles with aria-pressed, server-side filter dispatch
- DatasetList.svelte — card grid with progress bars, checkboxes, search
- DatasetPreview.svelte — presentational detail panel (container fetches)
- ColumnsTable.svelte — inline-edit with type chips, bold/italic fallback
- MetricsTable.svelte — inline-edit with expression hints
- 52 vitest tests across 7 test files
- i18n: 11 EN + 11 RU keys (with_mapping/с_маппингом)

Spec:
- 15 issues resolved (semantic label, filtering, endpoints, conflict, metric_count, RBAC, ID types, ports, i18n, validation, a11y, propagation, resize, perf, ownership)

Status: 14/14 backend tests pass, 52/52 frontend tests pass, build succeeds
Risk: Low — T051 browser validation pending (non-blocking)
2026-05-21 13:58:47 +03:00
673c0bb217 docs(env): add unified .env.example — 37 vars, 14 sections
- .env.example: единый источник истины для всех переменных окружения
- .gitignore: добавлено исключение !.env.example (правило .env* не применяется)
- Все ранее внесённые правки аудита (7 классов) уже закоммичены в 68740cd
- Итог: 33 QA-теста, 0 хардкод-секретов, 0 .bak, 0 except:pass
2026-05-21 10:09:04 +03:00
45382d6a17 chore(skills): clean up skill headers — remove stale @RELATION, @STATUS noise
- semantics-python: removed dead @RELATION -> [Std.Semantics.Belief] and [MolecularCoTLogging]
- semantics-core, semantics-contracts: removed @STATUS ACTIVE (noise)
- molecular-cot-logging: removed invalid @RELATION REPLACES -> [Std.Semantics.Belief]
- semantics-svelte: fix brackets on @RELATION -> [MolecularCoTLogging]

All skill headers now match the minimal template: @BRIEF + internal @RELATION only.
2026-05-21 00:08:34 +03:00
bd55697e94 fix(semantics): curator audit — Constant→Block, drop :Class suffix on relations 2026-05-21 00:02:45 +03:00
68740cd9ed semantic 2026-05-20 23:54:53 +03:00
a43886106e refactor(semantics): make axiom_config.yaml descriptive, not gatekeeping 2026-05-20 17:18:55 +03:00