5.7 KiB
ADR: Extract OCR / Markdown / Search into a shared teamhub_core engine
Status: accepted (staged, recognition engine extracted) · 2026-06-15 · scope: legacy-knowledge-indexer + TeamHUB/Engines
Контекст
Платформа (08_DECISIONS D10, CONVENTIONS «Shared engines», plans/LegacyHUB.md §4) требует вынести проверенный пайплайн LegacyHUB (OCR → Markdown → hybrid search) в переиспользуемое stateless ядро, чтобы QMS-Hub и MailHUB потребляли его, а не дублировали. LegacyHUB остаётся эталоном и первым потребителем.
Решение
Ядро teamhub_core живёт в C:\Users\manag\TeamHUB\Engines\engines/teamhub_core/
(НЕ в этом репозитории, НЕ в TeamHUB-Platform) и потребляется как pinned
versioned dependency / git submodule (D10). Извлечение делается поэтапно, чтобы
не дестабилизировать работающий эталон; на каждом шаге тесты зелёные.
Границы ядра (stateless)
| Пакет ядра | Источник в LegacyHUB | Содержимое |
|---|---|---|
ingest |
app/ingestion/{ocr,docling_extractor,chunker,normalizer,quality,table_processor,figure_processor}.py |
OCRmyPDF, Docling, chunker, quality-flags, нормализация (сохранение ГОСТ/ID) |
search |
app/indexing/{embeddings,reranker,hybrid_search,opensearch_client,qdrant_client}.py |
BGE-M3, reranker, run_search=RRF(BM25,dense)+rerank, bootstrap индексов |
storage |
app/storage/{minio_client,artifacts}.py |
put/get + retry, ensure_artifact |
contracts |
search/citation Pydantic-типы | контракт поиска/цитирования |
obs |
app/common/json_logger.py |
JSON-логи с маскированием (уже app-agnostic) |
Персистентность (app/db/*, Alembic), эмиссия событий, имена бакетов/индексов/
коллекций и REST-роуты ОСТАЮТСЯ в модуле.
Что уже сделано для расцепления (этот репозиторий)
- Имена параметризованы.
opensearch_index_chunks,qdrant_collection_chunks, всеminio_bucket_*читаются изSettings(env-aliases). Дефолты приведены к платформенному стандарту (teamhub-legacyhub-*); потребитель (QMS/MailHUB) переопределяет их через env, не трогая код. Жёстко вшитыхlegacyhub-*имён в логике больше нет. run_searchне зависит от БД.app/indexing/hybrid_search.pyимпортирует только контракты (app/api/schemas),Settingsи клиентов индексации — слой поиска уже stateless по отношению к Postgres/ORM.obs-ядро готово.app/common/json_logger.pyнаписан без app-specific импортов и переносится в ядро как есть.- Плейтменеджмент секретов вынесен из дефолтов (см.
_enforce_secret_policy). - Первый физический engine вынесен. OCRmyPDF/Tesseract + Docling recognition
теперь живут в
TeamHUB/Engines/engines/teamhub-document-recognition-engine; LegacyHUB оставляетapp/ingestion/ocr.pyиapp/ingestion/docling_extractor.pyкак тонкие адаптеры и source metadata вapp/ingestion/ENGINE_SOURCE.md.
Остаточные шаги (staged, координируются с QMS/MailHUB)
- Поддерживать LegacyHUB pin на
teamhub-document-recognition-engine-v0.1.0до следующего совместимого release. - Перенести
contracts(типы поиска/цитирования) изapp/api/schemasвteamhub_core.contracts;app/api/schemasре-экспортирует их для совместимости. - Перенести
search/ingest/storage/obsв ядро;run_searchпринимает имена индекса/коллекции/бакетов аргументами/конфигом, а не глобальнымSettingsмодуля. - Переключить LegacyHUB на ядро как pinned submodule;
app/indexing,app/ingestionстановятся тонкими адаптерами. Временная vendored-копия — только с задокументированным сроком удаления. - Контракт-тесты ядра единым сьютом (chunker/quality/hybrid/hashing/duplicates).
- Подключить QMS-Hub (свои бакеты
teamhub-qms-*, индексqms_chunks, своя PG) и MailHUB (поиск по письмам/вложениям) как вторых потребителей.
Последствия
- Физический вынос затрагивает три репозитория (LegacyHUB, Engines, потребители) и
выполняется отдельной скоординированной работой; в этом проходе закрыта
готовность к расцеплению (параметризация имён, stateless
run_search, app-agnostic obs-core) и зафиксирован план. - Риск регрессий минимизируется поэтапностью и зелёным тест-сьютом на каждом шаге.
См. также docs/ADR-layers.md (маппинг слоёв) и docs/dispatch-contract.md.