Перейти к содержимому

RAG_Support_Assistant — глубокий аудит, ревизия 2026-04-27

Это содержимое пока не доступно на вашем языке.

RAG_Support_Assistant — глубокий аудит, ревизия 2026-04-27

Section titled “RAG_Support_Assistant — глубокий аудит, ревизия 2026-04-27”

Дата: 2026-04-27 HEAD: ff7948f (master, +13 коммитов от edb856f baseline предыдущего аудита) Аудитор: Claude Opus 4.7 (1M context) Скоуп: delta-аудит после 13 коммитов hardening 2026-04-27, плюс верификация заявленного status предыдущего audit log Метод: статический анализ репозитория, real-shell smoke (pytest focus-set, mypy, bandit, pip-audit), верификация каждого «claim» из audit_opus_2026-04-26.md секция 12

TL;DR. Между двумя аудитами проект сделал большой шаг: api/app.py упал с 5288 до 2126 LOC (−60%), все 13 запланированных split-фаз 2a-2m закрыты, Phase 1-5 root-level cleanup завершены. Безопасность чистая (0 CVE, 0 High/Med bandit). Найдены две новые регрессии P1, которые предыдущий audit log пропустил: (а) 13 production import-сайтов всё ещё ходят через root shim-ы вместо canonical homes — каждый импорт production кода триггерит DeprecationWarning; (б) полный mypy llm/providers/ показывает 5 type errors, заявленных как «clean» (на деле «clean» — только под --follow-imports=skip). Остальное соответствует заявленному. Локальная оценка повышается 8.7/10 → 9.0/10, commercial — 7.7/10 → 8.0/10.

Сопутствующие документы:


Это delta-аудит к audit_opus_2026-04-26.md. Не повторяю архитектурную часть (стек, граф LangGraph, структура сервисов) — она с 26-го числа не менялась. Сосредотачиваюсь на трёх вопросах:

  1. Что реально закрыто за 27-04? Сверяю заявленные коммиты с фактической геометрией репо.
  2. Что ещё горит? Прогоняю real-shell smoke и ищу gap’ы между заявленным status и реальностью.
  3. Какой следующий шаг? Обновлённый roadmap.

Все находки помечены [LOCAL] (применимо для локального продукта) или [COMMERCIAL] (только для commercial-сценария из commercial-upgrade-plan.md).


Дименсия2026-04-262026-04-27Изменение
Архитектура RAG-пайплайна9.0/109.0/10без изменений (граф не менялся)
Качество кода8.0/108.5/10api/app.py 5288→2126 LOC (−60%); Phase 1-5 закрыты; 0 TODO/FIXME
Безопасность (local)8.5/108.7/100 CVE, bandit clean, security gates сохранены после 13 split-ов
Безопасность (commercial)7.0/107.5/10+ scanning chain holds через все splits, gates idempotent
Тесты8.0/108.0/1050/50 focus pass на новом scope; coverage до 70% всё ещё не подтверждён
Operability9.0/109.0/10без изменений; все probes/middlewares сохранились
Архитектура (структура repo)7.5/109.0/1014 routers вынесены; root tree почти чистый (3 shim-а)
Local total8.7/109.0/10+0.3
Commercial total7.7/108.0/10+0.3

1.2 Top-5 действий, упорядочены по impact × (1/effort)

Section titled “1.2 Top-5 действий, упорядочены по impact × (1/effort)”
#ДействиеImpactEffortКогда
1Заменить 13 production-импортов root shim-ов (manager, sqlite_trace) на canonical (vectordb.manager, tracing.sqlite_trace). После этого удалить shim-ы.🟠 Med1 часЭта неделя
2Закоммитить uncommitted Phase 4 (ingestion/loader.py + loader.py shim + 4 связанных файла) или откатить, если не финал. Worktree держится грязным с 26-го.🟠 Med30 минЭта неделя
3Починить 5 mypy errors в llm/providers/ (mistral.py:166 Headers→dict, runtime.py:64,74 **common_kwargs typing) — после чего поднять scope [[tool.mypy.overrides]] llm.providers.* до disallow_untyped_defs=true.🟡 Low2 часаБлижайший месяц
4Coverage gate 70%: разлочить test_upload_path_bypasses_body_middleware (зависает в shared-state run-е) и снять реальные числа — баг ещё не починен.🟡 LowполдняБлижайший месяц
5Финальный split тонкого app-shell-а: вынести /auth/login, /auth/refresh, /sessions/* в api/routers/session_auth.py, оставить в api/app.py только construction + lifespan + middlewares + Pydantic models.🟡 Low1 деньКогда удобно
Метрика2026-04-26 (аудит)2026-04-27 (сейчас)
Коммитов в master121134 (+13)
api/app.py LOC5288 (на момент аудита, до ae0562e)2126
Endpoints в api/app.py~70~5 (auth + sessions + UI/legacy aliases)
Sub-routers4 (на конец 26-04)14
Endpoints в sub-routers1264
/api* routes total6971 (после /health/live+/health/ready+/health split)
Root-level Python (вне shim-ов)8 (manager, sqlite_trace, loader, chunking, bitrix, mock_inbox, seed_docs, cache)2 (cache.py 266 LOC, main.py 413 LOC) — остальные либо shim, либо moved
Active legacy shims в корне33 (manager, sqlite_trace, loader — всё стало 15 LOC each)
Tests focus-set pass71/7150/50 (новый focus scope: jwt+tenant+health+metrics+agent+review+conv+module-layout+mock_inbox+seed_docs+loader)
Tests files / LOC115 / 17.6K109 / 18.2K (slightly меньше файлов, больше LOC — рефакторинг)
HIGH bandit00
MEDIUM bandit00
LOW bandit(н/д)87 (приемлемо: B101 asserts, B105 hardcoded password tokens — все false positive)
pip-audit CVEs00
TODO/FIXME/HACK в production00 (единственный hit — example URL в bitrix.py:77, не TODO)
mypy strict-clean modules5 (auth.*, db.models)5 (auth.* + db.models). db/engine.py declared informational-clean.
mypy informational-clean modules00 (заявлено llm/providers/ clean — НЕ подтверждено: 5 errors при полном follow-imports)

2. Что закрыто за 2026-04-27 (verified)

Section titled “2. Что закрыто за 2026-04-27 (verified)”

13 коммитов после baseline edb856f:

КоммитКатегорияЧто закрытоVerified
ae0562ebulk hardeningchore: harden runtime and split routers — общая правка после hardening pass
7128f0bPhase 2isplit analytics router (4 endpoints /analytics/*)✓ 136 LOC
8af2e9dPhase 2g+2hsplit admin_experiments (9 endpoints) + admin_evaluations (4 endpoints)✓ 497+183 LOC
4eaf78cPhase 2msplit misc router (/admin/providers, /channels/email/inbound)✓ 50 LOC
b813a15Phase 2bsplit feedback (3 endpoints /feedback, /feedback/stats, /escalate)✓ 163 LOC
6668ffePhase 2dsplit admin_ops (audit, traces, circuit-breaker reset)✓ 263 LOC
d82013aPhase 2ksplit upload (/upload, /tasks/{id})✓ 219 LOC
5864dd6Phase 2asplit health extension (/health, /health/ready) — добавлено в system.py✓ 154 LOC
5b4a954Phase 2lsplit conversation (/ask, /chat, /ask/stream, /chat/stream) — самый крупный split, 758 LOC ушло из api/app.py✓ 764 LOC
11e4427Type-checkchore: resolve provider mypy debt — runtime.py + gracekelly.py + db/engine.py типизация⚠ partially (см. §4.2)
de93817Phase 2 rootmove bitrix.pyintegrations/, mock_inbox.pyintegrations/, seed_docs.pydemo/
5d92049Phase 3 rootconsolidate manager.py (909→15 LOC shim) + sqlite_trace.py (972→15 LOC shim); vectordb/_base_manager.py + tracing/_base_trace.py — canonical
ff7948fPhase 5 rootmove chunking.pyscripts/chunking_eval.py

Дельта api/app.py: −3162 LOC (5288 → 2126), что покрывается split-коммитами:

  • conversation: −758
  • 8 sub-routers (analytics+feedback+admin_ops+upload+health-extras+experiments+evaluations+misc): остаточный delta ~−2400 LOC, что согласуется.

Тесты-добавки:

  • tests/test_conversation_router.py (новый, 9 LOC stub)
  • tests/test_module_layout.py (расширен, +20+13+9 LOC через 3 коммита) — фиксирует canonical home для manager/sqlite_trace/loader, проверяет что shim-ы выдают DeprecationWarning.
  • tests/test_mock_inbox_import.py / tests/test_seed_docs_import.py обновлены под integrations/demo paths.
  • Новый tests/test_loader.py (untracked) — Phase 4 в работе.

3. Что закрыто uncommitted (Phase 4 в работе)

Section titled “3. Что закрыто uncommitted (Phase 4 в работе)”

git status на момент аудита держит 11 модифицированных + 1 untracked файл, прямо относящихся к Phase 4 loader merge:

M ingestion/__init__.py (+ DocumentChangeTracker в публичном API)
M ingestion/loader.py (+ HTML support + DocumentChangeTracker class +
_read_html, +file_type=format alias, +SUPPORTED_EXTENSIONS)
M loader.py (305 → 15 LOC: реальная реализация заменена shim-ом)
M tasks/ingest_task.py (убран try/except ImportError fallback,
теперь прямо `from ingestion.loader import DocumentLoader`)
M tests/test_module_layout.py (+ test для loader)
?? tests/test_loader.py (новый юнит-набор для DocumentChangeTracker + html)

Также M:

  • DEPRECATIONS.md — Phase 4 переведён в ✅ DONE
  • audit_opus_2026-04-26.md (мелкие правки в строке статуса)
  • docs/SESSION-NOTES-2026-04-26-audit.md (handover дополнен)
  • docs/CHANGELOG.md (новая запись)
  • codex-tasks/cleanup-report.md
  • api/app.py (импорт-чейн правка)

Состояние работы: функционально завершено. python -m pytest tests/test_module_layout.py tests/test_loader.py проходит чисто (50/50 в моём focus-set), API роутов 71 (как и заявлено), from ingestion.loader import DocumentChangeTracker работает.

Риск: dirty worktree уже второй сессии — невидимые правки накапливаются, любой случайный git stash или сбой репо потеряют 39 entries. Рекомендую закоммитить двумя сообщениями (Phase 4 code + audit/doc updates) до начала любой следующей работы.


4. Новые находки (не закрытые)

Section titled “4. Новые находки (не закрытые)”

4.1 [P1] Production-код всё ещё импортирует root shim-ы

Section titled “4.1 [P1] Production-код всё ещё импортирует root shim-ы”

Что нашёл: root-shim-ы manager.py, sqlite_trace.py, loader.py создавались как backward-compat для внешних консумеров (DEPRECATIONS.md называет это «🟡 shim»). По плану production-imports должны были перейти на canonical: vectordb.manager, tracing.sqlite_trace, ingestion.loader. На деле 13 production-сайтов всё ещё ходят через shim:

api/app.py:145: from manager import build_vector_store, get_retriever, get_embeddings
api/app.py:961: import sqlite_trace
api/app.py:1524: from sqlite_trace import purge_old_traces
api/routers/admin_ops.py:135: from sqlite_trace import list_recent_traces
api/routers/admin_ops.py:158: from sqlite_trace import get_trace_detail
api/routers/admin_ops.py:186: from sqlite_trace import purge_old_traces
api/routers/feedback.py:53: from sqlite_trace import save_feedback
api/routers/feedback.py:151: from sqlite_trace import get_feedback_stats
api/routers/system.py:143: from sqlite_trace import get_metrics_snapshot
channels/telegram_bot.py:41: from manager import get_embeddings, get_retriever
scripts/check_alerts.py:20: from sqlite_trace import get_metrics_snapshot
scripts/kb_gap_detector.py:19: import sqlite_trace
scripts/nightly_eval.py:19: import sqlite_trace

Эффект. При каждом старте API или скрипта триггерится DeprecationWarning: Importing 'sqlite_trace' is deprecated; use 'tracing.sqlite_trace' instead. (аналогично для manager). В тестах warnings глушатся, в production логах они оседают как noise. Сами shim-ы свопают sys.modules[__name__] = _base, так что функционально всё работает — но это именно тот вид latent debt, который потом всплывает при удалении shim-а.

Severity: 🟡 P1 для local (cosmetic + future maintenance), 🟠 P2 для commercial (linter pipeline покажет deprecation warnings в каждом deploy).

Fix: глобальный sed-style rewrite по этим 13 сайтам:

  • from manager import Xfrom vectordb.manager import X (но vectordb.manager сам пере-экспортирует _base_manager, то есть фактически работает — просто оборачивает чище)
  • import sqlite_trace / from sqlite_trace import Xfrom tracing.sqlite_trace import X

Проверить, что vectordb/__init__.py и tracing/__init__.py экспортируют те же символы. Прогон pytest после правки. Trivial CC-задача (~1 час), не нужен Codex.

После fix: удалить shim-ы из корня (Phase 3+4 финал) — оставить только тот случай, когда есть внешние консумеры (нет, это локальный проект).

4.2 [P2] mypy llm/providers/ clean только под --follow-imports=skip

Section titled “4.2 [P2] mypy llm/providers/ clean только под --follow-imports=skip”

Что нашёл. DEPRECATIONS.md:181-198 заявляет:

llm.providers.* — informational mypy scope is clean as of 2026-04-27.

Команда из этого же файла:

mypy --follow-imports=skip --no-incremental llm/providers

Под этим режимом — действительно clean. Но при стандартном mypy auth db/models.py db/engine.py llm/providers/ (как у меня) выскакивает 5 ошибок:

llm/providers/mistral.py:166: error: Argument 2 to "_parse_response" of
"MistralProvider" has incompatible type "Headers"; expected "dict[str, str]"
[arg-type]
llm/providers/runtime.py:64: error: Argument 2 to "OllamaProvider" has
incompatible type "**dict[str, object]"; expected "str" [arg-type]
llm/providers/runtime.py:64: error: Argument 2 to "OllamaProvider" has
incompatible type "**dict[str, object]"; expected "float" [arg-type]
llm/providers/runtime.py:74: error: Argument 2 to "MistralProvider" has
incompatible type "**dict[str, object]"; expected "str" [arg-type]
llm/providers/runtime.py:74: error: Argument 2 to "MistralProvider" has
incompatible type "**dict[str, object]"; expected "float" [arg-type]

Природа.

  • mistral.py:166 — реальный type narrowing gap: httpx.Response.headers это httpx.Headers (Mapping-like), а не dict[str, str]. Лечится либо dict(response.headers), либо аннотацией _parse_response(headers: Mapping[str, str]).
  • runtime.py:64,74**common_kwargs (типа dict[str, object]) распаковывается в позиционные аргументы провайдеров, у которых параметры строго типизированы. Лечится либо cast(dict[str, str], common_kwargs) либо TypedDict для kwargs.

Severity: 🟡 P2 (informational scope не блокирует runtime, но текущая формулировка в DEPRECATIONS вводит в заблуждение — «clean» не absolute, а «clean только при skip-imports»).

Fix:

  1. Чинить 5 ошибок (Mapping → dict, TypedDict для kwargs).
  2. Снести --follow-imports=skip из DEPRECATIONS.md, поднять scope до disallow_untyped_defs=true + disallow_incomplete_defs=true в [[tool.mypy.overrides]] module = ["llm.providers.*"].
  3. Добавить mypy llm/providers/ в pre-commit (сейчас только auth + db/models).

4.3 [P3] cache.py (266 LOC, root-level) — рядом с cache/redis_cache.py

Section titled “4.3 [P3] cache.py (266 LOC, root-level) — рядом с cache/redis_cache.py”

Что нашёл. В корне живёт cache.py (266 LOC, in-memory LRU + disk persistence) параллельно с cache/redis_cache.py (Redis backend). DEPRECATIONS.md явно помечает это как «не дубль, разный concern», и это правда.

Foot-gun. Разработчик новый в репо, увидев from cache import RAGCache vs from cache.redis_cache import cache_json_get, легко спутает который backend используется. Нет shared interface.

Severity: 🟢 P3 (cosmetic).

Fix (опционально): переименовать cache.pycache/local_lru.py или cache/in_memory.py, чтобы оба cache-backend жили под одним пакетом. Импорты обновить (grep -r "from cache import" найдёт consumers). Не критично.

4.4 [P3] api/app.py остаточный shell — 2126 LOC

Section titled “4.4 [P3] api/app.py остаточный shell — 2126 LOC”

После Phase 2a-2m в api/app.py ещё:

КатегорияLOCЧто
Pydantic request/response models~70SessionInfo, HistoryMessage, HistoryResponse, LoginRequest, TokenResponse, RefreshRequest
Private helpers~110030+ _load_*, _serialize_*, _run_*, _probe_*, _record_* функций — широкий util-набор для regression jobs, curated dataset, vector store, health probes, citation stats, review queue
_lifespan~200startup probes + auto-migrate + ChromaDB init + cache init + cleanup
5 endpoints~250/auth/login, /auth/refresh, /sessions/{id}/history, /sessions, /sessions/{id}
6 middlewares~150request-id, body-size, cors+sessions, http-metrics, logger, tenant
2 legacy/UI endpoints~30/agent (HTML page), /admin/traces/{id} (UI), /metrics (legacy дубль /api/metrics)
App construction + router include~50app = FastAPI(...), router.include_router(...) цепочка, app.include_router(router)
Imports + setup~200большой блок с safe imports + safe fallbacks

Дубль /metrics/api/metrics. Первый (line 2114) — @app.get("/metrics") без префикса, для Prometheus pull по конвенции. Второй — через api/routers/system.py под префиксом /api. Содержательно одинаковые. Это намеренный дубль для backwards compat (Prometheus scrape configs обычно указывают на /metrics, не /api/metrics). В норме надо оставить, но задокументировать в system.py или README.

Severity: 🟢 P3 (косметика; дальнейший split — диминишинг return).

Fix (если хочется чистого app-shell): task #5 из §1.2 — вынести auth+sessions в api/routers/session_auth.py, helpers (regression/curated dataset/vector store) в services/. Это уже больше «кварталная задача», чем эта-неделя.

4.5 [P3] Coverage gate 70% — пайплайн есть, число не верифицировано

Section titled “4.5 [P3] Coverage gate 70% — пайплайн есть, число не верифицировано”

pyproject.toml содержит [tool.coverage.report] fail_under = 70. Но в audit log 2026-04-26 указано: «focus-set дал 24%, полный pytest пакет должен дать существенно выше, но test_upload_path_bypasses_body_middleware зависает в shared-state run-е». Этот test я не запускал в данной сессии — баг не починен. Реальное coverage repo — unknown.

Severity: 🟢 P3 (gate в конфиге есть; реальное число — неподтверждённое).

Fix: дебаг зависания (вероятно — лежащая в tmp/ БД или semaphore state из предыдущего теста), потом pytest --cov полный прогон, отчёт.


5. Что осталось из 26-04 audit log (трекинг открытых задач)

Section titled “5. Что осталось из 26-04 audit log (трекинг открытых задач)”
Из 12.5Статус 27-04Комментарий
A. Phase 2a-2m split-фазы✅ ALL DONE13 фаз закрыты за 27-04. Заявлено в audit log + verified мной.
B. Type-checking долг (llm/providers/)⚠ PARTIALзаявлено clean (informational), на деле 5 errors при полном follow-imports. См. §4.2.
C. DEPRECATIONS Phase 2-5✅ ALL DONEPhase 2 (integrations + demo), Phase 3 (manager+sqlite_trace shims), Phase 4 (loader merge — uncommitted в worktree), Phase 5 (chunking_eval).
D. Coverage до 70%❌ NOT DONEреальное число всё ещё неизвестно. Тест зависания не починен. См. §4.5.
E. Финальный thin app-shell (вынести auth+sessions)⏳ DEFERREDзаявлено как «отдельный cleanup», не обязательный. См. §1.2 task #5.

6. Безопасность — re-verified

Section titled “6. Безопасность — re-verified”
ПроверкаРезультат
bandit -r . -ll -c pyproject.toml -x ./tests,./.venv,./reports,./data0 High / 0 Medium / 87 Low (Low — приемлемо: B101 asserts в ML-evaluation коде, B105/B107 password placeholder в тестовых fixture-ах).
pip_audit -r requirements.txt0 known vulnerabilities.
auth/dependencies.py ALLOW_ANONYMOUS_ADMIN gate✓ сохранён (os.getenv("ALLOW_ANONYMOUS_ADMIN", "").strip() in ("1","true","yes")); по дефолту 503 при отсутствии API_KEY.
main.py HOST default127.0.0.1 (line 411). Docker compose не затронут.
main.py AUTO_MIGRATE✓ default true, gated env, log warning не аборт при сбое (line 375-390).
main.py SQLite WALjournal_mode=WAL, busy_timeout=5000, synchronous=NORMAL.
Field(max_length=…) на user input✓ сохранены через splits (AskRequest, RefreshRequest, etc.)
pre-commit (bandit + pip-audit).pre-commit-config.yaml секции присутствуют.
Secrets в .envMISTRAL_API_KEY в .env (gitignored), .env.example placeholder changeme, fail-fast при попытке paid profile без real key. Не commit-нул, не log-нул.
Anonymous-admin foot-gun✓ закрыт (опциональный opt-in env).

Регрессий безопасности — нет. Все 13 split-коммитов сохранили security gates.


7. Тестовый прогон в этой сессии

Section titled “7. Тестовый прогон в этой сессии”
python -m pytest \
tests/test_jwt_auth.py tests/test_tenant_propagation.py \
tests/test_health_liveness.py tests/test_metrics.py \
tests/test_agent_endpoints.py tests/test_review_queue.py \
tests/test_conversation_router.py tests/test_module_layout.py \
tests/test_mock_inbox_import.py tests/test_seed_docs_import.py \
tests/test_loader.py \
-p no:schemathesis -q --timeout=60
==> 50 passed, 4 warnings in 8.65s

Warnings — все три (Importing 'manager'/'sqlite_trace'/'loader' is deprecated) триггерятся намеренно в tests/test_module_layout.py через import importlib для верификации, что shim-ы правильно warning-ат.

python -m mypy auth db/models.py db/engine.py llm/providers/
==> Found 5 errors in 2 files (checked 12 source files)

Detail в §4.2.

python -m bandit -r . -ll -c pyproject.toml -x ./tests,./.venv,./reports,./data
==> No issues identified. (0 High / 0 Medium)
python -m pip_audit -r requirements.txt
==> No known vulnerabilities found

7.4 Что НЕ прогнано в этой сессии

Section titled “7.4 Что НЕ прогнано в этой сессии”
  • Полный pytest tests/ без --ignore=tests/integration — long run, infra-зависим (нужен Postgres/Redis testcontainer). Я положился на 50/50 focus.
  • python -m src.cli ... real-shell smoke — у проекта нет CLI entry point, только HTTP API. Smoke сделан через from api.app import app; routes = app.routes.
  • Live regression через GraceKelly — out of scope этого аудита.

8.1 Эта неделя (~2 часа суммарно)

Section titled “8.1 Эта неделя (~2 часа суммарно)”
  1. Закоммитить uncommitted Phase 4 (loader merge + связанные docs) — ~10 минут.
  2. Заменить 13 production imports root shim-ов на canonical (см. §4.1). После этого Phase 3+4 действительно «полностью закрыты», shim-ы можно удалять следующей сессией. ~1 час.
  3. (опц.) Документировать дубль /metrics/api/metrics в api/routers/system.py docstring + README. 5 минут.

8.2 Ближайший месяц (~1 день)

Section titled “8.2 Ближайший месяц (~1 день)”
  1. Починить 5 mypy errors в llm/providers/ (см. §4.2). После — поднять scope до disallow_untyped_defs=true для llm.providers.* в pyproject.toml. ~2 часа.
  2. Coverage gate 70%: дебаг test_upload_path_bypasses_body_middleware (зависание в shared-state run-е) → полный pytest прогон → realистичное число. Если ниже 70% — точечно добивать тестами там, где есть пробелы в production-критичной логике (auth, db/models, llm/providers). ~полдня.
  3. Удалить shim-ы manager.py, sqlite_trace.py, loader.py (после задачи 2). Проверить, что тест test_module_layout.py обновлён под отсутствие shim-а (или переписан как negative-test «from manager import …` should fail»). ~30 минут.

8.3 Квартал (если идёт commercial-сценарий)

Section titled “8.3 Квартал (если идёт commercial-сценарий)”
  1. Финальный thin app-shell (см. §4.4): вынести /auth/login, /auth/refresh, /sessions/* в api/routers/session_auth.py. Helpers regression/curated в services/. Цель — api/app.py ≤ 600 LOC (только construction+lifespan+middlewares).
  2. Service-слой: extract бизнес-логики из routers в services/ (regression_service, curated_dataset_service, review_queue_service). Routers → handlers thin shells.
  3. mypy strict для agent.* (LangGraph nodes) — самый сложный модуль для типизации, но добавит уверенности в pipeline-mutation коде.
  4. CI security pipeline: bandit + pip-audit + semgrep в GitHub Actions (сейчас только pre-commit local).

8.4 Что НЕ нужно делать (зафиксировано в аудите 26-04 + остаётся актуально)

Section titled “8.4 Что НЕ нужно делать (зафиксировано в аудите 26-04 + остаётся актуально)”
  • ❌ Переписывать LangGraph-граф — он хорош.
  • ❌ Менять стек БД / vector store / embedder.
  • ❌ Внедрять Kubernetes для local-продукта.
  • ❌ Тащить ещё одну observability-систему.
  • Новое: не трогать cache.py vs cache/redis_cache.py пока — DEPRECATIONS явно помечает их как разные concerns, переименование сейчас — ROI < risk.

Local: 9.0 / 10. На уровне мьюзельного зрелого SaaS, проникновение в production полностью оправдано. Архитектура и Operability — sterling. Главные пробелы (shim imports, mypy провайдеров, coverage число) — все размером на 2-4 часа работы.

Commercial: 8.0 / 10. До 9.0/10 (целевой уровень из commercial-upgrade-plan.md) осталось ~2 недели работы по roadmap-у §8: закрыть structural debt (shim cleanup

  • mypy + coverage), запустить CI security pipeline, добить app-shell. Никаких архитектурных пересмотров не требуется.

Самое сильное место (без изменений с 26-04) — RAG-пайплайн + observability.

Самое слабое место (новое) — две регрессии-claim’а: production код всё ещё дёргает root shim-ы (хотя shim-ы сделаны для backward-compat внешних, не своих), и llm/providers/ mypy clean только под flag-ом --follow-imports=skip. Оба — P1/P2, не блокеры; но нужно адресовать прежде, чем заявлять “Phase 3 закрыт”.

Прогресс с 26-04 — впечатляющий. За одну сессию закрыты 13 split-фаз + 4 root cleanup phase + mypy partial + 2 новых тест-сьюта. api/app.py срезан на 60%. Это редко увидишь в open-source RAG-репах за такой short turnaround.


10. Quick verify в новой сессии (5 команд)

Section titled “10. Quick verify в новой сессии (5 команд)”
Terminal window
# 1. Маршруты
python -c "from api.app import app; print(f'/api routes: {len([r for r in app.routes if hasattr(r,\"path\") and r.path.startswith(\"/api\")])}')"
# Ожидаем: 71
# 2. Focus tests
python -m pytest tests/test_jwt_auth.py tests/test_tenant_propagation.py tests/test_health_liveness.py tests/test_metrics.py tests/test_agent_endpoints.py tests/test_review_queue.py tests/test_conversation_router.py tests/test_module_layout.py tests/test_mock_inbox_import.py tests/test_seed_docs_import.py tests/test_loader.py -p no:schemathesis -q --timeout=60
# Ожидаем: 50 passed
# 3. mypy strict (только auth+db/models — clean)
python -m mypy auth db/models.py
# Ожидаем: Success: no issues found in 5 source files
# 4. mypy informational (llm/providers — известно 5 errors, см. §4.2)
python -m mypy llm/providers/
# Ожидаем: Found 5 errors in 2 files (или 0, если §1.2 task #3 уже сделан)
# 5. bandit
python -m bandit -r . -ll -c pyproject.toml -x ./tests,./.venv,./reports,./data 2>&1 | tail -5
# Ожидаем: 0 High / 0 Medium
# 6. pip-audit
python -m pip_audit -r requirements.txt 2>&1 | tail -3
# Ожидаем: No known vulnerabilities found

11. Pre-commit gate — что бы я сделал прямо сейчас

Section titled “11. Pre-commit gate — что бы я сделал прямо сейчас”

Если задача — shipping этого репо на small-team production за 1 неделю:

ШагКоманда
1. Закоммитить Phase 4git add ingestion/ loader.py tasks/ingest_task.py tests/test_module_layout.py tests/test_loader.py DEPRECATIONS.md docs/CHANGELOG.md docs/SESSION-NOTES-2026-04-26-audit.md && git commit -m "refactor(loader): merge Phase 4 — DocumentChangeTracker + HTML support in ingestion.loader"
2. Заменить shim importssed-rewrite по 13 сайтам (см. §4.1)
3. Удалить shim-ыrm manager.py sqlite_trace.py loader.py (все три файла теперь по 15 LOC)
4. mypy fix5 errors в llm/providers/ (§4.2)
5. Coverageunbreak test_upload_path_bypasses_body_middleware
6. Final commitgit commit -m "chore: post-audit hardening 2026-04-27 — shim cleanup, mypy providers, coverage unblock"

Это 3-4 часа работы, после которых local rating 9.5/10, commercial 8.5/10.