Commit Graph

792 Commits

Author SHA1 Message Date
b95df37cd5 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
ce368429f7 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
beed41d6c9 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
7c4843987b 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+58d06fb2'.
  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+58d06fb2', getFullYear() replaces
hardcoded 2025.
2026-07-07 12:29:46 +03:00
58d06fb287 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
18b9f2e94e 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
1e61f098bd 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 8fd23f7e).

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
98d91bb738 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
8fd23f7ea1 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
43e3f4135e fix(scripts): fix --target arg parsing in diag_container.py 2026-07-06 20:37:22 +03:00
98de628197 docs(adr): reference ADR-0009 SSL cert management findings
Production SSL failure for lite.ai.rusal.com confirmed: LLM_CA_CERT_URLS
not set → LLM CA certs not downloaded. System CA store has corporate
certs from /opt/certs but lite.ai.rusal.com uses a different CA.

Diagnostic script scripts/diag_container.py covers all 6 check categories
per ADR-0009: env, system CA, openssl capath/cafile, Python SSLContext,
httpx connectivity, encryption health.

Fix: set LLM_CA_CERT_URLS in .env.enterprise-clean or place the CA .crt
in ./certs/ on the host. Run diag_container.py to verify.
2026-07-06 20:27:28 +03:00
bcabe90e13 feat(scripts): add container diagnostic script for SSL cert + encryption health
Checks 6 categories:
  1. Environment — ENCRYPTION_KEY, LLM_SSL_VERIFY, LLM_CA_CERT_URLS
  2. System CA store — ca-certificates.crt, custom/LLM certs, hash symlinks
  3. OpenSSL connectivity — cafile vs capath (per ADR-0009 Finding 7)
  4. Python SSLContext(capath) — what _get_ssl_verify() uses
  5. httpx(capath) — integration test
  6. Encryption key health — decrypt test for all LLM provider api_keys

Usage:
  docker cp scripts/diag_container.py superset-tools-backend-1:/tmp/
  docker compose exec backend python3 /tmp/diag_container.py --target lite.ai.rusal.com:443
2026-07-06 20:27:03 +03:00
e7dbee563f fix(ui): render KeyRecoveryWizard into body portal to avoid layout margin
Modal now mounts at document.body level via svelte mount/unmount.
Extracted WizardContent.svelte for portal rendering.
Eliminates 32px margin from page layout wrapper
(max-w-7xl/space-y-6/px-4 container).

Added KeyRecoveryWizard as portal wrapper, WizardContent as
the actual modal component.
2026-07-06 19:00:24 +03:00
6db49e45a6 xz -3 2026-07-06 18:26:31 +03:00
7f9e781873 fix(security): address QA/security audit findings — authorization, i18n, error safety
Critical (C1): Added has_permission('security', 'READ') to /health and
  /fingerprint endpoints; has_permission('security', 'WRITE') to /recover.
  Previously any authenticated user could enumerate encrypted secrets and
  overwrite stored values.

High (Bug #1): Fixed recover endpoint — updated/failed status now correctly
  reflects whether a non-empty replacement value was submitted. Empty values
  now report 'skipped' instead of falsely 'updated'.

High (Bug #2, #3): Replaced all hardcoded English strings in
  KeyRecoveryWizard.svelte and SystemSettings.svelte with $t.settings.*
  i18n lookups. Keys already existed in en/ru settings.json.

High (H1): Added _sanitize_error() helper to truncate + scrub exception
  messages before logging, preventing potential secret leakage in log output.

Cleanup: Moved LLMProviderConfig import to module top. Instantiate
  ConnectionService once before for-loop. Added @TEST_EDGE declarations
  and @PRE/@SIDE_EFFECT to C4 contract.

Tests: 226 passed
2026-07-06 18:22:36 +03:00
2622431376 fix(i18n): remove duplicate closing braces in encryption recovery strings 2026-07-06 18:07:44 +03:00
5c59a2c79b feat(security): add encryption health inventory and key recovery wizard
Backend:
  - GET /api/security/encryption/health — inventory of all stored encrypted
    secrets (LLM providers, DB connections, profile Git tokens) with
    decrypt attempt and structured broken/healthy status
  - GET /api/security/encryption/fingerprint — non-secret key fingerprint
  - POST /api/security/encryption/recover — bulk replacement of
    undecryptable secrets with partial_success semantics

Frontend:
  - KeyRecoveryModel.svelte.ts — state machine (idle→scanning→
    healthy/needs_recovery→editing→saving→complete/partial_success/error)
  - KeyRecoveryWizard.svelte — tabbed dialog with LLM/DB/Git sections,
    security guidance, re-encrypt command display, edit/save flow
  - SystemSettings entry point — 'Check encrypted secrets' card with
    fingerprint and broken count
  - API methods: getEncryptionHealth, recoverEncryptedSecrets
  - Types: EncryptionRecoveryTypes
  - i18n: en/ru strings for recovery flow

Tests: 226 passed
2026-07-06 18:05:05 +03:00
556294aff5 fix(agent): pin gradio <6 to avoid breaking ChatInterface API changes 2026-07-06 16:18:55 +03:00
b6752e729e fix(docker): add alembic to requirements-backend.txt, entrypoint needs it for migrations 2026-07-06 15:49:48 +03:00
48e3ff4503 refactor(env): unify Docker env vars — canonical AUTH_SECRET_KEY, remove JWT_SECRET fallback
Canonical variables:
  - AUTH_SECRET_KEY — JWT signing key for backend + agent (was split across
    AUTH_SECRET_KEY / JWT_SECRET)
  - SERVICE_JWT — agent→backend service token
  - No JWT_SECRET fallback: decoder fails with migration guidance if only
    JWT_SECRET is set

Compose files unified:
  - docker-compose.yml, docker-compose.enterprise-clean.yml,
    docker-compose.e2e.yml — all use AUTH_SECRET_KEY
  - build.sh generated compose now passes AUTH_SECRET_KEY + ENCRYPTION_KEY
    to backend

Env examples unified and completed:
  - .env.example — comprehensive template, all compose vars
  - .env.enterprise-clean.example — production template
  - backend/.env.example — backend-only run
  - docker/.env.agent.example — agent-only run
  - NEW: .env.current.example, .env.master.example,
    .env.e2e.example, frontend/.env.example

Tests aligned:
  - conftest sets AUTH_SECRET_KEY (canonical value matched across test files)
  - test mocks use canonical name
  - 1176 passed, 0 failed
2026-07-06 14:24:17 +03:00
a5b7adb61c refactor(agent): lightweight JWT decoder — JWT_SECTRET first, AUTH_SECTRET_KEY fallback
Replaced src.core.auth.jwt.decode_token import with local _jwt_decoder.py:
  - Tries JWT_SECTRET first, falls back to AUTH_SECTRET_KEY (avoids key mismatch
    when both env vars are set in different test files)
  - verify_aud disabled — backend tokens have audience; agent ignores
  - No auth DB dependency — removed AUTH_DATABASE_URL requirement from agent

Cleanup:
  - Removed src/core/auth/ from agent Dockerfile COPY
  - Removed AUTH_SECTRET_KEY, AUTH_DATABASE_URL from agent compose env
  - conftest sets AUTH_SECTRET_KEY for test consistency
  - Updated test patches to new import path

Tests: 1176 passed, 0 failed
2026-07-06 13:45:22 +03:00
590b09f587 refactor(agent): use local JWT decoder instead of src.core.auth.jwt
Replace src.core.auth.jwt import with lightweight _jwt_decoder.py that
uses jose.jwt directly with JWT_SECRET env var. Avoids pulling AuthConfig
→ AUTH_DATABASE_URL/SECRET_KEY validators → SQLAlchemy models into agent.

Removed: AUTH_SECRET_KEY, AUTH_DATABASE_URL from agent compose env.
Removed: src/core/auth/ copies from Dockerfile.agent COPY section.
Added:   src/agent/_jwt_decoder.py — stateless JWT validation.
2026-07-06 13:37:08 +03:00
b2d5aa5bf8 fix(agent): add libpq5 system dep for psycopg v3 (langgraph checkpoint) 2026-07-06 12:23:35 +03:00
558171989d fix(agent): pass AUTH_DATABASE_URL to agent container, auth config requires it 2026-07-06 12:19:14 +03:00
468bdb9000 fix(agent): resolve missing imports — jose, auth config, AUTH_SECRET_KEY
- Added python-jose[cryptography] to requirements-agent.txt
- Made sqlalchemy.orm.Session and TokenBlacklist imports lazy in jwt.py
  so decode_token works without pulling ORM models into agent image
- Added src/core/auth/__init__.py, config.py, jwt.py to agent Dockerfile COPY
- Added AUTH_SECRET_KEY env var to agent compose (reads from JWT_SECRET)
2026-07-06 12:13:26 +03:00
627b75497c docs(adr): document agent source copy strategy and logger.py dependency 2026-07-06 11:35:57 +03:00
9f9ac07cac fix(agent): copy src/core/logger.py and ws_log_handler.py into agent image
run.py imports from src.core.logger which requires logger.py and its
dependency ws_log_handler.py. Previously only cot_logger.py was copied.
2026-07-06 11:35:12 +03:00
628805503b refactor(docker): split requirements by role, slim enterprise bundle by default
Split requirements.txt into role-specific files:
  - requirements-backend.txt — FastAPI API runtime
  - requirements-agent.txt — Gradio/LangGraph agent (no embeddings)
  - requirements-embeddings.txt — opt-in sentence-transformers

Default enterprise bundle (./build.sh bundle) builds slim agent without
sentence-transformers/torch (~500 MB saved). Embeddings opt-in via
./build.sh bundle:embeddings <tag>. Embedding router degrades gracefully
when package is absent (ImportError catch in _embedding_router.py).

Updated Dockerfiles:
  - backend.Dockerfile → requirements-backend.txt
  - Dockerfile.agent → requirements-agent.txt + WITH_EMBEDDINGS build arg
  - all-in-one.Dockerfile → requirements-backend.txt

Added embeddings variant to build.sh with full manifest/digest output.
Hardened .dockerignore (cache, report, model, archive patterns).

Other branch work: align git route mocks with async services, remove
legacy agent test files superseded by contract tests.
2026-07-06 10:06:07 +03:00
1586c31d9b chore: причесать .env.example — удалить дубликаты и мёртвые vars
- backend/.env.enterprise-clean.example — удалён (точная копия root)
- .env.enterprise-clean.example — очищен от мёртвых OPENAI_API_KEY,
  ANTHROPIC_API_KEY, добавлен пример Fernet-ключа
- docker/.env.agent.example — переписан под новую архитектуру:
  убраны LLM_*, JWT_SECRET (больше не читаются агентом),
  добавлен AUTH_SECRET_KEY
2026-07-06 08:55:11 +03:00
57b7ee05e0 test(git): align route mocks with async services 2026-07-06 01:23:20 +03:00
1e56416c9f test(backend): update legacy agent and auth expectations 2026-07-06 01:23:09 +03:00
28cd141e76 feat(reports): add task status settings and tests 2026-07-06 01:22:39 +03:00
99bbdb4398 docs(agent-chat): update 035 verification traceability 2026-07-06 01:22:07 +03:00
082d6af3ab test(agent-chat): audit guardrail and error handling 2026-07-06 01:20:12 +03:00
49e4ac0fe2 refactor(frontend): integrate compact filters into reports page
- Rename page title "Отчеты задач" → "Центр статусов"
- Remove standalone quick-status filter block (moved to FilterBar)
- Remove inline filter/sort/time-range HTML (replaced by FilterBar)
- Replace statusTotal() with  quickStatusCounts
- Pass quickStatusCounts and onQuickStatusToggle to FilterBar
- Error recovery button text "Повторить" → "Повторить загрузку"
2026-07-05 15:50:51 +03:00
86ac209615 feat(frontend): compact FilterBar with disclosure toggle and quick pills
- Quick status pills (Упавшие/В работе/Успешные) always visible
- Search input with flex spacer in same row
- Explicit "Фильтры" disclosure button with filter icon, badge count, chevron
- aria-expanded / aria-controls for accessibility
- Expandable panel: type, status, time range, sort controls
- Remove bottom status bar ("Показано X из Y", "Активно фильтров")
- Update tests for expanded state and quick pill interactions
2026-07-05 15:50:46 +03:00
95308273b3 refactor(frontend): replace raw buttons with /ui/Button in SummaryPanel
- Replace raw <button> with <Button variant="ghost">
- Dim zero-count badges with opacity-50
- Add transition-colors duration-300 to count numbers
- Replace inline reconnect link with themed <Button>
2026-07-05 15:50:41 +03:00
c75017f1e4 fix(frontend): prevent TaskList horizontal overflow
- Add min-w-0 overflow-hidden to TaskList shell container
- Add filtered_empty UX state to contract
- Update layout contract test to verify TaskList source directly
- Add transition-colors to status badges
2026-07-05 15:50:36 +03:00
147d711657 feat(agent-chat): complete context guardrail event coverage 2026-07-05 14:14:42 +03:00
45e781fb74 chore: commit remaining working changes
Backend:
- agent: confirmation, persistence, app, langgraph_setup updates
- routes: agent_superset_explore, environments, git helpers/operations
- services: git sync refactoring
- tests: git_status_route expanded

Frontend:
- Navbar: minor cleanup
- Profile: i18n (en/ru), page enhancements, integration tests
- New: _llm_params.py
2026-07-05 09:24:45 +03:00
b773a06d52 refactor(frontend): extract BulkReplaceModal.Model — state + FSM + API
- BulkReplaceModalModel.svelte.ts (170 LOC): 13 state atoms,
  7-state FSM (closed→configuring→previewing→confirming→applying→applied),
  3 API actions (handlePreview, handleApply, loadDictionaries),
  1 derived (isLargeChange), @RATIONALE/@REJECTED
- BulkReplaceModal.svelte: 461→~310 LOC (INV_7 compliance),
  delegates all state/FSM/API to model, retains modal chrome + previewAfter()
- Follows TopNavbar/TranslationRunResult pattern
2026-07-05 09:21:49 +03:00
a91023d83e fix(frontend): fix Svelte prop shorthand in TranslationRunResult
{model.targetLanguages} is invalid shorthand — Svelte only supports
bare identifiers, not property access. Changed to explicit
targetLanguages={model.targetLanguages}
2026-07-05 09:17:33 +03:00
97660cb71f refactor(frontend): extract TranslationRunResult.Model — state + API logic
- TranslationRunResultModel.svelte.ts (200 LOC): 16 $state atoms,
  3 $derived projections, 5 API actions (loadData, handleRetry,
  handleRetryInsert, loadMoreRecords, loadBatches), @RATIONALE/@REJECTED
- TranslationRunResult.svelte: 623→456 LOC (167 lines saved, -27%),
  delegates all state/API to model, retains template markup and
  DOM helpers (copyToClipboard)
- INV_1: 0 naked functions (all logic in model)
- Follows TopNavbar pattern — dense anchor, hierarchical ID,
  BINDS_TO -> [TranslationRunResult.Model]
2026-07-05 09:16:32 +03:00
669d8185f3 refactor(frontend): add @RATIONALE/@REJECTED to 5 C:4 contracts
- ConfigTabForm: rationale for single-tab vs wizard; rejected multi-step
- ValidationTaskForm: rationale for multi-step wizard; rejected flat form,
  tabs, dynamic schema generation
- GitWorkspacePanel: rationale for IntersectionObserver lazy diff chunking;
  rejected virtual scroll, server pagination, Web Worker
- Git.ManagerModel: rationale for model-first (cross-operation invariants,
  L1 testability); existing @REJECTED preserved
- AgentChat.Component: rationale for reusable component vs inline;
  rejected Web Component, iframe
2026-07-05 09:00:08 +03:00
deed06fada refactor(frontend): remove @PURPOSE duplicates, merge into @BRIEF (INV_4)
- ProviderConfig: remove duplicate @LAYER/@PURPOSE/@UX_STATE block
- SemanticLayerReview: generic @BRIEF → detailed @PURPOSE text,
  remove duplicate @LAYER/@SEMANTICS
- ExecutionMappingReview: same — generic @BRIEF → @PURPOSE detail
- TaskRunner: remove duplicate @SEMANTICS/@PURPOSE/@LAYER block
- ValidationFindingsPanel: generic @BRIEF → @PURPOSE detail,
  remove duplicate @LAYER/@SEMANTICS

All: INV_4 compliance — single source of truth for contract metadata
in #region HTML comment, no scattered duplicates
2026-07-05 08:54:38 +03:00
008a8a92a5 refactor(frontend): clean metadata on AssistantChatPanel + TaskDrawer
- AssistantChatPanel: C:3→C:4 (33 side-effecting functions), remove JSDoc
  duplicates (INV_4), add @PRE/@POST/@SIDE_EFFECT/@DATA_CONTRACT/@RATIONALE/@REJECTED
- TaskDrawer: remove JSDoc duplicates (INV_4), replace 4x @PURPOSE
  JSDoc blocks with @BRIEF/@PRE/@POST in function contracts (INV_4),
  add @RATIONALE/@REJECTED
- Both: consolidate all metadata in HTML comment #region, remove
  scattered JSDoc in <script>
2026-07-05 08:53:17 +03:00
bc3e288d0b refactor(frontend): extract TopNavbar.Model — search logic, semantic compliance
- Extract TopNavbarModel.svelte.ts (303 LOC) — search state, debounce,
  API aggregation, drawer preference hydration
- TopNavbar.svelte: 605→389 LOC (INV_7 compliance)
- Remove duplicate JSDoc metadata (INV_4)
- Add @RATIONALE, @REJECTED, @PRE, @POST, @SIDE_EFFECT, @DATA_CONTRACT
- Replace raw Tailwind (from-sky-500/via-cyan-500/to-indigo-600 →
  from-brand-gradient-from/via-brand-gradient-via/to-brand-gradient-to)
- Replace raw Tailwind focus:ring-sky-200 → focus:ring-primary-ring-light
- Fix hardcoded i18n 'Ассистент' → $t.assistant.assistant
- Add primary.ring-light token to tailwind.config.js
- Replace any types with concrete interfaces (DashboardSearchResult, etc.)
- 16 naked functions → 0 (INV_1)
2026-07-05 08:50:43 +03:00
ff60865183 feat(agent-chat): 035-agent-chat-context — контекст, guardrails, tools, database discovery
== User stories ==
US1: Контекст с дашборда/датасета → /agent с URL params
US2: Guardrails card — env badge, 7 risk tones, countdown, permission_denied
US3: Tools optimization — retry, timeout, summarise, RBAC + context affinity

== Backend ==
- _context.py (NEW): UIContext validation (7 checks)
- _tool_filter.py (NEW): RBAC + context affinity pipeline
- _confirmation.py: build_confirmation_contract_v2, permission_denied_payload
- tools.py: superset_list_databases, retry/summarise/timeout wrappers
- app.py: _inject_uicontext, _inject_env_id_into_tools, database
  prefetch в runtime context
- _persistence.py: prefetch_databases()
- agent_superset_explore.py: GET /databases endpoint
- _llm_async_http.py, _persistence.py: fix double /v1 в LLM URL
  (LM Studio Unexpected endpoint)

== Frontend ==
- AgentChatModel.svelte.ts: 5 atoms, 3 actions, countdown, context
- AgentChat.svelte: production banner, process steps, debug panel
- ConfirmationCard.svelte: 7 risk tones, permission_denied, countdown
- ToolCallCard.svelte: retrying/timeout/cancelled states
- StreamProcessor.svelte.ts: tool_retry, timeout, permission_denied
- TopNavbar: sparkles icon + Ассистент
- sidebarNavigation: AI section
- DashboardHeader, datasets/+page: contextual AI buttons
- Icon: sparkles, brain, cpu icons
- tailwind: assistant category colors
- i18n: en/ru nav keys

== Tests ==
- 159 backend agent tests (+16 US3: retry, timeout, summarise, contracts)
- 2544 frontend tests (+11 model + component tests)
- 15 JSON fixtures (10 API + 5 model)

== Specs ==
- specs/035-agent-chat-context/: spec, UX, plan, tasks, research,
  data-model, contracts, quickstart, traceability, fixtures, checklists

Closes #035
2026-07-04 22:47:17 +03:00
4c5fde8b5c chore(kilo): sync OpenCode config into Kilo format 2026-07-04 22:43:17 +03:00
1f502c9785 docs(readme): add SSL/TLS configuration section with passphrase and PKCS#12 options 2026-07-04 17:10:04 +03:00