Document evidence-led query discovery architecture

This commit is contained in:
DCCONSTRUCTIONS 2026-07-14 16:52:43 +03:00
parent 4ade361659
commit 56dbb49261
3 changed files with 251 additions and 0 deletions

View File

@ -0,0 +1,56 @@
# Offer Map и язык рынка
Этот документ — рабочая архитектурная опора для SEO-модуля. Она применяется к любому сайту и не содержит отраслевых словарей, названий продуктов или зашитых рынков.
## Принцип
```text
Site Graph + evidence
→ Offer Map
→ Market Archetype Router
→ Search Scope
→ semantic slots
→ deterministic query patterns
→ human candidate checker
→ observed language
→ Wordstat
→ clustering and strategy
```
LLM допускается в `Offer Map`, маршрутизации архетипов и выделении semantic slots. Она не доказывает спрос и не создаёт готовые ключи для Wordstat.
## Граница объектов
### Offer Map
Фактическая модель продукта, составленная из site evidence:
- core offer простым рыночным языком;
- market categories;
- возможности и дифференциаторы;
- buyer roles и deployment только с evidence;
- `do_not_overweight_terms`;
- правило: внутренние названия модулей, слоёв, экранов и архитектурных сущностей не являются языком рынка без external evidence.
### Opportunity Portfolio
Прикладные модули, вертикали и гипотезы расширения. Портфель полезен для исследования стратегии, но не создаёт поисковые направления автоматически и не является блокером для Product Core.
### Search Scope
Явно выбранные пользователем направления, которые разрешено отправить в semantic slots и pattern engine. Новый проект начинает с factual core. Модули и возможности добавляются сюда только отдельным человеческим решением.
## Candidate checker
Пользователь видит черновые формулировки, а не Topic Cards:
- vector / intent / page type / pattern;
- источник смысла в сайте;
- статус: draft, kept for collection, excluded или observed;
- решение человека хранится отдельно от внешнего evidence.
`kept for collection` означает только разрешение собирать observed language. Это не Wordstat input. Wordstat получают лишь explicit base probes или observed queries, прошедшие evidence gate.
## Универсальность
Archetypes и patterns являются конфигурацией, а не кодом под конкретную отрасль. Один и тот же конвейер применим к enterprise software, локальной услуге, e-commerce, медиа, образованию, промышленному оборудованию и другим типам сайтов.

View File

@ -0,0 +1,30 @@
# Open-source mini-audit: search language pipeline
Дата проверки: 2026-07-12. Критерии: активность, лицензия, открытые issues и комментарии, архитектурная совместимость с TypeScript/PostgreSQL evidence pipeline.
## Решения
| Project | Signals | Decision |
| --- | --- | --- |
| `altrr2/yandex-tools-mcp` | MIT, 38 stars, push 2026-07-08, без открытых issues | Использовать как reference-contract и набор интеграционных тест-кейсов. Не импортировать runtime: provider boundaries и credentials должны оставаться нашими. |
| `baltic-tea/yandex-wordstat-mcp` | 1 star, нет явной лицензии, push 2026-04-26 | Не подключать. Можно сверять Wordstat operators, retries и region cache с реализацией. |
| `neonwatty/autocomplete-cli` | архивирован, 1 star | Не подключать. Заимствовать только протокол expansion: seed, alphabet, question modifiers, language/region, raw artifact. |
| `chukhraiartur/seo-keyword-research-tool` | MIT, 158 stars, код не обновлялся с 2023, старые issues без дискуссии | Не подключать: хороший reference flow для autocomplete/PAA/related, но runtime зависит от SerpApi и не закрывает provenance. |
| `PhialsBasement/LibreCrawl` | MIT, 751 stars, активные свежие issues/PR | Не заменять текущий crawler. Брать regression cases для crawler hardening: anti-bot, JS pages, redirects, sitemap/robots. |
| `puneetindersingh/open-seo-crawler` | MIT, 11 stars, один открытый Playwright issue | Только источник идей для Playwright fallback; не dependency. |
| `sethblack/python-seo-analyzer` | большой активный проект, но Python + отдельный AI stack | Не интегрировать. Сверять набор technical-audit checks с нашим scanner. |
| `searchsolved/search-solved-public-seo` | 404 stars, активен, без явной лицензии, issues разного качества | Не импортировать. Использовать как catalogue маленьких проверяемых экспериментов для PAA, related и internal-search. |
| `FassihFayyaz/SEO-Clustering-Tool` | 5 stars, неактивен с 2025, timeout issue | Не dependency. Позже воспроизвести идею SERP URL-overlap clustering в нашем evidence schema. |
| `KeyBERT`, `YAKE` | зрелые библиотеки извлечения фраз | Не считать поисковым evidence. Возможны как offline triage для текста сайта. |
| `Natasha`, `pymorphy3` | зрелые русскоязычные NLP/morphology библиотеки | Кандидаты на отдельный opt-in Python normalizer после появления observed queries. Не тащить Python runtime в первый pre-Wordstat vertical slice. |
## Принятые заимствования
1. `autocomplete-cli`: контракт harvester-а — expansion, locale/region, raw artifact, дедупликация.
2. `yandex-tools-mcp`: test matrix для Wordstat/Yandex providers, а не runtime package.
3. `LibreCrawl` и `python-seo-analyzer`: наборы regression checks для сканера.
4. SEO clustering projects: будущий SERP-overlap алгоритм только после появления валидированных observed/Wordstat rows.
## Почему не подключаем репозитории напрямую
Прямой импорт смешал бы provider credentials, lifecycle jobs и raw evidence с чужими CLI/MCP/Streamlit/Flask приложениями. Для нашего конвейера ценнее переносить маленькие проверяемые алгоритмы и контракты, сохраняя одну authority chain: page evidence → Offer Map → scope → pattern → observation → decision.

View File

@ -0,0 +1,165 @@
# Query Discovery: язык рынка до Wordstat
## Канонический контракт v4
С `seo-demand-research-brief.v3` входом Query Discovery является не
одна product phrase, а `SemanticPortfolioFacet[]`.
```text
Offer Map + Business Synthesis + Demand Families + approved Opportunity Portfolio
→ Semantic Portfolio (evidence, risks, slot bundle, pattern eligibility)
→ balanced_auto Search Scope (34 safe core facets)
→ topic decomposition per facet
→ query-surface drafts
→ short market seeds
→ observed queries
→ normalization + relevance gate
→ canonical query clusters
→ human observed-language review
→ bounded Wordstat queue
Parallel, non-queue branch:
Semantic Portfolio + Offer Map + Opportunity Portfolio
→ DomainAgnosticityClassifier
→ ExpansionSurfaceBuilder + ApplicabilityMatrixBuilder
→ explicit exploration selection
→ ExpansionSeedGenerator
→ recursive Suggest (smoke / balanced / deep)
→ normalization + expansion surface-fit gate
→ human expansion review
```
`demandFamilies` — evidence для фасетов. Их фразы никогда не становятся
Wordstat input напрямую. Current applications и expansion hypotheses остаются
в портфеле и требуют явного выбора; default scope их не активирует.
Каждый topic, probe и candidate несёт `facetId`. Topic decomposition обязан
вернуть для каждого selected facet либо один topic, либо `rejectedFacet` с
причиной и evidence refs. Неудачная попытка выразить фасет рыночным языком не
заменяется общей формулировкой: она фиксируется как quality result.
## Граница ответственности
Перед Query Discovery стоят `Offer Map` и `Search Scope`. Карта возможностей, прикладные модули и гипотезы расширения живут в отдельном Opportunity Portfolio и не становятся search scope автоматически.
Модель не создаёт ключевые запросы и не оценивает спрос. Она создаёт только `seo.topic_decomposition.v1`: для каждого направления, явно разрешённого в Search Scope, возвращает класс оффера, `primaryMarketEntities`, `marketEntityFamily`, категории, сущности, синонимы, действия, процессы, боли, сегменты, интеграции, отдельные интенты и разрешённые группы шаблонов.
`primaryMarketEntities` — короткая рыночная категория, а не описание продукта. Для одного topic разрешена ровно одна такая сущность: она должна сохранить отличительный смысл самого фасета и не уводить в чужой конкурентный класс. Backend отвергает сущности, которые состоят только из общих модификаторов и классов продукта.
`marketEntityFamily` — 36 коротких внешне узнаваемых формулировок того же смысла. Это semantic slots, а не готовые ключи и не перечень фич. Backend оставляет только те элементы семьи, которые несут лексический маркер главной сущности: так «платформа управляемых ИИ-агентов» может дать близкие agent-specific поверхности, но не превратиться в ERP, CRM, BPM, «операционную платформу» или интеграционный шум. Главная сущность и эта контекстно связанная семья становятся входом pattern engine; остальные categories/coreEntities/marketSynonyms остаются provenance и контекстом. Для русскоязычного surface English-only probes не выпускаются. Интеграции и прикладные модули не порождают default core probes: это отдельные явно выбранные Search Scope направления.
Каждый внутренний topic обязан хранить исходные `facetId` и `sourceDirectionId`. Это authority chain: Search Scope vector → semantic slots → probe → observed query → Wordstat evidence. Текстовое fuzzy-сопоставление не может отменять выбранный `topicId`. Topic cards — provenance detail, а не основной пользовательский экран.
Topic decomposition может прийти из `codex_workspace` или из явного `codex_manual` review. В обоих случаях backend проверяет полный набор утверждённых направлений, точное совпадение `topicId/sourceDirectionId`, классы оффера и разрешённые pattern groups. Если remote workspace недоступен, система остаётся blocked; она не подменяет результат старыми model-generated anchors.
## Универсальный слой
`queryDiscovery` не содержит отраслевых словарей и не знает ничего о конкретном сайте. Универсальная библиотека применяет только классы оффера, facet kind, delivery model, sales motion и semantic slots:
- base entity;
- категория или сущность для процесса;
- проблема/автоматизация процесса;
- разработка или внедрение для service-class;
- интеграция с системой;
- информационный и comparison intent.
Шаблон создаёт `probe`, а не ключ. Pattern eligibility приходит из backend для конкретного фасета; модель не может назначить себе integration, service или transactional паттерн вне разрешённой группы. Pattern-only probe не может попасть в Wordstat; пользователь может оставить его только в очереди Suggest/first-party collection.
## Market seed и evidence gate
`MarketSeedGenerator` строит короткие probes из semantic slots и business model
signals. Это не ключи и не спрос. Local, integration, comparison и price
семейства включаются только при соответствующем facet/policy. Suggest seeds
выбираются round-robin между facets, поэтому один lexical family не съедает
весь collector budget.
Raw observation сначала проходит `ObservedQueryNormalizer`, затем
`ObservedRelevanceGate`. Gate разделяет clean commercial, informational,
integration/local/comparison reroute, brand/domain/free/education/job noise и
raw-only evidence.
Canonical cluster становится доступен для Wordstat queue только так:
1. фраза реально наблюдена в suggest, SERP или first-party источнике;
2. observation прошёл normalizer и relevance gate;
3. варианты собраны в canonical cluster внутри одного facet и intent;
4. пользователь явно утверждает cluster либо независимые evidence classes дают
право `auto_wordstat_ready` по policy.
`auto_wordstat_ready` не запускает провайдера. Он только разрешает построить
queue item. Model-only draft и raw observation не могут войти в очередь ни при
каком score.
Наблюдения хранят источник, topic, probe/pattern, язык, географию и ссылку на raw artifact. Wordstat сохраняет отдельное raw evidence и не является генератором языка спроса.
## Core Validation и Market Expansion
`Core Validation Queue` остаётся коротким evidence-backed batch. Его размер не
интерпретируется как полный SEO-охват. `Market Expansion Backlog` — отдельный
контур потенциальных process, role, industry, asset/object, integration,
problem, use-case и buying-stage surfaces.
`ExpansionSurface` не является ключом. Он хранит `relationshipToCore`,
structured slot bundle, applicability/evidence score, expansion risk и human
decision. Direct core не дублируется в expansion. Application, adjacent и
speculative surfaces не активируются автоматически.
`DomainAgnosticityClassifier` использует только абстрактные признаки Offer Map
и portfolio: delivery model, generic processes, buyer-role diversity,
cross-industry objects, integration layer, vertical constraints и current
applications. Названия конкретного проекта и отраслевые словари в production
policy отсутствуют.
Выбранная surface создаёт только `market_seed` (`isFinalKeyword=false`).
`smoke`, `balanced` и `deep` управляют budget, suffix/alphabet expansion и
depth-2 recursion. Даже clean expansion observation получает только
`human_expansion_review`; `wordstatReady` в этом контуре равен нулю до
отдельного решения и следующего bounded batch.
После фактического Wordstat запускается `PostWordstatExpansionPlanner`. Он
маршрутизирует top/related результаты в существующие surfaces или предлагает
новые observed proposals. Эти объекты помечены `sourcePhase=post_wordstat` и не
смешиваются с speculative pre-Wordstat backlog.
`PostWordstatProductFitGate` является обязательным следующим слоем. Он не
использует frequency как product-fit evidence и для каждой уникальной строки
определяет intent, page type, relationship to core, semantic/source affinity,
product-fit score, competitor/category warnings и рекомендуемый маршрут.
Результаты делятся на validated seeds, commercial batch review, content,
adjacent research и reject; дополнительно строятся canonical product-fit
clusters. Широкая related-фраза не становится коммерческим ключом из-за одной
частотности.
`PostWordstatBatch2Planner` принимает только human decisions. В Wordstat queue
попадают исключительно `approved_for_wordstat` candidates, queue ограничена 12
фразами и хранит provenance `wordstat_related_product_fit_approved`. Повторно
собранная exact-фраза становится `validated_seed` и автоматически исчезает из
очереди, но её decision сохраняется для SERP trace. SERP-проверка получает
только human-approved batch, а не весь related result set.
До observed language пользователь работает с экранами «Поисковые направления»
и «Черновики поисковых формулировок»: он может оставить или исключить pattern
candidate. После collector он работает в отдельном `Observed language review`,
а approved clusters отображаются в `Bounded Wordstat queue`. Ни одно из этих
действий не запускает Wordstat.
В шапке этого экрана и в пяти фильтрах всегда видны числа: всего, на разборе, оставлены, очередь Wordstat и скрытые. Пять правых действий карточки имеют постоянный порядок: оставить для сбора → вернуть на разбор → скрыть → очередь Wordstat → удалить. Решения сначала остаются локальным черновиком и пишутся в backend только отдельной кнопкой сохранения.
## API
- `GET /projects/:projectId/query-discovery/latest`
- `POST /projects/:projectId/query-discovery/topic-decomposition/manual`
- `POST /projects/:projectId/query-discovery/observations`
- `POST /projects/:projectId/query-discovery/observed-language/collect`
- `PUT /projects/:projectId/query-discovery/probes/:probeId/decision`
- `PUT /projects/:projectId/query-discovery/clusters/:clusterId/decision`
- `PUT /projects/:projectId/query-discovery/expansion-surfaces/:surfaceId/decision`
- `POST /projects/:projectId/query-discovery/market-expansion/collect`
- `PUT /projects/:projectId/post-wordstat/candidates/:candidateId/decision`
- `POST /projects/:projectId/post-wordstat/decisions/bulk`
- `POST /projects/:projectId/post-wordstat/batch2/collect`
- `GET /projects/:projectId/market-enrichment/probe-preview`
- `POST /projects/:projectId/market-enrichment`
Модельный task: `seo.topic_decomposition`. До его выполнения market enrichment и Wordstat preview остаются заблокированы; старый путь model-generated anchors не используется как fallback.