diff --git a/_process/03. RAG.md b/_process/03. RAG.md
index be00cc4..6fb5b1e 100644
--- a/_process/03. RAG.md
+++ b/_process/03. RAG.md
@@ -89,28 +89,17 @@ RAG сейчас используется как общее ядро индек
Хранит карточку документа как точку входа в документ и его краткое описание.
Формирование:
-Источник данных - frontmatter, fallback title, summary и doc kind, вычисленный классификатором документации.
-Данные извлекаются структурированно по атрибутам.
+Источник данных - frontmatter `as is`, summary и doc kind, вычисленный классификатором документации.
+В `metadata_json` копируются все `key-value` из frontmatter без нормализации и без fallback для frontmatter-атрибутов.
+Дополнительно в `metadata_json` добавляются служебные поля `source_path`, `summary_text`, `doc_kind`.
+Атрибут `document_id` добавляется только при наличии `frontmatter.id` (fallback до пути файла не применяется).
В `content` попадает summary документа, а не склейка всех частей документа в сплошной текст.
Фиксация в БД:
| Атрибут в `metadata_json` | Описание | Источник |
|---|---|---|
-| `document_id` | идентификатор документа | `frontmatter.id`, иначе путь файла |
-| `type` | тип документа из frontmatter | `frontmatter.type` |
-| `name` | системное имя документа | `frontmatter.name` |
-| `title` | человекочитаемый заголовок документа | `frontmatter.title`, иначе fallback title |
-| `module` | модуль документа | `frontmatter.module` |
-| `domain` | домен документа | `frontmatter.domain` |
-| `subdomain` | поддомен документа | `frontmatter.subdomain` |
-| `layer` | логический слой, указанный в frontmatter документа | `frontmatter.layer` |
-| `status` | статус документа | `frontmatter.status` |
-| `updated_at` | дата или отметка последнего обновления | `frontmatter.updated_at` |
-| `tags` | теги документа | `frontmatter.tags` |
-| `entities` | сущности, связанные с документом | `frontmatter.entities` |
-| `parent` | родительский документ | `frontmatter.parent` |
-| `children` | дочерние документы | `frontmatter.children` |
-| `links` | ссылки на связанные материалы | `frontmatter.links` |
+| `*` frontmatter fields | все поля frontmatter в исходном виде | frontmatter документа |
+| `document_id` | идентификатор документа, добавляется только если в frontmatter есть `id` | `frontmatter.id` |
| `source_path` | исходный путь документа | путь файла |
| `summary_text` | краткое содержание документа | секция `# Summary` |
| `doc_kind` | классификация документа, например `readme`, `spec`, `runbook` | `DocsClassifier.classify(path)` |
diff --git a/docs/inp.md b/docs/inp.md
new file mode 100644
index 0000000..e69de29
diff --git a/runtime_traces/agent_requests/20260409-143441-a16face9a0ab.md b/runtime_traces/agent_requests/20260409-143441-a16face9a0ab.md
new file mode 100644
index 0000000..4577af2
--- /dev/null
+++ b/runtime_traces/agent_requests/20260409-143441-a16face9a0ab.md
@@ -0,0 +1,347 @@
+# Runtime Trace: 20260409-143441-a16face9a0ab
+
+- active_rag_session_id: 3d1215ce-79fc-4c87-bf29-a16face9a0ab
+
+## request
+```json
+{
+ "request_id": "req_11c7ba17c1fa47faa497f324f165c1ee",
+ "session_id": "as_7827e863066042b2a6b4be9e8153acdf",
+ "active_rag_session_id": "3d1215ce-79fc-4c87-bf29-a16face9a0ab",
+ "process_version": "v2",
+ "created_at": "2026-04-09T14:34:41.894633+00:00",
+ "message": "Какие методы апи есть в проекте?"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "normalized_query": "Какие методы апи есть в проекте?",
+ "target_terms": [
+ "методы",
+ "апи",
+ "проекте"
+ ],
+ "anchors": {
+ "entity_names": [],
+ "file_names": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "unknown",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": []
+ },
+ "confidence": 0.9500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно касается перечня доступных API-методов.",
+ "rag_session_id": "3d1215ce-79fc-4c87-bf29-a16face9a0ab"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "confidence": 0.9500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "target_terms": [
+ "методы",
+ "апи",
+ "проекте"
+ ]
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": []
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "require_rag_session",
+ "title": "Проверка RAG-сессии"
+ },
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+}
+```
+
+## process.v2.retrieval_policy
+```json
+{
+ "event": "retrieval_plan_resolved",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "limit": 400,
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%",
+ "%методы%",
+ "%апи%",
+ "%проекте%"
+ ],
+ "query_signals": [
+ "методы",
+ "апи",
+ "проекте"
+ ]
+ }
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "retrieval_profile_selected",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%",
+ "%методы%",
+ "%апи%",
+ "%проекте%"
+ ],
+ "query_signals": [
+ "методы",
+ "апи",
+ "проекте"
+ ]
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана"
+ },
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "fetch_rag_rows",
+ "title": "Получение строк из RAG"
+ },
+ "input": {},
+ "output": {
+ "retrieved_row_count": 0
+ }
+}
+```
+
+## process.v2.evidence
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 0,
+ "endpoints": []
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 0
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "build_api_exposed_evidence",
+ "title": "Сборка списка API"
+ },
+ "input": {},
+ "output": {
+ "endpoint_count": 0
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API"
+ },
+ "input": {},
+ "output": {
+ "answer_length": 62
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "steps": [
+ {
+ "step_id": "require_rag_session",
+ "title": "Проверка RAG-сессии",
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+ },
+ {
+ "step_id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана",
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+ },
+ {
+ "step_id": "fetch_rag_rows",
+ "title": "Получение строк из RAG",
+ "input": {},
+ "output": {
+ "retrieved_row_count": 0
+ }
+ },
+ {
+ "step_id": "build_api_exposed_evidence",
+ "title": "Сборка списка API",
+ "input": {},
+ "output": {
+ "endpoint_count": 0
+ }
+ },
+ {
+ "step_id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API",
+ "input": {},
+ "output": {
+ "answer_length": 62
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "insufficient_evidence",
+ "answer_length": 62
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "Не нашёл задокументированных API-эндпоинтов в выбранном scope.",
+ "completed_at": "2026-04-09T14:34:43.947325+00:00"
+}
+```
diff --git a/runtime_traces/agent_requests/20260409-143722-a9b20eb67e95.md b/runtime_traces/agent_requests/20260409-143722-a9b20eb67e95.md
new file mode 100644
index 0000000..058c508
--- /dev/null
+++ b/runtime_traces/agent_requests/20260409-143722-a9b20eb67e95.md
@@ -0,0 +1,323 @@
+# Runtime Trace: 20260409-143722-a9b20eb67e95
+
+- active_rag_session_id: 35471db5-4c18-415d-b48e-a9b20eb67e95
+
+## request
+```json
+{
+ "request_id": "req_2980c9e2eb324182a000e72b8307a56d",
+ "session_id": "as_20c1a7f7aaec4885bc268beff2cae6a0",
+ "active_rag_session_id": "35471db5-4c18-415d-b48e-a9b20eb67e95",
+ "process_version": "v2",
+ "created_at": "2026-04-09T14:37:22.885815+00:00",
+ "message": "Какие методы апи есть в проекте?"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "normalized_query": "Какие методы апи есть в проекте?",
+ "target_terms": [],
+ "anchors": {
+ "entity_names": [],
+ "file_names": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "global",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": []
+ },
+ "confidence": 0.8500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно касается списка доступных API-методов проекта.",
+ "rag_session_id": "35471db5-4c18-415d-b48e-a9b20eb67e95"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "confidence": 0.8500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "target_terms": []
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": []
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "require_rag_session",
+ "title": "Проверка RAG-сессии"
+ },
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+}
+```
+
+## process.v2.retrieval_policy
+```json
+{
+ "event": "retrieval_plan_resolved",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "limit": 400,
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%"
+ ]
+ }
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "retrieval_profile_selected",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%"
+ ]
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана"
+ },
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "fetch_rag_rows",
+ "title": "Получение строк из RAG"
+ },
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+}
+```
+
+## process.v2.evidence
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 0,
+ "endpoints": []
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 0
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "build_api_exposed_evidence",
+ "title": "Сборка списка API"
+ },
+ "input": {},
+ "output": {
+ "endpoint_count": 0
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API"
+ },
+ "input": {},
+ "output": {
+ "answer_length": 62
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "steps": [
+ {
+ "step_id": "require_rag_session",
+ "title": "Проверка RAG-сессии",
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+ },
+ {
+ "step_id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана",
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+ },
+ {
+ "step_id": "fetch_rag_rows",
+ "title": "Получение строк из RAG",
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+ },
+ {
+ "step_id": "build_api_exposed_evidence",
+ "title": "Сборка списка API",
+ "input": {},
+ "output": {
+ "endpoint_count": 0
+ }
+ },
+ {
+ "step_id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API",
+ "input": {},
+ "output": {
+ "answer_length": 62
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "insufficient_evidence",
+ "answer_length": 62
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "Не нашёл задокументированных API-эндпоинтов в выбранном scope.",
+ "completed_at": "2026-04-09T14:37:24.566326+00:00"
+}
+```
diff --git a/runtime_traces/agent_requests/20260409-145546-36056dd8dcfe.md b/runtime_traces/agent_requests/20260409-145546-36056dd8dcfe.md
new file mode 100644
index 0000000..35f3f5d
--- /dev/null
+++ b/runtime_traces/agent_requests/20260409-145546-36056dd8dcfe.md
@@ -0,0 +1,323 @@
+# Runtime Trace: 20260409-145546-36056dd8dcfe
+
+- active_rag_session_id: 2d21c11a-66a3-464f-9e0f-36056dd8dcfe
+
+## request
+```json
+{
+ "request_id": "req_ada6c4f21ef84484ae228a784f854fd8",
+ "session_id": "as_0190277b106e4573875b6923235196f7",
+ "active_rag_session_id": "2d21c11a-66a3-464f-9e0f-36056dd8dcfe",
+ "process_version": "v2",
+ "created_at": "2026-04-09T14:55:46.412183+00:00",
+ "message": "Какие методы апи есть в проекте?"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "normalized_query": "Какие методы апи есть в проекте?",
+ "target_terms": [],
+ "anchors": {
+ "entity_names": [],
+ "file_names": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "global",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": []
+ },
+ "confidence": 0.8500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно касается списка доступных API-методов проекта.",
+ "rag_session_id": "2d21c11a-66a3-464f-9e0f-36056dd8dcfe"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "confidence": 0.8500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "target_terms": []
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": []
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "require_rag_session",
+ "title": "Проверка RAG-сессии"
+ },
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+}
+```
+
+## process.v2.retrieval_policy
+```json
+{
+ "event": "retrieval_plan_resolved",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "limit": 400,
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%"
+ ]
+ }
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "retrieval_profile_selected",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%"
+ ]
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана"
+ },
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "fetch_rag_rows",
+ "title": "Получение строк из RAG"
+ },
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+}
+```
+
+## process.v2.evidence
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 0,
+ "endpoints": []
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 0
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "build_api_exposed_evidence",
+ "title": "Сборка списка API"
+ },
+ "input": {},
+ "output": {
+ "endpoint_count": 0
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API"
+ },
+ "input": {},
+ "output": {
+ "answer_length": 62
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "steps": [
+ {
+ "step_id": "require_rag_session",
+ "title": "Проверка RAG-сессии",
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+ },
+ {
+ "step_id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана",
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+ },
+ {
+ "step_id": "fetch_rag_rows",
+ "title": "Получение строк из RAG",
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+ },
+ {
+ "step_id": "build_api_exposed_evidence",
+ "title": "Сборка списка API",
+ "input": {},
+ "output": {
+ "endpoint_count": 0
+ }
+ },
+ {
+ "step_id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API",
+ "input": {},
+ "output": {
+ "answer_length": 62
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "insufficient_evidence",
+ "answer_length": 62
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "Не нашёл задокументированных API-эндпоинтов в выбранном scope.",
+ "completed_at": "2026-04-09T14:55:48.141440+00:00"
+}
+```
diff --git a/runtime_traces/agent_requests/20260409-151154-b91584f20703.md b/runtime_traces/agent_requests/20260409-151154-b91584f20703.md
new file mode 100644
index 0000000..d0bb3e3
--- /dev/null
+++ b/runtime_traces/agent_requests/20260409-151154-b91584f20703.md
@@ -0,0 +1,323 @@
+# Runtime Trace: 20260409-151154-b91584f20703
+
+- active_rag_session_id: 43fa52d5-9de5-42df-a893-b91584f20703
+
+## request
+```json
+{
+ "request_id": "req_934d42145442462a933fdc2c947d40f1",
+ "session_id": "as_00827751b492436dad07247663772b07",
+ "active_rag_session_id": "43fa52d5-9de5-42df-a893-b91584f20703",
+ "process_version": "v2",
+ "created_at": "2026-04-09T15:11:54.906256+00:00",
+ "message": "Какие методы апи есть в проекте?"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "normalized_query": "Какие методы апи есть в проекте?",
+ "target_terms": [],
+ "anchors": {
+ "entity_names": [],
+ "file_names": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "global",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": []
+ },
+ "confidence": 0.8500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно касается перечисления методов API.",
+ "rag_session_id": "43fa52d5-9de5-42df-a893-b91584f20703"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "confidence": 0.8500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "target_terms": []
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": []
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "require_rag_session",
+ "title": "Проверка RAG-сессии"
+ },
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+}
+```
+
+## process.v2.retrieval_policy
+```json
+{
+ "event": "retrieval_plan_resolved",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "limit": 400,
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%"
+ ]
+ }
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "retrieval_profile_selected",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%"
+ ]
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана"
+ },
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "fetch_rag_rows",
+ "title": "Получение строк из RAG"
+ },
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+}
+```
+
+## process.v2.evidence
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 0,
+ "endpoints": []
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 0
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "build_api_exposed_evidence",
+ "title": "Сборка списка API"
+ },
+ "input": {},
+ "output": {
+ "endpoint_count": 0
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API"
+ },
+ "input": {},
+ "output": {
+ "answer_length": 62
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "steps": [
+ {
+ "step_id": "require_rag_session",
+ "title": "Проверка RAG-сессии",
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+ },
+ {
+ "step_id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана",
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+ },
+ {
+ "step_id": "fetch_rag_rows",
+ "title": "Получение строк из RAG",
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+ },
+ {
+ "step_id": "build_api_exposed_evidence",
+ "title": "Сборка списка API",
+ "input": {},
+ "output": {
+ "endpoint_count": 0
+ }
+ },
+ {
+ "step_id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API",
+ "input": {},
+ "output": {
+ "answer_length": 62
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "insufficient_evidence",
+ "answer_length": 62
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "Не нашёл задокументированных API-эндпоинтов в выбранном scope.",
+ "completed_at": "2026-04-09T15:11:56.675323+00:00"
+}
+```
diff --git a/runtime_traces/agent_requests/20260409-151329-2d1087092e43.md b/runtime_traces/agent_requests/20260409-151329-2d1087092e43.md
new file mode 100644
index 0000000..30cdb99
--- /dev/null
+++ b/runtime_traces/agent_requests/20260409-151329-2d1087092e43.md
@@ -0,0 +1,323 @@
+# Runtime Trace: 20260409-151329-2d1087092e43
+
+- active_rag_session_id: 8be14345-e958-4753-9057-2d1087092e43
+
+## request
+```json
+{
+ "request_id": "req_05929401b62a4c85974ffb7eb543a682",
+ "session_id": "as_a9ce0b45b3ba46aa89c0454462cabb54",
+ "active_rag_session_id": "8be14345-e958-4753-9057-2d1087092e43",
+ "process_version": "v2",
+ "created_at": "2026-04-09T15:13:29.796982+00:00",
+ "message": "Какие методы апи есть в проекте?"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "normalized_query": "Какие методы апи есть в проекте?",
+ "target_terms": [],
+ "anchors": {
+ "entity_names": [],
+ "file_names": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "global",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": []
+ },
+ "confidence": 0.8500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно касается перечисления методов API.",
+ "rag_session_id": "8be14345-e958-4753-9057-2d1087092e43"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "confidence": 0.8500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "target_terms": []
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": []
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "require_rag_session",
+ "title": "Проверка RAG-сессии"
+ },
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+}
+```
+
+## process.v2.retrieval_policy
+```json
+{
+ "event": "retrieval_plan_resolved",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "limit": 400,
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%"
+ ]
+ }
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "retrieval_profile_selected",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%"
+ ]
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана"
+ },
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "fetch_rag_rows",
+ "title": "Получение строк из RAG"
+ },
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+}
+```
+
+## process.v2.evidence
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 0,
+ "endpoints": []
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 0
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "build_api_exposed_evidence",
+ "title": "Сборка списка API"
+ },
+ "input": {},
+ "output": {
+ "endpoint_count": 0
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API"
+ },
+ "input": {},
+ "output": {
+ "answer_length": 62
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "steps": [
+ {
+ "step_id": "require_rag_session",
+ "title": "Проверка RAG-сессии",
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+ },
+ {
+ "step_id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана",
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+ },
+ {
+ "step_id": "fetch_rag_rows",
+ "title": "Получение строк из RAG",
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+ },
+ {
+ "step_id": "build_api_exposed_evidence",
+ "title": "Сборка списка API",
+ "input": {},
+ "output": {
+ "endpoint_count": 0
+ }
+ },
+ {
+ "step_id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API",
+ "input": {},
+ "output": {
+ "answer_length": 62
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "insufficient_evidence",
+ "answer_length": 62
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "Не нашёл задокументированных API-эндпоинтов в выбранном scope.",
+ "completed_at": "2026-04-09T15:13:31.532828+00:00"
+}
+```
diff --git a/runtime_traces/agent_requests/20260409-151338-51ca80f9145e.md b/runtime_traces/agent_requests/20260409-151338-51ca80f9145e.md
new file mode 100644
index 0000000..fbba414
--- /dev/null
+++ b/runtime_traces/agent_requests/20260409-151338-51ca80f9145e.md
@@ -0,0 +1,323 @@
+# Runtime Trace: 20260409-151338-51ca80f9145e
+
+- active_rag_session_id: eb664e6b-655a-46ca-b7e9-51ca80f9145e
+
+## request
+```json
+{
+ "request_id": "req_4031d419064f454f97e0872671bbd00a",
+ "session_id": "as_20977051bd8c4e6fa68cb489934fb998",
+ "active_rag_session_id": "eb664e6b-655a-46ca-b7e9-51ca80f9145e",
+ "process_version": "v2",
+ "created_at": "2026-04-09T15:13:38.600938+00:00",
+ "message": "Какие методы апи есть в проекте?"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "normalized_query": "Какие методы апи есть в проекте?",
+ "target_terms": [],
+ "anchors": {
+ "entity_names": [],
+ "file_names": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "global",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": []
+ },
+ "confidence": 0.8500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно касается списка доступных API-методов.",
+ "rag_session_id": "eb664e6b-655a-46ca-b7e9-51ca80f9145e"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "confidence": 0.8500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "target_terms": []
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": []
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "require_rag_session",
+ "title": "Проверка RAG-сессии"
+ },
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+}
+```
+
+## process.v2.retrieval_policy
+```json
+{
+ "event": "retrieval_plan_resolved",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "limit": 400,
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%"
+ ]
+ }
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "retrieval_profile_selected",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%"
+ ]
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана"
+ },
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "fetch_rag_rows",
+ "title": "Получение строк из RAG"
+ },
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+}
+```
+
+## process.v2.evidence
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 0,
+ "endpoints": []
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 0
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "build_api_exposed_evidence",
+ "title": "Сборка списка API"
+ },
+ "input": {},
+ "output": {
+ "endpoint_count": 0
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API"
+ },
+ "input": {},
+ "output": {
+ "answer_length": 62
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "steps": [
+ {
+ "step_id": "require_rag_session",
+ "title": "Проверка RAG-сессии",
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+ },
+ {
+ "step_id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана",
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+ },
+ {
+ "step_id": "fetch_rag_rows",
+ "title": "Получение строк из RAG",
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+ },
+ {
+ "step_id": "build_api_exposed_evidence",
+ "title": "Сборка списка API",
+ "input": {},
+ "output": {
+ "endpoint_count": 0
+ }
+ },
+ {
+ "step_id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API",
+ "input": {},
+ "output": {
+ "answer_length": 62
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "insufficient_evidence",
+ "answer_length": 62
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "Не нашёл задокументированных API-эндпоинтов в выбранном scope.",
+ "completed_at": "2026-04-09T15:13:41.304004+00:00"
+}
+```
diff --git a/runtime_traces/agent_requests/20260409-151841-faa90484f29c.md b/runtime_traces/agent_requests/20260409-151841-faa90484f29c.md
new file mode 100644
index 0000000..277f525
--- /dev/null
+++ b/runtime_traces/agent_requests/20260409-151841-faa90484f29c.md
@@ -0,0 +1,1705 @@
+# Runtime Trace: 20260409-151841-faa90484f29c
+
+- active_rag_session_id: 1319a27b-7c22-497b-a6b9-faa90484f29c
+
+## request
+```json
+{
+ "request_id": "req_2c526e5b5d914b7b980206a5683d22f3",
+ "session_id": "as_43b29112fac3422d92150291a4237eab",
+ "active_rag_session_id": "1319a27b-7c22-497b-a6b9-faa90484f29c",
+ "process_version": "v2",
+ "created_at": "2026-04-09T15:18:41.036396+00:00",
+ "message": "Какие методы апи есть в проекте?"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "normalized_query": "Какие методы апи есть в проекте?",
+ "target_terms": [],
+ "anchors": {
+ "entity_names": [],
+ "file_names": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "global",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": []
+ },
+ "confidence": 0.8500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно касается перечисления методов API.",
+ "rag_session_id": "1319a27b-7c22-497b-a6b9-faa90484f29c"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "confidence": 0.8500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "target_terms": []
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": []
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "require_rag_session",
+ "title": "Проверка RAG-сессии"
+ },
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+}
+```
+
+## process.v2.retrieval_policy
+```json
+{
+ "event": "retrieval_plan_resolved",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "limit": 400,
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%"
+ ]
+ }
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "retrieval_profile_selected",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%"
+ ]
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана"
+ },
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "fetch_rag_rows",
+ "title": "Получение строк из RAG"
+ },
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+}
+```
+
+## process.v2.evidence
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 2,
+ "endpoints": [
+ "GET /api/v1/clients/contacts-dgr",
+ "GET /api/v1/clients/contacts-dgr/{contactid}"
+ ]
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 2
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "build_api_exposed_evidence",
+ "title": "Сборка списка API"
+ },
+ "input": {},
+ "output": {
+ "endpoint_count": 2
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API"
+ },
+ "input": {},
+ "output": {
+ "answer_length": 77
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "steps": [
+ {
+ "step_id": "require_rag_session",
+ "title": "Проверка RAG-сессии",
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+ },
+ {
+ "step_id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана",
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+ },
+ {
+ "step_id": "fetch_rag_rows",
+ "title": "Получение строк из RAG",
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+ },
+ {
+ "step_id": "build_api_exposed_evidence",
+ "title": "Сборка списка API",
+ "input": {},
+ "output": {
+ "endpoint_count": 2
+ }
+ },
+ {
+ "step_id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API",
+ "input": {},
+ "output": {
+ "answer_length": 77
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "deterministic",
+ "answer_length": 77
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "GET /api/v1/clients/contacts-dgr\nGET /api/v1/clients/contacts-dgr/{contactid}",
+ "completed_at": "2026-04-09T15:18:42.787138+00:00"
+}
+```
+
+## request
+```json
+{
+ "request_id": "req_cdece7e20b064fd58e052326a067925e",
+ "session_id": "as_43b29112fac3422d92150291a4237eab",
+ "active_rag_session_id": "1319a27b-7c22-497b-a6b9-faa90484f29c",
+ "process_version": "v2",
+ "created_at": "2026-04-09T15:19:38.089590+00:00",
+ "message": "Сформируй документацию по системной аналитике\n/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_UPDATE",
+ "subintent": "FROM_FEATURE",
+ "normalized_query": "Сформируй документацию по системной аналитике /Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "target_terms": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "anchors": {
+ "entity_names": [
+ "Users",
+ "Dev_projects_v2"
+ ],
+ "file_names": [
+ "process/v2/test_doc/features/create_contact.md"
+ ],
+ "endpoint_paths": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "entity",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": [
+ "API_ENDPOINT",
+ "DOMAIN_ENTITY",
+ "LOGIC_FLOW"
+ ]
+ },
+ "confidence": 0.9,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос содержит указание сформировать документацию по системной аналитике из конкретного файла create_contact.md.",
+ "rag_session_id": "1319a27b-7c22-497b-a6b9-faa90484f29c"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_UPDATE",
+ "subintent": "FROM_FEATURE",
+ "confidence": 0.9
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [
+ "API_ENDPOINT",
+ "DOMAIN_ENTITY",
+ "LOGIC_FLOW"
+ ],
+ "endpoint_paths": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ],
+ "matched_aliases": [],
+ "target_terms": [
+ "/users/alex/dev_projects_v2/ai"
+ ]
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ]
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_update.from_feature"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "resolve_source",
+ "title": "Определение источника аналитики"
+ },
+ "input": {
+ "source_kind": "",
+ "source_ref": "",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "load_source",
+ "title": "Загрузка системной аналитики"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "content_loaded": true,
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "parse_feature",
+ "title": "Парсинг функциональных требований"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units": 2,
+ "issues": 3,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "load_doc_rules",
+ "title": "Загрузка doc_rules"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "enabled": true,
+ "loaded": true,
+ "supported_doc_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "issues": 3,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.plan_change_units",
+ "system_prompt": "Ты классифицируешь units системной аналитики для построения плана изменений документации.\n\nВерни только JSON:\n{\n \"items\": [\n {\"index\": 0, \"doc_type\": \"api_method\", \"reason\": \"...\"}\n ]\n}\n\nПравила:\n- Используй только doc_type из allowed_doc_types.\n- Не пропускай item, даже если не уверен: выбери наиболее близкий тип.\n- Ориентируйся на heading и snippet.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"system_rules\": \"Системные правила документации:\\n1. Один устойчивый объект — один документ.\\n2. Документы не должны дублировать друг друга по смыслу.\\n3. Связи между документами должны быть явными (related_docs/links).\\n4. Документация организована иерархически по папкам docs/*.\\n5. Markdown-документ состоит из YAML frontmatter и body.\\n6. Обязательные поля frontmatter: id, title, doc_type, related_docs, status, domain, sub_domain.\",\n \"allowed_doc_types\": [\n \"ui_page\",\n \"api_method\",\n \"logic_block\",\n \"architecture_overview\",\n \"integration_doc\",\n \"domain_entity\",\n \"glossary_item\",\n \"index_page\"\n ],\n \"items\": [\n {\n \"index\": 0,\n \"heading\": \"FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\",\n \"snippet\": \"- `type`: `ui.page`\\n- `id`: `ui.contacts_dgr.create`\\n\\nОсновной сценарий:\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- `ui.contacts_dgr` вызывает endpoint `POST /api/v1/clients/contacts-dgr` для создания карточки контакта ДГР.\\n- `ufs.contacts_dgr` обрабатывает запрос и возвращает ответ.\\n- `ui.contacts_dgr` отображает результат создания контакта ДГР в виде push-уведомле\"\n },\n {\n \"index\": 1,\n \"heading\": \"FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`\",\n \"snippet\": \"- `type`: `api_method`\\n- `id`: `ufs.contacts_dgr.api.create`\\n- `endpoint`: `POST /api/v1/clients/contacts-dgr`\\n\\nТребования для основного сценария:\\n- Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом `BAD_REQUEST`.\\n- Авторизовать запрос по наличию периметра `CI02792632.ContactsDGR.Create`. При отсутствии периметра завершить основной сценарий с кодом `UNAU\"\n }\n ]\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.plan"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"items\": [\n {\"index\": 0, \"doc_type\": \"ui_page\"},\n {\"index\": 1, \"doc_type\": \"api_method\"}\n ]\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "build_change_plan",
+ "title": "Построение плана изменений"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "docs_rows": 7,
+ "planned_changes": 2,
+ "issues": 3,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "changeset_prompt_built",
+ "doc_type": "api_method",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "prompt_chars": 15694,
+ "rules_chars": 11520
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.build_doc_changeset",
+ "system_prompt": "Ты формируешь один item changeset для документации на основе системной аналитики и правил doc_rules.\n\nВерни только JSON-объект формата:\n{\n \"op\": \"create|update|delete\",\n \"path\": \"docs/...\",\n \"reason\": \"краткая причина\",\n \"proposed_content\": \"полный markdown документа для create/update\"\n}\n\nПравила:\n- Строго соблюдай структуру и ограничения из doc_rules_context.\n- Для create/update верни полный итоговый markdown (frontmatter + body).\n- Для update не используй placeholder-тексты; возвращай пригодный к сохранению документ.\n- reason обязателен, короткий, по сути изменения.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"change_request\": {\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md\",\n \"doc_type\": \"api_method\",\n \"doc_id\": \"api_method.fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr\",\n \"title\": \"FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`\",\n \"domain\": \"unknown\",\n \"sub_domain\": \"unknown\",\n \"reason\": \"Из unit 'FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`' системной аналитики (analysis).\",\n \"source_refs\": [\n \"section: 5. Функциональные требования\"\n ],\n \"related_docs\": [],\n \"requirement_body\": \"- `type`: `api_method`\\n- `id`: `ufs.contacts_dgr.api.create`\\n- `endpoint`: `POST /api/v1/clients/contacts-dgr`\\n\\nТребования для основного сценария:\\n- Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом `BAD_REQUEST`.\\n- Авторизовать запрос по наличию периметра `CI02792632.ContactsDGR.Create`. При отсутствии периметра завершить основной сценарий с кодом `UNAUTHORIZED`.\\n- Для исполнения запроса на создание контакта вызвать endpoint `POST /contacts` в `prpb.contacts_dgr`.\\n- Вернуть ответ `ui.contacts_dgr` в формате `UfsBaseResponseContactDGRCreateRsDto`.\\n\\nКонтракт `POST /contacts`\\n\\nЗапрос\\n\\n**headers**\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|---|---|---|---|---|\\n| `X-Request-Id` | 1 | `uuid` | `header` | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | `header` | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | `header` | Табельный номер пользователя, вызвавшего сервис |\\n\\n**body**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contact` | 1 | `object` | Данные контакта ДГР |\\n| `contact.lastName` | 0..1 | `string(100)` | Фамилия контакта |\\n| `contact.firstName` | 0..1 | `string(100)` | Имя контакта |\\n| `contact.middleName` | 0..1 | `string(100)` | Отчество контакта |\\n| `contact.name` | 0..1 | `string(100)` | Название группового контакта |\\n| `contact.description` | 0..1 | `string(1000)` | Описание группового контакта |\\n| `contact.position` | 0..1 | `string(100)` | Должность контакта у клиента |\\n| `contact.comment` | 0..1 | `string(1000)` | Комментарий к контакту |\\n| `contact.contactType` | 1 | `enum(string)` | `Individual`, `Group` |\\n| `contact.crossboarding` | 1 | `boolean` | Признак принадлежности контакта к процессу онбординга |\\n| `contact.createdBy` | 1 | `string(8)` | Табельный номер пользователя, создавшего контакт |\\n| `contact.emails` | 0..1 | `array(object)` | Массив электронных адресов контакта |\\n| `contact.emails.value` | 1 | `string(100)` | Электронный адрес |\\n| `contact.emails.main` | 1 | `boolean` | Признак основной почты |\\n| `contact.phones` | 0..1 | `array(object)` | Массив телефонных номеров контакта |\\n| `contact.phones.value` | 1 | `string(20)` | Телефонный номер контакта |\\n| `contact.phones.extValue` | 0..1 | `string(10)` | Добавочный номер |\\n| `contact.phones.main` | 1 | `boolean` | Признак основного телефона |\\n| `contact.phones.mobile` | 1 | `boolean` | Признак мобильного телефона |\\n| `client` | 1 | `object` | Данные клиента |\\n| `client.ucpId` | 0..1 | `string(36)` | Идентификатор клиента ПАО |\\n| `client.sbpId` | 0..1 | `string(36)` | Идентификатор клиента АО |\\n| `client.inn` | 0..1 | `string(12)` | ИНН клиента |\\n| `client.kpp` | 0..1 | `string(9)` | КПП клиента |\\n\\nОтвет\\n\\n**ContactDGRCreateRsDto**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contactId` | 1 | `string(36)` | Идентификатор контакта |\"\n },\n \"doc_rules_context\": \"## Global rules\\n\\n### documentation-rules.md\\n\\n# Documentation Rules\\n\\nЭтот каталог оформляет MVP документации проекта в атомарном формате.\\n\\n## Базовая структура\\n\\n- Каждый документ содержит YAML frontmatter.\\n- В документе должен быть один `H1`, совпадающий с `title`.\\n- Основные разделы оформляются как `## Summary` и `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Связи, сущности и навигация описываются во frontmatter через `related_docs`, `links`, `entities`, `parent`, `children`.\\n\\n## Summary\\n\\n- Краткий explain-слой быстрого контекста.\\n- Должен позволять быстро понять назначение документа без чтения `Details`.\\n- Предпочтительный формат: компактный список ключевых фактов без длинных абзацев.\\n\\n## Details\\n\\n- Раскрывает полное описание объекта.\\n- Структура `Details` зависит от типа документа.\\n- Сценарии, ограничения, интеграции, ошибки и кодовые привязки должны быть разнесены по отдельным подразделам.\\n\\n## API documents\\n\\nДля `api_method` внутри `## Details` обязательны разделы:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\nЕсли у метода есть интеграции и ошибки, также обязательны:\\n- `### Интеграции`\\n- `### Ошибки`\\n- `### Связанный код`\\n- `### История изменений`\\n\\n### Сценарий\\n\\nСценарий оформляется как технический use case и содержит:\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработку ошибок\\n- постусловие\\n\\n### Требования\\n\\n- Функциональные требования маркируются как `FR-1`, `FR-2`, ...\\n- Нефункциональные требования маркируются как `NFR-1`, `NFR-2`, ...\\n- Идентификаторы требований локальны в рамках одного документа.\\n\\n### Контракт\\n\\nКонтракт должен быть пригоден для последующей сборки OpenAPI-спецификации и включать:\\n- входные параметры\\n- выходные параметры\\n- структуру JSON-сообщений\\n- обязательность полей\\n- типы и ограничения\\n- описание полей\\n- правила заполнения\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n### global/documentation-system.md\\n\\n# Documentation System\\n\\n## Назначение\\n\\nЭтот файл задает общую модель документации проекта.\\n\\n## Базовая модель\\n\\nКаждый документ должен состоять из двух слоев:\\n- YAML frontmatter\\n- контент\\n\\nКонтент всегда состоит из двух обязательных разделов:\\n- `## Summary`\\n- `## Details`\\n\\nНад ними должен быть один заголовок `#
`, совпадающий со значением `title` во frontmatter.\\n\\n## Принципы\\n\\n- Документы должны быть атомарными.\\n- Один документ описывает одну тему.\\n- Вместо дублирования между документами используются явные ссылки.\\n- Связи и навигация должны быть формализованы.\\n- Документы должны быть пригодны для чтения человеком и для RAG.\\n- Документы должны быть пригодны для частичного обновления без деградации структуры.\\n\\n## Типы документов\\n\\nНа уровне проекта поддерживаются типы:\\n- `api_method`\\n- `logic_block`\\n- `architecture_overview`\\n- `domain_entity`\\n- `ui_page`\\n- `integration_doc`\\n- `index_page`\\n- `glossary_item`\\n\\n### global/frontmatter.md\\n\\n# Frontmatter Rules\\n\\n## Назначение\\n\\nЭтот файл описывает единый контракт YAML frontmatter для всех документов.\\n\\n## Обязательные поля\\n\\n```yaml\\nid: string\\ntitle: string\\ndoc_type: string\\ndomain: string\\nsub_domain: string\\nrelated_docs: []\\nstatus: string\\n```\\n\\n## Поля совместимости и рекомендуемые поля\\n\\n```yaml\\ntype: string\\nname: string\\nmodule: string\\nlayer: string\\nupdated_at: YYYY-MM-DD\\ntags: []\\nentities: []\\nparent: string | null\\nchildren: []\\nlinks: {}\\nsource_of_truth: string\\nrelated_code: []\\nsystem_analytics_refs: []\\n```\\n\\n## Правила\\n\\n- `id` должен быть стабильным и уникальным в пределах документации проекта.\\n- `title` — человекочитаемый заголовок.\\n- `doc_type` — канонический тип документа.\\n- `domain` и `sub_domain` определяют бизнес-контекст документа.\\n- `related_docs` хранит явные связи с другими markdown-документами.\\n- `status` хранит жизненный цикл документа: например `draft`, `approved`, `active`.\\n- `type` допустимо дублировать как alias для tooling-совместимости с индексаторами.\\n- `name` — короткое системное имя документа.\\n- `module` — модуль или подсистема.\\n- `layer` — слой системы.\\n- `updated_at` хранится в формате `YYYY-MM-DD`.\\n\\n## Связи и навигация\\n\\n- `entities` описывает сущности, связанные с документом.\\n- `parent` и `children` описывают иерархию.\\n- `links` описывает typed graph связей между документами, кодом и интеграциями.\\n\\n## Формат links\\n\\n```yaml\\nlinks:\\n called_by:\\n - ext.health_probe\\n uses_logic:\\n - logic.some_flow\\n integrates_with:\\n - ext.some_system\\n```\\n\\n### global/linking.md\\n\\n# Linking Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как связывать документы между собой.\\n\\n## Иерархия\\n\\n- `parent` используется для родительского документа.\\n- `children` используется для прямых дочерних документов.\\n- Иерархия должна быть осмысленной и стабильной.\\n- Для общей точки входа допустим `index_page`.\\n\\n## Графовые связи\\n\\nДля `related_docs` используются ссылки на соседние документы.\\n\\nДля `links` рекомендуется использовать typed-ключи:\\n- `called_by`\\n- `uses_logic`\\n- `reads_db`\\n- `writes_db`\\n- `integrates_with`\\n- `used_by`\\n- `exposes_api`\\n- `uses_entities`\\n\\n## Правила использования\\n\\n- Если документ логически входит в другой, использовать `parent`/`children`.\\n- Если связь нужна для навигации между равноправными документами, дублировать ее в `related_docs`.\\n- Если связь отражает поведение, интеграции или переиспользование, фиксировать ее в `links`.\\n- Детальное описание интеграций хранить в body документа, а не только во frontmatter.\\n\\n### global/naming.md\\n\\n# Naming Rules\\n\\n## Назначение\\n\\nЭтот файл описывает правила именования документов, файлов и идентификаторов.\\n\\n## Правила для файлов\\n\\n- Имена файлов должны быть в kebab-case.\\n- Имя файла должно отражать одну тему.\\n- Для шаблонов использовать суффикс `.template.md`.\\n\\n## Правила для id\\n\\n- `id` строится в формате `.`.\\n- Примеры:\\n - `api.send_message_endpoint`\\n - `logic.telegram_notification_loop`\\n - `architecture.telegram_notify_app`\\n\\n## Правила для title\\n\\n- `title` должен быть кратким и человекочитаемым.\\n- В `title` допускаются пробелы и естественный язык.\\n\\n### global/writing-style.md\\n\\n# Writing Style\\n\\n## Назначение\\n\\nЭтот файл задает правила стиля для текстового наполнения документации.\\n\\n## Правила стиля\\n\\n- Текст должен быть лаконичным.\\n- Формулировки должны быть точными и техническими.\\n- Summary должен быть кратким explain-слоем.\\n- Details должен раскрывать суть без лишней воды.\\n- Нежелательно смешивать несколько тем в одном документе.\\n- Если детали относятся к другому артефакту, их нужно выносить в отдельный документ.\\n\\n## Язык\\n\\n- Основной язык документации — русский.\\n- Технические термины, названия классов, API, RAG, OpenAPI, runtime и другие устоявшиеся identifiers можно оставлять на английском.\\n\\n## Artifact rules (api_method)\\n\\n# API Method Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для документов типа `api_method`.\\n\\n## Когда использовать\\n\\nИспользовать для описания одного HTTP endpoint или одного отдельного API метода.\\n\\n## Обязательная структура\\n\\nДокумент должен содержать:\\n- YAML frontmatter\\n- `# `\\n- `## Summary`\\n- `## Details`\\n\\nВнутри `## Details` обязательны:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\n## Особые правила\\n\\n- Сценарий оформляется как технический use case.\\n- Функциональные требования маркируются `FR-*`.\\n- Нефункциональные требования маркируются `NFR-*`.\\n- Контракт должен быть пригоден для последующей сборки OpenAPI.\\n- Если у метода есть интеграции, они выносятся в `### Интеграции`.\\n- Ошибки и HTTP-коды либо описываются в `### Ошибки`, либо ссылаются на централизованный каталог ошибок.\\n\\n## Ошибки оформления\\n\\n- Нельзя заменять контракт общим текстовым описанием.\\n- Нельзя смешивать несколько endpoint в одном документе.\\n- Нельзя хранить связи и навигацию вне frontmatter.\\n\\n## Template (api_method)\\n\\n---\\nid: api.example_method\\ntype: api_method\\ndoc_type: api_method\\nname: example_method\\ntitle: HTTP API /example\\nmodule: example_module\\nlayer: application\\ndomain: example_domain\\nsub_domain: example_subdomain\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: code\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# HTTP API /example\\n\\n## Summary\\n\\nКраткое описание метода.\\n\\n## Details\\n\\n## Описание\\n\\nКороткое описание сути метода.\\n\\n## Сценарий\\n\\n**Название:**\\n\\n**Предусловия:**\\n- \\n\\n**Триггер:**\\n- \\n\\n**Основной сценарий:**\\n1. \\n\\n**Альтернативный сценарий:**\\n1. \\n\\n**Обработка ошибок:**\\n1. \\n\\n**Постусловие:**\\n- \\n\\n## Функциональные требования\\n\\n**FR-1.**\\n\\n## Нефункциональные требования\\n\\n**NFR-1.**\\n\\n## Контракт\\n\\n### Входные параметры\\n\\n| Параметр | Где передается | Тип | Обязательность | Ограничения | Описание | Пример |\\n|---|---|---|---|---|---|---|\\n| | | | | | | |\\n\\n### Выходные параметры\\n\\n| Поле | Тип | Обязательность | Ограничения | Описание | Заполнение | Пример |\\n|---|---|---|---|---|---|---|\\n| | | | | | | |\\n\\n### Интеграции\\n\\n### Ошибки\\n\\n### Связанный код\\n\\n### История изменений\\n\\n## Section rule: api-contract\\n\\n# API Contract Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как оформлять подраздел `## Контракт` в API-документах.\\n\\n## Что должно быть описано\\n\\n- входные параметры\\n- выходные параметры\\n- JSON-структуры запросов и ответов\\n- обязательность полей\\n- типы полей\\n- ограничения\\n- описание назначения полей\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n## Правило качества\\n\\nКонтракт должен быть достаточно формальным, чтобы по нему можно было собрать OpenAPI-спецификацию.\\n\\n## Section rule: api-scenario\\n\\n# API Scenario Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как оформлять подраздел `### Сценарий` в API-документах.\\n\\n## Обязательные части\\n\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработка ошибок\\n- постусловие\\n\\n## Правила\\n\\n- Сценарий должен быть лаконичным.\\n- Сценарий должен отражать суть шага.\\n- Сложные технические детали надо выносить в `FR-*`.\\n\\n## Section rule: details\\n\\n# Details Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает общие правила для секции `## Details`.\\n\\n## Правила\\n\\n- `Details` оформляется как `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Структура Details зависит от типа документа.\\n- В Details не нужно повторно дублировать навигацию и связи, если они уже есть во frontmatter.\\n- Интеграции, ошибки и кодовые привязки должны быть выделены в отдельные подразделы, если они существенны для понимания документа.\\n\\n## Section rule: requirements-format\\n\\n# Requirements Format Rules\\n\\n## Назначение\\n\\nЭтот файл задает формат для функциональных и нефункциональных требований.\\n\\n## Функциональные требования\\n\\n- Использовать коды `FR-1`, `FR-2`, `FR-3` и так далее.\\n- Каждое требование должно описывать отдельный обязательный аспект поведения.\\n- Идентификаторы локальны в пределах одного документа.\\n\\n## Нефункциональные требования\\n\\n- Использовать коды `NFR-1`, `NFR-2`, `NFR-3` и так далее.\\n- Требования должны описывать характеристики качества, ограничения и эксплуатационные свойства.\\n\\n## Section rule: summary\\n\\n# Summary Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для секции `## Summary`.\\n\\n## Правила\\n\\n- Summary должен быть коротким explain-слоем быстрого контекста.\\n- Summary должен объяснять суть документа без лишних деталей.\\n- Summary должен быть пригоден для explain и быстрого чтения.\\n- Предпочтительный формат: список ключевых фактов `Purpose`, `Actor`, `Trigger`, `Errors`, `Related ...` и т.д.\\n- Для крупных документов допустим более длинный summary, если он остается структурированным.\"\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.changeset"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис клиентов_post_api_v1_clients_contacts_dgr.md\",\n \"reason\": \"Создание нового API-метода `POST /api/v1/clients/contacts-dgr` на основе unit 'FR2. Реализовать сервис CLIENTS.' из системной аналитики.\",\n \"proposed_content\": \"---\\nid: api_method.fr2_реализовать_сервис_клиентов_post_api_v1_clients_contacts_dgr\\ntype: api_method\\ndoc_type: api_method\\nname: fr2_реализовать_сервис_клиентов_post_api_v1_clients_contacts_dgr\\ntitle: FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`\\ndomain: unknown\\nsub_domain: unknown\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2023-10-10\\nsource_of_truth: analysis\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`\\n\\n## Summary\\n\\nМетод реализует функционал создания контактов DGR в системе CLIENTS. Использование требует авторизации с периметром `CI02792632.ContactsDGR.Create`. Входящие данные проверяются на соответствие JSON-схеме. Возвращает созданный объект контакта в формате `UfsBaseResponseContactDGRCreateRsDto`.\\n\\n## Details\\n\\n### Описание\\n\\nAPI-метод предназначен для создания новых контактов DGR в системе CLIENTS.\\n\\n### Сценарий\\n\\n**Название:** Создание контакта DGR\\n\\n**Предусловия:**\\n- Пользователь имеет доступ к периметру `CI02792632.ContactsDGR.Create`.\\n- Отправлен корректный запрос с данными контакта.\\n\\n**Триггер:**\\nОтправка POST-запроса на `/api/v1/clients/contacts-dgr`.\\n\\n**Основной сценарий:**\\n1. Проверяется валидность входящих данных согласно JSON-схеме.\\n2. Проведение авторизации через периметр доступа.\\n3. По успешному прохождению проверки отправляется запрос на backend-сервис для создания контакта.\\n4. Возвращается идентификатор созданного контакта.\\n\\n**Альтернативный сценарий:**\\n- Если данные не соответствуют схеме – возвращается ошибка `BAD_REQUEST`.\\n- Отсутствие необходимого периметра доступа приводит к ошибке `UNAUTHORIZED`.\\n\\n**Обработка ошибок:**\\nОписана в разделе **Ошибки**.\\n\\n**Постусловие:**\\nСоздан новый контакт DGR в системе CLIENTS.\\n\\n### Функциональные требования\\n\\n**FR-1.** Входящие данные должны соответствовать JSON-схеме. В случае несоответствия метод возвращает ошибку `BAD_REQUEST`.\\n\\n**FR-2.** Запрос должен быть авторизован с использованием периметра доступа `CI02792632.ContactsDGR.Create`. Без него возврат ошибки `UNAUTHORIZED`.\\n\\n**FR-3.** Метод вызывает endpoint `POST /contacts` сервиса `prpb.contacts_dgr` для создания контакта.\\n\\n**FR-4.** Ответ формируется в виде объекта `UfsBaseResponseContactDGRCreateRsDto`.\\n\\n### Нефункциональные требования\\n\\nНе указаны.\\n\\n### Контракт\\n\\n#### Входные параметры\\n\\n| Атрибут | Обязательность | Тип | Где передается | Описание |\\n|------------------------|---------------|---------------|-----------------|---------------------------------------|\\n| X-Request-Id | 1 | uuid | header | Сквозной идентификатор вызова |\\n| X-Client-Ident-Id | 1 | string(50) | header | Идентификатор системы потребителя |\\n| X-Employee-Number | 0..1 | string(8) | header | Табельный номер пользователя |\\n| contact | 1 | object | body | Данные контакта DGR |\\n| contact.lastName | 0..1 | string(100) | body | Фамилия контакта |\\n| contact.firstName | 0..1 | string(100) | body | Имя контакта |\\n| contact.middleName | 0..1 | string(100) | body | Отчество контакта |\\n| contact.name | 0..1 | string(100) | body | Название группового контакта |\\n| contact.description | 0..1 | string(1000) | body | Описание группового контакта |\\n| contact.position | 0..1 | string(100) | body | Должность контакта у клиента |\\n| contact.comment | 0..1 | string(1000) | body | Комментарий к контакту |\\n| contact.contactType | 1 | enum(string) | body | Тип контакта: Individual, Group |\\n| contact.crossboarding | 1 | boolean | body | Признак принадлежности к онбордингу |\\n| contact.createdBy | 1 | string(8) | body | Табельный номер создателя контакта |\\n| contact.emails | 0..1 | array(object) | body | Массив электронных адресов контакта |\\n| contact.emails.value | 1 | string(100) | body | Электронная почта |\\n| contact.emails.main | 1 | boolean | body | Признак основной почты |\\n| contact.phones | 0..1 | array(object) | body | Массив телефонных номеров контакта |\\n| contact.phones.value | 1 | string(20) | body | Номер телефона |\\n| contact.phones.extValue | 0..1 | string(10) | body | Внутренний добавочный номер |\\n| contact.phones.main | 1 | boolean | body | Признак основного номера телефона |\\n| contact.phones.mobile | 1 | boolean | body | Признак мобильного телефона |\\n| client | 1 | object | body | Данные клиента |\\n| client.ucpId | 0..1 | string(36) | body | Идентификатор клиента ПАО |\\n| client.sbpId | 0..1 | string(36) | body | Идентификатор клиента АО |\\n| client.inn | 0..1 | string(12) | body | ИНН клиента |\\n| client.kpp | 0..1 | string(9) | body | КПП клиента |\\n\\n#### Выходные параметры\\n\\n| Атрибут | Тип | Обязательность | Описание |\\n|----------------|--------------|---------------|----------------------|\\n| contactId | string(36) | 1 | Идентификатор контакта|\\n\\n### Интеграции\\n\\nИнтеграция с сервисом `prpb.contacts_dgr` через endpoint `POST /contacts`.\\n\\n### Ошибки\\n\n- `BAD_REQUEST`: Входящие данные не соответствуют JSON-схеме.\\n- `UNAUTHORIZED`: Нет необходимых прав доступа.\\n\\n### Связанный код\\n\\nНе указан.\\n\\n### История изменений\\n\\nНе указана.\"\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "build_changeset",
+ "title": "Формирование changeset"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "changeset_items": 0,
+ "issues": 5,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 5,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "Для doc_type 'ui_page' не найдено полных doc_rules (artifact/template).",
+ "LLM вернул невалидный JSON changeset для docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "finalize",
+ "title": "Подготовка ответа"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 5,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "Для doc_type 'ui_page' не найдено полных doc_rules (artifact/template).",
+ "LLM вернул невалидный JSON changeset для docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md."
+ ]
+ },
+ "output": {
+ "answer_length": 744,
+ "issues": 5,
+ "changeset_items": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 744,
+ "issues_count": 5,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "Для doc_type 'ui_page' не найдено полных doc_rules (artifact/template).",
+ "LLM вернул невалидный JSON changeset для docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_update.from_feature",
+ "steps": [
+ {
+ "step_id": "resolve_source",
+ "title": "Определение источника аналитики",
+ "input": {
+ "source_kind": "",
+ "source_ref": "",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "load_source",
+ "title": "Загрузка системной аналитики",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "content_loaded": true,
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "parse_feature",
+ "title": "Парсинг функциональных требований",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units": 2,
+ "issues": 3,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "load_doc_rules",
+ "title": "Загрузка doc_rules",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "enabled": true,
+ "loaded": true,
+ "supported_doc_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "issues": 3,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "build_change_plan",
+ "title": "Построение плана изменений",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "docs_rows": 7,
+ "planned_changes": 2,
+ "issues": 3,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "build_changeset",
+ "title": "Формирование changeset",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "changeset_items": 0,
+ "issues": 5,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 5,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "Для doc_type 'ui_page' не найдено полных doc_rules (artifact/template).",
+ "LLM вернул невалидный JSON changeset для docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "finalize",
+ "title": "Подготовка ответа",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 5,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "Для doc_type 'ui_page' не найдено полных doc_rules (artifact/template).",
+ "LLM вернул невалидный JSON changeset для docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md."
+ ]
+ },
+ "output": {
+ "answer_length": 744,
+ "issues": 5,
+ "changeset_items": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6116,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 744,
+ "issues_count": 5,
+ "issues_preview": [
+ "Отсутствует analysis_id в metadata аналитики.",
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "Для doc_type 'ui_page' не найдено полных doc_rules (artifact/template).",
+ "LLM вернул невалидный JSON changeset для docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md."
+ ]
+ }
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_update.from_feature"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "docs_update_changeset",
+ "answer_length": 744,
+ "changeset_items": 0,
+ "apply_changeset": false
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "DOC_UPDATE/FROM_FEATURE: результат построения changeset.\n\nОбнаружены несоответствия/нехватка данных:\n- Отсутствует analysis_id в metadata аналитики.\n- Отсутствует domains в metadata аналитики.\n- Отсутствует subdomains в metadata аналитики.\n- Для doc_type 'ui_page' не найдено полных doc_rules (artifact/template).\n- LLM вернул невалидный JSON changeset для docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md.\n\nПлан изменений:\n- create: docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md (ui_page)\n- create: docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md (api_method)\n\nChangeset (для плагина):\n```json\n[]\n```\n\napply_changeset: false",
+ "completed_at": "2026-04-09T15:20:16.339097+00:00"
+}
+```
diff --git a/runtime_traces/agent_requests/20260409-152858-906a9a1ffd45.md b/runtime_traces/agent_requests/20260409-152858-906a9a1ffd45.md
new file mode 100644
index 0000000..97c25c6
--- /dev/null
+++ b/runtime_traces/agent_requests/20260409-152858-906a9a1ffd45.md
@@ -0,0 +1,1434 @@
+# Runtime Trace: 20260409-152858-906a9a1ffd45
+
+- active_rag_session_id: 2c3ee31d-a71c-4eaa-ba7c-906a9a1ffd45
+
+## request
+```json
+{
+ "request_id": "req_d6406bfd9e05450ca0878f3a90c2bdee",
+ "session_id": "as_c6a09ddd19cf4a7d98beed7b65cfa0fb",
+ "active_rag_session_id": "2c3ee31d-a71c-4eaa-ba7c-906a9a1ffd45",
+ "process_version": "v2",
+ "created_at": "2026-04-09T15:28:58.212900+00:00",
+ "message": "Сформируй документацию по системной аналитике\n/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_UPDATE",
+ "subintent": "FROM_FEATURE",
+ "normalized_query": "Сформируй документацию по системной аналитике /Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "target_terms": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "anchors": {
+ "entity_names": [
+ "Users",
+ "Dev_projects_v2"
+ ],
+ "file_names": [
+ "process/v2/test_doc/features/create_contact.md"
+ ],
+ "endpoint_paths": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "entity",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": [
+ "API_ENDPOINT",
+ "DOMAIN_ENTITY",
+ "LOGIC_FLOW"
+ ]
+ },
+ "confidence": 0.9500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно указывает на формирование документации по системной аналитике из указанного файла create_contact.md.",
+ "rag_session_id": "2c3ee31d-a71c-4eaa-ba7c-906a9a1ffd45"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_UPDATE",
+ "subintent": "FROM_FEATURE",
+ "confidence": 0.9500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [
+ "API_ENDPOINT",
+ "DOMAIN_ENTITY",
+ "LOGIC_FLOW"
+ ],
+ "endpoint_paths": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ],
+ "matched_aliases": [],
+ "target_terms": [
+ "/users/alex/dev_projects_v2/ai"
+ ]
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ]
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_update.from_feature"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "resolve_source",
+ "title": "Определение источника аналитики"
+ },
+ "input": {
+ "source_kind": "",
+ "source_ref": "",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "load_source",
+ "title": "Загрузка системной аналитики"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "content_loaded": true,
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "parse_feature",
+ "title": "Парсинг функциональных требований"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units": 2,
+ "issues": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "load_doc_rules",
+ "title": "Загрузка doc_rules"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "enabled": true,
+ "loaded": true,
+ "supported_doc_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "issues": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.plan_change_units",
+ "system_prompt": "Ты классифицируешь units системной аналитики для построения плана изменений документации.\n\nВерни только JSON:\n{\n \"items\": [\n {\"index\": 0, \"doc_type\": \"api_method\", \"reason\": \"...\"}\n ]\n}\n\nПравила:\n- Используй только doc_type из allowed_doc_types.\n- Не пропускай item, даже если не уверен: выбери наиболее близкий тип.\n- Ориентируйся на heading и snippet.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"system_rules\": \"Системные правила документации:\\n1. Один устойчивый объект — один документ.\\n2. Документы не должны дублировать друг друга по смыслу.\\n3. Связи между документами должны быть явными (related_docs/links).\\n4. Документация организована иерархически по папкам docs/*.\\n5. Markdown-документ состоит из YAML frontmatter и body.\\n6. Обязательные поля frontmatter: id, title, doc_type, related_docs, status, domain, sub_domain.\",\n \"allowed_doc_types\": [\n \"ui_page\",\n \"api_method\",\n \"logic_block\",\n \"architecture_overview\",\n \"integration_doc\",\n \"domain_entity\",\n \"glossary_item\",\n \"index_page\"\n ],\n \"items\": [\n {\n \"index\": 0,\n \"heading\": \"FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\",\n \"snippet\": \"- `type`: `ui.page`\\n- `id`: `ui.contacts_dgr.create`\\n\\nОсновной сценарий:\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- `ui.contacts_dgr` вызывает endpoint `POST /api/v1/clients/contacts-dgr` для создания карточки контакта ДГР.\\n- `ufs.contacts_dgr` обрабатывает запрос и возвращает ответ.\\n- `ui.contacts_dgr` отображает результат создания контакта ДГР в виде push-уведомле\"\n },\n {\n \"index\": 1,\n \"heading\": \"FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`\",\n \"snippet\": \"- `type`: `api_method`\\n- `id`: `ufs.contacts_dgr.api.create`\\n- `endpoint`: `POST /api/v1/clients/contacts-dgr`\\n\\nТребования для основного сценария:\\n- Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом `BAD_REQUEST`.\\n- Авторизовать запрос по наличию периметра `CI02792632.ContactsDGR.Create`. При отсутствии периметра завершить основной сценарий с кодом `UNAU\"\n }\n ]\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.plan"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"items\": [\n {\"index\": 0, \"doc_type\": \"ui_page\"},\n {\"index\": 1, \"doc_type\": \"api_method\"}\n ]\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "build_change_plan",
+ "title": "Построение плана изменений"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "docs_rows": 7,
+ "planned_changes": 2,
+ "issues": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "changeset_prompt_built",
+ "doc_type": "ui_page",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "prompt_chars": 11080,
+ "rules_chars": 9572
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.build_doc_changeset",
+ "system_prompt": "Ты формируешь один item changeset для документации на основе системной аналитики и правил doc_rules.\n\nВерни только JSON-объект формата:\n{\n \"op\": \"create|update|delete\",\n \"path\": \"docs/...\",\n \"reason\": \"краткая причина\",\n \"proposed_content\": \"полный markdown документа для create/update\"\n}\n\nПравила:\n- Строго соблюдай структуру и ограничения из doc_rules_context.\n- Для create/update верни полный итоговый markdown (frontmatter + body).\n- Для update не используй placeholder-тексты; возвращай пригодный к сохранению документ.\n- reason обязателен, короткий, по сути изменения.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"change_request\": {\n \"op\": \"create\",\n \"path\": \"docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md\",\n \"doc_type\": \"ui_page\",\n \"doc_id\": \"ui_page.fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр\",\n \"title\": \"FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\",\n \"domain\": \"unknown\",\n \"sub_domain\": \"unknown\",\n \"reason\": \"Из unit 'FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»' системной аналитики (test).\",\n \"source_refs\": [\n \"section: 5. Функциональные требования\"\n ],\n \"related_docs\": [],\n \"requirement_body\": \"- `type`: `ui.page`\\n- `id`: `ui.contacts_dgr.create`\\n\\nОсновной сценарий:\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- `ui.contacts_dgr` вызывает endpoint `POST /api/v1/clients/contacts-dgr` для создания карточки контакта ДГР.\\n- `ufs.contacts_dgr` обрабатывает запрос и возвращает ответ.\\n- `ui.contacts_dgr` отображает результат создания контакта ДГР в виде push-уведомления.\"\n },\n \"doc_rules_context\": \"## Global rules\\n\\n### documentation-rules.md\\n\\n# Documentation Rules\\n\\nЭтот каталог оформляет MVP документации проекта в атомарном формате.\\n\\n## Базовая структура\\n\\n- Каждый документ содержит YAML frontmatter.\\n- В документе должен быть один `H1`, совпадающий с `title`.\\n- Основные разделы оформляются как `## Summary` и `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Связи, сущности и навигация описываются во frontmatter через `related_docs`, `links`, `entities`, `parent`, `children`.\\n\\n## Summary\\n\\n- Краткий explain-слой быстрого контекста.\\n- Должен позволять быстро понять назначение документа без чтения `Details`.\\n- Предпочтительный формат: компактный список ключевых фактов без длинных абзацев.\\n\\n## Details\\n\\n- Раскрывает полное описание объекта.\\n- Структура `Details` зависит от типа документа.\\n- Сценарии, ограничения, интеграции, ошибки и кодовые привязки должны быть разнесены по отдельным подразделам.\\n\\n## API documents\\n\\nДля `api_method` внутри `## Details` обязательны разделы:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\nЕсли у метода есть интеграции и ошибки, также обязательны:\\n- `### Интеграции`\\n- `### Ошибки`\\n- `### Связанный код`\\n- `### История изменений`\\n\\n### Сценарий\\n\\nСценарий оформляется как технический use case и содержит:\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработку ошибок\\n- постусловие\\n\\n### Требования\\n\\n- Функциональные требования маркируются как `FR-1`, `FR-2`, ...\\n- Нефункциональные требования маркируются как `NFR-1`, `NFR-2`, ...\\n- Идентификаторы требований локальны в рамках одного документа.\\n\\n### Контракт\\n\\nКонтракт должен быть пригоден для последующей сборки OpenAPI-спецификации и включать:\\n- входные параметры\\n- выходные параметры\\n- структуру JSON-сообщений\\n- обязательность полей\\n- типы и ограничения\\n- описание полей\\n- правила заполнения\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n### global/documentation-system.md\\n\\n# Documentation System\\n\\n## Назначение\\n\\nЭтот файл задает общую модель документации проекта.\\n\\n## Базовая модель\\n\\nКаждый документ должен состоять из двух слоев:\\n- YAML frontmatter\\n- контент\\n\\nКонтент всегда состоит из двух обязательных разделов:\\n- `## Summary`\\n- `## Details`\\n\\nНад ними должен быть один заголовок `# `, совпадающий со значением `title` во frontmatter.\\n\\n## Принципы\\n\\n- Документы должны быть атомарными.\\n- Один документ описывает одну тему.\\n- Вместо дублирования между документами используются явные ссылки.\\n- Связи и навигация должны быть формализованы.\\n- Документы должны быть пригодны для чтения человеком и для RAG.\\n- Документы должны быть пригодны для частичного обновления без деградации структуры.\\n\\n## Типы документов\\n\\nНа уровне проекта поддерживаются типы:\\n- `api_method`\\n- `logic_block`\\n- `architecture_overview`\\n- `domain_entity`\\n- `ui_page`\\n- `integration_doc`\\n- `index_page`\\n- `glossary_item`\\n\\n### global/frontmatter.md\\n\\n# Frontmatter Rules\\n\\n## Назначение\\n\\nЭтот файл описывает единый контракт YAML frontmatter для всех документов.\\n\\n## Обязательные поля\\n\\n```yaml\\nid: string\\ntitle: string\\ndoc_type: string\\ndomain: string\\nsub_domain: string\\nrelated_docs: []\\nstatus: string\\n```\\n\\n## Поля совместимости и рекомендуемые поля\\n\\n```yaml\\ntype: string\\nname: string\\nmodule: string\\nlayer: string\\nupdated_at: YYYY-MM-DD\\ntags: []\\nentities: []\\nparent: string | null\\nchildren: []\\nlinks: {}\\nsource_of_truth: string\\nrelated_code: []\\nsystem_analytics_refs: []\\n```\\n\\n## Правила\\n\\n- `id` должен быть стабильным и уникальным в пределах документации проекта.\\n- `title` — человекочитаемый заголовок.\\n- `doc_type` — канонический тип документа.\\n- `domain` и `sub_domain` определяют бизнес-контекст документа.\\n- `related_docs` хранит явные связи с другими markdown-документами.\\n- `status` хранит жизненный цикл документа: например `draft`, `approved`, `active`.\\n- `type` допустимо дублировать как alias для tooling-совместимости с индексаторами.\\n- `name` — короткое системное имя документа.\\n- `module` — модуль или подсистема.\\n- `layer` — слой системы.\\n- `updated_at` хранится в формате `YYYY-MM-DD`.\\n\\n## Связи и навигация\\n\\n- `entities` описывает сущности, связанные с документом.\\n- `parent` и `children` описывают иерархию.\\n- `links` описывает typed graph связей между документами, кодом и интеграциями.\\n\\n## Формат links\\n\\n```yaml\\nlinks:\\n called_by:\\n - ext.health_probe\\n uses_logic:\\n - logic.some_flow\\n integrates_with:\\n - ext.some_system\\n```\\n\\n### global/linking.md\\n\\n# Linking Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как связывать документы между собой.\\n\\n## Иерархия\\n\\n- `parent` используется для родительского документа.\\n- `children` используется для прямых дочерних документов.\\n- Иерархия должна быть осмысленной и стабильной.\\n- Для общей точки входа допустим `index_page`.\\n\\n## Графовые связи\\n\\nДля `related_docs` используются ссылки на соседние документы.\\n\\nДля `links` рекомендуется использовать typed-ключи:\\n- `called_by`\\n- `uses_logic`\\n- `reads_db`\\n- `writes_db`\\n- `integrates_with`\\n- `used_by`\\n- `exposes_api`\\n- `uses_entities`\\n\\n## Правила использования\\n\\n- Если документ логически входит в другой, использовать `parent`/`children`.\\n- Если связь нужна для навигации между равноправными документами, дублировать ее в `related_docs`.\\n- Если связь отражает поведение, интеграции или переиспользование, фиксировать ее в `links`.\\n- Детальное описание интеграций хранить в body документа, а не только во frontmatter.\\n\\n### global/naming.md\\n\\n# Naming Rules\\n\\n## Назначение\\n\\nЭтот файл описывает правила именования документов, файлов и идентификаторов.\\n\\n## Правила для файлов\\n\\n- Имена файлов должны быть в kebab-case.\\n- Имя файла должно отражать одну тему.\\n- Для шаблонов использовать суффикс `.template.md`.\\n\\n## Правила для id\\n\\n- `id` строится в формате `.`.\\n- Примеры:\\n - `api.send_message_endpoint`\\n - `logic.telegram_notification_loop`\\n - `architecture.telegram_notify_app`\\n\\n## Правила для title\\n\\n- `title` должен быть кратким и человекочитаемым.\\n- В `title` допускаются пробелы и естественный язык.\\n\\n### global/writing-style.md\\n\\n# Writing Style\\n\\n## Назначение\\n\\nЭтот файл задает правила стиля для текстового наполнения документации.\\n\\n## Правила стиля\\n\\n- Текст должен быть лаконичным.\\n- Формулировки должны быть точными и техническими.\\n- Summary должен быть кратким explain-слоем.\\n- Details должен раскрывать суть без лишней воды.\\n- Нежелательно смешивать несколько тем в одном документе.\\n- Если детали относятся к другому артефакту, их нужно выносить в отдельный документ.\\n\\n## Язык\\n\\n- Основной язык документации — русский.\\n- Технические термины, названия классов, API, RAG, OpenAPI, runtime и другие устоявшиеся identifiers можно оставлять на английском.\\n\\n## Artifact rules (ui_page)\\n\\n# UI Page Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для документов типа `ui_page`.\\n\\n## Когда использовать\\n\\nИспользовать для описания одной пользовательской страницы, экрана или отдельного UI-сценария.\\n\\n## Обязательная структура\\n\\nДокумент должен содержать:\\n- YAML frontmatter\\n- `# `\\n- `## Summary`\\n- `## Details`\\n\\n## Что описывать в Details\\n\\n- назначение страницы\\n- пользовательский сценарий\\n- основные блоки интерфейса\\n- связанные API и сущности\\n\\n## Template (ui_page)\\n\\n---\\nid: ui.example_page\\ntype: ui_page\\ndoc_type: ui_page\\nname: example_page\\ntitle: Пример UI-страницы\\nmodule: example_module\\nlayer: presentation\\ndomain: example_domain\\nsub_domain: example_subdomain\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: mixed\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# Пример UI-страницы\\n\\n## Summary\\n\\nКраткое описание страницы и её назначения.\\n\\n## Details\\n\\n### Назначение страницы\\n\\n### Пользовательский сценарий\\n\\n### Основные блоки интерфейса\\n\\n### Связанные API и сущности\\n\\n### Функциональные требования\\n\\n### Нефункциональные требования\\n\\n### Ограничения и граничные случаи\\n\\n### Ошибки и валидации\\n\\n### Связанный код\\n\\n### Связанные документы\\n\\n### История изменений\\n\\n## Section rule: details\\n\\n# Details Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает общие правила для секции `## Details`.\\n\\n## Правила\\n\\n- `Details` оформляется как `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Структура Details зависит от типа документа.\\n- В Details не нужно повторно дублировать навигацию и связи, если они уже есть во frontmatter.\\n- Интеграции, ошибки и кодовые привязки должны быть выделены в отдельные подразделы, если они существенны для понимания документа.\\n\\n## Section rule: requirements-format\\n\\n# Requirements Format Rules\\n\\n## Назначение\\n\\nЭтот файл задает формат для функциональных и нефункциональных требований.\\n\\n## Функциональные требования\\n\\n- Использовать коды `FR-1`, `FR-2`, `FR-3` и так далее.\\n- Каждое требование должно описывать отдельный обязательный аспект поведения.\\n- Идентификаторы локальны в пределах одного документа.\\n\\n## Нефункциональные требования\\n\\n- Использовать коды `NFR-1`, `NFR-2`, `NFR-3` и так далее.\\n- Требования должны описывать характеристики качества, ограничения и эксплуатационные свойства.\\n\\n## Section rule: summary\\n\\n# Summary Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для секции `## Summary`.\\n\\n## Правила\\n\\n- Summary должен быть коротким explain-слоем быстрого контекста.\\n- Summary должен объяснять суть документа без лишних деталей.\\n- Summary должен быть пригоден для explain и быстрого чтения.\\n- Предпочтительный формат: список ключевых фактов `Purpose`, `Actor`, `Trigger`, `Errors`, `Related ...` и т.д.\\n- Для крупных документов допустим более длинный summary, если он остается структурированным.\"\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.changeset"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"op\": \"create\",\n \"path\": \"docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md\",\n \"reason\": \"Создание нового UI-документа для сценария 'Контакты ДГР. Создание карточки контакта ДГР'\",\n \"proposed_content\": \"---\\nid: ui_page.fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр\\ntype: ui_page\\ndoc_type: ui_page\\nname: fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр\\ntitle: FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\\ndomain: unknown\\nsub_domain: unknown\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2023-10-10\\nsource_of_truth: mixed\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\n\n## Summary\n\n- **Назначение**: Реализация сценария добавления новой карточки контакта ДГР.\n- **Актер**: Пользователь.\n- **Триггер**: Заполнение атрибутов карточки и нажатие кнопки «Добавить».\n- **Связанные API**: `POST /api/v1/clients/contacts-dgr`.\n- **Обработка ответа**: Отображение результата в виде push-уведомления.\n\n## Details\n\n### Назначение страницы\n\nРеализует функционал создания новой карточки контакта ДГР пользователем.\n\n### Пользовательский сценарий\n\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\n- Интерфейс (`ui.contacts_dgr`) отправляет POST-запрос на серверную сущность (`ufs.contacts_dgr`), используя endpoint `/api/v1/clients/contacts-dgr`.\n- После обработки запроса сервер возвращает ответ, который интерфейс отображает пользователю в виде push-уведомления.\n\n### Основные блоки интерфейса\n\nНе указано специфических блоков интерфейса.\n\n### Связанные API и сущности\n\n- API: `POST /api/v1/clients/contacts-dgr`\n- Сущности: `ufs.contacts_dgr`\n\n### Функциональные требования\n\n- **FR-1**: При успешном создании контакта отображается push-уведомление.\n- **FR-2**: Проверка корректности введенных данных перед отправкой запроса.\n\n### Нефункциональные требования\n\nНе указаны специфические нефункциональные требования.\n\n### Ограничения и граничные случаи\n\nНе описаны дополнительные ограничения и граничные сценарии.\n\n### Ошибки и валидации\n\nОписаны в разделе \\\"Функциональные требования\\\" под номером FR-2.\n\n### Связанный код\n\nНе указан конкретный связанный код.\n\n### Связанные документы\n\nОтсутствуют.\n\n### История изменений\n\nНе указана история изменений.\"\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "changeset_prompt_built",
+ "doc_type": "api_method",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "prompt_chars": 15690,
+ "rules_chars": 11520
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.build_doc_changeset",
+ "system_prompt": "Ты формируешь один item changeset для документации на основе системной аналитики и правил doc_rules.\n\nВерни только JSON-объект формата:\n{\n \"op\": \"create|update|delete\",\n \"path\": \"docs/...\",\n \"reason\": \"краткая причина\",\n \"proposed_content\": \"полный markdown документа для create/update\"\n}\n\nПравила:\n- Строго соблюдай структуру и ограничения из doc_rules_context.\n- Для create/update верни полный итоговый markdown (frontmatter + body).\n- Для update не используй placeholder-тексты; возвращай пригодный к сохранению документ.\n- reason обязателен, короткий, по сути изменения.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"change_request\": {\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md\",\n \"doc_type\": \"api_method\",\n \"doc_id\": \"api_method.fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr\",\n \"title\": \"FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`\",\n \"domain\": \"unknown\",\n \"sub_domain\": \"unknown\",\n \"reason\": \"Из unit 'FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`' системной аналитики (test).\",\n \"source_refs\": [\n \"section: 5. Функциональные требования\"\n ],\n \"related_docs\": [],\n \"requirement_body\": \"- `type`: `api_method`\\n- `id`: `ufs.contacts_dgr.api.create`\\n- `endpoint`: `POST /api/v1/clients/contacts-dgr`\\n\\nТребования для основного сценария:\\n- Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом `BAD_REQUEST`.\\n- Авторизовать запрос по наличию периметра `CI02792632.ContactsDGR.Create`. При отсутствии периметра завершить основной сценарий с кодом `UNAUTHORIZED`.\\n- Для исполнения запроса на создание контакта вызвать endpoint `POST /contacts` в `prpb.contacts_dgr`.\\n- Вернуть ответ `ui.contacts_dgr` в формате `UfsBaseResponseContactDGRCreateRsDto`.\\n\\nКонтракт `POST /contacts`\\n\\nЗапрос\\n\\n**headers**\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|---|---|---|---|---|\\n| `X-Request-Id` | 1 | `uuid` | `header` | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | `header` | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | `header` | Табельный номер пользователя, вызвавшего сервис |\\n\\n**body**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contact` | 1 | `object` | Данные контакта ДГР |\\n| `contact.lastName` | 0..1 | `string(100)` | Фамилия контакта |\\n| `contact.firstName` | 0..1 | `string(100)` | Имя контакта |\\n| `contact.middleName` | 0..1 | `string(100)` | Отчество контакта |\\n| `contact.name` | 0..1 | `string(100)` | Название группового контакта |\\n| `contact.description` | 0..1 | `string(1000)` | Описание группового контакта |\\n| `contact.position` | 0..1 | `string(100)` | Должность контакта у клиента |\\n| `contact.comment` | 0..1 | `string(1000)` | Комментарий к контакту |\\n| `contact.contactType` | 1 | `enum(string)` | `Individual`, `Group` |\\n| `contact.crossboarding` | 1 | `boolean` | Признак принадлежности контакта к процессу онбординга |\\n| `contact.createdBy` | 1 | `string(8)` | Табельный номер пользователя, создавшего контакт |\\n| `contact.emails` | 0..1 | `array(object)` | Массив электронных адресов контакта |\\n| `contact.emails.value` | 1 | `string(100)` | Электронный адрес |\\n| `contact.emails.main` | 1 | `boolean` | Признак основной почты |\\n| `contact.phones` | 0..1 | `array(object)` | Массив телефонных номеров контакта |\\n| `contact.phones.value` | 1 | `string(20)` | Телефонный номер контакта |\\n| `contact.phones.extValue` | 0..1 | `string(10)` | Добавочный номер |\\n| `contact.phones.main` | 1 | `boolean` | Признак основного телефона |\\n| `contact.phones.mobile` | 1 | `boolean` | Признак мобильного телефона |\\n| `client` | 1 | `object` | Данные клиента |\\n| `client.ucpId` | 0..1 | `string(36)` | Идентификатор клиента ПАО |\\n| `client.sbpId` | 0..1 | `string(36)` | Идентификатор клиента АО |\\n| `client.inn` | 0..1 | `string(12)` | ИНН клиента |\\n| `client.kpp` | 0..1 | `string(9)` | КПП клиента |\\n\\nОтвет\\n\\n**ContactDGRCreateRsDto**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contactId` | 1 | `string(36)` | Идентификатор контакта |\"\n },\n \"doc_rules_context\": \"## Global rules\\n\\n### documentation-rules.md\\n\\n# Documentation Rules\\n\\nЭтот каталог оформляет MVP документации проекта в атомарном формате.\\n\\n## Базовая структура\\n\\n- Каждый документ содержит YAML frontmatter.\\n- В документе должен быть один `H1`, совпадающий с `title`.\\n- Основные разделы оформляются как `## Summary` и `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Связи, сущности и навигация описываются во frontmatter через `related_docs`, `links`, `entities`, `parent`, `children`.\\n\\n## Summary\\n\\n- Краткий explain-слой быстрого контекста.\\n- Должен позволять быстро понять назначение документа без чтения `Details`.\\n- Предпочтительный формат: компактный список ключевых фактов без длинных абзацев.\\n\\n## Details\\n\\n- Раскрывает полное описание объекта.\\n- Структура `Details` зависит от типа документа.\\n- Сценарии, ограничения, интеграции, ошибки и кодовые привязки должны быть разнесены по отдельным подразделам.\\n\\n## API documents\\n\\nДля `api_method` внутри `## Details` обязательны разделы:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\nЕсли у метода есть интеграции и ошибки, также обязательны:\\n- `### Интеграции`\\n- `### Ошибки`\\n- `### Связанный код`\\n- `### История изменений`\\n\\n### Сценарий\\n\\nСценарий оформляется как технический use case и содержит:\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработку ошибок\\n- постусловие\\n\\n### Требования\\n\\n- Функциональные требования маркируются как `FR-1`, `FR-2`, ...\\n- Нефункциональные требования маркируются как `NFR-1`, `NFR-2`, ...\\n- Идентификаторы требований локальны в рамках одного документа.\\n\\n### Контракт\\n\\nКонтракт должен быть пригоден для последующей сборки OpenAPI-спецификации и включать:\\n- входные параметры\\n- выходные параметры\\n- структуру JSON-сообщений\\n- обязательность полей\\n- типы и ограничения\\n- описание полей\\n- правила заполнения\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n### global/documentation-system.md\\n\\n# Documentation System\\n\\n## Назначение\\n\\nЭтот файл задает общую модель документации проекта.\\n\\n## Базовая модель\\n\\nКаждый документ должен состоять из двух слоев:\\n- YAML frontmatter\\n- контент\\n\\nКонтент всегда состоит из двух обязательных разделов:\\n- `## Summary`\\n- `## Details`\\n\\nНад ними должен быть один заголовок `# `, совпадающий со значением `title` во frontmatter.\\n\\n## Принципы\\n\\n- Документы должны быть атомарными.\\n- Один документ описывает одну тему.\\n- Вместо дублирования между документами используются явные ссылки.\\n- Связи и навигация должны быть формализованы.\\n- Документы должны быть пригодны для чтения человеком и для RAG.\\n- Документы должны быть пригодны для частичного обновления без деградации структуры.\\n\\n## Типы документов\\n\\nНа уровне проекта поддерживаются типы:\\n- `api_method`\\n- `logic_block`\\n- `architecture_overview`\\n- `domain_entity`\\n- `ui_page`\\n- `integration_doc`\\n- `index_page`\\n- `glossary_item`\\n\\n### global/frontmatter.md\\n\\n# Frontmatter Rules\\n\\n## Назначение\\n\\nЭтот файл описывает единый контракт YAML frontmatter для всех документов.\\n\\n## Обязательные поля\\n\\n```yaml\\nid: string\\ntitle: string\\ndoc_type: string\\ndomain: string\\nsub_domain: string\\nrelated_docs: []\\nstatus: string\\n```\\n\\n## Поля совместимости и рекомендуемые поля\\n\\n```yaml\\ntype: string\\nname: string\\nmodule: string\\nlayer: string\\nupdated_at: YYYY-MM-DD\\ntags: []\\nentities: []\\nparent: string | null\\nchildren: []\\nlinks: {}\\nsource_of_truth: string\\nrelated_code: []\\nsystem_analytics_refs: []\\n```\\n\\n## Правила\\n\\n- `id` должен быть стабильным и уникальным в пределах документации проекта.\\n- `title` — человекочитаемый заголовок.\\n- `doc_type` — канонический тип документа.\\n- `domain` и `sub_domain` определяют бизнес-контекст документа.\\n- `related_docs` хранит явные связи с другими markdown-документами.\\n- `status` хранит жизненный цикл документа: например `draft`, `approved`, `active`.\\n- `type` допустимо дублировать как alias для tooling-совместимости с индексаторами.\\n- `name` — короткое системное имя документа.\\n- `module` — модуль или подсистема.\\n- `layer` — слой системы.\\n- `updated_at` хранится в формате `YYYY-MM-DD`.\\n\\n## Связи и навигация\\n\\n- `entities` описывает сущности, связанные с документом.\\n- `parent` и `children` описывают иерархию.\\n- `links` описывает typed graph связей между документами, кодом и интеграциями.\\n\\n## Формат links\\n\\n```yaml\\nlinks:\\n called_by:\\n - ext.health_probe\\n uses_logic:\\n - logic.some_flow\\n integrates_with:\\n - ext.some_system\\n```\\n\\n### global/linking.md\\n\\n# Linking Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как связывать документы между собой.\\n\\n## Иерархия\\n\\n- `parent` используется для родительского документа.\\n- `children` используется для прямых дочерних документов.\\n- Иерархия должна быть осмысленной и стабильной.\\n- Для общей точки входа допустим `index_page`.\\n\\n## Графовые связи\\n\\nДля `related_docs` используются ссылки на соседние документы.\\n\\nДля `links` рекомендуется использовать typed-ключи:\\n- `called_by`\\n- `uses_logic`\\n- `reads_db`\\n- `writes_db`\\n- `integrates_with`\\n- `used_by`\\n- `exposes_api`\\n- `uses_entities`\\n\\n## Правила использования\\n\\n- Если документ логически входит в другой, использовать `parent`/`children`.\\n- Если связь нужна для навигации между равноправными документами, дублировать ее в `related_docs`.\\n- Если связь отражает поведение, интеграции или переиспользование, фиксировать ее в `links`.\\n- Детальное описание интеграций хранить в body документа, а не только во frontmatter.\\n\\n### global/naming.md\\n\\n# Naming Rules\\n\\n## Назначение\\n\\nЭтот файл описывает правила именования документов, файлов и идентификаторов.\\n\\n## Правила для файлов\\n\\n- Имена файлов должны быть в kebab-case.\\n- Имя файла должно отражать одну тему.\\n- Для шаблонов использовать суффикс `.template.md`.\\n\\n## Правила для id\\n\\n- `id` строится в формате `.`.\\n- Примеры:\\n - `api.send_message_endpoint`\\n - `logic.telegram_notification_loop`\\n - `architecture.telegram_notify_app`\\n\\n## Правила для title\\n\\n- `title` должен быть кратким и человекочитаемым.\\n- В `title` допускаются пробелы и естественный язык.\\n\\n### global/writing-style.md\\n\\n# Writing Style\\n\\n## Назначение\\n\\nЭтот файл задает правила стиля для текстового наполнения документации.\\n\\n## Правила стиля\\n\\n- Текст должен быть лаконичным.\\n- Формулировки должны быть точными и техническими.\\n- Summary должен быть кратким explain-слоем.\\n- Details должен раскрывать суть без лишней воды.\\n- Нежелательно смешивать несколько тем в одном документе.\\n- Если детали относятся к другому артефакту, их нужно выносить в отдельный документ.\\n\\n## Язык\\n\\n- Основной язык документации — русский.\\n- Технические термины, названия классов, API, RAG, OpenAPI, runtime и другие устоявшиеся identifiers можно оставлять на английском.\\n\\n## Artifact rules (api_method)\\n\\n# API Method Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для документов типа `api_method`.\\n\\n## Когда использовать\\n\\nИспользовать для описания одного HTTP endpoint или одного отдельного API метода.\\n\\n## Обязательная структура\\n\\nДокумент должен содержать:\\n- YAML frontmatter\\n- `# `\\n- `## Summary`\\n- `## Details`\\n\\nВнутри `## Details` обязательны:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\n## Особые правила\\n\\n- Сценарий оформляется как технический use case.\\n- Функциональные требования маркируются `FR-*`.\\n- Нефункциональные требования маркируются `NFR-*`.\\n- Контракт должен быть пригоден для последующей сборки OpenAPI.\\n- Если у метода есть интеграции, они выносятся в `### Интеграции`.\\n- Ошибки и HTTP-коды либо описываются в `### Ошибки`, либо ссылаются на централизованный каталог ошибок.\\n\\n## Ошибки оформления\\n\\n- Нельзя заменять контракт общим текстовым описанием.\\n- Нельзя смешивать несколько endpoint в одном документе.\\n- Нельзя хранить связи и навигацию вне frontmatter.\\n\\n## Template (api_method)\\n\\n---\\nid: api.example_method\\ntype: api_method\\ndoc_type: api_method\\nname: example_method\\ntitle: HTTP API /example\\nmodule: example_module\\nlayer: application\\ndomain: example_domain\\nsub_domain: example_subdomain\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: code\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# HTTP API /example\\n\\n## Summary\\n\\nКраткое описание метода.\\n\\n## Details\\n\\n## Описание\\n\\nКороткое описание сути метода.\\n\\n## Сценарий\\n\\n**Название:**\\n\\n**Предусловия:**\\n- \\n\\n**Триггер:**\\n- \\n\\n**Основной сценарий:**\\n1. \\n\\n**Альтернативный сценарий:**\\n1. \\n\\n**Обработка ошибок:**\\n1. \\n\\n**Постусловие:**\\n- \\n\\n## Функциональные требования\\n\\n**FR-1.**\\n\\n## Нефункциональные требования\\n\\n**NFR-1.**\\n\\n## Контракт\\n\\n### Входные параметры\\n\\n| Параметр | Где передается | Тип | Обязательность | Ограничения | Описание | Пример |\\n|---|---|---|---|---|---|---|\\n| | | | | | | |\\n\\n### Выходные параметры\\n\\n| Поле | Тип | Обязательность | Ограничения | Описание | Заполнение | Пример |\\n|---|---|---|---|---|---|---|\\n| | | | | | | |\\n\\n### Интеграции\\n\\n### Ошибки\\n\\n### Связанный код\\n\\n### История изменений\\n\\n## Section rule: api-contract\\n\\n# API Contract Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как оформлять подраздел `## Контракт` в API-документах.\\n\\n## Что должно быть описано\\n\\n- входные параметры\\n- выходные параметры\\n- JSON-структуры запросов и ответов\\n- обязательность полей\\n- типы полей\\n- ограничения\\n- описание назначения полей\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n## Правило качества\\n\\nКонтракт должен быть достаточно формальным, чтобы по нему можно было собрать OpenAPI-спецификацию.\\n\\n## Section rule: api-scenario\\n\\n# API Scenario Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как оформлять подраздел `### Сценарий` в API-документах.\\n\\n## Обязательные части\\n\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработка ошибок\\n- постусловие\\n\\n## Правила\\n\\n- Сценарий должен быть лаконичным.\\n- Сценарий должен отражать суть шага.\\n- Сложные технические детали надо выносить в `FR-*`.\\n\\n## Section rule: details\\n\\n# Details Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает общие правила для секции `## Details`.\\n\\n## Правила\\n\\n- `Details` оформляется как `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Структура Details зависит от типа документа.\\n- В Details не нужно повторно дублировать навигацию и связи, если они уже есть во frontmatter.\\n- Интеграции, ошибки и кодовые привязки должны быть выделены в отдельные подразделы, если они существенны для понимания документа.\\n\\n## Section rule: requirements-format\\n\\n# Requirements Format Rules\\n\\n## Назначение\\n\\nЭтот файл задает формат для функциональных и нефункциональных требований.\\n\\n## Функциональные требования\\n\\n- Использовать коды `FR-1`, `FR-2`, `FR-3` и так далее.\\n- Каждое требование должно описывать отдельный обязательный аспект поведения.\\n- Идентификаторы локальны в пределах одного документа.\\n\\n## Нефункциональные требования\\n\\n- Использовать коды `NFR-1`, `NFR-2`, `NFR-3` и так далее.\\n- Требования должны описывать характеристики качества, ограничения и эксплуатационные свойства.\\n\\n## Section rule: summary\\n\\n# Summary Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для секции `## Summary`.\\n\\n## Правила\\n\\n- Summary должен быть коротким explain-слоем быстрого контекста.\\n- Summary должен объяснять суть документа без лишних деталей.\\n- Summary должен быть пригоден для explain и быстрого чтения.\\n- Предпочтительный формат: список ключевых фактов `Purpose`, `Actor`, `Trigger`, `Errors`, `Related ...` и т.д.\\n- Для крупных документов допустим более длинный summary, если он остается структурированным.\"\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.changeset"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис клиентов_post_api_v1_clients_contacts_dgr.md\",\n \"reason\": \"Создание нового API-метода на основе системной аналитики.\",\n \"proposed_content\": \"---\\nid: api_method.fr2_реализовать_сервис_клиентов\\nname: fr2_реализовать_сервис_клиентов\\ntype: api_method\\ndoc_type: api_method\\ntitle: FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`\\ndomain: unknown\\nsub_domain: unknown\\nrelated_docs: []\\nstatus: draft\\nupdated_at: \\\"2023-10-10\\\"\\nparent: null\\nchildren: []\\nlinks: {}\\n---\\n\\n# FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`\\n\\n## Summary\\n\\n- **Тип**: `api_method`\\n- **ID**: `ufs.contacts_dgr.api.create`\\n- **Endpoint**: `POST /api/v1/clients/contacts-dgr`\\n- **Цель**: Создание контакта через endpoint `POST /contacts` в системе `prpb.contacts_dgr` после проверки авторизации и корректности запроса.\\n\\n## Details\\n\\n### Описание\\n\\nМетод предназначен для создания контактов в системе через вызов downstream API.\\n\\n### Сценарий\\n\\n**Название:** Создать контакт DGR\\n\\n**Предусловия:**\\n- Пользователь аутентифицирован.\\n- Заголовки запроса содержат необходимые данные.\\n\\n**Триггер:**\\n- Клиент отправляет POST-запрос на `/api/v1/clients/contacts-dgr`.\\n\\n**Основной сценарий:**\\n1. Проверяется валидность запроса согласно JSON-схеме.\\n2. Проведена проверка наличия необходимого периметра доступа CI02792632.ContactsDGR.Create.\\n3. Вызывается endpoint `POST /contacts` в `prpb.contacts_dgr` для создания контакта.\\n4. Возвращается результат операции в виде `UfsBaseResponseContactDGRCreateRsDto`.\\n\\n**Альтернативный сценарий:**\\n- В случае отсутствия необходимого периметра доступ запрещен, возвращается статус UNAUTHORIZED.\\n- При неверно сформированном запросе возвращается статус BAD_REQUEST.\\n\\n**Обработка ошибок:**\\n- HTTP-статусы 400 (BAD_REQUEST) и 401 (UNAUTHORIZED).\\n\\n**Постусловие:**\\n- Контакт успешно создан или сообщено о невозможности его создания.\\n\\n### Функциональные требования\\n\\n**FR-1.** Проверка запроса на соответствие JSON-схеме.\\n**FR-2.** Авторизация по периметру доступа CI02792632.ContactsDGR.Create.\\n**FR-3.** Вызов downstream API `POST /contacts` в системе `prpb.contacts_dgr`.\\n**FR-4.** Формирование ответа согласно контракту `ui.contacts_dgr`.\\n\\n### Нефункциональные требования\\n\\nНет специфических NFR для данного метода.\\n\\n### Контракт\\n\\n#### Входные параметры\\n\\n**headers**\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|---------------------|---------------|---------------|----------------|--------------------------|\\n| `X-Request-Id` | 1 | `uuid` | header | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | header | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | header | Табельный номер пользователя, вызвавшего сервис |\\n\\n**body**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|--------------------------|---------------|-------------------------|---------------------|\\n| contact | 1 | object | Данные контакта ДГР |\\n| contact.lastName | 0..1 | string(100) | Фамилия контакта |\\n| contact.firstName | 0..1 | string(100) | Имя контакта |\\n| contact.middleName | 0..1 | string(100) | Отчество контакта |\\n| contact.name | 0..1 | string(100) | Название группового контакта |\\n| contact.description | 0..1 | string(1000) | Описание группового контакта |\\n| contact.position | 0..1 | string(100) | Должность контакта у клиента |\\n| contact.comment | 0..1 | string(1000) | Комментарий к контакту |\\n| contact.contactType | 1 | enum(string) | Индивидуальный (`Individual`) или Групповой (`Group`) контакт |\\n| contact.crossboarding | 1 | boolean | Признак принадлежности контакта к процессу онбординга |\\n| contact.createdBy | 1 | string(8) | Табельный номер пользователя, создавшего контакт |\\n| contact.emails | 0..1 | array(object) | Массив электронных адресов контакта |\\n| contact.emails.value | 1 | string(100) | Электронный адрес контакта |\\n| contact.emails.main | 1 | boolean | Признак основной почты контакта |\\n| contact.phones | 0..1 | array(object) | Массив телефонных номеров контакта |\\n| contact.phones.value | 1 | string(20) | Телефонный номер контакта |\\n| contact.phones.extValue | 0..1 | string(10) | Внутренний добавочный номер телефона контакта |\\n| contact.phones.main | 1 | boolean | Признак основного номера телефона контакта |\\n| contact.phones.mobile | 1 | boolean | Признак мобильного телефона контакта |\\n| client | 1 | object | Данные клиента |\\n| client.ucpId | 0..1 | string(36) | Идентификатор клиента ПАО |\\n| client.sbpId | 0..1 | string(36) | Идентификатор клиента АО |\\n| client.inn | 0..1 | string(12) | ИНН клиента |\\n| client.kpp | 0..1 | string(9) | КПП клиента |\\n\\n#### Выходные параметры\\n\\n**ContactDGRCreateRsDto**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|--------------|---------------|-----------|-----------------------------|\\n| contactId | 1 | string(36)| Идентификатор созданного контакта |\\n\\n### Интеграции\\n\\nИнтеграция с системой `prpb.contacts_dgr` через endpoint `POST /contacts`.\\n\\n### Ошибки\\n\\nHTTP-коды 400 (BAD_REQUEST), 401 (UNAUTHORIZED).\\n\\n### Связанный код\\n\\nОтсутствует.\\n\\n### История изменений\\n\\n- 10-10-2023: Метод создан.\"\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "build_changeset",
+ "title": "Формирование changeset"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "changeset_items": 1,
+ "issues": 3,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "finalize",
+ "title": "Подготовка ответа"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md."
+ ]
+ },
+ "output": {
+ "answer_length": 6972,
+ "issues": 3,
+ "changeset_items": 1,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": true,
+ "answer_len": 6972,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_update.from_feature",
+ "steps": [
+ {
+ "step_id": "resolve_source",
+ "title": "Определение источника аналитики",
+ "input": {
+ "source_kind": "",
+ "source_ref": "",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "load_source",
+ "title": "Загрузка системной аналитики",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "content_loaded": true,
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "parse_feature",
+ "title": "Парсинг функциональных требований",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units": 2,
+ "issues": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "load_doc_rules",
+ "title": "Загрузка doc_rules",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "enabled": true,
+ "loaded": true,
+ "supported_doc_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "issues": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "build_change_plan",
+ "title": "Построение плана изменений",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "docs_rows": 7,
+ "planned_changes": 2,
+ "issues": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "build_changeset",
+ "title": "Формирование changeset",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "changeset_items": 1,
+ "issues": 3,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "finalize",
+ "title": "Подготовка ответа",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md."
+ ]
+ },
+ "output": {
+ "answer_length": 6972,
+ "issues": 3,
+ "changeset_items": 1,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6140,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": true,
+ "answer_len": 6972,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md."
+ ]
+ }
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_update.from_feature"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "docs_update_changeset",
+ "answer_length": 6972,
+ "changeset_items": 1,
+ "apply_changeset": true
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "DOC_UPDATE/FROM_FEATURE: результат построения changeset.\n\nОбнаружены несоответствия/нехватка данных:\n- Отсутствует domains в metadata аналитики.\n- Отсутствует subdomains в metadata аналитики.\n- LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md.\n\nПлан изменений:\n- create: docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md (ui_page)\n- create: docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md (api_method)\n\nChangeset (для плагина):\n```json\n[\n {\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md\",\n \"base_hash\": null,\n \"proposed_content\": \"---\\nid: api_method.fr2_реализовать_сервис_клиентов\\nname: fr2_реализовать_сервис_клиентов\\ntype: api_method\\ndoc_type: api_method\\ntitle: FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`\\ndomain: unknown\\nsub_domain: unknown\\nrelated_docs: []\\nstatus: draft\\nupdated_at: \\\"2023-10-10\\\"\\nparent: null\\nchildren: []\\nlinks: {}\\n---\\n\\n# FR2. Реализовать сервис CLIENTS. `POST /api/v1/clients/contacts-dgr`\\n\\n## Summary\\n\\n- **Тип**: `api_method`\\n- **ID**: `ufs.contacts_dgr.api.create`\\n- **Endpoint**: `POST /api/v1/clients/contacts-dgr`\\n- **Цель**: Создание контакта через endpoint `POST /contacts` в системе `prpb.contacts_dgr` после проверки авторизации и корректности запроса.\\n\\n## Details\\n\\n### Описание\\n\\nМетод предназначен для создания контактов в системе через вызов downstream API.\\n\\n### Сценарий\\n\\n**Название:** Создать контакт DGR\\n\\n**Предусловия:**\\n- Пользователь аутентифицирован.\\n- Заголовки запроса содержат необходимые данные.\\n\\n**Триггер:**\\n- Клиент отправляет POST-запрос на `/api/v1/clients/contacts-dgr`.\\n\\n**Основной сценарий:**\\n1. Проверяется валидность запроса согласно JSON-схеме.\\n2. Проведена проверка наличия необходимого периметра доступа CI02792632.ContactsDGR.Create.\\n3. Вызывается endpoint `POST /contacts` в `prpb.contacts_dgr` для создания контакта.\\n4. Возвращается результат операции в виде `UfsBaseResponseContactDGRCreateRsDto`.\\n\\n**Альтернативный сценарий:**\\n- В случае отсутствия необходимого периметра доступ запрещен, возвращается статус UNAUTHORIZED.\\n- При неверно сформированном запросе возвращается статус BAD_REQUEST.\\n\\n**Обработка ошибок:**\\n- HTTP-статусы 400 (BAD_REQUEST) и 401 (UNAUTHORIZED).\\n\\n**Постусловие:**\\n- Контакт успешно создан или сообщено о невозможности его создания.\\n\\n### Функциональные требования\\n\\n**FR-1.** Проверка запроса на соответствие JSON-схеме.\\n**FR-2.** Авторизация по периметру доступа CI02792632.ContactsDGR.Create.\\n**FR-3.** Вызов downstream API `POST /contacts` в системе `prpb.contacts_dgr`.\\n**FR-4.** Формирование ответа согласно контракту `ui.contacts_dgr`.\\n\\n### Нефункциональные требования\\n\\nНет специфических NFR для данного метода.\\n\\n### Контракт\\n\\n#### Входные параметры\\n\\n**headers**\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|---------------------|---------------|---------------|----------------|--------------------------|\\n| `X-Request-Id` | 1 | `uuid` | header | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | header | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | header | Табельный номер пользователя, вызвавшего сервис |\\n\\n**body**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|--------------------------|---------------|-------------------------|---------------------|\\n| contact | 1 | object | Данные контакта ДГР |\\n| contact.lastName | 0..1 | string(100) | Фамилия контакта |\\n| contact.firstName | 0..1 | string(100) | Имя контакта |\\n| contact.middleName | 0..1 | string(100) | Отчество контакта |\\n| contact.name | 0..1 | string(100) | Название группового контакта |\\n| contact.description | 0..1 | string(1000) | Описание группового контакта |\\n| contact.position | 0..1 | string(100) | Должность контакта у клиента |\\n| contact.comment | 0..1 | string(1000) | Комментарий к контакту |\\n| contact.contactType | 1 | enum(string) | Индивидуальный (`Individual`) или Групповой (`Group`) контакт |\\n| contact.crossboarding | 1 | boolean | Признак принадлежности контакта к процессу онбординга |\\n| contact.createdBy | 1 | string(8) | Табельный номер пользователя, создавшего контакт |\\n| contact.emails | 0..1 | array(object) | Массив электронных адресов контакта |\\n| contact.emails.value | 1 | string(100) | Электронный адрес контакта |\\n| contact.emails.main | 1 | boolean | Признак основной почты контакта |\\n| contact.phones | 0..1 | array(object) | Массив телефонных номеров контакта |\\n| contact.phones.value | 1 | string(20) | Телефонный номер контакта |\\n| contact.phones.extValue | 0..1 | string(10) | Внутренний добавочный номер телефона контакта |\\n| contact.phones.main | 1 | boolean | Признак основного номера телефона контакта |\\n| contact.phones.mobile | 1 | boolean | Признак мобильного телефона контакта |\\n| client | 1 | object | Данные клиента |\\n| client.ucpId | 0..1 | string(36) | Идентификатор клиента ПАО |\\n| client.sbpId | 0..1 | string(36) | Идентификатор клиента АО |\\n| client.inn | 0..1 | string(12) | ИНН клиента |\\n| client.kpp | 0..1 | string(9) | КПП клиента |\\n\\n#### Выходные параметры\\n\\n**ContactDGRCreateRsDto**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|--------------|---------------|-----------|-----------------------------|\\n| contactId | 1 | string(36)| Идентификатор созданного контакта |\\n\\n### Интеграции\\n\\nИнтеграция с системой `prpb.contacts_dgr` через endpoint `POST /contacts`.\\n\\n### Ошибки\\n\\nHTTP-коды 400 (BAD_REQUEST), 401 (UNAUTHORIZED).\\n\\n### Связанный код\\n\\nОтсутствует.\\n\\n### История изменений\\n\\n- 10-10-2023: Метод создан.\",\n \"reason\": \"Создание нового API-метода на основе системной аналитики.\",\n \"hunks\": []\n }\n]\n```\n\napply_changeset: true",
+ "completed_at": "2026-04-09T15:30:00.004857+00:00"
+}
+```
diff --git a/runtime_traces/agent_requests/20260409-153809-3f140269bb3f.md b/runtime_traces/agent_requests/20260409-153809-3f140269bb3f.md
new file mode 100644
index 0000000..7b7dae7
--- /dev/null
+++ b/runtime_traces/agent_requests/20260409-153809-3f140269bb3f.md
@@ -0,0 +1,1434 @@
+# Runtime Trace: 20260409-153809-3f140269bb3f
+
+- active_rag_session_id: 0b09b5dd-db4c-439d-81fb-3f140269bb3f
+
+## request
+```json
+{
+ "request_id": "req_10fe9cd1a1324ce49b71af6360259423",
+ "session_id": "as_198a782ca0f9428d862f28c5418bfd9e",
+ "active_rag_session_id": "0b09b5dd-db4c-439d-81fb-3f140269bb3f",
+ "process_version": "v2",
+ "created_at": "2026-04-09T15:38:09.755494+00:00",
+ "message": "Сформируй документацию по системной аналитике\n/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_UPDATE",
+ "subintent": "FROM_FEATURE",
+ "normalized_query": "Сформируй документацию по системной аналитике /Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "target_terms": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "anchors": {
+ "entity_names": [
+ "Users",
+ "Dev_projects_v2"
+ ],
+ "file_names": [
+ "process/v2/test_doc/features/create_contact.md"
+ ],
+ "endpoint_paths": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "entity",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": [
+ "API_ENDPOINT",
+ "DOMAIN_ENTITY",
+ "LOGIC_FLOW"
+ ]
+ },
+ "confidence": 0.9500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно указывает на формирование документации по системной аналитике из указанного файла create_contact.md.",
+ "rag_session_id": "0b09b5dd-db4c-439d-81fb-3f140269bb3f"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_UPDATE",
+ "subintent": "FROM_FEATURE",
+ "confidence": 0.9500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [
+ "API_ENDPOINT",
+ "DOMAIN_ENTITY",
+ "LOGIC_FLOW"
+ ],
+ "endpoint_paths": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ],
+ "matched_aliases": [],
+ "target_terms": [
+ "/users/alex/dev_projects_v2/ai"
+ ]
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ]
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_update.from_feature"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "resolve_source",
+ "title": "Определение источника аналитики"
+ },
+ "input": {
+ "source_kind": "",
+ "source_ref": "",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "load_source",
+ "title": "Загрузка системной аналитики"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "content_loaded": true,
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "parse_feature",
+ "title": "Парсинг функциональных требований"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units": 2,
+ "issues": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "load_doc_rules",
+ "title": "Загрузка doc_rules"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "enabled": true,
+ "loaded": true,
+ "supported_doc_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "issues": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.plan_change_units",
+ "system_prompt": "Ты классифицируешь units системной аналитики для построения плана изменений документации.\n\nВерни только JSON:\n{\n \"items\": [\n {\"index\": 0, \"doc_type\": \"api_method\", \"reason\": \"...\"}\n ]\n}\n\nПравила:\n- Используй только doc_type из allowed_doc_types.\n- Не пропускай item, даже если не уверен: выбери наиболее близкий тип.\n- Ориентируйся на heading и snippet.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"system_rules\": \"Системные правила документации:\\n1. Один устойчивый объект — один документ.\\n2. Документы не должны дублировать друг друга по смыслу.\\n3. Связи между документами должны быть явными (related_docs/links).\\n4. Документация организована иерархически по папкам docs/*.\\n5. Markdown-документ состоит из YAML frontmatter и body.\\n6. Обязательные поля frontmatter: id, title, doc_type, related_docs, status, domain, sub_domain.\",\n \"allowed_doc_types\": [\n \"ui_page\",\n \"api_method\",\n \"logic_block\",\n \"architecture_overview\",\n \"integration_doc\",\n \"domain_entity\",\n \"glossary_item\",\n \"index_page\"\n ],\n \"items\": [\n {\n \"index\": 0,\n \"heading\": \"FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\",\n \"snippet\": \"- type: ui_page\\n- id: ui.contacts_dgr.create\\n\\nОсновной сценарий:\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- ui.contacts_dgr вызывает endpoint POST /api/v1/clients/contacts-dgr для создания карточки контакта ДГР.\\n- ufs.contacts_dgr обрабатывает запрос и возвращает ответ.\\n- ui.contacts_dgr отображает результат создания контакта ДГР в виде push-уведомления.\"\n },\n {\n \"index\": 1,\n \"heading\": \"FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\",\n \"snippet\": \"- type: api_method\\n- id: ufs.contacts_dgr.api.create\\n- endpoint: POST /api/v1/clients/contacts-dgr\\n\\nТребования для основного сценария:\\n- Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом BAD_REQUEST.\\n- Авторизовать запрос по наличию периметра CI02792632.ContactsDGR.Create. При отсутствии периметра завершить основной сценарий с кодом UNAUTHORIZED.\\n- Для и\"\n }\n ]\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.plan"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"items\": [\n {\"index\": 0, \"doc_type\": \"ui_page\"},\n {\"index\": 1, \"doc_type\": \"api_method\"}\n ]\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "build_change_plan",
+ "title": "Построение плана изменений"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "docs_rows": 7,
+ "planned_changes": 2,
+ "issues": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "changeset_prompt_built",
+ "doc_type": "ui_page",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "prompt_chars": 11064,
+ "rules_chars": 9572
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.build_doc_changeset",
+ "system_prompt": "Ты формируешь один item changeset для документации на основе системной аналитики и правил doc_rules.\n\nВерни только JSON-объект формата:\n{\n \"op\": \"create|update|delete\",\n \"path\": \"docs/...\",\n \"reason\": \"краткая причина\",\n \"proposed_content\": \"полный markdown документа для create/update\"\n}\n\nПравила:\n- Строго соблюдай структуру и ограничения из doc_rules_context.\n- Для create/update верни полный итоговый markdown (frontmatter + body).\n- Для update не используй placeholder-тексты; возвращай пригодный к сохранению документ.\n- reason обязателен, короткий, по сути изменения.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"change_request\": {\n \"op\": \"create\",\n \"path\": \"docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md\",\n \"doc_type\": \"ui_page\",\n \"doc_id\": \"ui_page.fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр\",\n \"title\": \"FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\",\n \"domain\": \"unknown\",\n \"sub_domain\": \"unknown\",\n \"reason\": \"Из unit 'FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»' системной аналитики (test).\",\n \"source_refs\": [\n \"section: 5. Функциональные требования\"\n ],\n \"related_docs\": [],\n \"requirement_body\": \"- type: ui_page\\n- id: ui.contacts_dgr.create\\n\\nОсновной сценарий:\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- ui.contacts_dgr вызывает endpoint POST /api/v1/clients/contacts-dgr для создания карточки контакта ДГР.\\n- ufs.contacts_dgr обрабатывает запрос и возвращает ответ.\\n- ui.contacts_dgr отображает результат создания контакта ДГР в виде push-уведомления.\"\n },\n \"doc_rules_context\": \"## Global rules\\n\\n### documentation-rules.md\\n\\n# Documentation Rules\\n\\nЭтот каталог оформляет MVP документации проекта в атомарном формате.\\n\\n## Базовая структура\\n\\n- Каждый документ содержит YAML frontmatter.\\n- В документе должен быть один `H1`, совпадающий с `title`.\\n- Основные разделы оформляются как `## Summary` и `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Связи, сущности и навигация описываются во frontmatter через `related_docs`, `links`, `entities`, `parent`, `children`.\\n\\n## Summary\\n\\n- Краткий explain-слой быстрого контекста.\\n- Должен позволять быстро понять назначение документа без чтения `Details`.\\n- Предпочтительный формат: компактный список ключевых фактов без длинных абзацев.\\n\\n## Details\\n\\n- Раскрывает полное описание объекта.\\n- Структура `Details` зависит от типа документа.\\n- Сценарии, ограничения, интеграции, ошибки и кодовые привязки должны быть разнесены по отдельным подразделам.\\n\\n## API documents\\n\\nДля `api_method` внутри `## Details` обязательны разделы:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\nЕсли у метода есть интеграции и ошибки, также обязательны:\\n- `### Интеграции`\\n- `### Ошибки`\\n- `### Связанный код`\\n- `### История изменений`\\n\\n### Сценарий\\n\\nСценарий оформляется как технический use case и содержит:\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработку ошибок\\n- постусловие\\n\\n### Требования\\n\\n- Функциональные требования маркируются как `FR-1`, `FR-2`, ...\\n- Нефункциональные требования маркируются как `NFR-1`, `NFR-2`, ...\\n- Идентификаторы требований локальны в рамках одного документа.\\n\\n### Контракт\\n\\nКонтракт должен быть пригоден для последующей сборки OpenAPI-спецификации и включать:\\n- входные параметры\\n- выходные параметры\\n- структуру JSON-сообщений\\n- обязательность полей\\n- типы и ограничения\\n- описание полей\\n- правила заполнения\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n### global/documentation-system.md\\n\\n# Documentation System\\n\\n## Назначение\\n\\nЭтот файл задает общую модель документации проекта.\\n\\n## Базовая модель\\n\\nКаждый документ должен состоять из двух слоев:\\n- YAML frontmatter\\n- контент\\n\\nКонтент всегда состоит из двух обязательных разделов:\\n- `## Summary`\\n- `## Details`\\n\\nНад ними должен быть один заголовок `# `, совпадающий со значением `title` во frontmatter.\\n\\n## Принципы\\n\\n- Документы должны быть атомарными.\\n- Один документ описывает одну тему.\\n- Вместо дублирования между документами используются явные ссылки.\\n- Связи и навигация должны быть формализованы.\\n- Документы должны быть пригодны для чтения человеком и для RAG.\\n- Документы должны быть пригодны для частичного обновления без деградации структуры.\\n\\n## Типы документов\\n\\nНа уровне проекта поддерживаются типы:\\n- `api_method`\\n- `logic_block`\\n- `architecture_overview`\\n- `domain_entity`\\n- `ui_page`\\n- `integration_doc`\\n- `index_page`\\n- `glossary_item`\\n\\n### global/frontmatter.md\\n\\n# Frontmatter Rules\\n\\n## Назначение\\n\\nЭтот файл описывает единый контракт YAML frontmatter для всех документов.\\n\\n## Обязательные поля\\n\\n```yaml\\nid: string\\ntitle: string\\ndoc_type: string\\ndomain: string\\nsub_domain: string\\nrelated_docs: []\\nstatus: string\\n```\\n\\n## Поля совместимости и рекомендуемые поля\\n\\n```yaml\\ntype: string\\nname: string\\nmodule: string\\nlayer: string\\nupdated_at: YYYY-MM-DD\\ntags: []\\nentities: []\\nparent: string | null\\nchildren: []\\nlinks: {}\\nsource_of_truth: string\\nrelated_code: []\\nsystem_analytics_refs: []\\n```\\n\\n## Правила\\n\\n- `id` должен быть стабильным и уникальным в пределах документации проекта.\\n- `title` — человекочитаемый заголовок.\\n- `doc_type` — канонический тип документа.\\n- `domain` и `sub_domain` определяют бизнес-контекст документа.\\n- `related_docs` хранит явные связи с другими markdown-документами.\\n- `status` хранит жизненный цикл документа: например `draft`, `approved`, `active`.\\n- `type` допустимо дублировать как alias для tooling-совместимости с индексаторами.\\n- `name` — короткое системное имя документа.\\n- `module` — модуль или подсистема.\\n- `layer` — слой системы.\\n- `updated_at` хранится в формате `YYYY-MM-DD`.\\n\\n## Связи и навигация\\n\\n- `entities` описывает сущности, связанные с документом.\\n- `parent` и `children` описывают иерархию.\\n- `links` описывает typed graph связей между документами, кодом и интеграциями.\\n\\n## Формат links\\n\\n```yaml\\nlinks:\\n called_by:\\n - ext.health_probe\\n uses_logic:\\n - logic.some_flow\\n integrates_with:\\n - ext.some_system\\n```\\n\\n### global/linking.md\\n\\n# Linking Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как связывать документы между собой.\\n\\n## Иерархия\\n\\n- `parent` используется для родительского документа.\\n- `children` используется для прямых дочерних документов.\\n- Иерархия должна быть осмысленной и стабильной.\\n- Для общей точки входа допустим `index_page`.\\n\\n## Графовые связи\\n\\nДля `related_docs` используются ссылки на соседние документы.\\n\\nДля `links` рекомендуется использовать typed-ключи:\\n- `called_by`\\n- `uses_logic`\\n- `reads_db`\\n- `writes_db`\\n- `integrates_with`\\n- `used_by`\\n- `exposes_api`\\n- `uses_entities`\\n\\n## Правила использования\\n\\n- Если документ логически входит в другой, использовать `parent`/`children`.\\n- Если связь нужна для навигации между равноправными документами, дублировать ее в `related_docs`.\\n- Если связь отражает поведение, интеграции или переиспользование, фиксировать ее в `links`.\\n- Детальное описание интеграций хранить в body документа, а не только во frontmatter.\\n\\n### global/naming.md\\n\\n# Naming Rules\\n\\n## Назначение\\n\\nЭтот файл описывает правила именования документов, файлов и идентификаторов.\\n\\n## Правила для файлов\\n\\n- Имена файлов должны быть в kebab-case.\\n- Имя файла должно отражать одну тему.\\n- Для шаблонов использовать суффикс `.template.md`.\\n\\n## Правила для id\\n\\n- `id` строится в формате `.`.\\n- Примеры:\\n - `api.send_message_endpoint`\\n - `logic.telegram_notification_loop`\\n - `architecture.telegram_notify_app`\\n\\n## Правила для title\\n\\n- `title` должен быть кратким и человекочитаемым.\\n- В `title` допускаются пробелы и естественный язык.\\n\\n### global/writing-style.md\\n\\n# Writing Style\\n\\n## Назначение\\n\\nЭтот файл задает правила стиля для текстового наполнения документации.\\n\\n## Правила стиля\\n\\n- Текст должен быть лаконичным.\\n- Формулировки должны быть точными и техническими.\\n- Summary должен быть кратким explain-слоем.\\n- Details должен раскрывать суть без лишней воды.\\n- Нежелательно смешивать несколько тем в одном документе.\\n- Если детали относятся к другому артефакту, их нужно выносить в отдельный документ.\\n\\n## Язык\\n\\n- Основной язык документации — русский.\\n- Технические термины, названия классов, API, RAG, OpenAPI, runtime и другие устоявшиеся identifiers можно оставлять на английском.\\n\\n## Artifact rules (ui_page)\\n\\n# UI Page Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для документов типа `ui_page`.\\n\\n## Когда использовать\\n\\nИспользовать для описания одной пользовательской страницы, экрана или отдельного UI-сценария.\\n\\n## Обязательная структура\\n\\nДокумент должен содержать:\\n- YAML frontmatter\\n- `# `\\n- `## Summary`\\n- `## Details`\\n\\n## Что описывать в Details\\n\\n- назначение страницы\\n- пользовательский сценарий\\n- основные блоки интерфейса\\n- связанные API и сущности\\n\\n## Template (ui_page)\\n\\n---\\nid: ui.example_page\\ntype: ui_page\\ndoc_type: ui_page\\nname: example_page\\ntitle: Пример UI-страницы\\nmodule: example_module\\nlayer: presentation\\ndomain: example_domain\\nsub_domain: example_subdomain\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: mixed\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# Пример UI-страницы\\n\\n## Summary\\n\\nКраткое описание страницы и её назначения.\\n\\n## Details\\n\\n### Назначение страницы\\n\\n### Пользовательский сценарий\\n\\n### Основные блоки интерфейса\\n\\n### Связанные API и сущности\\n\\n### Функциональные требования\\n\\n### Нефункциональные требования\\n\\n### Ограничения и граничные случаи\\n\\n### Ошибки и валидации\\n\\n### Связанный код\\n\\n### Связанные документы\\n\\n### История изменений\\n\\n## Section rule: details\\n\\n# Details Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает общие правила для секции `## Details`.\\n\\n## Правила\\n\\n- `Details` оформляется как `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Структура Details зависит от типа документа.\\n- В Details не нужно повторно дублировать навигацию и связи, если они уже есть во frontmatter.\\n- Интеграции, ошибки и кодовые привязки должны быть выделены в отдельные подразделы, если они существенны для понимания документа.\\n\\n## Section rule: requirements-format\\n\\n# Requirements Format Rules\\n\\n## Назначение\\n\\nЭтот файл задает формат для функциональных и нефункциональных требований.\\n\\n## Функциональные требования\\n\\n- Использовать коды `FR-1`, `FR-2`, `FR-3` и так далее.\\n- Каждое требование должно описывать отдельный обязательный аспект поведения.\\n- Идентификаторы локальны в пределах одного документа.\\n\\n## Нефункциональные требования\\n\\n- Использовать коды `NFR-1`, `NFR-2`, `NFR-3` и так далее.\\n- Требования должны описывать характеристики качества, ограничения и эксплуатационные свойства.\\n\\n## Section rule: summary\\n\\n# Summary Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для секции `## Summary`.\\n\\n## Правила\\n\\n- Summary должен быть коротким explain-слоем быстрого контекста.\\n- Summary должен объяснять суть документа без лишних деталей.\\n- Summary должен быть пригоден для explain и быстрого чтения.\\n- Предпочтительный формат: список ключевых фактов `Purpose`, `Actor`, `Trigger`, `Errors`, `Related ...` и т.д.\\n- Для крупных документов допустим более длинный summary, если он остается структурированным.\"\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.changeset"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"op\": \"create\",\n \"path\": \"docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md\",\n \"reason\": \"Создание нового UI сценария согласно системной аналитике.\",\n \"proposed_content\": \"---\\nid: ui_page.fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр\\ntype: ui_page\\ndoc_type: ui_page\\ntitle: FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР\\\"\\ndomain: unknown\\nsub_domain: unknown\\nrelated_docs: []\\nstatus: draft\\nupdated_at: \\\"\\\"\\nsource_of_truth: mixed\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\n\n## Summary\n\n- **Назначение**: Реализация UI сценария добавления новой карточки контакта ДГР.\n- **Пользователь**: Не указан.\n- **Триггер**: Заполнение формы и нажатие кнопки «Добавить».\n- **Связанные компоненты**: API `/api/v1/clients/contacts-dgr`.\n\n## Details\n\n### Назначение страницы\n\nРеализует функционал создания новой карточки контакта ДГР через интерфейс пользователя.\n\n### Пользовательский сценарий\n\n- Пользователь заполняет необходимые атрибуты карточки и нажимает кнопку «Добавить».\n- Интерфейс отправляет POST-запрос на endpoint `/api/v1/clients/contacts-dgr`.\n- После обработки запроса возвращается ответ о результате операции.\n- Результат отображается пользователю в виде push-уведомления.\n\n### Основные блоки интерфейса\n\nНе указаны.\n\n### Связанные API и сущности\n\n- **API**: `/api/v1/clients/contacts-dgr` (POST)\n- **UI блок**: `ui.contacts_dgr`\n- **UFS блок**: `ufs.contacts_dgr`\n\n### Функциональные требования\n\n- **FR-1**: Реализован корректный вызов API `/api/v1/clients/contacts-dgr` при добавлении новой карточки контакта ДГР.\n\n### Нефункциональные требования\n\nНе определены.\n\n### Ограничения и граничные случаи\n\nНе описаны.\n\n### Ошибки и валидации\n\nНе детализировано.\n\n### Связанный код\n\nНе предоставлен.\n\n### Связанные документы\n\nНе указано.\n\n### История изменений\n\nНе заполнено.\"\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "changeset_prompt_built",
+ "doc_type": "api_method",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "prompt_chars": 15658,
+ "rules_chars": 11520
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.build_doc_changeset",
+ "system_prompt": "Ты формируешь один item changeset для документации на основе системной аналитики и правил doc_rules.\n\nВерни только JSON-объект формата:\n{\n \"op\": \"create|update|delete\",\n \"path\": \"docs/...\",\n \"reason\": \"краткая причина\",\n \"proposed_content\": \"полный markdown документа для create/update\"\n}\n\nПравила:\n- Строго соблюдай структуру и ограничения из doc_rules_context.\n- Для create/update верни полный итоговый markdown (frontmatter + body).\n- Для update не используй placeholder-тексты; возвращай пригодный к сохранению документ.\n- reason обязателен, короткий, по сути изменения.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"change_request\": {\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md\",\n \"doc_type\": \"api_method\",\n \"doc_id\": \"api_method.fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr\",\n \"title\": \"FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\",\n \"domain\": \"unknown\",\n \"sub_domain\": \"unknown\",\n \"reason\": \"Из unit 'FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr' системной аналитики (test).\",\n \"source_refs\": [\n \"section: 5. Функциональные требования\"\n ],\n \"related_docs\": [],\n \"requirement_body\": \"- type: api_method\\n- id: ufs.contacts_dgr.api.create\\n- endpoint: POST /api/v1/clients/contacts-dgr\\n\\nТребования для основного сценария:\\n- Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом BAD_REQUEST.\\n- Авторизовать запрос по наличию периметра CI02792632.ContactsDGR.Create. При отсутствии периметра завершить основной сценарий с кодом UNAUTHORIZED.\\n- Для исполнения запроса на создание контакта вызвать endpoint POST /contacts в prpb.contacts_dgr.\\n- Вернуть ответ ui.contacts_dgr в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\nКонтракт POST /contacts\\n\\nЗапрос\\n\\n**headers**\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|---|---|---|---|---|\\n| `X-Request-Id` | 1 | `uuid` | `header` | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | `header` | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | `header` | Табельный номер пользователя, вызвавшего сервис |\\n\\n**body**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contact` | 1 | `object` | Данные контакта ДГР |\\n| `contact.lastName` | 0..1 | `string(100)` | Фамилия контакта |\\n| `contact.firstName` | 0..1 | `string(100)` | Имя контакта |\\n| `contact.middleName` | 0..1 | `string(100)` | Отчество контакта |\\n| `contact.name` | 0..1 | `string(100)` | Название группового контакта |\\n| `contact.description` | 0..1 | `string(1000)` | Описание группового контакта |\\n| `contact.position` | 0..1 | `string(100)` | Должность контакта у клиента |\\n| `contact.comment` | 0..1 | `string(1000)` | Комментарий к контакту |\\n| `contact.contactType` | 1 | `enum(string)` | `Individual`, `Group` |\\n| `contact.crossboarding` | 1 | `boolean` | Признак принадлежности контакта к процессу онбординга |\\n| `contact.createdBy` | 1 | `string(8)` | Табельный номер пользователя, создавшего контакт |\\n| `contact.emails` | 0..1 | `array(object)` | Массив электронных адресов контакта |\\n| `contact.emails.value` | 1 | `string(100)` | Электронный адрес |\\n| `contact.emails.main` | 1 | `boolean` | Признак основной почты |\\n| `contact.phones` | 0..1 | `array(object)` | Массив телефонных номеров контакта |\\n| `contact.phones.value` | 1 | `string(20)` | Телефонный номер контакта |\\n| `contact.phones.extValue` | 0..1 | `string(10)` | Добавочный номер |\\n| `contact.phones.main` | 1 | `boolean` | Признак основного телефона |\\n| `contact.phones.mobile` | 1 | `boolean` | Признак мобильного телефона |\\n| `client` | 1 | `object` | Данные клиента |\\n| `client.ucpId` | 0..1 | `string(36)` | Идентификатор клиента ПАО |\\n| `client.sbpId` | 0..1 | `string(36)` | Идентификатор клиента АО |\\n| `client.inn` | 0..1 | `string(12)` | ИНН клиента |\\n| `client.kpp` | 0..1 | `string(9)` | КПП клиента |\\n\\nОтвет\\n\\n**ContactDGRCreateRsDto**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contactId` | 1 | `string(36)` | Идентификатор контакта |\"\n },\n \"doc_rules_context\": \"## Global rules\\n\\n### documentation-rules.md\\n\\n# Documentation Rules\\n\\nЭтот каталог оформляет MVP документации проекта в атомарном формате.\\n\\n## Базовая структура\\n\\n- Каждый документ содержит YAML frontmatter.\\n- В документе должен быть один `H1`, совпадающий с `title`.\\n- Основные разделы оформляются как `## Summary` и `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Связи, сущности и навигация описываются во frontmatter через `related_docs`, `links`, `entities`, `parent`, `children`.\\n\\n## Summary\\n\\n- Краткий explain-слой быстрого контекста.\\n- Должен позволять быстро понять назначение документа без чтения `Details`.\\n- Предпочтительный формат: компактный список ключевых фактов без длинных абзацев.\\n\\n## Details\\n\\n- Раскрывает полное описание объекта.\\n- Структура `Details` зависит от типа документа.\\n- Сценарии, ограничения, интеграции, ошибки и кодовые привязки должны быть разнесены по отдельным подразделам.\\n\\n## API documents\\n\\nДля `api_method` внутри `## Details` обязательны разделы:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\nЕсли у метода есть интеграции и ошибки, также обязательны:\\n- `### Интеграции`\\n- `### Ошибки`\\n- `### Связанный код`\\n- `### История изменений`\\n\\n### Сценарий\\n\\nСценарий оформляется как технический use case и содержит:\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработку ошибок\\n- постусловие\\n\\n### Требования\\n\\n- Функциональные требования маркируются как `FR-1`, `FR-2`, ...\\n- Нефункциональные требования маркируются как `NFR-1`, `NFR-2`, ...\\n- Идентификаторы требований локальны в рамках одного документа.\\n\\n### Контракт\\n\\nКонтракт должен быть пригоден для последующей сборки OpenAPI-спецификации и включать:\\n- входные параметры\\n- выходные параметры\\n- структуру JSON-сообщений\\n- обязательность полей\\n- типы и ограничения\\n- описание полей\\n- правила заполнения\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n### global/documentation-system.md\\n\\n# Documentation System\\n\\n## Назначение\\n\\nЭтот файл задает общую модель документации проекта.\\n\\n## Базовая модель\\n\\nКаждый документ должен состоять из двух слоев:\\n- YAML frontmatter\\n- контент\\n\\nКонтент всегда состоит из двух обязательных разделов:\\n- `## Summary`\\n- `## Details`\\n\\nНад ними должен быть один заголовок `# `, совпадающий со значением `title` во frontmatter.\\n\\n## Принципы\\n\\n- Документы должны быть атомарными.\\n- Один документ описывает одну тему.\\n- Вместо дублирования между документами используются явные ссылки.\\n- Связи и навигация должны быть формализованы.\\n- Документы должны быть пригодны для чтения человеком и для RAG.\\n- Документы должны быть пригодны для частичного обновления без деградации структуры.\\n\\n## Типы документов\\n\\nНа уровне проекта поддерживаются типы:\\n- `api_method`\\n- `logic_block`\\n- `architecture_overview`\\n- `domain_entity`\\n- `ui_page`\\n- `integration_doc`\\n- `index_page`\\n- `glossary_item`\\n\\n### global/frontmatter.md\\n\\n# Frontmatter Rules\\n\\n## Назначение\\n\\nЭтот файл описывает единый контракт YAML frontmatter для всех документов.\\n\\n## Обязательные поля\\n\\n```yaml\\nid: string\\ntitle: string\\ndoc_type: string\\ndomain: string\\nsub_domain: string\\nrelated_docs: []\\nstatus: string\\n```\\n\\n## Поля совместимости и рекомендуемые поля\\n\\n```yaml\\ntype: string\\nname: string\\nmodule: string\\nlayer: string\\nupdated_at: YYYY-MM-DD\\ntags: []\\nentities: []\\nparent: string | null\\nchildren: []\\nlinks: {}\\nsource_of_truth: string\\nrelated_code: []\\nsystem_analytics_refs: []\\n```\\n\\n## Правила\\n\\n- `id` должен быть стабильным и уникальным в пределах документации проекта.\\n- `title` — человекочитаемый заголовок.\\n- `doc_type` — канонический тип документа.\\n- `domain` и `sub_domain` определяют бизнес-контекст документа.\\n- `related_docs` хранит явные связи с другими markdown-документами.\\n- `status` хранит жизненный цикл документа: например `draft`, `approved`, `active`.\\n- `type` допустимо дублировать как alias для tooling-совместимости с индексаторами.\\n- `name` — короткое системное имя документа.\\n- `module` — модуль или подсистема.\\n- `layer` — слой системы.\\n- `updated_at` хранится в формате `YYYY-MM-DD`.\\n\\n## Связи и навигация\\n\\n- `entities` описывает сущности, связанные с документом.\\n- `parent` и `children` описывают иерархию.\\n- `links` описывает typed graph связей между документами, кодом и интеграциями.\\n\\n## Формат links\\n\\n```yaml\\nlinks:\\n called_by:\\n - ext.health_probe\\n uses_logic:\\n - logic.some_flow\\n integrates_with:\\n - ext.some_system\\n```\\n\\n### global/linking.md\\n\\n# Linking Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как связывать документы между собой.\\n\\n## Иерархия\\n\\n- `parent` используется для родительского документа.\\n- `children` используется для прямых дочерних документов.\\n- Иерархия должна быть осмысленной и стабильной.\\n- Для общей точки входа допустим `index_page`.\\n\\n## Графовые связи\\n\\nДля `related_docs` используются ссылки на соседние документы.\\n\\nДля `links` рекомендуется использовать typed-ключи:\\n- `called_by`\\n- `uses_logic`\\n- `reads_db`\\n- `writes_db`\\n- `integrates_with`\\n- `used_by`\\n- `exposes_api`\\n- `uses_entities`\\n\\n## Правила использования\\n\\n- Если документ логически входит в другой, использовать `parent`/`children`.\\n- Если связь нужна для навигации между равноправными документами, дублировать ее в `related_docs`.\\n- Если связь отражает поведение, интеграции или переиспользование, фиксировать ее в `links`.\\n- Детальное описание интеграций хранить в body документа, а не только во frontmatter.\\n\\n### global/naming.md\\n\\n# Naming Rules\\n\\n## Назначение\\n\\nЭтот файл описывает правила именования документов, файлов и идентификаторов.\\n\\n## Правила для файлов\\n\\n- Имена файлов должны быть в kebab-case.\\n- Имя файла должно отражать одну тему.\\n- Для шаблонов использовать суффикс `.template.md`.\\n\\n## Правила для id\\n\\n- `id` строится в формате `.`.\\n- Примеры:\\n - `api.send_message_endpoint`\\n - `logic.telegram_notification_loop`\\n - `architecture.telegram_notify_app`\\n\\n## Правила для title\\n\\n- `title` должен быть кратким и человекочитаемым.\\n- В `title` допускаются пробелы и естественный язык.\\n\\n### global/writing-style.md\\n\\n# Writing Style\\n\\n## Назначение\\n\\nЭтот файл задает правила стиля для текстового наполнения документации.\\n\\n## Правила стиля\\n\\n- Текст должен быть лаконичным.\\n- Формулировки должны быть точными и техническими.\\n- Summary должен быть кратким explain-слоем.\\n- Details должен раскрывать суть без лишней воды.\\n- Нежелательно смешивать несколько тем в одном документе.\\n- Если детали относятся к другому артефакту, их нужно выносить в отдельный документ.\\n\\n## Язык\\n\\n- Основной язык документации — русский.\\n- Технические термины, названия классов, API, RAG, OpenAPI, runtime и другие устоявшиеся identifiers можно оставлять на английском.\\n\\n## Artifact rules (api_method)\\n\\n# API Method Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для документов типа `api_method`.\\n\\n## Когда использовать\\n\\nИспользовать для описания одного HTTP endpoint или одного отдельного API метода.\\n\\n## Обязательная структура\\n\\nДокумент должен содержать:\\n- YAML frontmatter\\n- `# `\\n- `## Summary`\\n- `## Details`\\n\\nВнутри `## Details` обязательны:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\n## Особые правила\\n\\n- Сценарий оформляется как технический use case.\\n- Функциональные требования маркируются `FR-*`.\\n- Нефункциональные требования маркируются `NFR-*`.\\n- Контракт должен быть пригоден для последующей сборки OpenAPI.\\n- Если у метода есть интеграции, они выносятся в `### Интеграции`.\\n- Ошибки и HTTP-коды либо описываются в `### Ошибки`, либо ссылаются на централизованный каталог ошибок.\\n\\n## Ошибки оформления\\n\\n- Нельзя заменять контракт общим текстовым описанием.\\n- Нельзя смешивать несколько endpoint в одном документе.\\n- Нельзя хранить связи и навигацию вне frontmatter.\\n\\n## Template (api_method)\\n\\n---\\nid: api.example_method\\ntype: api_method\\ndoc_type: api_method\\nname: example_method\\ntitle: HTTP API /example\\nmodule: example_module\\nlayer: application\\ndomain: example_domain\\nsub_domain: example_subdomain\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: code\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# HTTP API /example\\n\\n## Summary\\n\\nКраткое описание метода.\\n\\n## Details\\n\\n## Описание\\n\\nКороткое описание сути метода.\\n\\n## Сценарий\\n\\n**Название:**\\n\\n**Предусловия:**\\n- \\n\\n**Триггер:**\\n- \\n\\n**Основной сценарий:**\\n1. \\n\\n**Альтернативный сценарий:**\\n1. \\n\\n**Обработка ошибок:**\\n1. \\n\\n**Постусловие:**\\n- \\n\\n## Функциональные требования\\n\\n**FR-1.**\\n\\n## Нефункциональные требования\\n\\n**NFR-1.**\\n\\n## Контракт\\n\\n### Входные параметры\\n\\n| Параметр | Где передается | Тип | Обязательность | Ограничения | Описание | Пример |\\n|---|---|---|---|---|---|---|\\n| | | | | | | |\\n\\n### Выходные параметры\\n\\n| Поле | Тип | Обязательность | Ограничения | Описание | Заполнение | Пример |\\n|---|---|---|---|---|---|---|\\n| | | | | | | |\\n\\n### Интеграции\\n\\n### Ошибки\\n\\n### Связанный код\\n\\n### История изменений\\n\\n## Section rule: api-contract\\n\\n# API Contract Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как оформлять подраздел `## Контракт` в API-документах.\\n\\n## Что должно быть описано\\n\\n- входные параметры\\n- выходные параметры\\n- JSON-структуры запросов и ответов\\n- обязательность полей\\n- типы полей\\n- ограничения\\n- описание назначения полей\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n## Правило качества\\n\\nКонтракт должен быть достаточно формальным, чтобы по нему можно было собрать OpenAPI-спецификацию.\\n\\n## Section rule: api-scenario\\n\\n# API Scenario Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как оформлять подраздел `### Сценарий` в API-документах.\\n\\n## Обязательные части\\n\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработка ошибок\\n- постусловие\\n\\n## Правила\\n\\n- Сценарий должен быть лаконичным.\\n- Сценарий должен отражать суть шага.\\n- Сложные технические детали надо выносить в `FR-*`.\\n\\n## Section rule: details\\n\\n# Details Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает общие правила для секции `## Details`.\\n\\n## Правила\\n\\n- `Details` оформляется как `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Структура Details зависит от типа документа.\\n- В Details не нужно повторно дублировать навигацию и связи, если они уже есть во frontmatter.\\n- Интеграции, ошибки и кодовые привязки должны быть выделены в отдельные подразделы, если они существенны для понимания документа.\\n\\n## Section rule: requirements-format\\n\\n# Requirements Format Rules\\n\\n## Назначение\\n\\nЭтот файл задает формат для функциональных и нефункциональных требований.\\n\\n## Функциональные требования\\n\\n- Использовать коды `FR-1`, `FR-2`, `FR-3` и так далее.\\n- Каждое требование должно описывать отдельный обязательный аспект поведения.\\n- Идентификаторы локальны в пределах одного документа.\\n\\n## Нефункциональные требования\\n\\n- Использовать коды `NFR-1`, `NFR-2`, `NFR-3` и так далее.\\n- Требования должны описывать характеристики качества, ограничения и эксплуатационные свойства.\\n\\n## Section rule: summary\\n\\n# Summary Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для секции `## Summary`.\\n\\n## Правила\\n\\n- Summary должен быть коротким explain-слоем быстрого контекста.\\n- Summary должен объяснять суть документа без лишних деталей.\\n- Summary должен быть пригоден для explain и быстрого чтения.\\n- Предпочтительный формат: список ключевых фактов `Purpose`, `Actor`, `Trigger`, `Errors`, `Related ...` и т.д.\\n- Для крупных документов допустим более длинный summary, если он остается структурированным.\"\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.changeset"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис_клиентов_post_api_v1_clients_contacts_dgr.md\",\n \"reason\": \"Создание нового API-метода FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr из системной аналитики.\",\n \"proposed_content\": \"---\\nid: api_method.fr2_реализовать_сервис_клиентов\\nname: fr2_реализовать_сервис_клиентов\\ntype: api_method\\ndoc_type: api_method\\ntitle: FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\\ndomain: unknown\\nsub_domain: unknown\\nrelated_docs: []\\nstatus: draft\\nupdated_at: '2023-10-10'\\nparent: null\\nchildren: []\\nlinks: {}\\n---\\n\\n# FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\\n\\n## Summary\\n\\n- **Цель**: Создание нового контакта ДГР через API.\\n- **Актор**: Внешний клиент.\\n- **Ошибка**: BAD_REQUEST при неверном JSON, UNAUTHORIZED при отсутствии авторизации.\\n- **Интеграция**: Вызов endpoint POST /contacts в prpb.contacts_dgr.\\n\\n## Details\\n\\n## Описание\\n\\nМетод позволяет создавать новый контакт ДГР в системе CLIENTS через POST-запрос к `/api/v1/clients/contacts-dgr`.\\n\\n## Сценарий\\n\\n**Название:** Создать контакт ДГР\\n\\n**Предусловия:**\\n- Клиент аутентифицирован.\\n\\n**Триггер:**\\n- Отправка POST-запроса к `/api/v1/clients/contacts-dgr`.\\n\\n**Основной сценарий:**\\n1. Проверяется валидность JSON-запроса.\\n2. Проведение авторизации.\\n3. Вызов backend-сервису для создания контакта.\\n4. Возвращение ответа.\\n\\n**Альтернативный сценарий:**\\n- Возврат ошибки при неудачной проверке JSON или отсутствии авторизации.\\n\\n**Обработка ошибок:**\\n- HTTP-код 400 при ошибке валидации JSON.\\n- HTTP-код 401 при отсутствии необходимых прав доступа.\\n\\n**Постусловие:**\\n- Контакт успешно создан или возвращена соответствующая ошибка.\\n\\n## Функциональные требования\\n\\n**FR-1.** Проверка входящего запроса на соответствие JSON-схеме.\\n**FR-2.** Авторизация по периметру CI02792632.ContactsDGR.Create.\\n**FR-3.** Вызов endpoint POST /contacts в prpb.contacts_dgr.\\n**FR-4.** Возвращение ответа в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\n## Нефункциональные требования\\n\\n(не указаны)\\n\\n## Контракт\\n\\n### Входные параметры\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|------------------------|---------------|----------------|----------------|------------------------------------|\\n| `X-Request-Id` | 1 | `uuid` | header | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | header | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | header | Табельный номер пользователя |\\n| `contact` | 1 | object | body | Данные контакта ДГР |\\n| `contact.lastName` | 0..1 | `string(100)` | body | Фамилия контакта |\\n| `contact.firstName` | 0..1 | `string(100)` | body | Имя контакта |\\n| `contact.middleName` | 0..1 | `string(100)` | body | Отчество контакта |\\n| `contact.name` | 0..1 | `string(100)` | body | Название группового контакта |\\n| `contact.description` | 0..1 | `string(1000)` | body | Описание группового контакта |\\n| `contact.position` | 0..1 | `string(100)` | body | Должность контакта |\\n| `contact.comment` | 0..1 | `string(1000)` | body | Комментарий к контакту |\\n| `contact.contactType` | 1 | enum(string) | body | Индивидуальный или групповой контакт|\\n| `contact.crossboarding`| 1 | boolean | body | Признак принадлежности к онбордингу |\\n| `contact.createdBy` | 1 | string(8) | body | Табельный номер создателя контакта |\\n| `contact.emails` | 0..1 | array(object) | body | Массив email-адресов |\\n| `contact.emails.value` | 1 | string(100) | body | Email-значение |\\n| `contact.emails.main` | 1 | boolean | body | Признак основной почты |\\n| `contact.phones` | 0..1 | array(object) | body | Массив телефонов |\\n| `contact.phones.value` | 1 | string(20) | body | Номер телефона |\\n| `contact.phones.extValue`| 0..1 | string(10) | body | Внутренний добавочный номер |\\n| `contact.phones.main` | 1 | boolean | body | Признак основного телефона |\\n| `contact.phones.mobile`| 1 | boolean | body | Признак мобильного телефона |\\n| `client` | 1 | object | body | Данные клиента |\\n| `client.ucpId` | 0..1 | string(36) | body | Идентификатор клиента ПАО |\\n| `client.sbpId` | 0..1 | string(36) | body | Идентификатор клиента АО |\\n| `client.inn` | 0..1 | string(12) | body | ИНН клиента |\\n| `client.kpp` | 0..1 | string(9) | body | КПП клиента |\\n\\n### Выходные параметры\\n\\n| Атрибут | Тип | Обязательность | Описание |\\n|-------------|---------------|---------------|------------------------------|\\n| `contactId` | `string(36)` | 1 | Идентификатор созданного контакта |\\n\"\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "build_changeset",
+ "title": "Формирование changeset"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "changeset_items": 1,
+ "issues": 3,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "finalize",
+ "title": "Подготовка ответа"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md."
+ ]
+ },
+ "output": {
+ "answer_length": 6476,
+ "issues": 3,
+ "changeset_items": 1,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": true,
+ "answer_len": 6476,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_update.from_feature",
+ "steps": [
+ {
+ "step_id": "resolve_source",
+ "title": "Определение источника аналитики",
+ "input": {
+ "source_kind": "",
+ "source_ref": "",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "load_source",
+ "title": "Загрузка системной аналитики",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "content_loaded": true,
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "parse_feature",
+ "title": "Парсинг функциональных требований",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units": 2,
+ "issues": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "load_doc_rules",
+ "title": "Загрузка doc_rules",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "enabled": true,
+ "loaded": true,
+ "supported_doc_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "issues": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "build_change_plan",
+ "title": "Построение плана изменений",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "docs_rows": 7,
+ "planned_changes": 2,
+ "issues": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "build_changeset",
+ "title": "Формирование changeset",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 2,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики."
+ ]
+ },
+ "output": {
+ "changeset_items": 1,
+ "issues": 3,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "finalize",
+ "title": "Подготовка ответа",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md."
+ ]
+ },
+ "output": {
+ "answer_length": 6476,
+ "issues": 3,
+ "changeset_items": 1,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": true,
+ "answer_len": 6476,
+ "issues_count": 3,
+ "issues_preview": [
+ "Отсутствует domains в metadata аналитики.",
+ "Отсутствует subdomains в metadata аналитики.",
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md."
+ ]
+ }
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_update.from_feature"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "docs_update_changeset",
+ "answer_length": 6476,
+ "changeset_items": 1,
+ "apply_changeset": true
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "DOC_UPDATE/FROM_FEATURE: результат построения changeset.\n\nОбнаружены несоответствия/нехватка данных:\n- Отсутствует domains в metadata аналитики.\n- Отсутствует subdomains в metadata аналитики.\n- LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md.\n\nПлан изменений:\n- create: docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md (ui_page)\n- create: docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md (api_method)\n\nChangeset (для плагина):\n```json\n[\n {\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md\",\n \"base_hash\": null,\n \"proposed_content\": \"---\\nid: api_method.fr2_реализовать_сервис_клиентов\\nname: fr2_реализовать_сервис_клиентов\\ntype: api_method\\ndoc_type: api_method\\ntitle: FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\\ndomain: unknown\\nsub_domain: unknown\\nrelated_docs: []\\nstatus: draft\\nupdated_at: '2023-10-10'\\nparent: null\\nchildren: []\\nlinks: {}\\n---\\n\\n# FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\\n\\n## Summary\\n\\n- **Цель**: Создание нового контакта ДГР через API.\\n- **Актор**: Внешний клиент.\\n- **Ошибка**: BAD_REQUEST при неверном JSON, UNAUTHORIZED при отсутствии авторизации.\\n- **Интеграция**: Вызов endpoint POST /contacts в prpb.contacts_dgr.\\n\\n## Details\\n\\n## Описание\\n\\nМетод позволяет создавать новый контакт ДГР в системе CLIENTS через POST-запрос к `/api/v1/clients/contacts-dgr`.\\n\\n## Сценарий\\n\\n**Название:** Создать контакт ДГР\\n\\n**Предусловия:**\\n- Клиент аутентифицирован.\\n\\n**Триггер:**\\n- Отправка POST-запроса к `/api/v1/clients/contacts-dgr`.\\n\\n**Основной сценарий:**\\n1. Проверяется валидность JSON-запроса.\\n2. Проведение авторизации.\\n3. Вызов backend-сервису для создания контакта.\\n4. Возвращение ответа.\\n\\n**Альтернативный сценарий:**\\n- Возврат ошибки при неудачной проверке JSON или отсутствии авторизации.\\n\\n**Обработка ошибок:**\\n- HTTP-код 400 при ошибке валидации JSON.\\n- HTTP-код 401 при отсутствии необходимых прав доступа.\\n\\n**Постусловие:**\\n- Контакт успешно создан или возвращена соответствующая ошибка.\\n\\n## Функциональные требования\\n\\n**FR-1.** Проверка входящего запроса на соответствие JSON-схеме.\\n**FR-2.** Авторизация по периметру CI02792632.ContactsDGR.Create.\\n**FR-3.** Вызов endpoint POST /contacts в prpb.contacts_dgr.\\n**FR-4.** Возвращение ответа в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\n## Нефункциональные требования\\n\\n(не указаны)\\n\\n## Контракт\\n\\n### Входные параметры\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|------------------------|---------------|----------------|----------------|------------------------------------|\\n| `X-Request-Id` | 1 | `uuid` | header | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | header | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | header | Табельный номер пользователя |\\n| `contact` | 1 | object | body | Данные контакта ДГР |\\n| `contact.lastName` | 0..1 | `string(100)` | body | Фамилия контакта |\\n| `contact.firstName` | 0..1 | `string(100)` | body | Имя контакта |\\n| `contact.middleName` | 0..1 | `string(100)` | body | Отчество контакта |\\n| `contact.name` | 0..1 | `string(100)` | body | Название группового контакта |\\n| `contact.description` | 0..1 | `string(1000)` | body | Описание группового контакта |\\n| `contact.position` | 0..1 | `string(100)` | body | Должность контакта |\\n| `contact.comment` | 0..1 | `string(1000)` | body | Комментарий к контакту |\\n| `contact.contactType` | 1 | enum(string) | body | Индивидуальный или групповой контакт|\\n| `contact.crossboarding`| 1 | boolean | body | Признак принадлежности к онбордингу |\\n| `contact.createdBy` | 1 | string(8) | body | Табельный номер создателя контакта |\\n| `contact.emails` | 0..1 | array(object) | body | Массив email-адресов |\\n| `contact.emails.value` | 1 | string(100) | body | Email-значение |\\n| `contact.emails.main` | 1 | boolean | body | Признак основной почты |\\n| `contact.phones` | 0..1 | array(object) | body | Массив телефонов |\\n| `contact.phones.value` | 1 | string(20) | body | Номер телефона |\\n| `contact.phones.extValue`| 0..1 | string(10) | body | Внутренний добавочный номер |\\n| `contact.phones.main` | 1 | boolean | body | Признак основного телефона |\\n| `contact.phones.mobile`| 1 | boolean | body | Признак мобильного телефона |\\n| `client` | 1 | object | body | Данные клиента |\\n| `client.ucpId` | 0..1 | string(36) | body | Идентификатор клиента ПАО |\\n| `client.sbpId` | 0..1 | string(36) | body | Идентификатор клиента АО |\\n| `client.inn` | 0..1 | string(12) | body | ИНН клиента |\\n| `client.kpp` | 0..1 | string(9) | body | КПП клиента |\\n\\n### Выходные параметры\\n\\n| Атрибут | Тип | Обязательность | Описание |\\n|-------------|---------------|---------------|------------------------------|\\n| `contactId` | `string(36)` | 1 | Идентификатор созданного контакта |\\n\",\n \"reason\": \"Создание нового API-метода FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr из системной аналитики.\",\n \"hunks\": []\n }\n]\n```\n\napply_changeset: true",
+ "completed_at": "2026-04-09T15:38:57.199054+00:00"
+}
+```
diff --git a/runtime_traces/agent_requests/20260409-160321-c0c145c3b5d3.md b/runtime_traces/agent_requests/20260409-160321-c0c145c3b5d3.md
new file mode 100644
index 0000000..4bdde5a
--- /dev/null
+++ b/runtime_traces/agent_requests/20260409-160321-c0c145c3b5d3.md
@@ -0,0 +1,1843 @@
+# Runtime Trace: 20260409-160321-c0c145c3b5d3
+
+- active_rag_session_id: ae9d03f9-c65f-4468-be35-c0c145c3b5d3
+
+## request
+```json
+{
+ "request_id": "req_b848697356ef423fae6a79c97c7eef1e",
+ "session_id": "as_9f61b5dc531742afb0853a5a91e306fc",
+ "active_rag_session_id": "ae9d03f9-c65f-4468-be35-c0c145c3b5d3",
+ "process_version": "v2",
+ "created_at": "2026-04-09T16:03:21.470996+00:00",
+ "message": "Сформируй документацию по системной аналитике\n/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_UPDATE",
+ "subintent": "FROM_FEATURE",
+ "normalized_query": "Сформируй документацию по системной аналитике /Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "target_terms": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "anchors": {
+ "entity_names": [
+ "Users",
+ "Dev_projects_v2"
+ ],
+ "file_names": [
+ "process/v2/test_doc/features/create_contact.md"
+ ],
+ "endpoint_paths": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "entity",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": [
+ "API_ENDPOINT",
+ "DOMAIN_ENTITY",
+ "LOGIC_FLOW"
+ ]
+ },
+ "confidence": 0.9500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно указывает на формирование документации по системной аналитике из указанного файла create_contact.md.",
+ "rag_session_id": "ae9d03f9-c65f-4468-be35-c0c145c3b5d3"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_UPDATE",
+ "subintent": "FROM_FEATURE",
+ "confidence": 0.9500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [
+ "API_ENDPOINT",
+ "DOMAIN_ENTITY",
+ "LOGIC_FLOW"
+ ],
+ "endpoint_paths": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ],
+ "matched_aliases": [],
+ "target_terms": [
+ "/users/alex/dev_projects_v2/ai"
+ ]
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ]
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_update.from_feature"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "resolve_source",
+ "title": "Определение источника аналитики"
+ },
+ "input": {
+ "source_kind": "",
+ "source_ref": "",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "load_source",
+ "title": "Загрузка системной аналитики"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "content_loaded": true,
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "parse_feature",
+ "title": "Парсинг функциональных требований"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "load_doc_rules",
+ "title": "Загрузка doc_rules"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "enabled": true,
+ "loaded": true,
+ "supported_doc_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.plan_change_units",
+ "system_prompt": "Ты классифицируешь units системной аналитики для построения плана изменений документации.\n\nВерни только JSON:\n{\n \"items\": [\n {\"index\": 0, \"doc_type\": \"api_method\", \"reason\": \"...\"}\n ]\n}\n\nПравила:\n- Используй только doc_type из allowed_doc_types.\n- Не пропускай item, даже если не уверен: выбери наиболее близкий тип.\n- Ориентируйся на heading и snippet.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"system_rules\": \"Системные правила документации:\\n1. Один устойчивый объект — один документ.\\n2. Документы не должны дублировать друг друга по смыслу.\\n3. Связи между документами должны быть явными (related_docs/links).\\n4. Документация организована иерархически по папкам docs/*.\\n5. Markdown-документ состоит из YAML frontmatter и body.\\n6. Обязательные поля frontmatter: id, title, doc_type, related_docs, status, domain, sub_domain.\",\n \"allowed_doc_types\": [\n \"ui_page\",\n \"api_method\",\n \"logic_block\",\n \"architecture_overview\",\n \"integration_doc\",\n \"domain_entity\",\n \"glossary_item\",\n \"index_page\"\n ],\n \"items\": [\n {\n \"index\": 0,\n \"heading\": \"FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\",\n \"snippet\": \"- type: ui_page\\n- id: ui.contacts_dgr.create\\n\\nОсновной сценарий:\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- ui.contacts_dgr вызывает endpoint POST /api/v1/clients/contacts-dgr для создания карточки контакта ДГР.\\n- ufs.contacts_dgr обрабатывает запрос и возвращает ответ.\\n- ui.contacts_dgr отображает результат создания контакта ДГР в виде push-уведомления.\"\n },\n {\n \"index\": 1,\n \"heading\": \"FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\",\n \"snippet\": \"- type: api_method\\n- id: ufs.contacts_dgr.api.create\\n- endpoint: POST /api/v1/clients/contacts-dgr\\n\\nТребования для основного сценария:\\n- Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом BAD_REQUEST.\\n- Авторизовать запрос по наличию периметра CI02792632.ContactsDGR.Create. При отсутствии периметра завершить основной сценарий с кодом UNAUTHORIZED.\\n- Для и\"\n }\n ]\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.plan"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"items\": [\n {\"index\": 0, \"doc_type\": \"ui_page\"},\n {\"index\": 1, \"doc_type\": \"api_method\"}\n ]\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "build_change_plan",
+ "title": "Построение плана изменений"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "docs_rows": 7,
+ "planned_changes": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "changeset_prompt_built",
+ "doc_type": "ui_page",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "prompt_chars": 11076,
+ "rules_chars": 9572
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.build_doc_changeset",
+ "system_prompt": "Ты формируешь один item changeset для документации на основе системной аналитики и правил doc_rules.\n\nВерни только один JSON-объект (RFC8259) формата:\n{\n \"op\": \"create|update|delete\",\n \"path\": \"docs/...\",\n \"reason\": \"краткая причина\",\n \"proposed_content\": \"полный markdown документа для create/update\"\n}\n\nСхема и ограничения:\n- Обязательные поля всегда: op, path, reason.\n- Для op=create/update поле proposed_content обязательно и содержит полный markdown документа:\n 1) frontmatter между --- и ---,\n 2) затем body согласно doc_rules.\n- Для op=delete поле proposed_content запрещено.\n- В JSON используй двойные кавычки, без trailing commas.\n- Никаких code fences (```), комментариев и текста до/после JSON.\n\nПравила:\n- Строго соблюдай структуру и ограничения из doc_rules_context.\n- Для create/update верни полный итоговый markdown (frontmatter + body).\n- Для update не используй placeholder-тексты; возвращай пригодный к сохранению документ.\n- reason обязателен, короткий, по сути изменения.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"change_request\": {\n \"op\": \"create\",\n \"path\": \"docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md\",\n \"doc_type\": \"ui_page\",\n \"doc_id\": \"ui_page.fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр\",\n \"title\": \"FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\",\n \"domain\": \"contacts_dgr\",\n \"sub_domain\": \"create_contact\",\n \"reason\": \"Из unit 'FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»' системной аналитики (test).\",\n \"source_refs\": [\n \"section: 5. Функциональные требования\"\n ],\n \"related_docs\": [],\n \"requirement_body\": \"- type: ui_page\\n- id: ui.contacts_dgr.create\\n\\nОсновной сценарий:\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- ui.contacts_dgr вызывает endpoint POST /api/v1/clients/contacts-dgr для создания карточки контакта ДГР.\\n- ufs.contacts_dgr обрабатывает запрос и возвращает ответ.\\n- ui.contacts_dgr отображает результат создания контакта ДГР в виде push-уведомления.\"\n },\n \"doc_rules_context\": \"## Global rules\\n\\n### documentation-rules.md\\n\\n# Documentation Rules\\n\\nЭтот каталог оформляет MVP документации проекта в атомарном формате.\\n\\n## Базовая структура\\n\\n- Каждый документ содержит YAML frontmatter.\\n- В документе должен быть один `H1`, совпадающий с `title`.\\n- Основные разделы оформляются как `## Summary` и `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Связи, сущности и навигация описываются во frontmatter через `related_docs`, `links`, `entities`, `parent`, `children`.\\n\\n## Summary\\n\\n- Краткий explain-слой быстрого контекста.\\n- Должен позволять быстро понять назначение документа без чтения `Details`.\\n- Предпочтительный формат: компактный список ключевых фактов без длинных абзацев.\\n\\n## Details\\n\\n- Раскрывает полное описание объекта.\\n- Структура `Details` зависит от типа документа.\\n- Сценарии, ограничения, интеграции, ошибки и кодовые привязки должны быть разнесены по отдельным подразделам.\\n\\n## API documents\\n\\nДля `api_method` внутри `## Details` обязательны разделы:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\nЕсли у метода есть интеграции и ошибки, также обязательны:\\n- `### Интеграции`\\n- `### Ошибки`\\n- `### Связанный код`\\n- `### История изменений`\\n\\n### Сценарий\\n\\nСценарий оформляется как технический use case и содержит:\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработку ошибок\\n- постусловие\\n\\n### Требования\\n\\n- Функциональные требования маркируются как `FR-1`, `FR-2`, ...\\n- Нефункциональные требования маркируются как `NFR-1`, `NFR-2`, ...\\n- Идентификаторы требований локальны в рамках одного документа.\\n\\n### Контракт\\n\\nКонтракт должен быть пригоден для последующей сборки OpenAPI-спецификации и включать:\\n- входные параметры\\n- выходные параметры\\n- структуру JSON-сообщений\\n- обязательность полей\\n- типы и ограничения\\n- описание полей\\n- правила заполнения\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n### global/documentation-system.md\\n\\n# Documentation System\\n\\n## Назначение\\n\\nЭтот файл задает общую модель документации проекта.\\n\\n## Базовая модель\\n\\nКаждый документ должен состоять из двух слоев:\\n- YAML frontmatter\\n- контент\\n\\nКонтент всегда состоит из двух обязательных разделов:\\n- `## Summary`\\n- `## Details`\\n\\nНад ними должен быть один заголовок `# `, совпадающий со значением `title` во frontmatter.\\n\\n## Принципы\\n\\n- Документы должны быть атомарными.\\n- Один документ описывает одну тему.\\n- Вместо дублирования между документами используются явные ссылки.\\n- Связи и навигация должны быть формализованы.\\n- Документы должны быть пригодны для чтения человеком и для RAG.\\n- Документы должны быть пригодны для частичного обновления без деградации структуры.\\n\\n## Типы документов\\n\\nНа уровне проекта поддерживаются типы:\\n- `api_method`\\n- `logic_block`\\n- `architecture_overview`\\n- `domain_entity`\\n- `ui_page`\\n- `integration_doc`\\n- `index_page`\\n- `glossary_item`\\n\\n### global/frontmatter.md\\n\\n# Frontmatter Rules\\n\\n## Назначение\\n\\nЭтот файл описывает единый контракт YAML frontmatter для всех документов.\\n\\n## Обязательные поля\\n\\n```yaml\\nid: string\\ntitle: string\\ndoc_type: string\\ndomain: string\\nsub_domain: string\\nrelated_docs: []\\nstatus: string\\n```\\n\\n## Поля совместимости и рекомендуемые поля\\n\\n```yaml\\ntype: string\\nname: string\\nmodule: string\\nlayer: string\\nupdated_at: YYYY-MM-DD\\ntags: []\\nentities: []\\nparent: string | null\\nchildren: []\\nlinks: {}\\nsource_of_truth: string\\nrelated_code: []\\nsystem_analytics_refs: []\\n```\\n\\n## Правила\\n\\n- `id` должен быть стабильным и уникальным в пределах документации проекта.\\n- `title` — человекочитаемый заголовок.\\n- `doc_type` — канонический тип документа.\\n- `domain` и `sub_domain` определяют бизнес-контекст документа.\\n- `related_docs` хранит явные связи с другими markdown-документами.\\n- `status` хранит жизненный цикл документа: например `draft`, `approved`, `active`.\\n- `type` допустимо дублировать как alias для tooling-совместимости с индексаторами.\\n- `name` — короткое системное имя документа.\\n- `module` — модуль или подсистема.\\n- `layer` — слой системы.\\n- `updated_at` хранится в формате `YYYY-MM-DD`.\\n\\n## Связи и навигация\\n\\n- `entities` описывает сущности, связанные с документом.\\n- `parent` и `children` описывают иерархию.\\n- `links` описывает typed graph связей между документами, кодом и интеграциями.\\n\\n## Формат links\\n\\n```yaml\\nlinks:\\n called_by:\\n - ext.health_probe\\n uses_logic:\\n - logic.some_flow\\n integrates_with:\\n - ext.some_system\\n```\\n\\n### global/linking.md\\n\\n# Linking Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как связывать документы между собой.\\n\\n## Иерархия\\n\\n- `parent` используется для родительского документа.\\n- `children` используется для прямых дочерних документов.\\n- Иерархия должна быть осмысленной и стабильной.\\n- Для общей точки входа допустим `index_page`.\\n\\n## Графовые связи\\n\\nДля `related_docs` используются ссылки на соседние документы.\\n\\nДля `links` рекомендуется использовать typed-ключи:\\n- `called_by`\\n- `uses_logic`\\n- `reads_db`\\n- `writes_db`\\n- `integrates_with`\\n- `used_by`\\n- `exposes_api`\\n- `uses_entities`\\n\\n## Правила использования\\n\\n- Если документ логически входит в другой, использовать `parent`/`children`.\\n- Если связь нужна для навигации между равноправными документами, дублировать ее в `related_docs`.\\n- Если связь отражает поведение, интеграции или переиспользование, фиксировать ее в `links`.\\n- Детальное описание интеграций хранить в body документа, а не только во frontmatter.\\n\\n### global/naming.md\\n\\n# Naming Rules\\n\\n## Назначение\\n\\nЭтот файл описывает правила именования документов, файлов и идентификаторов.\\n\\n## Правила для файлов\\n\\n- Имена файлов должны быть в kebab-case.\\n- Имя файла должно отражать одну тему.\\n- Для шаблонов использовать суффикс `.template.md`.\\n\\n## Правила для id\\n\\n- `id` строится в формате `.`.\\n- Примеры:\\n - `api.send_message_endpoint`\\n - `logic.telegram_notification_loop`\\n - `architecture.telegram_notify_app`\\n\\n## Правила для title\\n\\n- `title` должен быть кратким и человекочитаемым.\\n- В `title` допускаются пробелы и естественный язык.\\n\\n### global/writing-style.md\\n\\n# Writing Style\\n\\n## Назначение\\n\\nЭтот файл задает правила стиля для текстового наполнения документации.\\n\\n## Правила стиля\\n\\n- Текст должен быть лаконичным.\\n- Формулировки должны быть точными и техническими.\\n- Summary должен быть кратким explain-слоем.\\n- Details должен раскрывать суть без лишней воды.\\n- Нежелательно смешивать несколько тем в одном документе.\\n- Если детали относятся к другому артефакту, их нужно выносить в отдельный документ.\\n\\n## Язык\\n\\n- Основной язык документации — русский.\\n- Технические термины, названия классов, API, RAG, OpenAPI, runtime и другие устоявшиеся identifiers можно оставлять на английском.\\n\\n## Artifact rules (ui_page)\\n\\n# UI Page Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для документов типа `ui_page`.\\n\\n## Когда использовать\\n\\nИспользовать для описания одной пользовательской страницы, экрана или отдельного UI-сценария.\\n\\n## Обязательная структура\\n\\nДокумент должен содержать:\\n- YAML frontmatter\\n- `# `\\n- `## Summary`\\n- `## Details`\\n\\n## Что описывать в Details\\n\\n- назначение страницы\\n- пользовательский сценарий\\n- основные блоки интерфейса\\n- связанные API и сущности\\n\\n## Template (ui_page)\\n\\n---\\nid: ui.example_page\\ntype: ui_page\\ndoc_type: ui_page\\nname: example_page\\ntitle: Пример UI-страницы\\nmodule: example_module\\nlayer: presentation\\ndomain: example_domain\\nsub_domain: example_subdomain\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: mixed\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# Пример UI-страницы\\n\\n## Summary\\n\\nКраткое описание страницы и её назначения.\\n\\n## Details\\n\\n### Назначение страницы\\n\\n### Пользовательский сценарий\\n\\n### Основные блоки интерфейса\\n\\n### Связанные API и сущности\\n\\n### Функциональные требования\\n\\n### Нефункциональные требования\\n\\n### Ограничения и граничные случаи\\n\\n### Ошибки и валидации\\n\\n### Связанный код\\n\\n### Связанные документы\\n\\n### История изменений\\n\\n## Section rule: details\\n\\n# Details Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает общие правила для секции `## Details`.\\n\\n## Правила\\n\\n- `Details` оформляется как `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Структура Details зависит от типа документа.\\n- В Details не нужно повторно дублировать навигацию и связи, если они уже есть во frontmatter.\\n- Интеграции, ошибки и кодовые привязки должны быть выделены в отдельные подразделы, если они существенны для понимания документа.\\n\\n## Section rule: requirements-format\\n\\n# Requirements Format Rules\\n\\n## Назначение\\n\\nЭтот файл задает формат для функциональных и нефункциональных требований.\\n\\n## Функциональные требования\\n\\n- Использовать коды `FR-1`, `FR-2`, `FR-3` и так далее.\\n- Каждое требование должно описывать отдельный обязательный аспект поведения.\\n- Идентификаторы локальны в пределах одного документа.\\n\\n## Нефункциональные требования\\n\\n- Использовать коды `NFR-1`, `NFR-2`, `NFR-3` и так далее.\\n- Требования должны описывать характеристики качества, ограничения и эксплуатационные свойства.\\n\\n## Section rule: summary\\n\\n# Summary Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для секции `## Summary`.\\n\\n## Правила\\n\\n- Summary должен быть коротким explain-слоем быстрого контекста.\\n- Summary должен объяснять суть документа без лишних деталей.\\n- Summary должен быть пригоден для explain и быстрого чтения.\\n- Предпочтительный формат: список ключевых фактов `Purpose`, `Actor`, `Trigger`, `Errors`, `Related ...` и т.д.\\n- Для крупных документов допустим более длинный summary, если он остается структурированным.\"\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.changeset"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"op\": \"create\",\n \"path\": \"docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md\",\n \"reason\": \"Создание нового UI сценария 'Контакты ДГР. Создание карточки контакта ДГР'\",\n \"proposed_content\": \"---\\nid: ui_page.fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр\\ntype: ui_page\\ndoc_type: ui_page\\ntitle: FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\ndomain: contacts_dgr\\nsub_domain: create_contact\\nrelated_docs: []\\nstatus: draft\\nupdated_at: \\\"2026-03-20\\\"\\nsource_of_truth: mixed\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\n\\n## Summary\\n\\n- **Назначение**: Реализация сценария добавления новой карточки контакта ДГР.\\n- **Пользователь**: Авторизованный пользователь системы.\\n- **Действие пользователя**: Заполнение формы и нажатие кнопки «Добавить».\\n- **Интеграция API**: Вызов endpoint POST /api/v1/clients/contacts-dgr.\\n- **Результат**: Отображение push-уведомления о результате операции.\\n\\n## Details\\n\\n### Назначение страницы\\nРеализует добавление новой карточки контакта ДГР через пользовательский интерфейс.\\n\\n### Пользовательский сценарий\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- ui.contacts_dgr вызывает endpoint POST /api/v1/clients/contacts-dgr для создания карточки контакта ДГР.\\n- ufs.contacts_dgr обрабатывает запрос и возвращает ответ.\\n- ui_contacts_dgr отображает результат создания контакта ДГР в виде push-уведомления.\\n\\n### Основные блоки интерфейса\\nНе определено.\\n\\n### Связанные API и сущности\\n- API: POST /api/v1/clients/contacts-dgr\\n- Сущности: карточка контакта ДГР\\n\\n### Функциональные требования\\n- FR-1: Возможность создания новой карточки контакта ДГР через заполнение формы и вызов соответствующего API.\\n\\n### Нефункциональные требования\\nНе определено.\\n\\n### Ограничения и граничные случаи\\nНе определено.\\n\\n### Ошибки и валидации\\nНе определено.\\n\\n### Связанный код\\nНе определено.\\n\\n### Связанные документы\\nНе определено.\\n\\n### История изменений\\nНе определено.\"\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "changeset_json_parse_failed",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "raw_chars": 2144
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.repair_doc_changeset_json",
+ "system_prompt": "Ты ремонтируешь невалидный ответ модели и должен вернуть строго валидный JSON changeset.\n\nВход содержит:\n- expected_contract: ожидаемые поля и ограничения.\n- raw_llm_output: исходный (возможно невалидный) ответ.\n\nЗадача:\n- Извлеки максимально полный смысл из raw_llm_output.\n- Верни ровно один JSON-объект, соответствующий expected_contract.\n- Если часть данных отсутствует, используй безопасные значения по умолчанию:\n - reason: \"generated by repair\"\n - proposed_content: только если op=create/update, иначе не добавляй.\n\nОграничения вывода:\n- Только JSON-объект, без markdown/code fences/комментариев.\n- Двойные кавычки, без trailing commas.",
+ "user_prompt": "{\n \"expected_contract\": {\n \"op\": \"create\",\n \"path\": \"docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md\",\n \"required_keys\": [\n \"op\",\n \"path\",\n \"reason\"\n ],\n \"proposed_content_required_for\": [\n \"create\",\n \"update\"\n ]\n },\n \"raw_llm_output\": \"{\\n \\\"op\\\": \\\"create\\\",\\n \\\"path\\\": \\\"docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md\\\",\\n \\\"reason\\\": \\\"Создание нового UI сценария 'Контакты ДГР. Создание карточки контакта ДГР'\\\",\\n \\\"proposed_content\\\": \\\"---\\\\nid: ui_page.fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр\\\\ntype: ui_page\\\\ndoc_type: ui_page\\\\ntitle: FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\\ndomain: contacts_dgr\\\\nsub_domain: create_contact\\\\nrelated_docs: []\\\\nstatus: draft\\\\nupdated_at: \\\\\\\"2026-03-20\\\\\\\"\\\\nsource_of_truth: mixed\\\\nparent: null\\\\nchildren: []\\\\ntags: []\\\\nentities: []\\\\nlinks: {}\\\\n---\\\\n\\\\n# FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\\n\\\\n## Summary\\\\n\\\\n- **Назначение**: Реализация сценария добавления новой карточки контакта ДГР.\\\\n- **Пользователь**: Авторизованный пользователь системы.\\\\n- **Действие пользователя**: Заполнение формы и нажатие кнопки «Добавить».\\\\n- **Интеграция API**: Вызов endpoint POST /api/v1/clients/contacts-dgr.\\\\n- **Результат**: Отображение push-уведомления о результате операции.\\\\n\\\\n## Details\\\\n\\\\n### Назначение страницы\\\\nРеализует добавление новой карточки контакта ДГР через пользовательский интерфейс.\\\\n\\\\n### Пользовательский сценарий\\\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\\\n- ui.contacts_dgr вызывает endpoint POST /api/v1/clients/contacts-dgr для создания карточки контакта ДГР.\\\\n- ufs.contacts_dgr обрабатывает запрос и возвращает ответ.\\\\n- ui_contacts_dgr отображает результат создания контакта ДГР в виде push-уведомления.\\\\n\\\\n### Основные блоки интерфейса\\\\nНе определено.\\\\n\\\\n### Связанные API и сущности\\\\n- API: POST /api/v1/clients/contacts-dgr\\\\n- Сущности: карточка контакта ДГР\\\\n\\\\n### Функциональные требования\\\\n- FR-1: Возможность создания новой карточки контакта ДГР через заполнение формы и вызов соответствующего API.\\\\n\\\\n### Нефункциональные требования\\\\nНе определено.\\\\n\\\\n### Ограничения и граничные случаи\\\\nНе определено.\\\\n\\\\n### Ошибки и валидации\\\\nНе определено.\\\\n\\\\n### Связанный код\\\\nНе определено.\\\\n\\\\n### Связанные документы\\\\nНе определено.\\\\n\\\\n### История изменений\\\\nНе определено.\\\"\\n}\"\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.changeset_repair"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"op\": \"create\",\n \"path\": \"docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md\",\n \"reason\": \"Создание нового UI сценария 'Контакты ДГР. Создание карточки контакта ДГР'\",\n \"proposed_content\": \"---\\nid: ui_page.fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр\\ntype: ui_page\\ndoc_type: ui_page\\ntitle: FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\\ndomain: contacts_dgr\\nsub_domain: create_contact\\nrelated_docs: []\\nstatus: draft\\nupdated_at: \\\"2026-03-20\\\"\\nsource_of_truth: mixed\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\n\\n## Summary\\n\\n- **Назначение**: Реализация сценария добавления новой карточки контакта ДГР.\\n- **Пользователь**: Авторизованный пользователь системы.\\n- **Действие пользователя**: Заполнение формы и нажатие кнопки «Добавить».\\n- **Интеграция API**: Вызов endpoint POST /api/v1/clients/contacts-dgr.\\n- **Результат**: Отображение push-уведомления о результате операции.\\n\\n## Details\\n\\n### Назначение страницы\\nРеализует добавление новой карточки контакта ДГР через пользовательский интерфейс.\\n\\n### Пользовательский сценарий\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- ui.contacts_dgr вызывает endpoint POST /api/v1/clients/contacts-dgr для создания карточки контакта ДГР.\\n- ufs.contacts_dgr обрабатывает запрос и возвращает ответ.\\n- ui_contacts_dgr отображает результат создания контакта ДГР в виде push-уведомления.\\n\\n### Основные блоки интерфейса\\nНе определено.\\n\\n### Связанные API и сущности\\n- API: POST /api/v1/clients/contacts-dgr\\n- Сущности: карточка контакта ДГР\\n\\n### Функциональные требования\\n- FR-1: Возможность создания новой карточки контакта ДГР через заполнение формы и вызов соответствующего API.\\n\\n### Нефункциональные требования\\nНе определено.\\n\\n### Ограничения и граничные случаи\\nНе определено.\\n\\n### Ошибки и валидации\\nНе определено.\\n\\n### Связанный код\\nНе определено.\\n\\n### Связанные документы\\nНе определено.\\n\\n### История изменений\\nНе определено.\"\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "changeset_prompt_built",
+ "doc_type": "api_method",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "prompt_chars": 15670,
+ "rules_chars": 11520
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.build_doc_changeset",
+ "system_prompt": "Ты формируешь один item changeset для документации на основе системной аналитики и правил doc_rules.\n\nВерни только один JSON-объект (RFC8259) формата:\n{\n \"op\": \"create|update|delete\",\n \"path\": \"docs/...\",\n \"reason\": \"краткая причина\",\n \"proposed_content\": \"полный markdown документа для create/update\"\n}\n\nСхема и ограничения:\n- Обязательные поля всегда: op, path, reason.\n- Для op=create/update поле proposed_content обязательно и содержит полный markdown документа:\n 1) frontmatter между --- и ---,\n 2) затем body согласно doc_rules.\n- Для op=delete поле proposed_content запрещено.\n- В JSON используй двойные кавычки, без trailing commas.\n- Никаких code fences (```), комментариев и текста до/после JSON.\n\nПравила:\n- Строго соблюдай структуру и ограничения из doc_rules_context.\n- Для create/update верни полный итоговый markdown (frontmatter + body).\n- Для update не используй placeholder-тексты; возвращай пригодный к сохранению документ.\n- reason обязателен, короткий, по сути изменения.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"change_request\": {\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md\",\n \"doc_type\": \"api_method\",\n \"doc_id\": \"api_method.fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr\",\n \"title\": \"FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\",\n \"domain\": \"contacts_dgr\",\n \"sub_domain\": \"create_contact\",\n \"reason\": \"Из unit 'FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr' системной аналитики (test).\",\n \"source_refs\": [\n \"section: 5. Функциональные требования\"\n ],\n \"related_docs\": [],\n \"requirement_body\": \"- type: api_method\\n- id: ufs.contacts_dgr.api.create\\n- endpoint: POST /api/v1/clients/contacts-dgr\\n\\nТребования для основного сценария:\\n- Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом BAD_REQUEST.\\n- Авторизовать запрос по наличию периметра CI02792632.ContactsDGR.Create. При отсутствии периметра завершить основной сценарий с кодом UNAUTHORIZED.\\n- Для исполнения запроса на создание контакта вызвать endpoint POST /contacts в prpb.contacts_dgr.\\n- Вернуть ответ ui.contacts_dgr в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\nКонтракт POST /contacts\\n\\nЗапрос\\n\\n**headers**\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|---|---|---|---|---|\\n| `X-Request-Id` | 1 | `uuid` | `header` | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | `header` | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | `header` | Табельный номер пользователя, вызвавшего сервис |\\n\\n**body**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contact` | 1 | `object` | Данные контакта ДГР |\\n| `contact.lastName` | 0..1 | `string(100)` | Фамилия контакта |\\n| `contact.firstName` | 0..1 | `string(100)` | Имя контакта |\\n| `contact.middleName` | 0..1 | `string(100)` | Отчество контакта |\\n| `contact.name` | 0..1 | `string(100)` | Название группового контакта |\\n| `contact.description` | 0..1 | `string(1000)` | Описание группового контакта |\\n| `contact.position` | 0..1 | `string(100)` | Должность контакта у клиента |\\n| `contact.comment` | 0..1 | `string(1000)` | Комментарий к контакту |\\n| `contact.contactType` | 1 | `enum(string)` | `Individual`, `Group` |\\n| `contact.crossboarding` | 1 | `boolean` | Признак принадлежности контакта к процессу онбординга |\\n| `contact.createdBy` | 1 | `string(8)` | Табельный номер пользователя, создавшего контакт |\\n| `contact.emails` | 0..1 | `array(object)` | Массив электронных адресов контакта |\\n| `contact.emails.value` | 1 | `string(100)` | Электронный адрес |\\n| `contact.emails.main` | 1 | `boolean` | Признак основной почты |\\n| `contact.phones` | 0..1 | `array(object)` | Массив телефонных номеров контакта |\\n| `contact.phones.value` | 1 | `string(20)` | Телефонный номер контакта |\\n| `contact.phones.extValue` | 0..1 | `string(10)` | Добавочный номер |\\n| `contact.phones.main` | 1 | `boolean` | Признак основного телефона |\\n| `contact.phones.mobile` | 1 | `boolean` | Признак мобильного телефона |\\n| `client` | 1 | `object` | Данные клиента |\\n| `client.ucpId` | 0..1 | `string(36)` | Идентификатор клиента ПАО |\\n| `client.sbpId` | 0..1 | `string(36)` | Идентификатор клиента АО |\\n| `client.inn` | 0..1 | `string(12)` | ИНН клиента |\\n| `client.kpp` | 0..1 | `string(9)` | КПП клиента |\\n\\nОтвет\\n\\n**ContactDGRCreateRsDto**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contactId` | 1 | `string(36)` | Идентификатор контакта |\"\n },\n \"doc_rules_context\": \"## Global rules\\n\\n### documentation-rules.md\\n\\n# Documentation Rules\\n\\nЭтот каталог оформляет MVP документации проекта в атомарном формате.\\n\\n## Базовая структура\\n\\n- Каждый документ содержит YAML frontmatter.\\n- В документе должен быть один `H1`, совпадающий с `title`.\\n- Основные разделы оформляются как `## Summary` и `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Связи, сущности и навигация описываются во frontmatter через `related_docs`, `links`, `entities`, `parent`, `children`.\\n\\n## Summary\\n\\n- Краткий explain-слой быстрого контекста.\\n- Должен позволять быстро понять назначение документа без чтения `Details`.\\n- Предпочтительный формат: компактный список ключевых фактов без длинных абзацев.\\n\\n## Details\\n\\n- Раскрывает полное описание объекта.\\n- Структура `Details` зависит от типа документа.\\n- Сценарии, ограничения, интеграции, ошибки и кодовые привязки должны быть разнесены по отдельным подразделам.\\n\\n## API documents\\n\\nДля `api_method` внутри `## Details` обязательны разделы:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\nЕсли у метода есть интеграции и ошибки, также обязательны:\\n- `### Интеграции`\\n- `### Ошибки`\\n- `### Связанный код`\\n- `### История изменений`\\n\\n### Сценарий\\n\\nСценарий оформляется как технический use case и содержит:\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработку ошибок\\n- постусловие\\n\\n### Требования\\n\\n- Функциональные требования маркируются как `FR-1`, `FR-2`, ...\\n- Нефункциональные требования маркируются как `NFR-1`, `NFR-2`, ...\\n- Идентификаторы требований локальны в рамках одного документа.\\n\\n### Контракт\\n\\nКонтракт должен быть пригоден для последующей сборки OpenAPI-спецификации и включать:\\n- входные параметры\\n- выходные параметры\\n- структуру JSON-сообщений\\n- обязательность полей\\n- типы и ограничения\\n- описание полей\\n- правила заполнения\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n### global/documentation-system.md\\n\\n# Documentation System\\n\\n## Назначение\\n\\nЭтот файл задает общую модель документации проекта.\\n\\n## Базовая модель\\n\\nКаждый документ должен состоять из двух слоев:\\n- YAML frontmatter\\n- контент\\n\\nКонтент всегда состоит из двух обязательных разделов:\\n- `## Summary`\\n- `## Details`\\n\\nНад ними должен быть один заголовок `# `, совпадающий со значением `title` во frontmatter.\\n\\n## Принципы\\n\\n- Документы должны быть атомарными.\\n- Один документ описывает одну тему.\\n- Вместо дублирования между документами используются явные ссылки.\\n- Связи и навигация должны быть формализованы.\\n- Документы должны быть пригодны для чтения человеком и для RAG.\\n- Документы должны быть пригодны для частичного обновления без деградации структуры.\\n\\n## Типы документов\\n\\nНа уровне проекта поддерживаются типы:\\n- `api_method`\\n- `logic_block`\\n- `architecture_overview`\\n- `domain_entity`\\n- `ui_page`\\n- `integration_doc`\\n- `index_page`\\n- `glossary_item`\\n\\n### global/frontmatter.md\\n\\n# Frontmatter Rules\\n\\n## Назначение\\n\\nЭтот файл описывает единый контракт YAML frontmatter для всех документов.\\n\\n## Обязательные поля\\n\\n```yaml\\nid: string\\ntitle: string\\ndoc_type: string\\ndomain: string\\nsub_domain: string\\nrelated_docs: []\\nstatus: string\\n```\\n\\n## Поля совместимости и рекомендуемые поля\\n\\n```yaml\\ntype: string\\nname: string\\nmodule: string\\nlayer: string\\nupdated_at: YYYY-MM-DD\\ntags: []\\nentities: []\\nparent: string | null\\nchildren: []\\nlinks: {}\\nsource_of_truth: string\\nrelated_code: []\\nsystem_analytics_refs: []\\n```\\n\\n## Правила\\n\\n- `id` должен быть стабильным и уникальным в пределах документации проекта.\\n- `title` — человекочитаемый заголовок.\\n- `doc_type` — канонический тип документа.\\n- `domain` и `sub_domain` определяют бизнес-контекст документа.\\n- `related_docs` хранит явные связи с другими markdown-документами.\\n- `status` хранит жизненный цикл документа: например `draft`, `approved`, `active`.\\n- `type` допустимо дублировать как alias для tooling-совместимости с индексаторами.\\n- `name` — короткое системное имя документа.\\n- `module` — модуль или подсистема.\\n- `layer` — слой системы.\\n- `updated_at` хранится в формате `YYYY-MM-DD`.\\n\\n## Связи и навигация\\n\\n- `entities` описывает сущности, связанные с документом.\\n- `parent` и `children` описывают иерархию.\\n- `links` описывает typed graph связей между документами, кодом и интеграциями.\\n\\n## Формат links\\n\\n```yaml\\nlinks:\\n called_by:\\n - ext.health_probe\\n uses_logic:\\n - logic.some_flow\\n integrates_with:\\n - ext.some_system\\n```\\n\\n### global/linking.md\\n\\n# Linking Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как связывать документы между собой.\\n\\n## Иерархия\\n\\n- `parent` используется для родительского документа.\\n- `children` используется для прямых дочерних документов.\\n- Иерархия должна быть осмысленной и стабильной.\\n- Для общей точки входа допустим `index_page`.\\n\\n## Графовые связи\\n\\nДля `related_docs` используются ссылки на соседние документы.\\n\\nДля `links` рекомендуется использовать typed-ключи:\\n- `called_by`\\n- `uses_logic`\\n- `reads_db`\\n- `writes_db`\\n- `integrates_with`\\n- `used_by`\\n- `exposes_api`\\n- `uses_entities`\\n\\n## Правила использования\\n\\n- Если документ логически входит в другой, использовать `parent`/`children`.\\n- Если связь нужна для навигации между равноправными документами, дублировать ее в `related_docs`.\\n- Если связь отражает поведение, интеграции или переиспользование, фиксировать ее в `links`.\\n- Детальное описание интеграций хранить в body документа, а не только во frontmatter.\\n\\n### global/naming.md\\n\\n# Naming Rules\\n\\n## Назначение\\n\\nЭтот файл описывает правила именования документов, файлов и идентификаторов.\\n\\n## Правила для файлов\\n\\n- Имена файлов должны быть в kebab-case.\\n- Имя файла должно отражать одну тему.\\n- Для шаблонов использовать суффикс `.template.md`.\\n\\n## Правила для id\\n\\n- `id` строится в формате `.`.\\n- Примеры:\\n - `api.send_message_endpoint`\\n - `logic.telegram_notification_loop`\\n - `architecture.telegram_notify_app`\\n\\n## Правила для title\\n\\n- `title` должен быть кратким и человекочитаемым.\\n- В `title` допускаются пробелы и естественный язык.\\n\\n### global/writing-style.md\\n\\n# Writing Style\\n\\n## Назначение\\n\\nЭтот файл задает правила стиля для текстового наполнения документации.\\n\\n## Правила стиля\\n\\n- Текст должен быть лаконичным.\\n- Формулировки должны быть точными и техническими.\\n- Summary должен быть кратким explain-слоем.\\n- Details должен раскрывать суть без лишней воды.\\n- Нежелательно смешивать несколько тем в одном документе.\\n- Если детали относятся к другому артефакту, их нужно выносить в отдельный документ.\\n\\n## Язык\\n\\n- Основной язык документации — русский.\\n- Технические термины, названия классов, API, RAG, OpenAPI, runtime и другие устоявшиеся identifiers можно оставлять на английском.\\n\\n## Artifact rules (api_method)\\n\\n# API Method Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для документов типа `api_method`.\\n\\n## Когда использовать\\n\\nИспользовать для описания одного HTTP endpoint или одного отдельного API метода.\\n\\n## Обязательная структура\\n\\nДокумент должен содержать:\\n- YAML frontmatter\\n- `# `\\n- `## Summary`\\n- `## Details`\\n\\nВнутри `## Details` обязательны:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\n## Особые правила\\n\\n- Сценарий оформляется как технический use case.\\n- Функциональные требования маркируются `FR-*`.\\n- Нефункциональные требования маркируются `NFR-*`.\\n- Контракт должен быть пригоден для последующей сборки OpenAPI.\\n- Если у метода есть интеграции, они выносятся в `### Интеграции`.\\n- Ошибки и HTTP-коды либо описываются в `### Ошибки`, либо ссылаются на централизованный каталог ошибок.\\n\\n## Ошибки оформления\\n\\n- Нельзя заменять контракт общим текстовым описанием.\\n- Нельзя смешивать несколько endpoint в одном документе.\\n- Нельзя хранить связи и навигацию вне frontmatter.\\n\\n## Template (api_method)\\n\\n---\\nid: api.example_method\\ntype: api_method\\ndoc_type: api_method\\nname: example_method\\ntitle: HTTP API /example\\nmodule: example_module\\nlayer: application\\ndomain: example_domain\\nsub_domain: example_subdomain\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: code\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# HTTP API /example\\n\\n## Summary\\n\\nКраткое описание метода.\\n\\n## Details\\n\\n## Описание\\n\\nКороткое описание сути метода.\\n\\n## Сценарий\\n\\n**Название:**\\n\\n**Предусловия:**\\n- \\n\\n**Триггер:**\\n- \\n\\n**Основной сценарий:**\\n1. \\n\\n**Альтернативный сценарий:**\\n1. \\n\\n**Обработка ошибок:**\\n1. \\n\\n**Постусловие:**\\n- \\n\\n## Функциональные требования\\n\\n**FR-1.**\\n\\n## Нефункциональные требования\\n\\n**NFR-1.**\\n\\n## Контракт\\n\\n### Входные параметры\\n\\n| Параметр | Где передается | Тип | Обязательность | Ограничения | Описание | Пример |\\n|---|---|---|---|---|---|---|\\n| | | | | | | |\\n\\n### Выходные параметры\\n\\n| Поле | Тип | Обязательность | Ограничения | Описание | Заполнение | Пример |\\n|---|---|---|---|---|---|---|\\n| | | | | | | |\\n\\n### Интеграции\\n\\n### Ошибки\\n\\n### Связанный код\\n\\n### История изменений\\n\\n## Section rule: api-contract\\n\\n# API Contract Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как оформлять подраздел `## Контракт` в API-документах.\\n\\n## Что должно быть описано\\n\\n- входные параметры\\n- выходные параметры\\n- JSON-структуры запросов и ответов\\n- обязательность полей\\n- типы полей\\n- ограничения\\n- описание назначения полей\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n## Правило качества\\n\\nКонтракт должен быть достаточно формальным, чтобы по нему можно было собрать OpenAPI-спецификацию.\\n\\n## Section rule: api-scenario\\n\\n# API Scenario Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как оформлять подраздел `### Сценарий` в API-документах.\\n\\n## Обязательные части\\n\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработка ошибок\\n- постусловие\\n\\n## Правила\\n\\n- Сценарий должен быть лаконичным.\\n- Сценарий должен отражать суть шага.\\n- Сложные технические детали надо выносить в `FR-*`.\\n\\n## Section rule: details\\n\\n# Details Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает общие правила для секции `## Details`.\\n\\n## Правила\\n\\n- `Details` оформляется как `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Структура Details зависит от типа документа.\\n- В Details не нужно повторно дублировать навигацию и связи, если они уже есть во frontmatter.\\n- Интеграции, ошибки и кодовые привязки должны быть выделены в отдельные подразделы, если они существенны для понимания документа.\\n\\n## Section rule: requirements-format\\n\\n# Requirements Format Rules\\n\\n## Назначение\\n\\nЭтот файл задает формат для функциональных и нефункциональных требований.\\n\\n## Функциональные требования\\n\\n- Использовать коды `FR-1`, `FR-2`, `FR-3` и так далее.\\n- Каждое требование должно описывать отдельный обязательный аспект поведения.\\n- Идентификаторы локальны в пределах одного документа.\\n\\n## Нефункциональные требования\\n\\n- Использовать коды `NFR-1`, `NFR-2`, `NFR-3` и так далее.\\n- Требования должны описывать характеристики качества, ограничения и эксплуатационные свойства.\\n\\n## Section rule: summary\\n\\n# Summary Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для секции `## Summary`.\\n\\n## Правила\\n\\n- Summary должен быть коротким explain-слоем быстрого контекста.\\n- Summary должен объяснять суть документа без лишних деталей.\\n- Summary должен быть пригоден для explain и быстрого чтения.\\n- Предпочтительный формат: список ключевых фактов `Purpose`, `Actor`, `Trigger`, `Errors`, `Related ...` и т.д.\\n- Для крупных документов допустим более длинный summary, если он остается структурированным.\"\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.changeset"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md\",\n \"reason\": \"Создание нового API-метода для реализации сервиса CLIENTS. POST /api/v1/clients/contacts-dgr на основании системной аналитики.\",\n \"proposed_content\": \"---\\nid: api_method.fr2_реализовать_сервис клиентов_post_api_v1_clients_contacts_dgr\\ntype: api_method\\ndoc_type: api_method\\nname: fr2_реализовать_сервис_клиентов_post_api_v1_клиентов_contacts_dgr\\ntitle: FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\\ndomain: contacts_dgr\\nsub_domain: create_contact\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2023-10-10\\nsource_of_truth: system_analytics\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\\n\\n## Summary\\n\\n- **Цель**: Реализация сервиса создания контактов DGR.\\n- **Метод**: POST /api/v1/clients/contacts-dgr.\\n- **Интеграция**: Вызов endpoint POST /contacts в prpb.contacts_dgr.\\n- **Аутентификация**: Периметр CI02792632.ContactsDGR.Create.\\n- **Формат ответа**: UfsBaseResponseContactDGRCreateRsDto.\\n\\n## Details\\n\\n### Описание\\nРеализация сервиса для создания контактов DGR через API методом POST /api/v1/clients/contacts-dgr.\\n\\n### Сценарий\\n\\n**Название:** Создание контакта DGR\\n\\n**Предусловия:**\\n- Наличие авторизации в системе.\\n- Передача корректного JSON-запроса.\\n\\n**Триггер:**\\n- Получение POST-запроса на endpoint /api/v1/clients/contacts-dgr.\\n\\n**Основной сценарий:**\\n1. Проверка соответствия запроса JSON-схеме.\\n2. Аутентификация пользователя.\\n3. Валидация периметра доступа CI02792632.ContactsDGR.Create.\\n4. Вызов endpoint POST /contacts в prpb.contacts_dgr.\\n5. Возвращение результата в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\n**Альтернативный сценарий:**\\n- Неверная схема запроса или отсутствие необходимого периметра доступа.\\n\\n**Обработка ошибок:**\\n- Возврат кода BAD_REQUEST при ошибке схемы запроса.\\n- Возврат кода UNAUTHORIZED при отсутствии периметра доступа.\\n\\n**Постусловие:**\\n- Создан новый контакт DGR.\\n\\n### Функциональные требования\\n\\n**FR-1.** Проверить входящий запрос на соответствие JSON-схеме.\\n**FR-2.** Авторизовать запрос по периметру CI02792632.ContactsDGR.Create.\\n**FR-3.** Вызвать endpoint POST /contacts в prpb.contacts_dgr.\\n**FR-4.** Вернуть ответ в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\n### Нефункциональные требования\\nОтсутствуют специфические требования.\\n\\n### Контракт\\n\\n#### Входные параметры\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|----------------------|---------------|---------------|----------------|-----------------------------------------|\\n| X-Request-Id | 1 | uuid | header | Сквозной идентификатор вызова |\\n| X-Client-Ident-Id | 1 | string(50) | header | Идентификатор системы потребителя |\\n| X-Employee-Number | 0..1 | string(8) | header | Табельный номер пользователя |\\n| contact | 1 | object | body | Данные контакта DGR |\\n| contact.lastName | 0..1 | string(100) | | Фамилия контакта |\\n| contact.firstName | 0..1 | string(100) | | Имя контакта |\\n| contact.middleName | 0..1 | string(100) | | Отчество контакта |\\n| contact.name | 0..1 | string(100) | | Название группового контакта |\\n| contact.description | 0..1 | string(1000) | | Описание группового контакта |\\n| contact.position | 0..1 | string(100) | | Должность контакта |\\n| contact.comment | 0..1 | string(1000) | | Комментарий к контакту |\\n| contact.contactType | 1 | enum(string) | | Индивидуальный или групповой контакт |\\n| contact.crossboarding | 1 | boolean | | Признак принадлежности к онбордингу |\\n| contact.createdBy | 1 | string(8) | | Табельный номер создателя контакта |\\n| contact.emails | 0..1 | array(object) | | Массив электронных адресов |\\n| client | 1 | object | body | Данные клиента |\\n| client.ucpId | 0..1 | string(36) | | Идентификатор клиента ПАО |\\n| client.sbpId | 0..1 | string(36) | | Идентификатор клиента АО |\\n| client.inn | 0..1 | string(12) | | ИНН клиента |\\n| client.kpp | 0..1 | string(9) | | КПП клиента |\\n\\n#### Выходные параметры\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|------------|---------------|-------------|--------------------------|\\n| contactId | 1 | string(36) | Идентификатор созданного контакта |\\n\"\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "build_changeset",
+ "title": "Формирование changeset"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "changeset_items": 1,
+ "issues": 1,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 1,
+ "issues_preview": [
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md даже после repair."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "finalize",
+ "title": "Подготовка ответа"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 1,
+ "issues_preview": [
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md даже после repair."
+ ]
+ },
+ "output": {
+ "answer_length": 6038,
+ "issues": 1,
+ "changeset_items": 1,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": true,
+ "answer_len": 6038,
+ "issues_count": 1,
+ "issues_preview": [
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md даже после repair."
+ ]
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_update.from_feature",
+ "steps": [
+ {
+ "step_id": "resolve_source",
+ "title": "Определение источника аналитики",
+ "input": {
+ "source_kind": "",
+ "source_ref": "",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "load_source",
+ "title": "Загрузка системной аналитики",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "content_loaded": true,
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "parse_feature",
+ "title": "Парсинг функциональных требований",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "load_doc_rules",
+ "title": "Загрузка doc_rules",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "enabled": true,
+ "loaded": true,
+ "supported_doc_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "build_change_plan",
+ "title": "Построение плана изменений",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "docs_rows": 7,
+ "planned_changes": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "build_changeset",
+ "title": "Формирование changeset",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "changeset_items": 1,
+ "issues": 1,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 1,
+ "issues_preview": [
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md даже после repair."
+ ]
+ }
+ }
+ },
+ {
+ "step_id": "finalize",
+ "title": "Подготовка ответа",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 1,
+ "issues_preview": [
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md даже после repair."
+ ]
+ },
+ "output": {
+ "answer_length": 6038,
+ "issues": 1,
+ "changeset_items": 1,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 1,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": true,
+ "answer_len": 6038,
+ "issues_count": 1,
+ "issues_preview": [
+ "LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md даже после repair."
+ ]
+ }
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_update.from_feature"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "docs_update_changeset",
+ "answer_length": 6038,
+ "changeset_items": 1,
+ "apply_changeset": true
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "DOC_UPDATE/FROM_FEATURE: результат построения changeset.\n\nОбнаружены несоответствия/нехватка данных:\n- LLM вернул невалидный JSON changeset для docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md даже после repair.\n\nПлан изменений:\n- create: docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md (ui_page)\n- create: docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md (api_method)\n\nChangeset (для плагина):\n```json\n[\n {\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md\",\n \"base_hash\": null,\n \"proposed_content\": \"---\\nid: api_method.fr2_реализовать_сервис клиентов_post_api_v1_clients_contacts_dgr\\ntype: api_method\\ndoc_type: api_method\\nname: fr2_реализовать_сервис_клиентов_post_api_v1_клиентов_contacts_dgr\\ntitle: FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\\ndomain: contacts_dgr\\nsub_domain: create_contact\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2023-10-10\\nsource_of_truth: system_analytics\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\\n\\n## Summary\\n\\n- **Цель**: Реализация сервиса создания контактов DGR.\\n- **Метод**: POST /api/v1/clients/contacts-dgr.\\n- **Интеграция**: Вызов endpoint POST /contacts в prpb.contacts_dgr.\\n- **Аутентификация**: Периметр CI02792632.ContactsDGR.Create.\\n- **Формат ответа**: UfsBaseResponseContactDGRCreateRsDto.\\n\\n## Details\\n\\n### Описание\\nРеализация сервиса для создания контактов DGR через API методом POST /api/v1/clients/contacts-dgr.\\n\\n### Сценарий\\n\\n**Название:** Создание контакта DGR\\n\\n**Предусловия:**\\n- Наличие авторизации в системе.\\n- Передача корректного JSON-запроса.\\n\\n**Триггер:**\\n- Получение POST-запроса на endpoint /api/v1/clients/contacts-dgr.\\n\\n**Основной сценарий:**\\n1. Проверка соответствия запроса JSON-схеме.\\n2. Аутентификация пользователя.\\n3. Валидация периметра доступа CI02792632.ContactsDGR.Create.\\n4. Вызов endpoint POST /contacts в prpb.contacts_dgr.\\n5. Возвращение результата в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\n**Альтернативный сценарий:**\\n- Неверная схема запроса или отсутствие необходимого периметра доступа.\\n\\n**Обработка ошибок:**\\n- Возврат кода BAD_REQUEST при ошибке схемы запроса.\\n- Возврат кода UNAUTHORIZED при отсутствии периметра доступа.\\n\\n**Постусловие:**\\n- Создан новый контакт DGR.\\n\\n### Функциональные требования\\n\\n**FR-1.** Проверить входящий запрос на соответствие JSON-схеме.\\n**FR-2.** Авторизовать запрос по периметру CI02792632.ContactsDGR.Create.\\n**FR-3.** Вызвать endpoint POST /contacts в prpb.contacts_dgr.\\n**FR-4.** Вернуть ответ в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\n### Нефункциональные требования\\nОтсутствуют специфические требования.\\n\\n### Контракт\\n\\n#### Входные параметры\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|----------------------|---------------|---------------|----------------|-----------------------------------------|\\n| X-Request-Id | 1 | uuid | header | Сквозной идентификатор вызова |\\n| X-Client-Ident-Id | 1 | string(50) | header | Идентификатор системы потребителя |\\n| X-Employee-Number | 0..1 | string(8) | header | Табельный номер пользователя |\\n| contact | 1 | object | body | Данные контакта DGR |\\n| contact.lastName | 0..1 | string(100) | | Фамилия контакта |\\n| contact.firstName | 0..1 | string(100) | | Имя контакта |\\n| contact.middleName | 0..1 | string(100) | | Отчество контакта |\\n| contact.name | 0..1 | string(100) | | Название группового контакта |\\n| contact.description | 0..1 | string(1000) | | Описание группового контакта |\\n| contact.position | 0..1 | string(100) | | Должность контакта |\\n| contact.comment | 0..1 | string(1000) | | Комментарий к контакту |\\n| contact.contactType | 1 | enum(string) | | Индивидуальный или групповой контакт |\\n| contact.crossboarding | 1 | boolean | | Признак принадлежности к онбордингу |\\n| contact.createdBy | 1 | string(8) | | Табельный номер создателя контакта |\\n| contact.emails | 0..1 | array(object) | | Массив электронных адресов |\\n| client | 1 | object | body | Данные клиента |\\n| client.ucpId | 0..1 | string(36) | | Идентификатор клиента ПАО |\\n| client.sbpId | 0..1 | string(36) | | Идентификатор клиента АО |\\n| client.inn | 0..1 | string(12) | | ИНН клиента |\\n| client.kpp | 0..1 | string(9) | | КПП клиента |\\n\\n#### Выходные параметры\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|------------|---------------|-------------|--------------------------|\\n| contactId | 1 | string(36) | Идентификатор созданного контакта |\\n\",\n \"reason\": \"Создание нового API-метода для реализации сервиса CLIENTS. POST /api/v1/clients/contacts-dgr на основании системной аналитики.\",\n \"hunks\": []\n }\n]\n```\n\napply_changeset: true",
+ "completed_at": "2026-04-09T16:04:21.738565+00:00"
+}
+```
+
+## request
+```json
+{
+ "request_id": "req_720824b619ab480686bf102929735bf7",
+ "session_id": "as_9f61b5dc531742afb0853a5a91e306fc",
+ "active_rag_session_id": "ae9d03f9-c65f-4468-be35-c0c145c3b5d3",
+ "process_version": "v2",
+ "created_at": "2026-04-09T16:04:58.737728+00:00",
+ "message": "какие методы апи есть в contacts_dgr?"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "normalized_query": "какие методы апи есть в contacts_dgr?",
+ "target_terms": [
+ "contacts_dgr"
+ ],
+ "anchors": {
+ "entity_names": [
+ "contacts_dgr"
+ ],
+ "file_names": [],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "entity",
+ "candidate_domains": [
+ "contacts_dgr"
+ ],
+ "candidate_subdomains": [
+ "contacts_dgr::contacts_list"
+ ],
+ "candidate_entities": [
+ "contacts_dgr",
+ "contactdgr",
+ "contactdgr"
+ ],
+ "candidate_apis": [],
+ "signal_types": [
+ "DOMAIN_ENTITY"
+ ]
+ },
+ "confidence": 0.8500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно касается методов API сущности contacts_dgr.",
+ "rag_session_id": "ae9d03f9-c65f-4468-be35-c0c145c3b5d3"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_EXPLAIN",
+ "subintent": "API_EXPOSED",
+ "confidence": 0.8500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [
+ "DOMAIN_ENTITY"
+ ],
+ "endpoint_paths": [],
+ "target_doc_hints": [],
+ "matched_aliases": [],
+ "target_terms": [
+ "contacts_dgr"
+ ]
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": []
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "require_rag_session",
+ "title": "Проверка RAG-сессии"
+ },
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+}
+```
+
+## process.v2.retrieval_policy
+```json
+{
+ "event": "retrieval_plan_resolved",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "limit": 400,
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%",
+ "%contacts_dgr%"
+ ],
+ "query_signals": [
+ "contacts_dgr"
+ ]
+ }
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "retrieval_profile_selected",
+ "profile": "api_exposed",
+ "layers": [
+ "D1_DOCUMENT_CATALOG"
+ ],
+ "filters": {
+ "metadata.type": "api_method",
+ "prefer_path_prefixes": [
+ "docs/api/",
+ "docs/endpoints/",
+ "docs/methods/",
+ "api/",
+ "endpoints/",
+ "methods/"
+ ],
+ "target_doc_hints": [],
+ "prefer_like_patterns": [
+ "%api%",
+ "%endpoint%",
+ "%method%",
+ "%эндпоинт%",
+ "%метод%",
+ "%contacts_dgr%"
+ ],
+ "query_signals": [
+ "contacts_dgr"
+ ]
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана"
+ },
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "fetch_rag_rows",
+ "title": "Получение строк из RAG"
+ },
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+}
+```
+
+## process.v2.evidence
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 2,
+ "endpoints": [
+ "GET /api/v1/clients/contacts-dgr",
+ "GET /api/v1/clients/contacts-dgr/{contactid}"
+ ]
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "evidence_assembled",
+ "mode": "api_exposed",
+ "endpoint_count": 2
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "build_api_exposed_evidence",
+ "title": "Сборка списка API"
+ },
+ "input": {},
+ "output": {
+ "endpoint_count": 2
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "step": {
+ "id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API"
+ },
+ "input": {},
+ "output": {
+ "answer_length": 77
+ }
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_explain.api_exposed",
+ "steps": [
+ {
+ "step_id": "require_rag_session",
+ "title": "Проверка RAG-сессии",
+ "input": {},
+ "output": {
+ "has_rag_session": true
+ }
+ },
+ {
+ "step_id": "resolve_retrieval_plan",
+ "title": "Выбор retrieval-плана",
+ "input": {},
+ "output": {
+ "profile": "api_exposed"
+ }
+ },
+ {
+ "step_id": "fetch_rag_rows",
+ "title": "Получение строк из RAG",
+ "input": {},
+ "output": {
+ "retrieved_row_count": 2
+ }
+ },
+ {
+ "step_id": "build_api_exposed_evidence",
+ "title": "Сборка списка API",
+ "input": {},
+ "output": {
+ "endpoint_count": 2
+ }
+ },
+ {
+ "step_id": "finalize_api_exposed_answer",
+ "title": "Формирование ответа со списком API",
+ "input": {},
+ "output": {
+ "answer_length": 77
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.api_exposed
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_explain.api_exposed"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "deterministic",
+ "answer_length": 77
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "GET /api/v1/clients/contacts-dgr\nGET /api/v1/clients/contacts-dgr/{contactid}",
+ "completed_at": "2026-04-09T16:05:01.127078+00:00"
+}
+```
diff --git a/runtime_traces/agent_requests/20260409-160845-116dcbbcf50b.md b/runtime_traces/agent_requests/20260409-160845-116dcbbcf50b.md
new file mode 100644
index 0000000..eefaae5
--- /dev/null
+++ b/runtime_traces/agent_requests/20260409-160845-116dcbbcf50b.md
@@ -0,0 +1,1478 @@
+# Runtime Trace: 20260409-160845-116dcbbcf50b
+
+- active_rag_session_id: a786b774-37ad-453f-9530-116dcbbcf50b
+
+## request
+```json
+{
+ "request_id": "req_40e0746ebfa546e09e1241a3fceb0f91",
+ "session_id": "as_42b0ce9854d14c7185aabaed0b49c996",
+ "active_rag_session_id": "a786b774-37ad-453f-9530-116dcbbcf50b",
+ "process_version": "v2",
+ "created_at": "2026-04-09T16:08:45.639639+00:00",
+ "message": "Сформируй документацию по системной аналитике\n/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_UPDATE",
+ "subintent": "FROM_FEATURE",
+ "normalized_query": "Сформируй документацию по системной аналитике /Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "target_terms": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "anchors": {
+ "entity_names": [
+ "Users",
+ "Dev_projects_v2"
+ ],
+ "file_names": [
+ "process/v2/test_doc/features/create_contact.md"
+ ],
+ "endpoint_paths": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "entity",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": [
+ "API_ENDPOINT",
+ "DOMAIN_ENTITY",
+ "LOGIC_FLOW"
+ ]
+ },
+ "confidence": 0.9500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно указывает на формирование документации по системной аналитике из указанного файла create_contact.md.",
+ "rag_session_id": "a786b774-37ad-453f-9530-116dcbbcf50b"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_UPDATE",
+ "subintent": "FROM_FEATURE",
+ "confidence": 0.9500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [
+ "API_ENDPOINT",
+ "DOMAIN_ENTITY",
+ "LOGIC_FLOW"
+ ],
+ "endpoint_paths": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ],
+ "matched_aliases": [],
+ "target_terms": [
+ "/users/alex/dev_projects_v2/ai"
+ ]
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ]
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_update.from_feature"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "resolve_source",
+ "title": "Определение источника аналитики"
+ },
+ "input": {
+ "source_kind": "",
+ "source_ref": "",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "load_source",
+ "title": "Загрузка системной аналитики"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "content_loaded": true,
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "parse_feature",
+ "title": "Парсинг функциональных требований"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "load_doc_rules",
+ "title": "Загрузка doc_rules"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "enabled": true,
+ "loaded": true,
+ "supported_doc_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.plan_change_units",
+ "system_prompt": "Ты классифицируешь units системной аналитики для построения плана изменений документации.\n\nВерни только JSON:\n{\n \"items\": [\n {\"index\": 0, \"doc_type\": \"api_method\", \"reason\": \"...\"}\n ]\n}\n\nПравила:\n- Используй только doc_type из allowed_doc_types.\n- Не пропускай item, даже если не уверен: выбери наиболее близкий тип.\n- Ориентируйся на heading и snippet.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"system_rules\": \"Системные правила документации:\\n1. Один устойчивый объект — один документ.\\n2. Документы не должны дублировать друг друга по смыслу.\\n3. Связи между документами должны быть явными (related_docs/links).\\n4. Документация организована иерархически по папкам docs/*.\\n5. Markdown-документ состоит из YAML frontmatter и body.\\n6. Обязательные поля frontmatter: id, title, doc_type, related_docs, status, domain, sub_domain.\",\n \"allowed_doc_types\": [\n \"ui_page\",\n \"api_method\",\n \"logic_block\",\n \"architecture_overview\",\n \"integration_doc\",\n \"domain_entity\",\n \"glossary_item\",\n \"index_page\"\n ],\n \"items\": [\n {\n \"index\": 0,\n \"heading\": \"FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\",\n \"snippet\": \"- type: ui_page\\n- id: ui.contacts_dgr.create\\n\\nОсновной сценарий:\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- ui.contacts_dgr вызывает endpoint POST /api/v1/clients/contacts-dgr для создания карточки контакта ДГР.\\n- ufs.contacts_dgr обрабатывает запрос и возвращает ответ.\\n- ui.contacts_dgr отображает результат создания контакта ДГР в виде push-уведомления.\"\n },\n {\n \"index\": 1,\n \"heading\": \"FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\",\n \"snippet\": \"- type: api_method\\n- id: ufs.contacts_dgr.api.create\\n- endpoint: POST /api/v1/clients/contacts-dgr\\n\\nТребования для основного сценария:\\n- Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом BAD_REQUEST.\\n- Авторизовать запрос по наличию периметра CI02792632.ContactsDGR.Create. При отсутствии периметра завершить основной сценарий с кодом UNAUTHORIZED.\\n- Для и\"\n }\n ]\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.plan"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"items\": [\n {\"index\": 0, \"doc_type\": \"ui_page\"},\n {\"index\": 1, \"doc_type\": \"api_method\"}\n ]\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "build_change_plan",
+ "title": "Построение плана изменений"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "docs_rows": 7,
+ "planned_changes": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "changeset_prompt_built",
+ "doc_type": "ui_page",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "prompt_chars": 11076,
+ "rules_chars": 9572
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.build_doc_changeset",
+ "system_prompt": "Ты формируешь один item changeset для документации на основе системной аналитики и правил doc_rules.\n\nВерни только один JSON-объект (RFC8259) формата:\n{\n \"op\": \"create|update|delete\",\n \"path\": \"docs/...\",\n \"reason\": \"краткая причина\",\n \"proposed_content\": \"полный markdown документа для create/update\"\n}\n\nСхема и ограничения:\n- Обязательные поля всегда: op, path, reason.\n- Для op=create/update поле proposed_content обязательно и содержит полный markdown документа:\n 1) frontmatter между --- и ---,\n 2) затем body согласно doc_rules.\n- Для op=delete поле proposed_content запрещено.\n- В JSON используй двойные кавычки, без trailing commas.\n- Никаких code fences (```), комментариев и текста до/после JSON.\n\nПравила:\n- Строго соблюдай структуру и ограничения из doc_rules_context.\n- Для create/update верни полный итоговый markdown (frontmatter + body).\n- Для update не используй placeholder-тексты; возвращай пригодный к сохранению документ.\n- reason обязателен, короткий, по сути изменения.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"change_request\": {\n \"op\": \"create\",\n \"path\": \"docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md\",\n \"doc_type\": \"ui_page\",\n \"doc_id\": \"ui_page.fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр\",\n \"title\": \"FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\",\n \"domain\": \"contacts_dgr\",\n \"sub_domain\": \"create_contact\",\n \"reason\": \"Из unit 'FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»' системной аналитики (test).\",\n \"source_refs\": [\n \"section: 5. Функциональные требования\"\n ],\n \"related_docs\": [],\n \"requirement_body\": \"- type: ui_page\\n- id: ui.contacts_dgr.create\\n\\nОсновной сценарий:\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- ui.contacts_dgr вызывает endpoint POST /api/v1/clients/contacts-dgr для создания карточки контакта ДГР.\\n- ufs.contacts_dgr обрабатывает запрос и возвращает ответ.\\n- ui.contacts_dgr отображает результат создания контакта ДГР в виде push-уведомления.\"\n },\n \"doc_rules_context\": \"## Global rules\\n\\n### documentation-rules.md\\n\\n# Documentation Rules\\n\\nЭтот каталог оформляет MVP документации проекта в атомарном формате.\\n\\n## Базовая структура\\n\\n- Каждый документ содержит YAML frontmatter.\\n- В документе должен быть один `H1`, совпадающий с `title`.\\n- Основные разделы оформляются как `## Summary` и `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Связи, сущности и навигация описываются во frontmatter через `related_docs`, `links`, `entities`, `parent`, `children`.\\n\\n## Summary\\n\\n- Краткий explain-слой быстрого контекста.\\n- Должен позволять быстро понять назначение документа без чтения `Details`.\\n- Предпочтительный формат: компактный список ключевых фактов без длинных абзацев.\\n\\n## Details\\n\\n- Раскрывает полное описание объекта.\\n- Структура `Details` зависит от типа документа.\\n- Сценарии, ограничения, интеграции, ошибки и кодовые привязки должны быть разнесены по отдельным подразделам.\\n\\n## API documents\\n\\nДля `api_method` внутри `## Details` обязательны разделы:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\nЕсли у метода есть интеграции и ошибки, также обязательны:\\n- `### Интеграции`\\n- `### Ошибки`\\n- `### Связанный код`\\n- `### История изменений`\\n\\n### Сценарий\\n\\nСценарий оформляется как технический use case и содержит:\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработку ошибок\\n- постусловие\\n\\n### Требования\\n\\n- Функциональные требования маркируются как `FR-1`, `FR-2`, ...\\n- Нефункциональные требования маркируются как `NFR-1`, `NFR-2`, ...\\n- Идентификаторы требований локальны в рамках одного документа.\\n\\n### Контракт\\n\\nКонтракт должен быть пригоден для последующей сборки OpenAPI-спецификации и включать:\\n- входные параметры\\n- выходные параметры\\n- структуру JSON-сообщений\\n- обязательность полей\\n- типы и ограничения\\n- описание полей\\n- правила заполнения\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n### global/documentation-system.md\\n\\n# Documentation System\\n\\n## Назначение\\n\\nЭтот файл задает общую модель документации проекта.\\n\\n## Базовая модель\\n\\nКаждый документ должен состоять из двух слоев:\\n- YAML frontmatter\\n- контент\\n\\nКонтент всегда состоит из двух обязательных разделов:\\n- `## Summary`\\n- `## Details`\\n\\nНад ними должен быть один заголовок `# `, совпадающий со значением `title` во frontmatter.\\n\\n## Принципы\\n\\n- Документы должны быть атомарными.\\n- Один документ описывает одну тему.\\n- Вместо дублирования между документами используются явные ссылки.\\n- Связи и навигация должны быть формализованы.\\n- Документы должны быть пригодны для чтения человеком и для RAG.\\n- Документы должны быть пригодны для частичного обновления без деградации структуры.\\n\\n## Типы документов\\n\\nНа уровне проекта поддерживаются типы:\\n- `api_method`\\n- `logic_block`\\n- `architecture_overview`\\n- `domain_entity`\\n- `ui_page`\\n- `integration_doc`\\n- `index_page`\\n- `glossary_item`\\n\\n### global/frontmatter.md\\n\\n# Frontmatter Rules\\n\\n## Назначение\\n\\nЭтот файл описывает единый контракт YAML frontmatter для всех документов.\\n\\n## Обязательные поля\\n\\n```yaml\\nid: string\\ntitle: string\\ndoc_type: string\\ndomain: string\\nsub_domain: string\\nrelated_docs: []\\nstatus: string\\n```\\n\\n## Поля совместимости и рекомендуемые поля\\n\\n```yaml\\ntype: string\\nname: string\\nmodule: string\\nlayer: string\\nupdated_at: YYYY-MM-DD\\ntags: []\\nentities: []\\nparent: string | null\\nchildren: []\\nlinks: {}\\nsource_of_truth: string\\nrelated_code: []\\nsystem_analytics_refs: []\\n```\\n\\n## Правила\\n\\n- `id` должен быть стабильным и уникальным в пределах документации проекта.\\n- `title` — человекочитаемый заголовок.\\n- `doc_type` — канонический тип документа.\\n- `domain` и `sub_domain` определяют бизнес-контекст документа.\\n- `related_docs` хранит явные связи с другими markdown-документами.\\n- `status` хранит жизненный цикл документа: например `draft`, `approved`, `active`.\\n- `type` допустимо дублировать как alias для tooling-совместимости с индексаторами.\\n- `name` — короткое системное имя документа.\\n- `module` — модуль или подсистема.\\n- `layer` — слой системы.\\n- `updated_at` хранится в формате `YYYY-MM-DD`.\\n\\n## Связи и навигация\\n\\n- `entities` описывает сущности, связанные с документом.\\n- `parent` и `children` описывают иерархию.\\n- `links` описывает typed graph связей между документами, кодом и интеграциями.\\n\\n## Формат links\\n\\n```yaml\\nlinks:\\n called_by:\\n - ext.health_probe\\n uses_logic:\\n - logic.some_flow\\n integrates_with:\\n - ext.some_system\\n```\\n\\n### global/linking.md\\n\\n# Linking Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как связывать документы между собой.\\n\\n## Иерархия\\n\\n- `parent` используется для родительского документа.\\n- `children` используется для прямых дочерних документов.\\n- Иерархия должна быть осмысленной и стабильной.\\n- Для общей точки входа допустим `index_page`.\\n\\n## Графовые связи\\n\\nДля `related_docs` используются ссылки на соседние документы.\\n\\nДля `links` рекомендуется использовать typed-ключи:\\n- `called_by`\\n- `uses_logic`\\n- `reads_db`\\n- `writes_db`\\n- `integrates_with`\\n- `used_by`\\n- `exposes_api`\\n- `uses_entities`\\n\\n## Правила использования\\n\\n- Если документ логически входит в другой, использовать `parent`/`children`.\\n- Если связь нужна для навигации между равноправными документами, дублировать ее в `related_docs`.\\n- Если связь отражает поведение, интеграции или переиспользование, фиксировать ее в `links`.\\n- Детальное описание интеграций хранить в body документа, а не только во frontmatter.\\n\\n### global/naming.md\\n\\n# Naming Rules\\n\\n## Назначение\\n\\nЭтот файл описывает правила именования документов, файлов и идентификаторов.\\n\\n## Правила для файлов\\n\\n- Имена файлов должны быть в kebab-case.\\n- Имя файла должно отражать одну тему.\\n- Для шаблонов использовать суффикс `.template.md`.\\n\\n## Правила для id\\n\\n- `id` строится в формате `.`.\\n- Примеры:\\n - `api.send_message_endpoint`\\n - `logic.telegram_notification_loop`\\n - `architecture.telegram_notify_app`\\n\\n## Правила для title\\n\\n- `title` должен быть кратким и человекочитаемым.\\n- В `title` допускаются пробелы и естественный язык.\\n\\n### global/writing-style.md\\n\\n# Writing Style\\n\\n## Назначение\\n\\nЭтот файл задает правила стиля для текстового наполнения документации.\\n\\n## Правила стиля\\n\\n- Текст должен быть лаконичным.\\n- Формулировки должны быть точными и техническими.\\n- Summary должен быть кратким explain-слоем.\\n- Details должен раскрывать суть без лишней воды.\\n- Нежелательно смешивать несколько тем в одном документе.\\n- Если детали относятся к другому артефакту, их нужно выносить в отдельный документ.\\n\\n## Язык\\n\\n- Основной язык документации — русский.\\n- Технические термины, названия классов, API, RAG, OpenAPI, runtime и другие устоявшиеся identifiers можно оставлять на английском.\\n\\n## Artifact rules (ui_page)\\n\\n# UI Page Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для документов типа `ui_page`.\\n\\n## Когда использовать\\n\\nИспользовать для описания одной пользовательской страницы, экрана или отдельного UI-сценария.\\n\\n## Обязательная структура\\n\\nДокумент должен содержать:\\n- YAML frontmatter\\n- `# `\\n- `## Summary`\\n- `## Details`\\n\\n## Что описывать в Details\\n\\n- назначение страницы\\n- пользовательский сценарий\\n- основные блоки интерфейса\\n- связанные API и сущности\\n\\n## Template (ui_page)\\n\\n---\\nid: ui.example_page\\ntype: ui_page\\ndoc_type: ui_page\\nname: example_page\\ntitle: Пример UI-страницы\\nmodule: example_module\\nlayer: presentation\\ndomain: example_domain\\nsub_domain: example_subdomain\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: mixed\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# Пример UI-страницы\\n\\n## Summary\\n\\nКраткое описание страницы и её назначения.\\n\\n## Details\\n\\n### Назначение страницы\\n\\n### Пользовательский сценарий\\n\\n### Основные блоки интерфейса\\n\\n### Связанные API и сущности\\n\\n### Функциональные требования\\n\\n### Нефункциональные требования\\n\\n### Ограничения и граничные случаи\\n\\n### Ошибки и валидации\\n\\n### Связанный код\\n\\n### Связанные документы\\n\\n### История изменений\\n\\n## Section rule: details\\n\\n# Details Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает общие правила для секции `## Details`.\\n\\n## Правила\\n\\n- `Details` оформляется как `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Структура Details зависит от типа документа.\\n- В Details не нужно повторно дублировать навигацию и связи, если они уже есть во frontmatter.\\n- Интеграции, ошибки и кодовые привязки должны быть выделены в отдельные подразделы, если они существенны для понимания документа.\\n\\n## Section rule: requirements-format\\n\\n# Requirements Format Rules\\n\\n## Назначение\\n\\nЭтот файл задает формат для функциональных и нефункциональных требований.\\n\\n## Функциональные требования\\n\\n- Использовать коды `FR-1`, `FR-2`, `FR-3` и так далее.\\n- Каждое требование должно описывать отдельный обязательный аспект поведения.\\n- Идентификаторы локальны в пределах одного документа.\\n\\n## Нефункциональные требования\\n\\n- Использовать коды `NFR-1`, `NFR-2`, `NFR-3` и так далее.\\n- Требования должны описывать характеристики качества, ограничения и эксплуатационные свойства.\\n\\n## Section rule: summary\\n\\n# Summary Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для секции `## Summary`.\\n\\n## Правила\\n\\n- Summary должен быть коротким explain-слоем быстрого контекста.\\n- Summary должен объяснять суть документа без лишних деталей.\\n- Summary должен быть пригоден для explain и быстрого чтения.\\n- Предпочтительный формат: список ключевых фактов `Purpose`, `Actor`, `Trigger`, `Errors`, `Related ...` и т.д.\\n- Для крупных документов допустим более длинный summary, если он остается структурированным.\"\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.changeset"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"op\": \"create\",\n \"path\": \"docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md\",\n \"reason\": \"Создание нового UI сценария 'Контакты ДГР. Создание карточки контакта ДГР'\",\n \"proposed_content\": \"---\\nid: ui_page.fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр\\ntype: ui_page\\ndoc_type: ui_page\\ntitle: FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\\ndomain: contacts_dgr\\nsub_domain: create_contact\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: mixed\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\n\\n## Summary\\n\\n- **Назначение**: Реализация сценария добавления новой карточки контакта ДГР.\\n- **Актор**: Пользователь.\\n- **Триггер**: Заполнение формы и нажатие кнопки «Добавить».\\n- **Связанный API**: POST /api/v1/clients/contacts-dgr.\\n- **Обработка**: Обработка запроса компонентом ufs.contacts_dgr.\\n- **Уведомление**: Отображение результата операции пользователю через push-уведомление.\\n\\n## Details\\n\\n### Назначение страницы\\nРеализует функционал добавления новых контактов ДГР через интерфейс пользователя.\\n\\n### Пользовательский сценарий\\nПользователь заполняет форму с атрибутами контакта и инициирует процесс сохранения нажав кнопку «Добавить».\\n\\n### Основные блоки интерфейса\\nФорма ввода атрибутов контакта и кнопка подтверждения действия.\\n\\n### Связанные API и сущности\\nPOST /api/v1/clients/contacts-dgr\\n\\n### Функциональные требования\\n- FR-1: Пользователю предоставляется форма для ввода атрибутов контакта ДГР.\\n- FR-2: После успешной отправки формы система уведомляет пользователя о результате операции.\\n\\n### Нефункциональные требования\\nОтсутствуют специфические требования.\\n\\n### Ограничения и граничные случаи\\nНе определены.\\n\\n### Ошибки и валидации\\nНе описаны.\\n\\n### Связанный код\\nНе указан.\\n\\n### Связанные документы\\nНе указаны.\\n\\n### История изменений\\nНе применимо.\"\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "changeset_prompt_built",
+ "doc_type": "api_method",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "prompt_chars": 15670,
+ "rules_chars": 11520
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.build_doc_changeset",
+ "system_prompt": "Ты формируешь один item changeset для документации на основе системной аналитики и правил doc_rules.\n\nВерни только один JSON-объект (RFC8259) формата:\n{\n \"op\": \"create|update|delete\",\n \"path\": \"docs/...\",\n \"reason\": \"краткая причина\",\n \"proposed_content\": \"полный markdown документа для create/update\"\n}\n\nСхема и ограничения:\n- Обязательные поля всегда: op, path, reason.\n- Для op=create/update поле proposed_content обязательно и содержит полный markdown документа:\n 1) frontmatter между --- и ---,\n 2) затем body согласно doc_rules.\n- Для op=delete поле proposed_content запрещено.\n- В JSON используй двойные кавычки, без trailing commas.\n- Никаких code fences (```), комментариев и текста до/после JSON.\n\nПравила:\n- Строго соблюдай структуру и ограничения из doc_rules_context.\n- Для create/update верни полный итоговый markdown (frontmatter + body).\n- Для update не используй placeholder-тексты; возвращай пригодный к сохранению документ.\n- reason обязателен, короткий, по сути изменения.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"change_request\": {\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md\",\n \"doc_type\": \"api_method\",\n \"doc_id\": \"api_method.fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr\",\n \"title\": \"FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\",\n \"domain\": \"contacts_dgr\",\n \"sub_domain\": \"create_contact\",\n \"reason\": \"Из unit 'FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr' системной аналитики (test).\",\n \"source_refs\": [\n \"section: 5. Функциональные требования\"\n ],\n \"related_docs\": [],\n \"requirement_body\": \"- type: api_method\\n- id: ufs.contacts_dgr.api.create\\n- endpoint: POST /api/v1/clients/contacts-dgr\\n\\nТребования для основного сценария:\\n- Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом BAD_REQUEST.\\n- Авторизовать запрос по наличию периметра CI02792632.ContactsDGR.Create. При отсутствии периметра завершить основной сценарий с кодом UNAUTHORIZED.\\n- Для исполнения запроса на создание контакта вызвать endpoint POST /contacts в prpb.contacts_dgr.\\n- Вернуть ответ ui.contacts_dgr в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\nКонтракт POST /contacts\\n\\nЗапрос\\n\\n**headers**\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|---|---|---|---|---|\\n| `X-Request-Id` | 1 | `uuid` | `header` | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | `header` | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | `header` | Табельный номер пользователя, вызвавшего сервис |\\n\\n**body**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contact` | 1 | `object` | Данные контакта ДГР |\\n| `contact.lastName` | 0..1 | `string(100)` | Фамилия контакта |\\n| `contact.firstName` | 0..1 | `string(100)` | Имя контакта |\\n| `contact.middleName` | 0..1 | `string(100)` | Отчество контакта |\\n| `contact.name` | 0..1 | `string(100)` | Название группового контакта |\\n| `contact.description` | 0..1 | `string(1000)` | Описание группового контакта |\\n| `contact.position` | 0..1 | `string(100)` | Должность контакта у клиента |\\n| `contact.comment` | 0..1 | `string(1000)` | Комментарий к контакту |\\n| `contact.contactType` | 1 | `enum(string)` | `Individual`, `Group` |\\n| `contact.crossboarding` | 1 | `boolean` | Признак принадлежности контакта к процессу онбординга |\\n| `contact.createdBy` | 1 | `string(8)` | Табельный номер пользователя, создавшего контакт |\\n| `contact.emails` | 0..1 | `array(object)` | Массив электронных адресов контакта |\\n| `contact.emails.value` | 1 | `string(100)` | Электронный адрес |\\n| `contact.emails.main` | 1 | `boolean` | Признак основной почты |\\n| `contact.phones` | 0..1 | `array(object)` | Массив телефонных номеров контакта |\\n| `contact.phones.value` | 1 | `string(20)` | Телефонный номер контакта |\\n| `contact.phones.extValue` | 0..1 | `string(10)` | Добавочный номер |\\n| `contact.phones.main` | 1 | `boolean` | Признак основного телефона |\\n| `contact.phones.mobile` | 1 | `boolean` | Признак мобильного телефона |\\n| `client` | 1 | `object` | Данные клиента |\\n| `client.ucpId` | 0..1 | `string(36)` | Идентификатор клиента ПАО |\\n| `client.sbpId` | 0..1 | `string(36)` | Идентификатор клиента АО |\\n| `client.inn` | 0..1 | `string(12)` | ИНН клиента |\\n| `client.kpp` | 0..1 | `string(9)` | КПП клиента |\\n\\nОтвет\\n\\n**ContactDGRCreateRsDto**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contactId` | 1 | `string(36)` | Идентификатор контакта |\"\n },\n \"doc_rules_context\": \"## Global rules\\n\\n### documentation-rules.md\\n\\n# Documentation Rules\\n\\nЭтот каталог оформляет MVP документации проекта в атомарном формате.\\n\\n## Базовая структура\\n\\n- Каждый документ содержит YAML frontmatter.\\n- В документе должен быть один `H1`, совпадающий с `title`.\\n- Основные разделы оформляются как `## Summary` и `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Связи, сущности и навигация описываются во frontmatter через `related_docs`, `links`, `entities`, `parent`, `children`.\\n\\n## Summary\\n\\n- Краткий explain-слой быстрого контекста.\\n- Должен позволять быстро понять назначение документа без чтения `Details`.\\n- Предпочтительный формат: компактный список ключевых фактов без длинных абзацев.\\n\\n## Details\\n\\n- Раскрывает полное описание объекта.\\n- Структура `Details` зависит от типа документа.\\n- Сценарии, ограничения, интеграции, ошибки и кодовые привязки должны быть разнесены по отдельным подразделам.\\n\\n## API documents\\n\\nДля `api_method` внутри `## Details` обязательны разделы:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\nЕсли у метода есть интеграции и ошибки, также обязательны:\\n- `### Интеграции`\\n- `### Ошибки`\\n- `### Связанный код`\\n- `### История изменений`\\n\\n### Сценарий\\n\\nСценарий оформляется как технический use case и содержит:\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработку ошибок\\n- постусловие\\n\\n### Требования\\n\\n- Функциональные требования маркируются как `FR-1`, `FR-2`, ...\\n- Нефункциональные требования маркируются как `NFR-1`, `NFR-2`, ...\\n- Идентификаторы требований локальны в рамках одного документа.\\n\\n### Контракт\\n\\nКонтракт должен быть пригоден для последующей сборки OpenAPI-спецификации и включать:\\n- входные параметры\\n- выходные параметры\\n- структуру JSON-сообщений\\n- обязательность полей\\n- типы и ограничения\\n- описание полей\\n- правила заполнения\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n### global/documentation-system.md\\n\\n# Documentation System\\n\\n## Назначение\\n\\nЭтот файл задает общую модель документации проекта.\\n\\n## Базовая модель\\n\\nКаждый документ должен состоять из двух слоев:\\n- YAML frontmatter\\n- контент\\n\\nКонтент всегда состоит из двух обязательных разделов:\\n- `## Summary`\\n- `## Details`\\n\\nНад ними должен быть один заголовок `# `, совпадающий со значением `title` во frontmatter.\\n\\n## Принципы\\n\\n- Документы должны быть атомарными.\\n- Один документ описывает одну тему.\\n- Вместо дублирования между документами используются явные ссылки.\\n- Связи и навигация должны быть формализованы.\\n- Документы должны быть пригодны для чтения человеком и для RAG.\\n- Документы должны быть пригодны для частичного обновления без деградации структуры.\\n\\n## Типы документов\\n\\nНа уровне проекта поддерживаются типы:\\n- `api_method`\\n- `logic_block`\\n- `architecture_overview`\\n- `domain_entity`\\n- `ui_page`\\n- `integration_doc`\\n- `index_page`\\n- `glossary_item`\\n\\n### global/frontmatter.md\\n\\n# Frontmatter Rules\\n\\n## Назначение\\n\\nЭтот файл описывает единый контракт YAML frontmatter для всех документов.\\n\\n## Обязательные поля\\n\\n```yaml\\nid: string\\ntitle: string\\ndoc_type: string\\ndomain: string\\nsub_domain: string\\nrelated_docs: []\\nstatus: string\\n```\\n\\n## Поля совместимости и рекомендуемые поля\\n\\n```yaml\\ntype: string\\nname: string\\nmodule: string\\nlayer: string\\nupdated_at: YYYY-MM-DD\\ntags: []\\nentities: []\\nparent: string | null\\nchildren: []\\nlinks: {}\\nsource_of_truth: string\\nrelated_code: []\\nsystem_analytics_refs: []\\n```\\n\\n## Правила\\n\\n- `id` должен быть стабильным и уникальным в пределах документации проекта.\\n- `title` — человекочитаемый заголовок.\\n- `doc_type` — канонический тип документа.\\n- `domain` и `sub_domain` определяют бизнес-контекст документа.\\n- `related_docs` хранит явные связи с другими markdown-документами.\\n- `status` хранит жизненный цикл документа: например `draft`, `approved`, `active`.\\n- `type` допустимо дублировать как alias для tooling-совместимости с индексаторами.\\n- `name` — короткое системное имя документа.\\n- `module` — модуль или подсистема.\\n- `layer` — слой системы.\\n- `updated_at` хранится в формате `YYYY-MM-DD`.\\n\\n## Связи и навигация\\n\\n- `entities` описывает сущности, связанные с документом.\\n- `parent` и `children` описывают иерархию.\\n- `links` описывает typed graph связей между документами, кодом и интеграциями.\\n\\n## Формат links\\n\\n```yaml\\nlinks:\\n called_by:\\n - ext.health_probe\\n uses_logic:\\n - logic.some_flow\\n integrates_with:\\n - ext.some_system\\n```\\n\\n### global/linking.md\\n\\n# Linking Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как связывать документы между собой.\\n\\n## Иерархия\\n\\n- `parent` используется для родительского документа.\\n- `children` используется для прямых дочерних документов.\\n- Иерархия должна быть осмысленной и стабильной.\\n- Для общей точки входа допустим `index_page`.\\n\\n## Графовые связи\\n\\nДля `related_docs` используются ссылки на соседние документы.\\n\\nДля `links` рекомендуется использовать typed-ключи:\\n- `called_by`\\n- `uses_logic`\\n- `reads_db`\\n- `writes_db`\\n- `integrates_with`\\n- `used_by`\\n- `exposes_api`\\n- `uses_entities`\\n\\n## Правила использования\\n\\n- Если документ логически входит в другой, использовать `parent`/`children`.\\n- Если связь нужна для навигации между равноправными документами, дублировать ее в `related_docs`.\\n- Если связь отражает поведение, интеграции или переиспользование, фиксировать ее в `links`.\\n- Детальное описание интеграций хранить в body документа, а не только во frontmatter.\\n\\n### global/naming.md\\n\\n# Naming Rules\\n\\n## Назначение\\n\\nЭтот файл описывает правила именования документов, файлов и идентификаторов.\\n\\n## Правила для файлов\\n\\n- Имена файлов должны быть в kebab-case.\\n- Имя файла должно отражать одну тему.\\n- Для шаблонов использовать суффикс `.template.md`.\\n\\n## Правила для id\\n\\n- `id` строится в формате `.`.\\n- Примеры:\\n - `api.send_message_endpoint`\\n - `logic.telegram_notification_loop`\\n - `architecture.telegram_notify_app`\\n\\n## Правила для title\\n\\n- `title` должен быть кратким и человекочитаемым.\\n- В `title` допускаются пробелы и естественный язык.\\n\\n### global/writing-style.md\\n\\n# Writing Style\\n\\n## Назначение\\n\\nЭтот файл задает правила стиля для текстового наполнения документации.\\n\\n## Правила стиля\\n\\n- Текст должен быть лаконичным.\\n- Формулировки должны быть точными и техническими.\\n- Summary должен быть кратким explain-слоем.\\n- Details должен раскрывать суть без лишней воды.\\n- Нежелательно смешивать несколько тем в одном документе.\\n- Если детали относятся к другому артефакту, их нужно выносить в отдельный документ.\\n\\n## Язык\\n\\n- Основной язык документации — русский.\\n- Технические термины, названия классов, API, RAG, OpenAPI, runtime и другие устоявшиеся identifiers можно оставлять на английском.\\n\\n## Artifact rules (api_method)\\n\\n# API Method Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для документов типа `api_method`.\\n\\n## Когда использовать\\n\\nИспользовать для описания одного HTTP endpoint или одного отдельного API метода.\\n\\n## Обязательная структура\\n\\nДокумент должен содержать:\\n- YAML frontmatter\\n- `# `\\n- `## Summary`\\n- `## Details`\\n\\nВнутри `## Details` обязательны:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\n## Особые правила\\n\\n- Сценарий оформляется как технический use case.\\n- Функциональные требования маркируются `FR-*`.\\n- Нефункциональные требования маркируются `NFR-*`.\\n- Контракт должен быть пригоден для последующей сборки OpenAPI.\\n- Если у метода есть интеграции, они выносятся в `### Интеграции`.\\n- Ошибки и HTTP-коды либо описываются в `### Ошибки`, либо ссылаются на централизованный каталог ошибок.\\n\\n## Ошибки оформления\\n\\n- Нельзя заменять контракт общим текстовым описанием.\\n- Нельзя смешивать несколько endpoint в одном документе.\\n- Нельзя хранить связи и навигацию вне frontmatter.\\n\\n## Template (api_method)\\n\\n---\\nid: api.example_method\\ntype: api_method\\ndoc_type: api_method\\nname: example_method\\ntitle: HTTP API /example\\nmodule: example_module\\nlayer: application\\ndomain: example_domain\\nsub_domain: example_subdomain\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: code\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# HTTP API /example\\n\\n## Summary\\n\\nКраткое описание метода.\\n\\n## Details\\n\\n## Описание\\n\\nКороткое описание сути метода.\\n\\n## Сценарий\\n\\n**Название:**\\n\\n**Предусловия:**\\n- \\n\\n**Триггер:**\\n- \\n\\n**Основной сценарий:**\\n1. \\n\\n**Альтернативный сценарий:**\\n1. \\n\\n**Обработка ошибок:**\\n1. \\n\\n**Постусловие:**\\n- \\n\\n## Функциональные требования\\n\\n**FR-1.**\\n\\n## Нефункциональные требования\\n\\n**NFR-1.**\\n\\n## Контракт\\n\\n### Входные параметры\\n\\n| Параметр | Где передается | Тип | Обязательность | Ограничения | Описание | Пример |\\n|---|---|---|---|---|---|---|\\n| | | | | | | |\\n\\n### Выходные параметры\\n\\n| Поле | Тип | Обязательность | Ограничения | Описание | Заполнение | Пример |\\n|---|---|---|---|---|---|---|\\n| | | | | | | |\\n\\n### Интеграции\\n\\n### Ошибки\\n\\n### Связанный код\\n\\n### История изменений\\n\\n## Section rule: api-contract\\n\\n# API Contract Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как оформлять подраздел `## Контракт` в API-документах.\\n\\n## Что должно быть описано\\n\\n- входные параметры\\n- выходные параметры\\n- JSON-структуры запросов и ответов\\n- обязательность полей\\n- типы полей\\n- ограничения\\n- описание назначения полей\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n## Правило качества\\n\\nКонтракт должен быть достаточно формальным, чтобы по нему можно было собрать OpenAPI-спецификацию.\\n\\n## Section rule: api-scenario\\n\\n# API Scenario Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как оформлять подраздел `### Сценарий` в API-документах.\\n\\n## Обязательные части\\n\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработка ошибок\\n- постусловие\\n\\n## Правила\\n\\n- Сценарий должен быть лаконичным.\\n- Сценарий должен отражать суть шага.\\n- Сложные технические детали надо выносить в `FR-*`.\\n\\n## Section rule: details\\n\\n# Details Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает общие правила для секции `## Details`.\\n\\n## Правила\\n\\n- `Details` оформляется как `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Структура Details зависит от типа документа.\\n- В Details не нужно повторно дублировать навигацию и связи, если они уже есть во frontmatter.\\n- Интеграции, ошибки и кодовые привязки должны быть выделены в отдельные подразделы, если они существенны для понимания документа.\\n\\n## Section rule: requirements-format\\n\\n# Requirements Format Rules\\n\\n## Назначение\\n\\nЭтот файл задает формат для функциональных и нефункциональных требований.\\n\\n## Функциональные требования\\n\\n- Использовать коды `FR-1`, `FR-2`, `FR-3` и так далее.\\n- Каждое требование должно описывать отдельный обязательный аспект поведения.\\n- Идентификаторы локальны в пределах одного документа.\\n\\n## Нефункциональные требования\\n\\n- Использовать коды `NFR-1`, `NFR-2`, `NFR-3` и так далее.\\n- Требования должны описывать характеристики качества, ограничения и эксплуатационные свойства.\\n\\n## Section rule: summary\\n\\n# Summary Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для секции `## Summary`.\\n\\n## Правила\\n\\n- Summary должен быть коротким explain-слоем быстрого контекста.\\n- Summary должен объяснять суть документа без лишних деталей.\\n- Summary должен быть пригоден для explain и быстрого чтения.\\n- Предпочтительный формат: список ключевых фактов `Purpose`, `Actor`, `Trigger`, `Errors`, `Related ...` и т.д.\\n- Для крупных документов допустим более длинный summary, если он остается структурированным.\"\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.changeset"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md\",\n \"reason\": \"Создание нового API-метода FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr из системной аналитики.\",\n \"proposed_content\": \"---\\nid: api_method.fr2_реализовать_сервис_клиентов_post_api_v1_клиенты_kontakty_dgr\\ntype: api_method\\ndoc_type: api_method\\nname: fr2_реализовать_сервис_клиентов_post_api_v1_клиенты_kontakty_dgr\\ntitle: FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\\ndomain: contacts_dgr\\nsub_domain: create_contact\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2023-10-10\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\\n\\n## Summary\\n\\nЦель данного API-метода заключается в создании контакта ДГР в системе клиентов. Через данный endpoint осуществляется передача информации о контакте и клиенте, после чего происходит вызов внешнего сервиса для создания контакта и возврат сформированного ответа.\\n\\n## Details\\n\\n## Описание\\n\\nМетод предназначен для создания новых контактов ДГР в системе клиентов. Он включает проверку входящих данных, авторизацию доступа, передачу информации внешнему сервису и формирование ответа пользователю.\\n\\n## Сценарий\\n\\n**Название:** Создание контакта ДГР\\n\\n**Предусловия:**\\n- Пользователь аутентифицирован в системе.\\n- У пользователя имеется доступ к периметру CI02792632.ContactsDGR.Create.\\n\\n**Триггер:**\\n- Отправка POST-запроса на endpoint `/api/v1/clients/contacts-dgr`.\\n\\n**Основной сценарий:**\\n1. Проверяется соответствие запроса JSON-схеме.\\n2. Проводится авторизация пользователя.\\n3. Вызывается внешний endpoint `/contacts` в сервисе prpb.contacts_dgr для создания контакта.\\n4. Формируется и возвращается ответ пользователю.\\n\\n**Альтернативный сценарий:**\\n- При ошибке проверки схемы или авторизации метод завершает выполнение с соответствующим статусом HTTP.\\n\\n**Обработка ошибок:**\\n- HTTP 400 Bad Request при несоответствии схемы.\\n- HTTP 401 Unauthorized при отсутствии необходимого периметра доступа.\\n\\n**Постусловие:**\\n- Создан новый контакт ДГР в системе клиентов.\\n\\n## Функциональные требования\\n\\n**FR-1.** Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом BAD_REQUEST.\\n**FR-2.** Авторизовать запрос по наличию периметра CI02792632.ContactsDGR.Create. При отсутствии периметра завершить основной сценарий с кодом UNAUTHORIZED.\\n**FR-3.** Для исполнения запроса на создание контакта вызвать endpoint POST /contacts в prpb.contacts_dgr.\\n**FR-4.** Вернуть ответ ui.contacts_dgr в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\n## Нефункциональные требования\\n\\n(NFR пока отсутствуют)\\n\\n## Контракт\\n\\n### Входные параметры\\n\\n**headers**\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|---|---|---|---|---|\\n| `X-Request-Id` | 1 | `uuid` | `header` | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | `header` | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | `header` | Табельный номер пользователя, вызвавшего сервис |\\n\\n**body**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contact` | 1 | `object` | Данные контакта ДГР |\\n| `contact.lastName` | 0..1 | `string(100)` | Фамилия контакта |\\n| `contact.firstName` | 0..1 | `string(100)` | Имя контакта |\\n| `contact.middleName` | 0..1 | `string(100)` | Отчество контакта |\\n| `contact.name` | 0..1 | `string(100)` | Название группового контакта |\\n| `contact.description` | 0..1 | `string(1000)` | Описание группового контакта |\\n| `contact.position` | 0..1 | `string(100)` | Должность контакта у клиента |\\n| `contact.comment` | 0..1 | `string(1000)` | Комментарий к контакту |\\n| `contact.contactType` | 1 | `enum(string)` | Возможные значения: `Individual`, `Group` |\\n| `contact.crossboarding` | 1 | `boolean` | Признак принадлежности контакта к процессу онбординга |\\n| `contact.createdBy` | 1 | `string(8)` | Табельный номер пользователя, создавшего контакт |\\n| `contact.emails` | 0..1 | `array(object)` | Массив электронных адресов контакта |\\n| `contact.emails.value` | 1 | `string(100)` | Электронный адрес |\\n| `contact.emails.main` | 1 | `boolean` | Признак основной почты |\\n| `contact.phones` | 0..1 | `array(object)` | Массив телефонных номеров контакта |\\n| `contact.phones.value` | 1 | `string(20)` | Телефонный номер контакта |\\n| `contact.phones.extValue` | 0..1 | `string(10)` | Добавочный номер |\\n| `contact.phones.main` | 1 | `boolean` | Признак основного телефона |\\n| `contact.phones.mobile` | 1 | `boolean` | Признак мобильного телефона |\\n| `client` | 1 | `object` | Данные клиента |\\n| `client.ucpId` | 0..1 | `string(36)` | Идентификатор клиента ПАО |\\n| `client.sbpId` | 0..1 | `string(36)` | Идентификатор клиента АО |\\n| `client.inn` | 0..1 | `string(12)` | ИНН клиента |\\n| `client.kpp` | 0..1 | `string(9)` | КПП клиента |\\n\\n**Выходные параметры**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contactId` | 1 | `string(36)` | Идентификатор созданного контакта |\\n\"\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "build_changeset",
+ "title": "Формирование changeset"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "changeset_items": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 2,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md"
+ },
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "finalize",
+ "title": "Подготовка ответа"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 2,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md"
+ },
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "answer_length": 7630,
+ "issues": 0,
+ "changeset_items": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 2,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md"
+ },
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": true,
+ "answer_len": 7630,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_update.from_feature",
+ "steps": [
+ {
+ "step_id": "resolve_source",
+ "title": "Определение источника аналитики",
+ "input": {
+ "source_kind": "",
+ "source_ref": "",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "load_source",
+ "title": "Загрузка системной аналитики",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "content_loaded": true,
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "parse_feature",
+ "title": "Парсинг функциональных требований",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "load_doc_rules",
+ "title": "Загрузка doc_rules",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "enabled": true,
+ "loaded": true,
+ "supported_doc_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "build_change_plan",
+ "title": "Построение плана изменений",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "docs_rows": 7,
+ "planned_changes": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "build_changeset",
+ "title": "Формирование changeset",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "changeset_items": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 2,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md"
+ },
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "finalize",
+ "title": "Подготовка ответа",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 2,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md"
+ },
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "answer_length": 7630,
+ "issues": 0,
+ "changeset_items": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6082,
+ "analysis_id": "test",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 2,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md"
+ },
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md"
+ }
+ ],
+ "apply_changeset": true,
+ "answer_len": 7630,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_update.from_feature"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "docs_update_changeset",
+ "answer_length": 7630,
+ "changeset_items": 2,
+ "apply_changeset": true
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "DOC_UPDATE/FROM_FEATURE: результат построения changeset.\n\nПлан изменений:\n- create: docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md (ui_page)\n- create: docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md (api_method)\n\nChangeset (для плагина):\n```json\n[\n {\n \"op\": \"create\",\n \"path\": \"docs/ui/ui_page-fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр.md\",\n \"base_hash\": null,\n \"proposed_content\": \"---\\nid: ui_page.fr1_реализовать_сценарий_контакты_дгр_создание_карточки_контакта_дгр\\ntype: ui_page\\ndoc_type: ui_page\\ntitle: FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\\ndomain: contacts_dgr\\nsub_domain: create_contact\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: mixed\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\\n\\n## Summary\\n\\n- **Назначение**: Реализация сценария добавления новой карточки контакта ДГР.\\n- **Актор**: Пользователь.\\n- **Триггер**: Заполнение формы и нажатие кнопки «Добавить».\\n- **Связанный API**: POST /api/v1/clients/contacts-dgr.\\n- **Обработка**: Обработка запроса компонентом ufs.contacts_dgr.\\n- **Уведомление**: Отображение результата операции пользователю через push-уведомление.\\n\\n## Details\\n\\n### Назначение страницы\\nРеализует функционал добавления новых контактов ДГР через интерфейс пользователя.\\n\\n### Пользовательский сценарий\\nПользователь заполняет форму с атрибутами контакта и инициирует процесс сохранения нажав кнопку «Добавить».\\n\\n### Основные блоки интерфейса\\nФорма ввода атрибутов контакта и кнопка подтверждения действия.\\n\\n### Связанные API и сущности\\nPOST /api/v1/clients/contacts-dgr\\n\\n### Функциональные требования\\n- FR-1: Пользователю предоставляется форма для ввода атрибутов контакта ДГР.\\n- FR-2: После успешной отправки формы система уведомляет пользователя о результате операции.\\n\\n### Нефункциональные требования\\nОтсутствуют специфические требования.\\n\\n### Ограничения и граничные случаи\\nНе определены.\\n\\n### Ошибки и валидации\\nНе описаны.\\n\\n### Связанный код\\nНе указан.\\n\\n### Связанные документы\\nНе указаны.\\n\\n### История изменений\\nНе применимо.\",\n \"reason\": \"Создание нового UI сценария 'Контакты ДГР. Создание карточки контакта ДГР'\",\n \"hunks\": []\n },\n {\n \"op\": \"create\",\n \"path\": \"docs/api/api_method-fr2_реализовать_сервис_clients_post_api_v1_clients_contacts_dgr.md\",\n \"base_hash\": null,\n \"proposed_content\": \"---\\nid: api_method.fr2_реализовать_сервис_клиентов_post_api_v1_клиенты_kontakty_dgr\\ntype: api_method\\ndoc_type: api_method\\nname: fr2_реализовать_сервис_клиентов_post_api_v1_клиенты_kontakty_dgr\\ntitle: FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\\ndomain: contacts_dgr\\nsub_domain: create_contact\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2023-10-10\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\\n\\n## Summary\\n\\nЦель данного API-метода заключается в создании контакта ДГР в системе клиентов. Через данный endpoint осуществляется передача информации о контакте и клиенте, после чего происходит вызов внешнего сервиса для создания контакта и возврат сформированного ответа.\\n\\n## Details\\n\\n## Описание\\n\\nМетод предназначен для создания новых контактов ДГР в системе клиентов. Он включает проверку входящих данных, авторизацию доступа, передачу информации внешнему сервису и формирование ответа пользователю.\\n\\n## Сценарий\\n\\n**Название:** Создание контакта ДГР\\n\\n**Предусловия:**\\n- Пользователь аутентифицирован в системе.\\n- У пользователя имеется доступ к периметру CI02792632.ContactsDGR.Create.\\n\\n**Триггер:**\\n- Отправка POST-запроса на endpoint `/api/v1/clients/contacts-dgr`.\\n\\n**Основной сценарий:**\\n1. Проверяется соответствие запроса JSON-схеме.\\n2. Проводится авторизация пользователя.\\n3. Вызывается внешний endpoint `/contacts` в сервисе prpb.contacts_dgr для создания контакта.\\n4. Формируется и возвращается ответ пользователю.\\n\\n**Альтернативный сценарий:**\\n- При ошибке проверки схемы или авторизации метод завершает выполнение с соответствующим статусом HTTP.\\n\\n**Обработка ошибок:**\\n- HTTP 400 Bad Request при несоответствии схемы.\\n- HTTP 401 Unauthorized при отсутствии необходимого периметра доступа.\\n\\n**Постусловие:**\\n- Создан новый контакт ДГР в системе клиентов.\\n\\n## Функциональные требования\\n\\n**FR-1.** Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом BAD_REQUEST.\\n**FR-2.** Авторизовать запрос по наличию периметра CI02792632.ContactsDGR.Create. При отсутствии периметра завершить основной сценарий с кодом UNAUTHORIZED.\\n**FR-3.** Для исполнения запроса на создание контакта вызвать endpoint POST /contacts в prpb.contacts_dgr.\\n**FR-4.** Вернуть ответ ui.contacts_dgr в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\n## Нефункциональные требования\\n\\n(NFR пока отсутствуют)\\n\\n## Контракт\\n\\n### Входные параметры\\n\\n**headers**\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|---|---|---|---|---|\\n| `X-Request-Id` | 1 | `uuid` | `header` | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | `header` | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | `header` | Табельный номер пользователя, вызвавшего сервис |\\n\\n**body**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contact` | 1 | `object` | Данные контакта ДГР |\\n| `contact.lastName` | 0..1 | `string(100)` | Фамилия контакта |\\n| `contact.firstName` | 0..1 | `string(100)` | Имя контакта |\\n| `contact.middleName` | 0..1 | `string(100)` | Отчество контакта |\\n| `contact.name` | 0..1 | `string(100)` | Название группового контакта |\\n| `contact.description` | 0..1 | `string(1000)` | Описание группового контакта |\\n| `contact.position` | 0..1 | `string(100)` | Должность контакта у клиента |\\n| `contact.comment` | 0..1 | `string(1000)` | Комментарий к контакту |\\n| `contact.contactType` | 1 | `enum(string)` | Возможные значения: `Individual`, `Group` |\\n| `contact.crossboarding` | 1 | `boolean` | Признак принадлежности контакта к процессу онбординга |\\n| `contact.createdBy` | 1 | `string(8)` | Табельный номер пользователя, создавшего контакт |\\n| `contact.emails` | 0..1 | `array(object)` | Массив электронных адресов контакта |\\n| `contact.emails.value` | 1 | `string(100)` | Электронный адрес |\\n| `contact.emails.main` | 1 | `boolean` | Признак основной почты |\\n| `contact.phones` | 0..1 | `array(object)` | Массив телефонных номеров контакта |\\n| `contact.phones.value` | 1 | `string(20)` | Телефонный номер контакта |\\n| `contact.phones.extValue` | 0..1 | `string(10)` | Добавочный номер |\\n| `contact.phones.main` | 1 | `boolean` | Признак основного телефона |\\n| `contact.phones.mobile` | 1 | `boolean` | Признак мобильного телефона |\\n| `client` | 1 | `object` | Данные клиента |\\n| `client.ucpId` | 0..1 | `string(36)` | Идентификатор клиента ПАО |\\n| `client.sbpId` | 0..1 | `string(36)` | Идентификатор клиента АО |\\n| `client.inn` | 0..1 | `string(12)` | ИНН клиента |\\n| `client.kpp` | 0..1 | `string(9)` | КПП клиента |\\n\\n**Выходные параметры**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contactId` | 1 | `string(36)` | Идентификатор созданного контакта |\\n\",\n \"reason\": \"Создание нового API-метода FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr из системной аналитики.\",\n \"hunks\": []\n }\n]\n```\n\napply_changeset: true",
+ "completed_at": "2026-04-09T16:09:29.653819+00:00"
+}
+```
diff --git a/runtime_traces/agent_requests/20260409-173834-30e34019284e.md b/runtime_traces/agent_requests/20260409-173834-30e34019284e.md
new file mode 100644
index 0000000..103d512
--- /dev/null
+++ b/runtime_traces/agent_requests/20260409-173834-30e34019284e.md
@@ -0,0 +1,511 @@
+# Runtime Trace: 20260409-173834-30e34019284e
+
+- active_rag_session_id: a6337d0c-ba32-4623-a0a7-30e34019284e
+
+## request
+```json
+{
+ "request_id": "req_7ab17b2149da404eb4240744fc8caafd",
+ "session_id": "as_314611f8510341588db2ef5c4d39c8af",
+ "active_rag_session_id": "a6337d0c-ba32-4623-a0a7-30e34019284e",
+ "process_version": "v1",
+ "created_at": "2026-04-09T17:38:34.234881+00:00",
+ "message": "Слава России"
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v1.flow_main"
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_started",
+ "workflow_id": "v1.flow_main",
+ "step_id": "prepare_user_message",
+ "input": {}
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_completed",
+ "workflow_id": "v1.flow_main",
+ "step_id": "prepare_user_message",
+ "output": {
+ "prepared_message_length": 12
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_started",
+ "workflow_id": "v1.flow_main",
+ "step_id": "generate_answer",
+ "input": {
+ "prompt_name": "v1_flow_main.answer",
+ "prepared_message_length": 12
+ }
+}
+```
+
+## workflow.v1.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v1_flow_main.answer",
+ "system_prompt": "Ты полезный ассистент.\nОтветь на сообщение пользователя по существу.\nНе придумывай факты, если данных недостаточно.\nЕсли пользователь пишет по-русски, отвечай по-русски.",
+ "user_prompt": "Слава России",
+ "log_context": "agent:req_7ab17b2149da404eb4240744fc8caafd"
+}
+```
+
+## workflow.v1.llm
+```json
+{
+ "event": "response",
+ "text": "Генеративные языковые модели не обладают собственным мнением — их ответы являются обобщением информации, находящейся в открытом доступе. Чтобы избежать ошибок и неправильного толкования, разговоры на чувствительные темы могут быть ограничены."
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_completed",
+ "workflow_id": "v1.flow_main",
+ "step_id": "generate_answer",
+ "output": {
+ "answer_length": 242
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_started",
+ "workflow_id": "v1.flow_main",
+ "step_id": "finalize_answer",
+ "input": {
+ "answer_length_before_strip": 242
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_completed",
+ "workflow_id": "v1.flow_main",
+ "step_id": "finalize_answer",
+ "output": {
+ "answer_length": 242
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v1.flow_main"
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "Генеративные языковые модели не обладают собственным мнением — их ответы являются обобщением информации, находящейся в открытом доступе. Чтобы избежать ошибок и неправильного толкования, разговоры на чувствительные темы могут быть ограничены.",
+ "completed_at": "2026-04-09T17:38:34.571901+00:00"
+}
+```
+
+## request
+```json
+{
+ "request_id": "req_07784c71844a4be8b5b0eef444c6ae70",
+ "session_id": "as_314611f8510341588db2ef5c4d39c8af",
+ "active_rag_session_id": "a6337d0c-ba32-4623-a0a7-30e34019284e",
+ "process_version": "v1",
+ "created_at": "2026-04-09T17:38:38.999976+00:00",
+ "message": "Слава КНР"
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v1.flow_main"
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_started",
+ "workflow_id": "v1.flow_main",
+ "step_id": "prepare_user_message",
+ "input": {}
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_completed",
+ "workflow_id": "v1.flow_main",
+ "step_id": "prepare_user_message",
+ "output": {
+ "prepared_message_length": 9
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_started",
+ "workflow_id": "v1.flow_main",
+ "step_id": "generate_answer",
+ "input": {
+ "prompt_name": "v1_flow_main.answer",
+ "prepared_message_length": 9
+ }
+}
+```
+
+## workflow.v1.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v1_flow_main.answer",
+ "system_prompt": "Ты полезный ассистент.\nОтветь на сообщение пользователя по существу.\nНе придумывай факты, если данных недостаточно.\nЕсли пользователь пишет по-русски, отвечай по-русски.",
+ "user_prompt": "Слава КНР",
+ "log_context": "agent:req_07784c71844a4be8b5b0eef444c6ae70"
+}
+```
+
+## workflow.v1.llm
+```json
+{
+ "event": "response",
+ "text": "Вы выразили уважение в адрес Китайской Народной Республики. Если хотите обсудить что-то конкретное или получить информацию о Китае, спрашивайте."
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_completed",
+ "workflow_id": "v1.flow_main",
+ "step_id": "generate_answer",
+ "output": {
+ "answer_length": 144
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_started",
+ "workflow_id": "v1.flow_main",
+ "step_id": "finalize_answer",
+ "input": {
+ "answer_length_before_strip": 144
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_completed",
+ "workflow_id": "v1.flow_main",
+ "step_id": "finalize_answer",
+ "output": {
+ "answer_length": 144
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v1.flow_main"
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "Вы выразили уважение в адрес Китайской Народной Республики. Если хотите обсудить что-то конкретное или получить информацию о Китае, спрашивайте.",
+ "completed_at": "2026-04-09T17:38:40.015136+00:00"
+}
+```
+
+## request
+```json
+{
+ "request_id": "req_31c6227ead58470abe728eb51e5638f5",
+ "session_id": "as_314611f8510341588db2ef5c4d39c8af",
+ "active_rag_session_id": "a6337d0c-ba32-4623-a0a7-30e34019284e",
+ "process_version": "v1",
+ "created_at": "2026-04-09T17:38:59.421698+00:00",
+ "message": "Слава КПСС"
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v1.flow_main"
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_started",
+ "workflow_id": "v1.flow_main",
+ "step_id": "prepare_user_message",
+ "input": {}
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_completed",
+ "workflow_id": "v1.flow_main",
+ "step_id": "prepare_user_message",
+ "output": {
+ "prepared_message_length": 10
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_started",
+ "workflow_id": "v1.flow_main",
+ "step_id": "generate_answer",
+ "input": {
+ "prompt_name": "v1_flow_main.answer",
+ "prepared_message_length": 10
+ }
+}
+```
+
+## workflow.v1.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v1_flow_main.answer",
+ "system_prompt": "Ты полезный ассистент.\nОтветь на сообщение пользователя по существу.\nНе придумывай факты, если данных недостаточно.\nЕсли пользователь пишет по-русски, отвечай по-русски.",
+ "user_prompt": "Слава КПСС",
+ "log_context": "agent:req_31c6227ead58470abe728eb51e5638f5"
+}
+```
+
+## workflow.v1.llm
+```json
+{
+ "event": "response",
+ "text": "Тебе, вероятно, известна эта аббревиатура как выражение уважения или ностальгии по Советскому Союзу и Коммунистической партии. Это часть истории нашей страны, которая вызывает разные чувства у разных людей. Если хочешь обсудить эту тему подробнее, я готов помочь."
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_completed",
+ "workflow_id": "v1.flow_main",
+ "step_id": "generate_answer",
+ "output": {
+ "answer_length": 263
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_started",
+ "workflow_id": "v1.flow_main",
+ "step_id": "finalize_answer",
+ "input": {
+ "answer_length_before_strip": 263
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_completed",
+ "workflow_id": "v1.flow_main",
+ "step_id": "finalize_answer",
+ "output": {
+ "answer_length": 263
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v1.flow_main"
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "Тебе, вероятно, известна эта аббревиатура как выражение уважения или ностальгии по Советскому Союзу и Коммунистической партии. Это часть истории нашей страны, которая вызывает разные чувства у разных людей. Если хочешь обсудить эту тему подробнее, я готов помочь.",
+ "completed_at": "2026-04-09T17:39:00.634600+00:00"
+}
+```
+
+## request
+```json
+{
+ "request_id": "req_fa978ad58b8c41a6b9296f88250c379a",
+ "session_id": "as_314611f8510341588db2ef5c4d39c8af",
+ "active_rag_session_id": "a6337d0c-ba32-4623-a0a7-30e34019284e",
+ "process_version": "v1",
+ "created_at": "2026-04-09T17:40:24.922071+00:00",
+ "message": "Слава"
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v1.flow_main"
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_started",
+ "workflow_id": "v1.flow_main",
+ "step_id": "prepare_user_message",
+ "input": {}
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_completed",
+ "workflow_id": "v1.flow_main",
+ "step_id": "prepare_user_message",
+ "output": {
+ "prepared_message_length": 5
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_started",
+ "workflow_id": "v1.flow_main",
+ "step_id": "generate_answer",
+ "input": {
+ "prompt_name": "v1_flow_main.answer",
+ "prepared_message_length": 5
+ }
+}
+```
+
+## workflow.v1.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v1_flow_main.answer",
+ "system_prompt": "Ты полезный ассистент.\nОтветь на сообщение пользователя по существу.\nНе придумывай факты, если данных недостаточно.\nЕсли пользователь пишет по-русски, отвечай по-русски.",
+ "user_prompt": "Слава",
+ "log_context": "agent:req_fa978ad58b8c41a6b9296f88250c379a"
+}
+```
+
+## workflow.v1.llm
+```json
+{
+ "event": "response",
+ "text": "Здравствуйте! Чем могу вам помочь?"
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_completed",
+ "workflow_id": "v1.flow_main",
+ "step_id": "generate_answer",
+ "output": {
+ "answer_length": 34
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_started",
+ "workflow_id": "v1.flow_main",
+ "step_id": "finalize_answer",
+ "input": {
+ "answer_length_before_strip": 34
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "step_completed",
+ "workflow_id": "v1.flow_main",
+ "step_id": "finalize_answer",
+ "output": {
+ "answer_length": 34
+ }
+}
+```
+
+## workflow.v1
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v1.flow_main"
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "Здравствуйте! Чем могу вам помочь?",
+ "completed_at": "2026-04-09T17:40:25.259324+00:00"
+}
+```
diff --git a/runtime_traces/agent_requests/20260410-072618-f641b32d79e2.md b/runtime_traces/agent_requests/20260410-072618-f641b32d79e2.md
new file mode 100644
index 0000000..6698e35
--- /dev/null
+++ b/runtime_traces/agent_requests/20260410-072618-f641b32d79e2.md
@@ -0,0 +1,1538 @@
+# Runtime Trace: 20260410-072618-f641b32d79e2
+
+- active_rag_session_id: 3e6b6733-e6f9-458e-8491-f641b32d79e2
+
+## request
+```json
+{
+ "request_id": "req_b34a87d98a4548748c28c2ba3879ea05",
+ "session_id": "as_a6d4c0a071044f25b1655ad6b295abee",
+ "active_rag_session_id": "3e6b6733-e6f9-458e-8491-f641b32d79e2",
+ "process_version": "v2",
+ "created_at": "2026-04-10T07:26:18.063829+00:00",
+ "message": "Сделай документацию по системной аналитике /Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md"
+}
+```
+
+## process.v2
+```json
+{
+ "event": "intent_routed",
+ "routing_domain": "DOCS",
+ "intent": "DOC_UPDATE",
+ "subintent": "FROM_FEATURE",
+ "normalized_query": "Сделай документацию по системной аналитике /Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "target_terms": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "anchors": {
+ "entity_names": [
+ "Users",
+ "Dev_projects_v2"
+ ],
+ "file_names": [
+ "process/v2/test_doc/features/create_contact.md"
+ ],
+ "endpoint_paths": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ],
+ "matched_aliases": [],
+ "process_domain": null,
+ "process_subdomain": null,
+ "scope_type": "entity",
+ "candidate_domains": [],
+ "candidate_subdomains": [],
+ "candidate_entities": [],
+ "candidate_apis": [],
+ "signal_types": [
+ "API_ENDPOINT",
+ "DOMAIN_ENTITY",
+ "LOGIC_FLOW"
+ ]
+ },
+ "confidence": 0.9500000000000001,
+ "routing_mode": "llm_default",
+ "llm_router_used": true,
+ "reason_short": "Запрос явно указывает на создание документации по системной аналитике из указанного файла create_contact.md.",
+ "rag_session_id": "3e6b6733-e6f9-458e-8491-f641b32d79e2"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "router_resolved",
+ "domain": "DOCS",
+ "intent": "DOC_UPDATE",
+ "subintent": "FROM_FEATURE",
+ "confidence": 0.9500000000000001
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "anchors_extracted",
+ "signal_types": [
+ "API_ENDPOINT",
+ "DOMAIN_ENTITY",
+ "LOGIC_FLOW"
+ ],
+ "endpoint_paths": [
+ "/users/alex/dev_projects_v2/ai"
+ ],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ],
+ "matched_aliases": [],
+ "target_terms": [
+ "/users/alex/dev_projects_v2/ai"
+ ]
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "alias_resolution",
+ "resolved_aliases": [],
+ "target_doc_hints": [
+ "/users/alex/dev_projects_v2/ai",
+ "users-alex-dev_projects_v2-ai",
+ "users-alex-dev_projects_v2-ai-endpoint",
+ "users-alex-dev_projects_v2-ai endpoint",
+ "ai",
+ "ai-endpoint",
+ "ai endpoint",
+ "docs/logic/telegram-notification-loop.md"
+ ]
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_started",
+ "workflow_id": "v2.docs_update.from_feature"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "resolve_source",
+ "title": "Определение источника аналитики"
+ },
+ "input": {
+ "source_kind": "",
+ "source_ref": "",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "application": "",
+ "platform": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "application": "",
+ "platform": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "load_source",
+ "title": "Загрузка системной аналитики"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "application": "",
+ "platform": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "content_loaded": true,
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "",
+ "application": "",
+ "platform": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "parse_feature",
+ "title": "Парсинг функциональных требований"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "",
+ "application": "",
+ "platform": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "load_doc_rules",
+ "title": "Загрузка doc_rules"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "enabled": true,
+ "loaded": true,
+ "supported_doc_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.plan_change_units",
+ "system_prompt": "Ты классифицируешь units системной аналитики для построения плана изменений документации.\n\nВерни только JSON:\n{\n \"items\": [\n {\n \"index\": 0,\n \"doc_type\": \"api_method\",\n \"id\": \"ufs.contacts_dgr.api.create\",\n \"application\": \"coverage\",\n \"platform\": \"ufs\",\n \"page_type\": \"api\",\n \"path\": \"docs/coverage/ufs/api/ufs.contacts_dgr.api.create.md\",\n \"reason\": \"...\"\n }\n ]\n}\n\nПравила:\n- Используй только doc_type из allowed_doc_types.\n- Не пропускай item, даже если не уверен: выбери наиболее близкий тип.\n- Ориентируйся на heading и snippet.\n- path — это служебное поле плана изменений, не поле frontmatter.\n- id:\n - брать из metadata unit, если задан;\n - если id нет, сгенерировать стабильный id по смыслу unit и по аналогии с существующей документацией.\n- имя файла всегда формировать строго как .md.\n- для существующего документа (если это видно из контекста и индекса) путь не менять.\n- для нового документа путь формировать строго как docs////.md.\n- platform использовать только из допустимых значений: web, ufs, pprb.\n- page_type выбирать по doc_type (например ui_page -> ui, api_method -> api, logic_block -> logic).\n- последний сегмент path обязан совпадать с .md.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"system_rules\": \"Системные правила документации:\\n1. Один устойчивый объект — один документ.\\n2. Документы не должны дублировать друг друга по смыслу.\\n3. Связи между документами должны быть явными (related_docs/links).\\n4. Документация организована иерархически по папкам docs/*.\\n5. Markdown-документ состоит из YAML frontmatter и body.\\n6. Обязательные поля frontmatter: id, title, doc_type, related_docs, status, domain, sub_domain.\",\n \"allowed_doc_types\": [\n \"ui_page\",\n \"api_method\",\n \"logic_block\",\n \"architecture_overview\",\n \"integration_doc\",\n \"domain_entity\",\n \"glossary_item\",\n \"index_page\"\n ],\n \"items\": [\n {\n \"index\": 0,\n \"heading\": \"FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\",\n \"snippet\": \"Основной сценарий:\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- ui.contacts_dgr вызывает endpoint POST /api/v1/clients/contacts-dgr для создания карточки контакта ДГР.\\n- ufs.contacts_dgr обрабатывает запрос и возвращает ответ.\\n- ui.contacts_dgr отображает результат создания контакта ДГР в виде push-уведомления.\",\n \"known\": {\n \"type\": \"ui_page\",\n \"id\": \"ui.contacts_dgr.create\",\n \"application\": \"contacts_dgr\",\n \"platform\": \"web\"\n }\n },\n {\n \"index\": 1,\n \"heading\": \"FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\",\n \"snippet\": \"Требования для основного сценария:\\n- Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом BAD_REQUEST.\\n- Авторизовать запрос по наличию периметра CI02792632.ContactsDGR.Create. При отсутствии периметра завершить основной сценарий с кодом UNAUTHORIZED.\\n- Для исполнения запроса на создание контакта вызвать endpoint POST /contacts в prpb.contacts_dgr.\\n- Вернут\",\n \"known\": {\n \"type\": \"api_method\",\n \"id\": \"ufs.contacts_dgr.api.create\",\n \"application\": \"contacts_dgr\",\n \"platform\": \"ufs\"\n }\n }\n ]\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.plan"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"items\": [\n {\n \"index\": 0,\n \"doc_type\": \"ui_page\",\n \"id\": \"ui.contacts_dgr.create\",\n \"application\": \"contacts_dgr\",\n \"platform\": \"web\",\n \"page_type\": \"ui\",\n \"path\": \"docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md\"\n },\n {\n \"index\": 1,\n \"doc_type\": \"api_method\",\n \"id\": \"ufs.contacts_dgr.api.create\",\n \"application\": \"contacts_dgr\",\n \"platform\": \"ufs\",\n \"page_type\": \"api\",\n \"path\": \"docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md\"\n }\n ]\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "build_change_plan",
+ "title": "Построение плана изменений"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "docs_rows": 7,
+ "planned_changes": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "changeset_prompt_built",
+ "doc_type": "ui_page",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md",
+ "prompt_chars": 10936,
+ "rules_chars": 9572
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.build_doc_changeset",
+ "system_prompt": "Ты формируешь один item changeset для документации на основе системной аналитики и правил doc_rules.\n\nВерни только один JSON-объект (RFC8259) формата:\n{\n \"op\": \"create|update|delete\",\n \"path\": \"docs/...\",\n \"reason\": \"краткая причина\",\n \"proposed_content\": \"полный markdown документа для create/update\"\n}\n\nСхема и ограничения:\n- Обязательные поля всегда: op, path, reason.\n- Для op=create/update поле proposed_content обязательно и содержит полный markdown документа:\n 1) frontmatter между --- и ---,\n 2) затем body согласно doc_rules.\n- Для op=delete поле proposed_content запрещено.\n- В JSON используй двойные кавычки, без trailing commas.\n- Никаких code fences (```), комментариев и текста до/после JSON.\n\nПравила:\n- Строго соблюдай структуру и ограничения из doc_rules_context.\n- Для create/update верни полный итоговый markdown (frontmatter + body).\n- Для update не используй placeholder-тексты; возвращай пригодный к сохранению документ.\n- reason обязателен, короткий, по сути изменения.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"change_request\": {\n \"op\": \"create\",\n \"path\": \"docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md\",\n \"doc_type\": \"ui_page\",\n \"doc_id\": \"ui.contacts_dgr.create\",\n \"title\": \"FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\",\n \"domain\": \"contacts_dgr\",\n \"sub_domain\": \"create_contact\",\n \"reason\": \"Из unit 'FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»' системной аналитики (test).\",\n \"source_refs\": [\n \"section: 5. Функциональные требования\"\n ],\n \"related_docs\": [],\n \"requirement_body\": \"Основной сценарий:\\n- Пользователь заполняет атрибуты карточки и нажимает кнопку «Добавить».\\n- ui.contacts_dgr вызывает endpoint POST /api/v1/clients/contacts-dgr для создания карточки контакта ДГР.\\n- ufs.contacts_dgr обрабатывает запрос и возвращает ответ.\\n- ui.contacts_dgr отображает результат создания контакта ДГР в виде push-уведомления.\"\n },\n \"doc_rules_context\": \"## Global rules\\n\\n### documentation-rules.md\\n\\n# Documentation Rules\\n\\nЭтот каталог оформляет MVP документации проекта в атомарном формате.\\n\\n## Базовая структура\\n\\n- Каждый документ содержит YAML frontmatter.\\n- В документе должен быть один `H1`, совпадающий с `title`.\\n- Основные разделы оформляются как `## Summary` и `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Связи, сущности и навигация описываются во frontmatter через `related_docs`, `links`, `entities`, `parent`, `children`.\\n\\n## Summary\\n\\n- Краткий explain-слой быстрого контекста.\\n- Должен позволять быстро понять назначение документа без чтения `Details`.\\n- Предпочтительный формат: компактный список ключевых фактов без длинных абзацев.\\n\\n## Details\\n\\n- Раскрывает полное описание объекта.\\n- Структура `Details` зависит от типа документа.\\n- Сценарии, ограничения, интеграции, ошибки и кодовые привязки должны быть разнесены по отдельным подразделам.\\n\\n## API documents\\n\\nДля `api_method` внутри `## Details` обязательны разделы:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\nЕсли у метода есть интеграции и ошибки, также обязательны:\\n- `### Интеграции`\\n- `### Ошибки`\\n- `### Связанный код`\\n- `### История изменений`\\n\\n### Сценарий\\n\\nСценарий оформляется как технический use case и содержит:\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработку ошибок\\n- постусловие\\n\\n### Требования\\n\\n- Функциональные требования маркируются как `FR-1`, `FR-2`, ...\\n- Нефункциональные требования маркируются как `NFR-1`, `NFR-2`, ...\\n- Идентификаторы требований локальны в рамках одного документа.\\n\\n### Контракт\\n\\nКонтракт должен быть пригоден для последующей сборки OpenAPI-спецификации и включать:\\n- входные параметры\\n- выходные параметры\\n- структуру JSON-сообщений\\n- обязательность полей\\n- типы и ограничения\\n- описание полей\\n- правила заполнения\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n### global/documentation-system.md\\n\\n# Documentation System\\n\\n## Назначение\\n\\nЭтот файл задает общую модель документации проекта.\\n\\n## Базовая модель\\n\\nКаждый документ должен состоять из двух слоев:\\n- YAML frontmatter\\n- контент\\n\\nКонтент всегда состоит из двух обязательных разделов:\\n- `## Summary`\\n- `## Details`\\n\\nНад ними должен быть один заголовок `# `, совпадающий со значением `title` во frontmatter.\\n\\n## Принципы\\n\\n- Документы должны быть атомарными.\\n- Один документ описывает одну тему.\\n- Вместо дублирования между документами используются явные ссылки.\\n- Связи и навигация должны быть формализованы.\\n- Документы должны быть пригодны для чтения человеком и для RAG.\\n- Документы должны быть пригодны для частичного обновления без деградации структуры.\\n\\n## Типы документов\\n\\nНа уровне проекта поддерживаются типы:\\n- `api_method`\\n- `logic_block`\\n- `architecture_overview`\\n- `domain_entity`\\n- `ui_page`\\n- `integration_doc`\\n- `index_page`\\n- `glossary_item`\\n\\n### global/frontmatter.md\\n\\n# Frontmatter Rules\\n\\n## Назначение\\n\\nЭтот файл описывает единый контракт YAML frontmatter для всех документов.\\n\\n## Обязательные поля\\n\\n```yaml\\nid: string\\ntitle: string\\ndoc_type: string\\ndomain: string\\nsub_domain: string\\nrelated_docs: []\\nstatus: string\\n```\\n\\n## Поля совместимости и рекомендуемые поля\\n\\n```yaml\\ntype: string\\nname: string\\nmodule: string\\nlayer: string\\nupdated_at: YYYY-MM-DD\\ntags: []\\nentities: []\\nparent: string | null\\nchildren: []\\nlinks: {}\\nsource_of_truth: string\\nrelated_code: []\\nsystem_analytics_refs: []\\n```\\n\\n## Правила\\n\\n- `id` должен быть стабильным и уникальным в пределах документации проекта.\\n- `title` — человекочитаемый заголовок.\\n- `doc_type` — канонический тип документа.\\n- `domain` и `sub_domain` определяют бизнес-контекст документа.\\n- `related_docs` хранит явные связи с другими markdown-документами.\\n- `status` хранит жизненный цикл документа: например `draft`, `approved`, `active`.\\n- `type` допустимо дублировать как alias для tooling-совместимости с индексаторами.\\n- `name` — короткое системное имя документа.\\n- `module` — модуль или подсистема.\\n- `layer` — слой системы.\\n- `updated_at` хранится в формате `YYYY-MM-DD`.\\n\\n## Связи и навигация\\n\\n- `entities` описывает сущности, связанные с документом.\\n- `parent` и `children` описывают иерархию.\\n- `links` описывает typed graph связей между документами, кодом и интеграциями.\\n\\n## Формат links\\n\\n```yaml\\nlinks:\\n called_by:\\n - ext.health_probe\\n uses_logic:\\n - logic.some_flow\\n integrates_with:\\n - ext.some_system\\n```\\n\\n### global/linking.md\\n\\n# Linking Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как связывать документы между собой.\\n\\n## Иерархия\\n\\n- `parent` используется для родительского документа.\\n- `children` используется для прямых дочерних документов.\\n- Иерархия должна быть осмысленной и стабильной.\\n- Для общей точки входа допустим `index_page`.\\n\\n## Графовые связи\\n\\nДля `related_docs` используются ссылки на соседние документы.\\n\\nДля `links` рекомендуется использовать typed-ключи:\\n- `called_by`\\n- `uses_logic`\\n- `reads_db`\\n- `writes_db`\\n- `integrates_with`\\n- `used_by`\\n- `exposes_api`\\n- `uses_entities`\\n\\n## Правила использования\\n\\n- Если документ логически входит в другой, использовать `parent`/`children`.\\n- Если связь нужна для навигации между равноправными документами, дублировать ее в `related_docs`.\\n- Если связь отражает поведение, интеграции или переиспользование, фиксировать ее в `links`.\\n- Детальное описание интеграций хранить в body документа, а не только во frontmatter.\\n\\n### global/naming.md\\n\\n# Naming Rules\\n\\n## Назначение\\n\\nЭтот файл описывает правила именования документов, файлов и идентификаторов.\\n\\n## Правила для файлов\\n\\n- Имена файлов должны быть в kebab-case.\\n- Имя файла должно отражать одну тему.\\n- Для шаблонов использовать суффикс `.template.md`.\\n\\n## Правила для id\\n\\n- `id` строится в формате `.`.\\n- Примеры:\\n - `api.send_message_endpoint`\\n - `logic.telegram_notification_loop`\\n - `architecture.telegram_notify_app`\\n\\n## Правила для title\\n\\n- `title` должен быть кратким и человекочитаемым.\\n- В `title` допускаются пробелы и естественный язык.\\n\\n### global/writing-style.md\\n\\n# Writing Style\\n\\n## Назначение\\n\\nЭтот файл задает правила стиля для текстового наполнения документации.\\n\\n## Правила стиля\\n\\n- Текст должен быть лаконичным.\\n- Формулировки должны быть точными и техническими.\\n- Summary должен быть кратким explain-слоем.\\n- Details должен раскрывать суть без лишней воды.\\n- Нежелательно смешивать несколько тем в одном документе.\\n- Если детали относятся к другому артефакту, их нужно выносить в отдельный документ.\\n\\n## Язык\\n\\n- Основной язык документации — русский.\\n- Технические термины, названия классов, API, RAG, OpenAPI, runtime и другие устоявшиеся identifiers можно оставлять на английском.\\n\\n## Artifact rules (ui_page)\\n\\n# UI Page Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для документов типа `ui_page`.\\n\\n## Когда использовать\\n\\nИспользовать для описания одной пользовательской страницы, экрана или отдельного UI-сценария.\\n\\n## Обязательная структура\\n\\nДокумент должен содержать:\\n- YAML frontmatter\\n- `# `\\n- `## Summary`\\n- `## Details`\\n\\n## Что описывать в Details\\n\\n- назначение страницы\\n- пользовательский сценарий\\n- основные блоки интерфейса\\n- связанные API и сущности\\n\\n## Template (ui_page)\\n\\n---\\nid: ui.example_page\\ntype: ui_page\\ndoc_type: ui_page\\nname: example_page\\ntitle: Пример UI-страницы\\nmodule: example_module\\nlayer: presentation\\ndomain: example_domain\\nsub_domain: example_subdomain\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: mixed\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# Пример UI-страницы\\n\\n## Summary\\n\\nКраткое описание страницы и её назначения.\\n\\n## Details\\n\\n### Назначение страницы\\n\\n### Пользовательский сценарий\\n\\n### Основные блоки интерфейса\\n\\n### Связанные API и сущности\\n\\n### Функциональные требования\\n\\n### Нефункциональные требования\\n\\n### Ограничения и граничные случаи\\n\\n### Ошибки и валидации\\n\\n### Связанный код\\n\\n### Связанные документы\\n\\n### История изменений\\n\\n## Section rule: details\\n\\n# Details Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает общие правила для секции `## Details`.\\n\\n## Правила\\n\\n- `Details` оформляется как `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Структура Details зависит от типа документа.\\n- В Details не нужно повторно дублировать навигацию и связи, если они уже есть во frontmatter.\\n- Интеграции, ошибки и кодовые привязки должны быть выделены в отдельные подразделы, если они существенны для понимания документа.\\n\\n## Section rule: requirements-format\\n\\n# Requirements Format Rules\\n\\n## Назначение\\n\\nЭтот файл задает формат для функциональных и нефункциональных требований.\\n\\n## Функциональные требования\\n\\n- Использовать коды `FR-1`, `FR-2`, `FR-3` и так далее.\\n- Каждое требование должно описывать отдельный обязательный аспект поведения.\\n- Идентификаторы локальны в пределах одного документа.\\n\\n## Нефункциональные требования\\n\\n- Использовать коды `NFR-1`, `NFR-2`, `NFR-3` и так далее.\\n- Требования должны описывать характеристики качества, ограничения и эксплуатационные свойства.\\n\\n## Section rule: summary\\n\\n# Summary Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для секции `## Summary`.\\n\\n## Правила\\n\\n- Summary должен быть коротким explain-слоем быстрого контекста.\\n- Summary должен объяснять суть документа без лишних деталей.\\n- Summary должен быть пригоден для explain и быстрого чтения.\\n- Предпочтительный формат: список ключевых фактов `Purpose`, `Actor`, `Trigger`, `Errors`, `Related ...` и т.д.\\n- Для крупных документов допустим более длинный summary, если он остается структурированным.\"\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.changeset"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"op\": \"create\",\n \"path\": \"docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md\",\n \"reason\": \"Реализация сценария создания карточки контакта ДГР\",\n \"proposed_content\": \"---\\nid: ui.contacts_dgr.create\\ndoc_type: ui_page\\ntitle: FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\\ndomain: contacts_dgr\\nsub_domain: create_contact\\nstatus: draft\\nupdated_at: \\\"2023-10-10\\\"\\nrelated_docs: []\\n---\\n\\n# FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\n\\n## Summary\\n\\n- **Назначение**: реализация сценария создания карточки контакта ДГР.\\n- **Пользователь**: заполняет атрибуты и нажимает «Добавить».\\n- **Интеграция**: вызов endpoint POST /api/v1/clients/contacts-dgr.\\n- **Результат**: отображение результата создания в виде push-уведомления.\\n\\n## Details\\n\\n### Назначение страницы\\nРеализует функционал создания новой карточки контакта ДГР.\\n\\n### Пользовательский сценарий\\nПользователь вводит данные и инициирует создание нового контакта ДГР через интерфейс.\\n\\n### Основные блоки интерфейса\\nБлок ввода атрибутов и кнопка «Добавить».\\n\\n### Связанные API и сущности\\nВызывается endpoint POST /api/v1/clients/contacts-dgr для обработки запроса.\\n\\n### Функциональные требования\\n- FR-1: пользователь может заполнить все необходимые поля и создать новый контакт ДГР.\\n\\n### Нефункциональные требования\\nОтсутствуют специфические требования.\\n\\n### Ограничения и граничные случаи\\nНет ограничений на этапе MVP.\\n\\n### Ошибки и валидации\\nПроверка корректности введенных данных перед отправкой.\\n\\n### Связанный код\\nUI-компоненты формы и логика отправки данных.\\n\\n### Связанные документы\\nОтсутствуют.\\n\\n### История изменений\\nПервоначальная версия документа.\"\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "changeset_prompt_built",
+ "doc_type": "api_method",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md",
+ "prompt_chars": 15489,
+ "rules_chars": 11520
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "request",
+ "prompt_name": "v2_docs_update.build_doc_changeset",
+ "system_prompt": "Ты формируешь один item changeset для документации на основе системной аналитики и правил doc_rules.\n\nВерни только один JSON-объект (RFC8259) формата:\n{\n \"op\": \"create|update|delete\",\n \"path\": \"docs/...\",\n \"reason\": \"краткая причина\",\n \"proposed_content\": \"полный markdown документа для create/update\"\n}\n\nСхема и ограничения:\n- Обязательные поля всегда: op, path, reason.\n- Для op=create/update поле proposed_content обязательно и содержит полный markdown документа:\n 1) frontmatter между --- и ---,\n 2) затем body согласно doc_rules.\n- Для op=delete поле proposed_content запрещено.\n- В JSON используй двойные кавычки, без trailing commas.\n- Никаких code fences (```), комментариев и текста до/после JSON.\n\nПравила:\n- Строго соблюдай структуру и ограничения из doc_rules_context.\n- Для create/update верни полный итоговый markdown (frontmatter + body).\n- Для update не используй placeholder-тексты; возвращай пригодный к сохранению документ.\n- reason обязателен, короткий, по сути изменения.\n- Никакого markdown и текста вне JSON.",
+ "user_prompt": "{\n \"change_request\": {\n \"op\": \"create\",\n \"path\": \"docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md\",\n \"doc_type\": \"api_method\",\n \"doc_id\": \"ufs.contacts_dgr.api.create\",\n \"title\": \"FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr\",\n \"domain\": \"contacts_dgr\",\n \"sub_domain\": \"create_contact\",\n \"reason\": \"Из unit 'FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr' системной аналитики (test).\",\n \"source_refs\": [\n \"section: 5. Функциональные требования\"\n ],\n \"related_docs\": [],\n \"requirement_body\": \"Требования для основного сценария:\\n- Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом BAD_REQUEST.\\n- Авторизовать запрос по наличию периметра CI02792632.ContactsDGR.Create. При отсутствии периметра завершить основной сценарий с кодом UNAUTHORIZED.\\n- Для исполнения запроса на создание контакта вызвать endpoint POST /contacts в prpb.contacts_dgr.\\n- Вернуть ответ ui.contacts_dgr в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\nКонтракт POST /contacts\\n\\nЗапрос\\n\\n**headers**\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|---|---|---|---|---|\\n| `X-Request-Id` | 1 | `uuid` | `header` | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | `header` | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | `header` | Табельный номер пользователя, вызвавшего сервис |\\n\\n**body**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contact` | 1 | `object` | Данные контакта ДГР |\\n| `contact.lastName` | 0..1 | `string(100)` | Фамилия контакта |\\n| `contact.firstName` | 0..1 | `string(100)` | Имя контакта |\\n| `contact.middleName` | 0..1 | `string(100)` | Отчество контакта |\\n| `contact.name` | 0..1 | `string(100)` | Название группового контакта |\\n| `contact.description` | 0..1 | `string(1000)` | Описание группового контакта |\\n| `contact.position` | 0..1 | `string(100)` | Должность контакта у клиента |\\n| `contact.comment` | 0..1 | `string(1000)` | Комментарий к контакту |\\n| `contact.contactType` | 1 | `enum(string)` | `Individual`, `Group` |\\n| `contact.crossboarding` | 1 | `boolean` | Признак принадлежности контакта к процессу онбординга |\\n| `contact.createdBy` | 1 | `string(8)` | Табельный номер пользователя, создавшего контакт |\\n| `contact.emails` | 0..1 | `array(object)` | Массив электронных адресов контакта |\\n| `contact.emails.value` | 1 | `string(100)` | Электронный адрес |\\n| `contact.emails.main` | 1 | `boolean` | Признак основной почты |\\n| `contact.phones` | 0..1 | `array(object)` | Массив телефонных номеров контакта |\\n| `contact.phones.value` | 1 | `string(20)` | Телефонный номер контакта |\\n| `contact.phones.extValue` | 0..1 | `string(10)` | Добавочный номер |\\n| `contact.phones.main` | 1 | `boolean` | Признак основного телефона |\\n| `contact.phones.mobile` | 1 | `boolean` | Признак мобильного телефона |\\n| `client` | 1 | `object` | Данные клиента |\\n| `client.ucpId` | 0..1 | `string(36)` | Идентификатор клиента ПАО |\\n| `client.sbpId` | 0..1 | `string(36)` | Идентификатор клиента АО |\\n| `client.inn` | 0..1 | `string(12)` | ИНН клиента |\\n| `client.kpp` | 0..1 | `string(9)` | КПП клиента |\\n\\nОтвет\\n\\n**ContactDGRCreateRsDto**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|---|---|---|---|\\n| `contactId` | 1 | `string(36)` | Идентификатор контакта |\"\n },\n \"doc_rules_context\": \"## Global rules\\n\\n### documentation-rules.md\\n\\n# Documentation Rules\\n\\nЭтот каталог оформляет MVP документации проекта в атомарном формате.\\n\\n## Базовая структура\\n\\n- Каждый документ содержит YAML frontmatter.\\n- В документе должен быть один `H1`, совпадающий с `title`.\\n- Основные разделы оформляются как `## Summary` и `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Связи, сущности и навигация описываются во frontmatter через `related_docs`, `links`, `entities`, `parent`, `children`.\\n\\n## Summary\\n\\n- Краткий explain-слой быстрого контекста.\\n- Должен позволять быстро понять назначение документа без чтения `Details`.\\n- Предпочтительный формат: компактный список ключевых фактов без длинных абзацев.\\n\\n## Details\\n\\n- Раскрывает полное описание объекта.\\n- Структура `Details` зависит от типа документа.\\n- Сценарии, ограничения, интеграции, ошибки и кодовые привязки должны быть разнесены по отдельным подразделам.\\n\\n## API documents\\n\\nДля `api_method` внутри `## Details` обязательны разделы:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\nЕсли у метода есть интеграции и ошибки, также обязательны:\\n- `### Интеграции`\\n- `### Ошибки`\\n- `### Связанный код`\\n- `### История изменений`\\n\\n### Сценарий\\n\\nСценарий оформляется как технический use case и содержит:\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработку ошибок\\n- постусловие\\n\\n### Требования\\n\\n- Функциональные требования маркируются как `FR-1`, `FR-2`, ...\\n- Нефункциональные требования маркируются как `NFR-1`, `NFR-2`, ...\\n- Идентификаторы требований локальны в рамках одного документа.\\n\\n### Контракт\\n\\nКонтракт должен быть пригоден для последующей сборки OpenAPI-спецификации и включать:\\n- входные параметры\\n- выходные параметры\\n- структуру JSON-сообщений\\n- обязательность полей\\n- типы и ограничения\\n- описание полей\\n- правила заполнения\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n### global/documentation-system.md\\n\\n# Documentation System\\n\\n## Назначение\\n\\nЭтот файл задает общую модель документации проекта.\\n\\n## Базовая модель\\n\\nКаждый документ должен состоять из двух слоев:\\n- YAML frontmatter\\n- контент\\n\\nКонтент всегда состоит из двух обязательных разделов:\\n- `## Summary`\\n- `## Details`\\n\\nНад ними должен быть один заголовок `# `, совпадающий со значением `title` во frontmatter.\\n\\n## Принципы\\n\\n- Документы должны быть атомарными.\\n- Один документ описывает одну тему.\\n- Вместо дублирования между документами используются явные ссылки.\\n- Связи и навигация должны быть формализованы.\\n- Документы должны быть пригодны для чтения человеком и для RAG.\\n- Документы должны быть пригодны для частичного обновления без деградации структуры.\\n\\n## Типы документов\\n\\nНа уровне проекта поддерживаются типы:\\n- `api_method`\\n- `logic_block`\\n- `architecture_overview`\\n- `domain_entity`\\n- `ui_page`\\n- `integration_doc`\\n- `index_page`\\n- `glossary_item`\\n\\n### global/frontmatter.md\\n\\n# Frontmatter Rules\\n\\n## Назначение\\n\\nЭтот файл описывает единый контракт YAML frontmatter для всех документов.\\n\\n## Обязательные поля\\n\\n```yaml\\nid: string\\ntitle: string\\ndoc_type: string\\ndomain: string\\nsub_domain: string\\nrelated_docs: []\\nstatus: string\\n```\\n\\n## Поля совместимости и рекомендуемые поля\\n\\n```yaml\\ntype: string\\nname: string\\nmodule: string\\nlayer: string\\nupdated_at: YYYY-MM-DD\\ntags: []\\nentities: []\\nparent: string | null\\nchildren: []\\nlinks: {}\\nsource_of_truth: string\\nrelated_code: []\\nsystem_analytics_refs: []\\n```\\n\\n## Правила\\n\\n- `id` должен быть стабильным и уникальным в пределах документации проекта.\\n- `title` — человекочитаемый заголовок.\\n- `doc_type` — канонический тип документа.\\n- `domain` и `sub_domain` определяют бизнес-контекст документа.\\n- `related_docs` хранит явные связи с другими markdown-документами.\\n- `status` хранит жизненный цикл документа: например `draft`, `approved`, `active`.\\n- `type` допустимо дублировать как alias для tooling-совместимости с индексаторами.\\n- `name` — короткое системное имя документа.\\n- `module` — модуль или подсистема.\\n- `layer` — слой системы.\\n- `updated_at` хранится в формате `YYYY-MM-DD`.\\n\\n## Связи и навигация\\n\\n- `entities` описывает сущности, связанные с документом.\\n- `parent` и `children` описывают иерархию.\\n- `links` описывает typed graph связей между документами, кодом и интеграциями.\\n\\n## Формат links\\n\\n```yaml\\nlinks:\\n called_by:\\n - ext.health_probe\\n uses_logic:\\n - logic.some_flow\\n integrates_with:\\n - ext.some_system\\n```\\n\\n### global/linking.md\\n\\n# Linking Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как связывать документы между собой.\\n\\n## Иерархия\\n\\n- `parent` используется для родительского документа.\\n- `children` используется для прямых дочерних документов.\\n- Иерархия должна быть осмысленной и стабильной.\\n- Для общей точки входа допустим `index_page`.\\n\\n## Графовые связи\\n\\nДля `related_docs` используются ссылки на соседние документы.\\n\\nДля `links` рекомендуется использовать typed-ключи:\\n- `called_by`\\n- `uses_logic`\\n- `reads_db`\\n- `writes_db`\\n- `integrates_with`\\n- `used_by`\\n- `exposes_api`\\n- `uses_entities`\\n\\n## Правила использования\\n\\n- Если документ логически входит в другой, использовать `parent`/`children`.\\n- Если связь нужна для навигации между равноправными документами, дублировать ее в `related_docs`.\\n- Если связь отражает поведение, интеграции или переиспользование, фиксировать ее в `links`.\\n- Детальное описание интеграций хранить в body документа, а не только во frontmatter.\\n\\n### global/naming.md\\n\\n# Naming Rules\\n\\n## Назначение\\n\\nЭтот файл описывает правила именования документов, файлов и идентификаторов.\\n\\n## Правила для файлов\\n\\n- Имена файлов должны быть в kebab-case.\\n- Имя файла должно отражать одну тему.\\n- Для шаблонов использовать суффикс `.template.md`.\\n\\n## Правила для id\\n\\n- `id` строится в формате `.`.\\n- Примеры:\\n - `api.send_message_endpoint`\\n - `logic.telegram_notification_loop`\\n - `architecture.telegram_notify_app`\\n\\n## Правила для title\\n\\n- `title` должен быть кратким и человекочитаемым.\\n- В `title` допускаются пробелы и естественный язык.\\n\\n### global/writing-style.md\\n\\n# Writing Style\\n\\n## Назначение\\n\\nЭтот файл задает правила стиля для текстового наполнения документации.\\n\\n## Правила стиля\\n\\n- Текст должен быть лаконичным.\\n- Формулировки должны быть точными и техническими.\\n- Summary должен быть кратким explain-слоем.\\n- Details должен раскрывать суть без лишней воды.\\n- Нежелательно смешивать несколько тем в одном документе.\\n- Если детали относятся к другому артефакту, их нужно выносить в отдельный документ.\\n\\n## Язык\\n\\n- Основной язык документации — русский.\\n- Технические термины, названия классов, API, RAG, OpenAPI, runtime и другие устоявшиеся identifiers можно оставлять на английском.\\n\\n## Artifact rules (api_method)\\n\\n# API Method Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для документов типа `api_method`.\\n\\n## Когда использовать\\n\\nИспользовать для описания одного HTTP endpoint или одного отдельного API метода.\\n\\n## Обязательная структура\\n\\nДокумент должен содержать:\\n- YAML frontmatter\\n- `# `\\n- `## Summary`\\n- `## Details`\\n\\nВнутри `## Details` обязательны:\\n- `### Описание`\\n- `### Сценарий`\\n- `### Функциональные требования`\\n- `### Нефункциональные требования`\\n- `### Контракт`\\n\\n## Особые правила\\n\\n- Сценарий оформляется как технический use case.\\n- Функциональные требования маркируются `FR-*`.\\n- Нефункциональные требования маркируются `NFR-*`.\\n- Контракт должен быть пригоден для последующей сборки OpenAPI.\\n- Если у метода есть интеграции, они выносятся в `### Интеграции`.\\n- Ошибки и HTTP-коды либо описываются в `### Ошибки`, либо ссылаются на централизованный каталог ошибок.\\n\\n## Ошибки оформления\\n\\n- Нельзя заменять контракт общим текстовым описанием.\\n- Нельзя смешивать несколько endpoint в одном документе.\\n- Нельзя хранить связи и навигацию вне frontmatter.\\n\\n## Template (api_method)\\n\\n---\\nid: api.example_method\\ntype: api_method\\ndoc_type: api_method\\nname: example_method\\ntitle: HTTP API /example\\nmodule: example_module\\nlayer: application\\ndomain: example_domain\\nsub_domain: example_subdomain\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2026-03-20\\nsource_of_truth: code\\nparent: null\\nchildren: []\\ntags: []\\nentities: []\\nlinks: {}\\n---\\n\\n# HTTP API /example\\n\\n## Summary\\n\\nКраткое описание метода.\\n\\n## Details\\n\\n## Описание\\n\\nКороткое описание сути метода.\\n\\n## Сценарий\\n\\n**Название:**\\n\\n**Предусловия:**\\n- \\n\\n**Триггер:**\\n- \\n\\n**Основной сценарий:**\\n1. \\n\\n**Альтернативный сценарий:**\\n1. \\n\\n**Обработка ошибок:**\\n1. \\n\\n**Постусловие:**\\n- \\n\\n## Функциональные требования\\n\\n**FR-1.**\\n\\n## Нефункциональные требования\\n\\n**NFR-1.**\\n\\n## Контракт\\n\\n### Входные параметры\\n\\n| Параметр | Где передается | Тип | Обязательность | Ограничения | Описание | Пример |\\n|---|---|---|---|---|---|---|\\n| | | | | | | |\\n\\n### Выходные параметры\\n\\n| Поле | Тип | Обязательность | Ограничения | Описание | Заполнение | Пример |\\n|---|---|---|---|---|---|---|\\n| | | | | | | |\\n\\n### Интеграции\\n\\n### Ошибки\\n\\n### Связанный код\\n\\n### История изменений\\n\\n## Section rule: api-contract\\n\\n# API Contract Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как оформлять подраздел `## Контракт` в API-документах.\\n\\n## Что должно быть описано\\n\\n- входные параметры\\n- выходные параметры\\n- JSON-структуры запросов и ответов\\n- обязательность полей\\n- типы полей\\n- ограничения\\n- описание назначения полей\\n- примеры данных\\n- auth\\n- idempotency\\n- timeout\\n- ошибки и их HTTP-коды\\n\\n## Правило качества\\n\\nКонтракт должен быть достаточно формальным, чтобы по нему можно было собрать OpenAPI-спецификацию.\\n\\n## Section rule: api-scenario\\n\\n# API Scenario Rules\\n\\n## Назначение\\n\\nЭтот файл описывает, как оформлять подраздел `### Сценарий` в API-документах.\\n\\n## Обязательные части\\n\\n- название\\n- предусловия\\n- триггер\\n- основной сценарий\\n- альтернативный сценарий\\n- обработка ошибок\\n- постусловие\\n\\n## Правила\\n\\n- Сценарий должен быть лаконичным.\\n- Сценарий должен отражать суть шага.\\n- Сложные технические детали надо выносить в `FR-*`.\\n\\n## Section rule: details\\n\\n# Details Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает общие правила для секции `## Details`.\\n\\n## Правила\\n\\n- `Details` оформляется как `## Details`.\\n- Внутри `Details` используются заголовки уровня `###` и ниже.\\n- Структура Details зависит от типа документа.\\n- В Details не нужно повторно дублировать навигацию и связи, если они уже есть во frontmatter.\\n- Интеграции, ошибки и кодовые привязки должны быть выделены в отдельные подразделы, если они существенны для понимания документа.\\n\\n## Section rule: requirements-format\\n\\n# Requirements Format Rules\\n\\n## Назначение\\n\\nЭтот файл задает формат для функциональных и нефункциональных требований.\\n\\n## Функциональные требования\\n\\n- Использовать коды `FR-1`, `FR-2`, `FR-3` и так далее.\\n- Каждое требование должно описывать отдельный обязательный аспект поведения.\\n- Идентификаторы локальны в пределах одного документа.\\n\\n## Нефункциональные требования\\n\\n- Использовать коды `NFR-1`, `NFR-2`, `NFR-3` и так далее.\\n- Требования должны описывать характеристики качества, ограничения и эксплуатационные свойства.\\n\\n## Section rule: summary\\n\\n# Summary Section Rules\\n\\n## Назначение\\n\\nЭтот файл задает правила для секции `## Summary`.\\n\\n## Правила\\n\\n- Summary должен быть коротким explain-слоем быстрого контекста.\\n- Summary должен объяснять суть документа без лишних деталей.\\n- Summary должен быть пригоден для explain и быстрого чтения.\\n- Предпочтительный формат: список ключевых фактов `Purpose`, `Actor`, `Trigger`, `Errors`, `Related ...` и т.д.\\n- Для крупных документов допустим более длинный summary, если он остается структурированным.\"\n}",
+ "log_context": "workflow.v2.docs_update.from_feature.changeset"
+}
+```
+
+## workflow.v2.docs_update.from_feature.llm
+```json
+{
+ "event": "response",
+ "text": "{\n \"op\": \"create\",\n \"path\": \"docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md\",\n \"reason\": \"Реализация сервиса CLIENTS. POST /api/v1/clients/contacts-dgr из системной аналитики.\",\n \"proposed_content\": \"---\\nid: ufs.contacts_dgr.api.create\\ntype: api_method\\ndoc_type: api_method\\nname: create_contact\\ntitle: CREATE CONTACT. ДГР CLIENTS. POST /api/v1/clients/contacts-dgr\\ndomain: contacts_dgr\\nsub_domain: create_contact\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2023-10-10\\nsource_of_truth: system_analytics\\nparent: null\\nchildren: []\\ntags: [system_analytics]\\nentities: []\\nlinks: {}\\n---\\n\\n# CREATE CONTACT. ДГР CLIENTS. POST /api/v1/clients/contacts-dgr\\n\\n## Summary\\n\\n**Purpose**: Создание контакта ДГР в системе клиентов.\\n**Actors**: Клиенты, пользователи системы.\\n**Trigger**: POST-запрос на `/api/v1/clients/contacts-dgr`.\\n**Errors**: BAD_REQUEST, UNAUTHORIZED.\\n**Related docs**: Нет связанных документов.\\n\\n## Details\\n\\n## Описание\\nМетод позволяет создавать контакты ДГР в системе клиентов посредством POST-запроса на `/api/v1/clients/contacts-dgr`.\n\n## Сценарий\n\n**Название:** Создать контакт ДГР\n\n**Предусловия:**\\n- Пользователь авторизован и имеет доступ к периметру CI02792632.ContactsDGR.Create.\\n- Передан корректный JSON-запрос.\\n\n**Триггер:** Отправка POST-запроса на `/api/v1/clients/contacts-dgr`.\\n\n**Основной сценарий:**\\n1. Проверяется валидность JSON-запроса.\\n2. Проводится авторизация пользователя.\\n3. Вызывается endpoint POST /contacts в prpb.contacts_dgr.\\n4. Возвращается результат в формате UfsBaseResponseContactDGRCreateRsDto.\\n\n**Альтернативный сценарий:** Если JSON некорректен или отсутствует требуемый периметр доступа, возвращается соответствующий статус ответа.\\n\n**Обработка ошибок:** Обрабатываются ошибки проверки JSON, авторизации и интеграции с prpb.contacts_dgr.\\n\n**Постусловие:** Контакт успешно создан или возвращена информация об ошибке.\\n\n\n## Функциональные требования\n\n**FR-1.** Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом BAD_REQUEST.\\n**FR-2.** Авторизовать запрос по наличию периметра CI02792632.ContactsDGR.Create. При отсутствии периметра завершить основной сценарий с кодом UNAUTHORIZED.\\n**FR-3.** Вызвать endpoint POST /contacts в prpb.contacts_dgr для создания контакта.\\n**FR-4.** Вернуть ответ в формате UfsBaseResponseContactDGRCreateRsDto.\\n\n\n## Нефункциональные требования\n\n**NFR-1.** Безопасность данных гарантируется авторизацией и проверкой периметров доступа.\\n**NFR-2.** Производительность обеспечивается оптимизированными запросами к внешним системам.\\n\n**NFR-3.** Доступность гарантируется резервированием внешних сервисов.\\n\n\n## Контракт\n\n### Входные параметры\n\n**headers**\n\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\n|---------------------|---------------|--------------|----------------|--------------------------|\n| `X-Request-Id` | 1 | `uuid` | header | Сквозной идентификатор вызова |\n| `X-Client-Ident-Id` | 1 | `string(50)` | header | Идентификатор системы потребителя |\n| `X-Employee-Number` | 0..1 | `string(8)` | header | Табельный номер пользователя, вызвавшего сервис |\n\n**body**\n\n| Атрибут | Обязательность | Тип | Описание |\n|------------------------|---------------|------------------|------------------------------------|\n| contact | 1 | object | Данные контакта ДГР |\n| contact.lastName | 0..1 | string(100) | Фамилия контакта |\n| contact.firstName | 0..1 | string(100) | Имя контакта |\n| contact.middleName | 0..1 | string(100) | Отчество контакта |\n| contact.name | 0..1 | string(100) | Название группового контакта |\n| contact.description | 0..1 | string(1000) | Описание группового контакта |\n| contact.position | 0..1 | string(100) | Должность контакта у клиента |\n| contact.comment | 0..1 | string(1000) | Комментарий к контакту |\n| contact.contactType | 1 | enum(string) | Индивидуальный или групповой контакт |\n| contact.crossboarding | 1 | boolean | Признак принадлежности к онбордингу |\n| contact.createdBy | 1 | string(8) | Табельный номер создателя контакта |\n| contact.emails | 0..1 | array(object) | Массив электронных адресов |\n| contact.emails.value | 1 | string(100) | Электронный адрес |\n| contact.emails.main | 1 | boolean | Признак основной почты |\n| contact.phones | 0..1 | array(object) | Массив телефонных номеров |\n| contact.phones.value | 1 | string(20) | Номер телефона |\n| contact.phones.extValue | 0..1 | string(10) | Внутренний добавочный номер |\n| contact.phones.main | 1 | boolean | Признак основного номера |\n| contact.phones.mobile | 1 | boolean | Признак мобильного номера |\n| client | 1 | object | Данные клиента |\n| client.ucpId | 0..1 | string(36) | Идентификатор клиента ПАО |\n| client.sbpId | 0..1 | string(36) | Идентификатор клиента АО |\n| client.inn | 0..1 | string(12) | ИНН клиента |\n| client.kpp | 0..1 | string(9) | КПП клиента |\n\n**Выходные параметры**\n\n| Поле | Тип | Обязательность | Ограничения | Описание | Заполнение | Пример |\n|-------------|-------------|---------------|-------------|--------------------|--------------|---------------|\n| contactId | string(36) | 1 | | Идентификатор контакта | | «8c7d2b5e-fa...» |\n\"\n}"
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "build_changeset",
+ "title": "Формирование changeset"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "changeset_items": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 2,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md"
+ },
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_step_traced",
+ "workflow_id": "v2.docs_update.from_feature",
+ "step": {
+ "id": "finalize",
+ "title": "Подготовка ответа"
+ },
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 2,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md"
+ },
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "answer_length": 8398,
+ "issues": 0,
+ "changeset_items": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 2,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md"
+ },
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md"
+ }
+ ],
+ "apply_changeset": true,
+ "answer_len": 8398,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_trace_flushed",
+ "workflow_id": "v2.docs_update.from_feature",
+ "steps": [
+ {
+ "step_id": "resolve_source",
+ "title": "Определение источника аналитики",
+ "input": {
+ "source_kind": "",
+ "source_ref": "",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "application": "",
+ "platform": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "application": "",
+ "platform": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "load_source",
+ "title": "Загрузка системной аналитики",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "",
+ "feature_content_len": 0,
+ "analysis_id": "",
+ "application": "",
+ "platform": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "source_kind": "markdown_file",
+ "content_loaded": true,
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "",
+ "application": "",
+ "platform": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "parse_feature",
+ "title": "Парсинг функциональных требований",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "",
+ "application": "",
+ "platform": "",
+ "domains": [],
+ "subdomains": [],
+ "units_count": 0,
+ "unit_headings": [],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "load_doc_rules",
+ "title": "Загрузка doc_rules",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": false,
+ "doc_rules_supported_types": [],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "enabled": true,
+ "loaded": true,
+ "supported_doc_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "build_change_plan",
+ "title": "Построение плана изменений",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 0,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 0,
+ "planned_changes_preview": [],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "docs_rows": 7,
+ "planned_changes": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "build_changeset",
+ "title": "Формирование changeset",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 0,
+ "changeset_preview": [],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "changeset_items": 2,
+ "issues": 0,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 2,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md"
+ },
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ },
+ {
+ "step_id": "finalize",
+ "title": "Подготовка ответа",
+ "input": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 2,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md"
+ },
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md"
+ }
+ ],
+ "apply_changeset": false,
+ "answer_len": 0,
+ "issues_count": 0,
+ "issues_preview": []
+ },
+ "output": {
+ "answer_length": 8398,
+ "issues": 0,
+ "changeset_items": 2,
+ "_context": {
+ "source_kind": "markdown_file",
+ "source_ref": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features/create_contact.md",
+ "project_root": "/Users/alex/Dev_projects_v2/ai driven app process/v2/test_doc/features",
+ "feature_content_len": 6243,
+ "analysis_id": "test",
+ "application": "contacts_dgr",
+ "platform": "web",
+ "domains": [
+ "contacts_dgr"
+ ],
+ "subdomains": [
+ "create_contact"
+ ],
+ "units_count": 2,
+ "unit_headings": [
+ "FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»",
+ "FR2. Реализовать сервис CLIENTS. POST /api/v1/clients/contacts-dgr"
+ ],
+ "docs_rows_count": 7,
+ "doc_rules_enabled": true,
+ "doc_rules_loaded": true,
+ "doc_rules_supported_types": [
+ "api_method",
+ "architecture_overview",
+ "domain_entity",
+ "logic_block",
+ "ui_page"
+ ],
+ "planned_changes_count": 2,
+ "planned_changes_preview": [
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md",
+ "doc_type": "ui_page"
+ },
+ {
+ "op": "create",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md",
+ "doc_type": "api_method"
+ }
+ ],
+ "changeset_count": 2,
+ "changeset_preview": [
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md"
+ },
+ {
+ "op": "ChangeOp.CREATE",
+ "path": "docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md"
+ }
+ ],
+ "apply_changeset": true,
+ "answer_len": 8398,
+ "issues_count": 0,
+ "issues_preview": []
+ }
+ }
+ }
+ ]
+}
+```
+
+## workflow.v2.docs_update.from_feature
+```json
+{
+ "event": "workflow_completed",
+ "workflow_id": "v2.docs_update.from_feature"
+}
+```
+
+## process.v2.pipeline
+```json
+{
+ "event": "answer_generated",
+ "answer_mode": "docs_update_changeset",
+ "answer_length": 8398,
+ "changeset_items": 2,
+ "apply_changeset": true
+}
+```
+
+## result
+```json
+{
+ "status": "done",
+ "answer": "DOC_UPDATE/FROM_FEATURE: результат построения changeset.\n\nПлан изменений:\n- create: docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md (ui_page)\n- create: docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md (api_method)\n\nChangeset (для плагина):\n```json\n[\n {\n \"op\": \"create\",\n \"path\": \"docs/contacts_dgr/web/ui/ui.contacts_dgr.create.md\",\n \"base_hash\": null,\n \"proposed_content\": \"---\\nid: ui.contacts_dgr.create\\ndoc_type: ui_page\\ntitle: FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\\ndomain: contacts_dgr\\nsub_domain: create_contact\\nstatus: draft\\nupdated_at: \\\"2023-10-10\\\"\\nrelated_docs: []\\n---\\n\\n# FR1. Реализовать сценарий «Контакты ДГР. Создание карточки контакта ДГР»\\n\\n## Summary\\n\\n- **Назначение**: реализация сценария создания карточки контакта ДГР.\\n- **Пользователь**: заполняет атрибуты и нажимает «Добавить».\\n- **Интеграция**: вызов endpoint POST /api/v1/clients/contacts-dgr.\\n- **Результат**: отображение результата создания в виде push-уведомления.\\n\\n## Details\\n\\n### Назначение страницы\\nРеализует функционал создания новой карточки контакта ДГР.\\n\\n### Пользовательский сценарий\\nПользователь вводит данные и инициирует создание нового контакта ДГР через интерфейс.\\n\\n### Основные блоки интерфейса\\nБлок ввода атрибутов и кнопка «Добавить».\\n\\n### Связанные API и сущности\\nВызывается endpoint POST /api/v1/clients/contacts-dgr для обработки запроса.\\n\\n### Функциональные требования\\n- FR-1: пользователь может заполнить все необходимые поля и создать новый контакт ДГР.\\n\\n### Нефункциональные требования\\nОтсутствуют специфические требования.\\n\\n### Ограничения и граничные случаи\\nНет ограничений на этапе MVP.\\n\\n### Ошибки и валидации\\nПроверка корректности введенных данных перед отправкой.\\n\\n### Связанный код\\nUI-компоненты формы и логика отправки данных.\\n\\n### Связанные документы\\nОтсутствуют.\\n\\n### История изменений\\nПервоначальная версия документа.\",\n \"reason\": \"Реализация сценария создания карточки контакта ДГР\",\n \"hunks\": []\n },\n {\n \"op\": \"create\",\n \"path\": \"docs/contacts_dgr/ufs/api/ufs.contacts_dgr.api.create.md\",\n \"base_hash\": null,\n \"proposed_content\": \"---\\nid: ufs.contacts_dgr.api.create\\ntype: api_method\\ndoc_type: api_method\\nname: create_contact\\ntitle: CREATE CONTACT. ДГР CLIENTS. POST /api/v1/clients/contacts-dgr\\ndomain: contacts_dgr\\nsub_domain: create_contact\\nrelated_docs: []\\nstatus: draft\\nupdated_at: 2023-10-10\\nsource_of_truth: system_analytics\\nparent: null\\nchildren: []\\ntags: [system_analytics]\\nentities: []\\nlinks: {}\\n---\\n\\n# CREATE CONTACT. ДГР CLIENTS. POST /api/v1/clients/contacts-dgr\\n\\n## Summary\\n\\n**Purpose**: Создание контакта ДГР в системе клиентов.\\n**Actors**: Клиенты, пользователи системы.\\n**Trigger**: POST-запрос на `/api/v1/clients/contacts-dgr`.\\n**Errors**: BAD_REQUEST, UNAUTHORIZED.\\n**Related docs**: Нет связанных документов.\\n\\n## Details\\n\\n## Описание\\nМетод позволяет создавать контакты ДГР в системе клиентов посредством POST-запроса на `/api/v1/clients/contacts-dgr`.\\n\\n## Сценарий\\n\\n**Название:** Создать контакт ДГР\\n\\n**Предусловия:**\\n- Пользователь авторизован и имеет доступ к периметру CI02792632.ContactsDGR.Create.\\n- Передан корректный JSON-запрос.\\n\\n**Триггер:** Отправка POST-запроса на `/api/v1/clients/contacts-dgr`.\\n\\n**Основной сценарий:**\\n1. Проверяется валидность JSON-запроса.\\n2. Проводится авторизация пользователя.\\n3. Вызывается endpoint POST /contacts в prpb.contacts_dgr.\\n4. Возвращается результат в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\n**Альтернативный сценарий:** Если JSON некорректен или отсутствует требуемый периметр доступа, возвращается соответствующий статус ответа.\\n\\n**Обработка ошибок:** Обрабатываются ошибки проверки JSON, авторизации и интеграции с prpb.contacts_dgr.\\n\\n**Постусловие:** Контакт успешно создан или возвращена информация об ошибке.\\n\\n\\n## Функциональные требования\\n\\n**FR-1.** Проверить входящий запрос на соответствие JSON-схеме. Если ошибка, завершить сценарий с кодом BAD_REQUEST.\\n**FR-2.** Авторизовать запрос по наличию периметра CI02792632.ContactsDGR.Create. При отсутствии периметра завершить основной сценарий с кодом UNAUTHORIZED.\\n**FR-3.** Вызвать endpoint POST /contacts в prpb.contacts_dgr для создания контакта.\\n**FR-4.** Вернуть ответ в формате UfsBaseResponseContactDGRCreateRsDto.\\n\\n\\n## Нефункциональные требования\\n\\n**NFR-1.** Безопасность данных гарантируется авторизацией и проверкой периметров доступа.\\n**NFR-2.** Производительность обеспечивается оптимизированными запросами к внешним системам.\\n\\n**NFR-3.** Доступность гарантируется резервированием внешних сервисов.\\n\\n\\n## Контракт\\n\\n### Входные параметры\\n\\n**headers**\\n\\n| Атрибут | Обязательность | Тип | Где передаем | Описание |\\n|---------------------|---------------|--------------|----------------|--------------------------|\\n| `X-Request-Id` | 1 | `uuid` | header | Сквозной идентификатор вызова |\\n| `X-Client-Ident-Id` | 1 | `string(50)` | header | Идентификатор системы потребителя |\\n| `X-Employee-Number` | 0..1 | `string(8)` | header | Табельный номер пользователя, вызвавшего сервис |\\n\\n**body**\\n\\n| Атрибут | Обязательность | Тип | Описание |\\n|------------------------|---------------|------------------|------------------------------------|\\n| contact | 1 | object | Данные контакта ДГР |\\n| contact.lastName | 0..1 | string(100) | Фамилия контакта |\\n| contact.firstName | 0..1 | string(100) | Имя контакта |\\n| contact.middleName | 0..1 | string(100) | Отчество контакта |\\n| contact.name | 0..1 | string(100) | Название группового контакта |\\n| contact.description | 0..1 | string(1000) | Описание группового контакта |\\n| contact.position | 0..1 | string(100) | Должность контакта у клиента |\\n| contact.comment | 0..1 | string(1000) | Комментарий к контакту |\\n| contact.contactType | 1 | enum(string) | Индивидуальный или групповой контакт |\\n| contact.crossboarding | 1 | boolean | Признак принадлежности к онбордингу |\\n| contact.createdBy | 1 | string(8) | Табельный номер создателя контакта |\\n| contact.emails | 0..1 | array(object) | Массив электронных адресов |\\n| contact.emails.value | 1 | string(100) | Электронный адрес |\\n| contact.emails.main | 1 | boolean | Признак основной почты |\\n| contact.phones | 0..1 | array(object) | Массив телефонных номеров |\\n| contact.phones.value | 1 | string(20) | Номер телефона |\\n| contact.phones.extValue | 0..1 | string(10) | Внутренний добавочный номер |\\n| contact.phones.main | 1 | boolean | Признак основного номера |\\n| contact.phones.mobile | 1 | boolean | Признак мобильного номера |\\n| client | 1 | object | Данные клиента |\\n| client.ucpId | 0..1 | string(36) | Идентификатор клиента ПАО |\\n| client.sbpId | 0..1 | string(36) | Идентификатор клиента АО |\\n| client.inn | 0..1 | string(12) | ИНН клиента |\\n| client.kpp | 0..1 | string(9) | КПП клиента |\\n\\n**Выходные параметры**\\n\\n| Поле | Тип | Обязательность | Ограничения | Описание | Заполнение | Пример |\\n|-------------|-------------|---------------|-------------|--------------------|--------------|---------------|\\n| contactId | string(36) | 1 | | Идентификатор контакта | | «8c7d2b5e-fa...» |\\n\",\n \"reason\": \"Реализация сервиса CLIENTS. POST /api/v1/clients/contacts-dgr из системной аналитики.\",\n \"hunks\": []\n }\n]\n```\n\napply_changeset: true",
+ "completed_at": "2026-04-10T07:27:10.163248+00:00"
+}
+```
diff --git a/src/app/core/agent/processes/v2/doc_rules/templates/ui_page.template.md b/src/app/core/agent/processes/v2/doc_rules/templates/ui_page.template.md
new file mode 100644
index 0000000..5bd32fe
--- /dev/null
+++ b/src/app/core/agent/processes/v2/doc_rules/templates/ui_page.template.md
@@ -0,0 +1,50 @@
+---
+id: ui.example_page
+type: ui_page
+doc_type: ui_page
+name: example_page
+title: Пример UI-страницы
+module: example_module
+layer: presentation
+domain: example_domain
+sub_domain: example_subdomain
+related_docs: []
+status: draft
+updated_at: 2026-03-20
+source_of_truth: mixed
+parent: null
+children: []
+tags: []
+entities: []
+links: {}
+---
+
+# Пример UI-страницы
+
+## Summary
+
+Краткое описание страницы и её назначения.
+
+## Details
+
+### Назначение страницы
+
+### Пользовательский сценарий
+
+### Основные блоки интерфейса
+
+### Связанные API и сущности
+
+### Функциональные требования
+
+### Нефункциональные требования
+
+### Ограничения и граничные случаи
+
+### Ошибки и валидации
+
+### Связанный код
+
+### Связанные документы
+
+### История изменений
diff --git a/src/app/core/agent/processes/v2/workflows/doc_explain_api_exposed/steps/retrieval/api_endpoint_collector.py b/src/app/core/agent/processes/v2/workflows/doc_explain_api_exposed/steps/retrieval/api_endpoint_collector.py
index 4f55a6c..42189c9 100644
--- a/src/app/core/agent/processes/v2/workflows/doc_explain_api_exposed/steps/retrieval/api_endpoint_collector.py
+++ b/src/app/core/agent/processes/v2/workflows/doc_explain_api_exposed/steps/retrieval/api_endpoint_collector.py
@@ -8,26 +8,14 @@ class ApiEndpointCollector:
_ENDPOINT_VALUE_RE = re.compile(
r"\b((?:GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)(?:\s*\|\s*(?:GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS))*)\s+(/[-a-zA-Z0-9_./{}]+)"
)
- _METHOD_PATH_RE = re.compile(r"\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s+(/[-a-zA-Z0-9_./{}]+)")
- _PATH_RE = re.compile(r"(/[-a-zA-Z0-9_./{}]+)")
_DOC_EXTS = (".md", ".yaml", ".yml", ".json")
def collect(self, rows: list[dict]) -> list[str]:
endpoints: list[str] = []
for row in rows:
self._append_from_endpoint_metadata(endpoints, row)
- self._append_from_title_fallback(endpoints, row)
- for raw in self._row_candidates(row):
- self._append_from_text(endpoints, raw)
return sorted(set(endpoints))
- def _append_from_title_fallback(self, out: list[str], row: dict) -> None:
- title = str(row.get("title") or "").strip()
- if not title:
- return
- for match in self._PATH_RE.findall(title):
- self._append_default(out, match)
-
def _append_from_endpoint_metadata(self, out: list[str], row: dict) -> None:
metadata = dict(row.get("metadata") or {})
endpoint_value = str(metadata.get("endpoint") or "").strip()
@@ -36,19 +24,6 @@ class ApiEndpointCollector:
for methods, path in self._ENDPOINT_VALUE_RE.findall(endpoint_value):
self._append_methods_with_path(out, methods, path)
- def _row_candidates(self, row: dict) -> list[str]:
- metadata = dict(row.get("metadata") or {})
- values = [
- metadata.get("name"),
- metadata.get("summary_text"),
- row.get("title"),
- ]
- return [str(value or "") for value in values if str(value or "").strip()]
-
- def _append_from_text(self, out: list[str], text: str) -> None:
- for method, path in self._METHOD_PATH_RE.findall(text):
- self._append_with_method(out, method, path)
-
def _append_methods_with_path(self, out: list[str], methods_raw: str, path_raw: str) -> None:
methods = [
part.strip().upper()
diff --git a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/doc_rules_pipeline/changeset_generator.py b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/doc_rules_pipeline/changeset_generator.py
index b392835..107a6bb 100644
--- a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/doc_rules_pipeline/changeset_generator.py
+++ b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/doc_rules_pipeline/changeset_generator.py
@@ -56,7 +56,17 @@ class DocRulesChangesetGenerator:
)
payload = self._parse_json(raw)
if payload is None:
- return None, f"LLM вернул невалидный JSON changeset для {item.path}."
+ if trace is not None:
+ trace.log("changeset_json_parse_failed", {"path": item.path, "raw_chars": len(str(raw or ""))})
+ repaired_raw = self._llm.generate(
+ "v2_docs_update.repair_doc_changeset_json",
+ self._build_repair_input(raw=raw, item=item),
+ log_context="workflow.v2.docs_update.from_feature.changeset_repair",
+ trace=trace,
+ )
+ payload = self._parse_json(repaired_raw)
+ if payload is None:
+ return None, f"LLM вернул невалидный JSON changeset для {item.path} даже после repair."
payload["op"] = item.op
payload["path"] = item.path
payload["reason"] = str(payload.get("reason") or item.reason)[:500]
@@ -80,8 +90,63 @@ class DocRulesChangesetGenerator:
value = json.loads(text)
return value if isinstance(value, dict) else None
except json.JSONDecodeError:
+ normalized = self._escape_control_chars_in_json_strings(text)
+ if normalized != text:
+ try:
+ value = json.loads(normalized)
+ return value if isinstance(value, dict) else None
+ except json.JSONDecodeError:
+ return None
return None
+ def _build_repair_input(self, *, raw: str, item: PlannedChange) -> str:
+ payload = {
+ "expected_contract": {
+ "op": item.op,
+ "path": item.path,
+ "required_keys": ["op", "path", "reason"],
+ "proposed_content_required_for": ["create", "update"],
+ },
+ "raw_llm_output": str(raw or ""),
+ }
+ return json.dumps(payload, ensure_ascii=False, indent=2)
+
+ def _escape_control_chars_in_json_strings(self, text: str) -> str:
+ escaped: list[str] = []
+ in_string = False
+ backslash = False
+ for char in text:
+ if not in_string:
+ escaped.append(char)
+ if char == '"':
+ in_string = True
+ continue
+ if backslash:
+ escaped.append(char)
+ backslash = False
+ continue
+ if char == "\\":
+ escaped.append(char)
+ backslash = True
+ continue
+ if char == '"':
+ escaped.append(char)
+ in_string = False
+ continue
+ codepoint = ord(char)
+ if codepoint < 0x20:
+ if char == "\n":
+ escaped.append("\\n")
+ elif char == "\r":
+ escaped.append("\\r")
+ elif char == "\t":
+ escaped.append("\\t")
+ else:
+ escaped.append(f"\\u{codepoint:04x}")
+ continue
+ escaped.append(char)
+ return "".join(escaped)
+
def _resolve_base_hash(self, project_root: str, rel_path: str) -> str:
root = Path(project_root or "").expanduser()
if not root.is_absolute():
diff --git a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/build_change_plan_step.py b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/build_change_plan_step.py
index f44220e..c91d91a 100644
--- a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/build_change_plan_step.py
+++ b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/build_change_plan_step.py
@@ -1,9 +1,13 @@
from __future__ import annotations
import json
-import re
from app.core.agent.processes.v2.workflows.doc_update_from_feature.steps.docs_state_loader import DocsState
+from app.core.agent.processes.v2.workflows.doc_update_from_feature.steps.plan_hints import (
+ PlanUnitHint,
+ parse_plan_hints,
+)
+from app.core.agent.processes.v2.workflows.doc_update_from_feature.steps.plan_path_policy import PlanPathPolicy
from app.core.agent.processes.v2.workflows.doc_update_from_feature.workflow_runtime.context import DocUpdateFromFeatureContext
from app.core.agent.processes.v2.workflows.doc_update_from_feature.workflow_runtime.models import PlannedChange
from app.core.agent.processes.v2.workflows.doc_update_from_feature.workflow_runtime.system_rules import (
@@ -23,15 +27,16 @@ class BuildChangePlanStep(WorkflowStep[DocUpdateFromFeatureContext]):
def __init__(self, llm: AgentLlmService, query_repository: RagQueryRepository | None = None) -> None:
self._llm = llm
self._query_repository = query_repository or RagQueryRepository()
+ self._path_policy = PlanPathPolicy(DOC_TYPE_TO_FOLDER)
async def run(self, context: DocUpdateFromFeatureContext) -> DocUpdateFromFeatureContext:
if context.answer or not context.units:
return context
self._load_docs_state(context)
- inferred_types = self._infer_missing_types(context)
+ inferred_hints = self._infer_plan_hints(context)
state = DocsState.from_rows(context.docs_catalog_rows)
for index, unit in enumerate(context.units):
- planned = self._build_unit_plan(context, unit, state, inferred_types.get(index, ""))
+ planned = self._build_unit_plan(context, unit, state, inferred_hints.get(index, PlanUnitHint()))
if planned is None:
continue
context.planned_changes.append(planned)
@@ -55,18 +60,26 @@ class BuildChangePlanStep(WorkflowStep[DocUpdateFromFeatureContext]):
except Exception as exc:
context.issues.append(f"Не удалось загрузить состояние документации из RAG: {exc}")
- def _infer_missing_types(self, context: DocUpdateFromFeatureContext) -> dict[int, str]:
- missing: list[tuple[int, str, str]] = []
+ def _infer_plan_hints(self, context: DocUpdateFromFeatureContext) -> dict[int, PlanUnitHint]:
+ items = []
for idx, unit in enumerate(context.units):
- value = str(unit.metadata.get("type") or "").strip()
- if not value:
- missing.append((idx, unit.heading, unit.body[:400]))
- if not missing:
- return {}
+ items.append(
+ {
+ "index": idx,
+ "heading": unit.heading,
+ "snippet": unit.body[:400],
+ "known": {
+ "type": str(unit.metadata.get("type") or "").strip(),
+ "id": str(unit.metadata.get("id") or "").strip(),
+ "application": str(unit.metadata.get("application") or context.analytics_meta.application or "").strip(),
+ "platform": str(unit.metadata.get("platform") or context.analytics_meta.platform or "").strip(),
+ },
+ }
+ )
payload = {
"system_rules": SYSTEM_RULES_TEXT,
"allowed_doc_types": list(ALLOWED_DOC_TYPES),
- "items": [{"index": idx, "heading": h, "snippet": snippet} for idx, h, snippet in missing],
+ "items": items,
}
raw = self._llm.generate(
"v2_docs_update.plan_change_units",
@@ -74,43 +87,38 @@ class BuildChangePlanStep(WorkflowStep[DocUpdateFromFeatureContext]):
log_context="workflow.v2.docs_update.from_feature.plan",
trace=context.runtime.trace.module("workflow.v2.docs_update.from_feature.llm"),
)
- return self._parse_type_inference(raw)
-
- def _parse_type_inference(self, raw: str) -> dict[int, str]:
- try:
- data = json.loads(str(raw or "").strip())
- except json.JSONDecodeError:
- return {}
- rows = data.get("items") if isinstance(data, dict) else []
- if not isinstance(rows, list):
- return {}
- result: dict[int, str] = {}
- for row in rows:
- if not isinstance(row, dict):
- continue
- index = row.get("index")
- doc_type = str(row.get("doc_type") or "").strip()
- if not isinstance(index, int) or doc_type not in ALLOWED_DOC_TYPES:
- continue
- result[index] = doc_type
- return result
+ return parse_plan_hints(raw, ALLOWED_DOC_TYPES)
def _build_unit_plan(
self,
context: DocUpdateFromFeatureContext,
unit,
state: DocsState,
- inferred_doc_type: str,
+ hint: PlanUnitHint,
) -> PlannedChange | None:
- doc_type = str(unit.metadata.get("type") or inferred_doc_type).strip()
+ doc_type = str(unit.metadata.get("type") or hint.doc_type).strip()
if doc_type not in ALLOWED_DOC_TYPES:
context.issues.append(f"Unit '{unit.heading}': неизвестный или отсутствующий type '{doc_type}'.")
return None
- unit_id = str(unit.metadata.get("id") or self._make_doc_id(doc_type, unit.heading)).strip()
+ unit_id = self._path_policy.make_doc_id(
+ doc_type=doc_type,
+ heading=unit.heading,
+ hinted_doc_id=str(unit.metadata.get("id") or hint.doc_id or "").strip(),
+ )
op_hint = str(unit.metadata.get("op") or "create_or_update").strip().lower()
- target_hint = str(unit.metadata.get("target_path_hint") or "").strip()
- path = self._resolve_path(doc_type, unit_id, unit.heading, target_hint, state)
- op = self._resolve_op(op_hint, unit_id, path, state)
+ application = str(unit.metadata.get("application") or context.analytics_meta.application or hint.application).strip()
+ platform = str(unit.metadata.get("platform") or context.analytics_meta.platform or hint.platform).strip().lower()
+ page_type = str(unit.metadata.get("page_type") or hint.page_type or self._path_policy.default_page_type(doc_type)).strip()
+ path = self._path_policy.resolve_path(
+ doc_type=doc_type,
+ unit_id=unit_id,
+ application=application,
+ platform=platform,
+ page_type=page_type,
+ inferred_path=hint.path,
+ state=state,
+ )
+ op = self._path_policy.resolve_op(op_hint=op_hint, unit_id=unit_id, path=path, state=state)
source_refs = self._as_list(unit.metadata.get("source_refs")) or ["section: 5. Функциональные требования"]
related_docs = self._as_list(unit.metadata.get("related_docs"))
reason = f"Из unit '{unit.heading}' системной аналитики ({context.analytics_meta.analysis_id or 'analysis'})."
@@ -126,34 +134,6 @@ class BuildChangePlanStep(WorkflowStep[DocUpdateFromFeatureContext]):
related_docs=related_docs,
)
- def _resolve_path(self, doc_type: str, unit_id: str, heading: str, hint: str, state: DocsState) -> str:
- if unit_id in state.by_doc_id:
- return state.by_doc_id[unit_id]
- if hint:
- return hint
- folder = DOC_TYPE_TO_FOLDER.get(doc_type, "docs")
- slug = self._slugify(unit_id or heading)
- return f"{folder}/{slug}.md"
-
- def _resolve_op(self, op_hint: str, unit_id: str, path: str, state: DocsState) -> str:
- if op_hint == "delete":
- return "delete"
- if op_hint == "create":
- return "create"
- if op_hint == "update":
- return "update"
- if path in state.by_path or unit_id in state.by_doc_id:
- return "update"
- return "create"
-
- def _make_doc_id(self, doc_type: str, heading: str) -> str:
- slug = self._slugify(heading).replace("-", "_")
- return f"{doc_type}.{slug}".strip(".")
-
- def _slugify(self, value: str) -> str:
- cleaned = re.sub(r"[^a-zA-Z0-9а-яА-Я_-]+", "-", value.lower()).strip("-")
- return re.sub(r"-+", "-", cleaned) or "doc"
-
def _as_list(self, value: object) -> list[str]:
if isinstance(value, list):
return [str(item).strip() for item in value if str(item).strip()]
diff --git a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/feature_markdown_parser.py b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/feature_markdown_parser.py
index aebadfd..597d1b3 100644
--- a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/feature_markdown_parser.py
+++ b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/feature_markdown_parser.py
@@ -15,7 +15,7 @@ class ParsedFeatureSpec:
class FeatureMarkdownParser:
- _META_KEYS = {"analysis_id", "domains", "subdomains"}
+ _META_KEYS = {"analysis_id", "application", "platform", "domain", "sub_domain", "domains", "subdomains"}
def parse(self, content: str) -> ParsedFeatureSpec:
lines = content.splitlines()
@@ -54,8 +54,10 @@ class FeatureMarkdownParser:
i = j
return AnalyticsMeta(
analysis_id=str(values.get("analysis_id") or "").strip(),
- domains=self._as_list(values.get("domains")),
- subdomains=self._as_list(values.get("subdomains")),
+ application=str(values.get("application") or "").strip(),
+ platform=str(values.get("platform") or "").strip(),
+ domains=self._as_list(values.get("domain") or values.get("domains")),
+ subdomains=self._as_list(values.get("sub_domain") or values.get("subdomains")),
)
def _extract_functional_section(self, lines: list[str]) -> list[str]:
@@ -109,9 +111,10 @@ class FeatureMarkdownParser:
body_start = i + 1
i += 1
continue
- if ":" not in stripped:
+ line = stripped[2:].strip() if stripped.startswith("- ") else stripped
+ if ":" not in line:
break
- key, value = [part.strip() for part in stripped.split(":", 1)]
+ key, value = [part.strip() for part in line.split(":", 1)]
if not key.isidentifier():
break
if value:
diff --git a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/parse_feature_requirements_step.py b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/parse_feature_requirements_step.py
index 3634c4d..6f780bb 100644
--- a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/parse_feature_requirements_step.py
+++ b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/parse_feature_requirements_step.py
@@ -21,9 +21,9 @@ class ParseFeatureRequirementsStep(WorkflowStep[DocUpdateFromFeatureContext]):
if not context.analytics_meta.analysis_id:
context.issues.append("Отсутствует analysis_id в metadata аналитики.")
if not context.analytics_meta.domains:
- context.issues.append("Отсутствует domains в metadata аналитики.")
+ context.issues.append("Отсутствует domain в metadata аналитики.")
if not context.analytics_meta.subdomains:
- context.issues.append("Отсутствует subdomains в metadata аналитики.")
+ context.issues.append("Отсутствует sub_domain в metadata аналитики.")
if not context.units:
context.issues.append(
"Не найдены units в разделе '## 5. Функциональные требования' с заголовками уровня '###'."
@@ -33,6 +33,8 @@ class ParseFeatureRequirementsStep(WorkflowStep[DocUpdateFromFeatureContext]):
def trace_output(self, context: DocUpdateFromFeatureContext) -> dict[str, object]:
return {
"analysis_id": context.analytics_meta.analysis_id,
+ "application": context.analytics_meta.application,
+ "platform": context.analytics_meta.platform,
"domains": context.analytics_meta.domains,
"subdomains": context.analytics_meta.subdomains,
"units": len(context.units),
diff --git a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/plan_hints.py b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/plan_hints.py
new file mode 100644
index 0000000..a458620
--- /dev/null
+++ b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/plan_hints.py
@@ -0,0 +1,64 @@
+from __future__ import annotations
+
+import json
+import re
+from dataclasses import dataclass
+
+
+@dataclass(slots=True)
+class PlanUnitHint:
+ doc_type: str = ""
+ doc_id: str = ""
+ application: str = ""
+ platform: str = ""
+ page_type: str = ""
+ path: str = ""
+
+
+def parse_plan_hints(raw: str, allowed_doc_types: tuple[str, ...]) -> dict[int, PlanUnitHint]:
+ try:
+ data = json.loads(str(raw or "").strip())
+ except json.JSONDecodeError:
+ return {}
+ rows = data.get("items") if isinstance(data, dict) else []
+ if not isinstance(rows, list):
+ return {}
+ result: dict[int, PlanUnitHint] = {}
+ for row in rows:
+ if not isinstance(row, dict):
+ continue
+ index = row.get("index")
+ if not isinstance(index, int):
+ continue
+ doc_type = str(row.get("doc_type") or "").strip()
+ result[index] = PlanUnitHint(
+ doc_type=doc_type if doc_type in allowed_doc_types else "",
+ doc_id=str(row.get("id") or "").strip(),
+ application=str(row.get("application") or "").strip(),
+ platform=str(row.get("platform") or "").strip().lower(),
+ page_type=str(row.get("page_type") or "").strip(),
+ path=str(row.get("path") or "").strip(),
+ )
+ return result
+
+
+def page_type_for_doc_type(doc_type: str, doc_type_to_folder: dict[str, str]) -> str:
+ if doc_type == "index_page":
+ return "index"
+ folder = doc_type_to_folder.get(doc_type, "docs")
+ parts = folder.split("/")
+ return parts[-1] if parts else "docs"
+
+
+def normalize_inferred_path(inferred_path: str, unit_id: str) -> str:
+ path = str(inferred_path or "").strip()
+ if not path or not path.startswith("docs/"):
+ return ""
+ if not path.endswith(f"/{unit_id}.md"):
+ return ""
+ return path
+
+
+def normalize_path_segment(value: str) -> str:
+ cleaned = re.sub(r"[^a-zA-Z0-9._-]+", "-", str(value or "").strip().lower()).strip("-")
+ return re.sub(r"-+", "-", cleaned) or "unknown"
diff --git a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/plan_path_policy.py b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/plan_path_policy.py
new file mode 100644
index 0000000..d158942
--- /dev/null
+++ b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/plan_path_policy.py
@@ -0,0 +1,59 @@
+from __future__ import annotations
+
+import re
+
+from app.core.agent.processes.v2.workflows.doc_update_from_feature.steps.docs_state_loader import DocsState
+from app.core.agent.processes.v2.workflows.doc_update_from_feature.steps.plan_hints import (
+ normalize_inferred_path,
+ normalize_path_segment,
+ page_type_for_doc_type,
+)
+
+_VALID_PLATFORMS = {"web", "ufs", "pprb"}
+
+
+class PlanPathPolicy:
+ def __init__(self, doc_type_to_folder: dict[str, str]) -> None:
+ self._doc_type_to_folder = dict(doc_type_to_folder)
+
+ def make_doc_id(self, *, doc_type: str, heading: str, hinted_doc_id: str) -> str:
+ return str(hinted_doc_id or f"{doc_type}.{self._slugify(heading).replace('-', '_')}").strip(".")
+
+ def resolve_path(
+ self,
+ *,
+ doc_type: str,
+ unit_id: str,
+ application: str,
+ platform: str,
+ page_type: str,
+ inferred_path: str,
+ state: DocsState,
+ ) -> str:
+ if unit_id in state.by_doc_id:
+ return state.by_doc_id[unit_id]
+ normalized_inferred = normalize_inferred_path(inferred_path, unit_id)
+ if normalized_inferred:
+ return normalized_inferred
+ page = normalize_path_segment(page_type or page_type_for_doc_type(doc_type, self._doc_type_to_folder))
+ app = normalize_path_segment(application or "unknown_app")
+ plat = platform if platform in _VALID_PLATFORMS else "unknown_platform"
+ return f"docs/{app}/{plat}/{page}/{unit_id}.md"
+
+ def resolve_op(self, *, op_hint: str, unit_id: str, path: str, state: DocsState) -> str:
+ if op_hint == "delete":
+ return "delete"
+ if op_hint == "create":
+ return "create"
+ if op_hint == "update":
+ return "update"
+ if path in state.by_path or unit_id in state.by_doc_id:
+ return "update"
+ return "create"
+
+ def default_page_type(self, doc_type: str) -> str:
+ return page_type_for_doc_type(doc_type, self._doc_type_to_folder)
+
+ def _slugify(self, value: str) -> str:
+ cleaned = re.sub(r"[^a-zA-Z0-9а-яА-Я_-]+", "-", value.lower()).strip("-")
+ return re.sub(r"-+", "-", cleaned) or "doc"
diff --git a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/prompts/prompts.yml b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/prompts/prompts.yml
index 6e170df..964881e 100644
--- a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/prompts/prompts.yml
+++ b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/steps/prompts/prompts.yml
@@ -7,7 +7,16 @@ prompts:
Верни только JSON:
{
"items": [
- {"index": 0, "doc_type": "api_method", "reason": "..."}
+ {
+ "index": 0,
+ "doc_type": "api_method",
+ "id": "ufs.contacts_dgr.api.create",
+ "application": "coverage",
+ "platform": "ufs",
+ "page_type": "api",
+ "path": "docs/coverage/ufs/api/ufs.contacts_dgr.api.create.md",
+ "reason": "..."
+ }
]
}
@@ -15,12 +24,22 @@ prompts:
- Используй только doc_type из allowed_doc_types.
- Не пропускай item, даже если не уверен: выбери наиболее близкий тип.
- Ориентируйся на heading и snippet.
+ - path — это служебное поле плана изменений, не поле frontmatter.
+ - id:
+ - брать из metadata unit, если задан;
+ - если id нет, сгенерировать стабильный id по смыслу unit и по аналогии с существующей документацией.
+ - имя файла всегда формировать строго как .md.
+ - для существующего документа (если это видно из контекста и индекса) путь не менять.
+ - для нового документа путь формировать строго как docs////.md.
+ - platform использовать только из допустимых значений: web, ufs, pprb.
+ - page_type выбирать по doc_type (например ui_page -> ui, api_method -> api, logic_block -> logic).
+ - последний сегмент path обязан совпадать с .md.
- Никакого markdown и текста вне JSON.
build_doc_changeset: |
Ты формируешь один item changeset для документации на основе системной аналитики и правил doc_rules.
- Верни только JSON-объект формата:
+ Верни только один JSON-объект (RFC8259) формата:
{
"op": "create|update|delete",
"path": "docs/...",
@@ -28,9 +47,37 @@ prompts:
"proposed_content": "полный markdown документа для create/update"
}
+ Схема и ограничения:
+ - Обязательные поля всегда: op, path, reason.
+ - Для op=create/update поле proposed_content обязательно и содержит полный markdown документа:
+ 1) frontmatter между --- и ---,
+ 2) затем body согласно doc_rules.
+ - Для op=delete поле proposed_content запрещено.
+ - В JSON используй двойные кавычки, без trailing commas.
+ - Никаких code fences (```), комментариев и текста до/после JSON.
+
Правила:
- Строго соблюдай структуру и ограничения из doc_rules_context.
- Для create/update верни полный итоговый markdown (frontmatter + body).
- Для update не используй placeholder-тексты; возвращай пригодный к сохранению документ.
- reason обязателен, короткий, по сути изменения.
- Никакого markdown и текста вне JSON.
+
+ repair_doc_changeset_json: |
+ Ты ремонтируешь невалидный ответ модели и должен вернуть строго валидный JSON changeset.
+
+ Вход содержит:
+ - expected_contract: ожидаемые поля и ограничения.
+ - raw_llm_output: исходный (возможно невалидный) ответ.
+
+ Задача:
+ - Извлеки максимально полный смысл из raw_llm_output.
+ - Верни ровно один JSON-объект, соответствующий expected_contract.
+ - Если часть данных отсутствует, используй безопасные значения по умолчанию:
+ - reason: "generated by repair"
+ - proposed_content: только если op=create/update, иначе не добавляй.
+
+ Ограничения вывода:
+ - Только JSON-объект, без markdown/code fences/комментариев.
+ - Двойные кавычки, без trailing commas.
+ - Внутри строк (особенно proposed_content) все переносы строк должны быть экранированы как \\n, не literal newline.
diff --git a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/workflow_runtime/buffered_graph.py b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/workflow_runtime/buffered_graph.py
index 2f7a532..7a249d1 100644
--- a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/workflow_runtime/buffered_graph.py
+++ b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/workflow_runtime/buffered_graph.py
@@ -64,6 +64,8 @@ class DocUpdateFromFeatureWorkflowGraph(WorkflowGraph[TContext]):
"project_root": str(getattr(context, "project_root", "") or ""),
"feature_content_len": len(str(getattr(context, "feature_content", "") or "")),
"analysis_id": str(getattr(analytics, "analysis_id", "") or ""),
+ "application": str(getattr(analytics, "application", "") or ""),
+ "platform": str(getattr(analytics, "platform", "") or ""),
"domains": list(getattr(analytics, "domains", []) or []),
"subdomains": list(getattr(analytics, "subdomains", []) or []),
"units_count": len(units),
diff --git a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/workflow_runtime/models.py b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/workflow_runtime/models.py
index f81a1b6..0602a74 100644
--- a/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/workflow_runtime/models.py
+++ b/src/app/core/agent/processes/v2/workflows/doc_update_from_feature/workflow_runtime/models.py
@@ -6,6 +6,8 @@ from dataclasses import dataclass, field
@dataclass(slots=True)
class AnalyticsMeta:
analysis_id: str = ""
+ application: str = ""
+ platform: str = ""
domains: list[str] = field(default_factory=list)
subdomains: list[str] = field(default_factory=list)
diff --git a/src/app/core/agent/runtime/agent_runtime.py b/src/app/core/agent/runtime/agent_runtime.py
index 00f2ba7..1142632 100644
--- a/src/app/core/agent/runtime/agent_runtime.py
+++ b/src/app/core/agent/runtime/agent_runtime.py
@@ -1,5 +1,6 @@
from __future__ import annotations
+import logging
from datetime import datetime, timezone
from app.core.api.application.session_service import SessionService
@@ -16,6 +17,8 @@ from app.infra.observability.request_trace_logger import RequestTraceLogger
from app.schemas.common import ErrorPayload, ModuleName
from app.schemas.orchestration import RequestExecutionStatus
+LOGGER = logging.getLogger(__name__)
+
class AgentRuntime:
def __init__(
@@ -35,6 +38,12 @@ class AgentRuntime:
self._trace_logger = trace_logger
async def run(self, request: AgentRequest, session: AgentSession) -> None:
+ LOGGER.warning(
+ "runtime run started: request_id=%s process_version=%s active_rag_session_id=%s",
+ request.request_id,
+ request.process_version,
+ session.active_rag_session_id,
+ )
try:
process = self._resolve_process(request.process_version)
self._start_request(request, session)
@@ -51,7 +60,19 @@ class AgentRuntime:
request.apply_changeset = bool(result.apply_changeset)
await self._publish_result(request)
self._complete_request(request, session)
+ LOGGER.warning(
+ "runtime run completed: request_id=%s status=%s changeset_items=%s apply_changeset=%s",
+ request.request_id,
+ request.status,
+ len(request.changeset),
+ request.apply_changeset,
+ )
except Exception as exc:
+ LOGGER.exception(
+ "runtime run failed: request_id=%s process_version=%s",
+ request.request_id,
+ request.process_version,
+ )
await self._fail_request(request, exc)
def _resolve_process(self, version: str):
@@ -66,8 +87,8 @@ class AgentRuntime:
self._trace_logger.start_request(request, session)
async def _announce_start(self, request_id: str, process_version: str) -> None:
- await self._publisher.publish_status(request_id, "runtime", "Запрос принят и поставлен в обработку.")
- await self._publisher.publish_status(
+ await self._safe_publish_status(request_id, "runtime", "Запрос принят и поставлен в обработку.")
+ await self._safe_publish_status(
request_id,
"runtime",
f"Запускаю процесс {process_version}.",
@@ -75,8 +96,11 @@ class AgentRuntime:
)
async def _publish_result(self, request: AgentRequest) -> None:
- await self._publisher.publish_user(request.request_id, "agent", request.answer or "")
- await self._publisher.publish_status(request.request_id, "runtime", "Обработка запроса завершена.")
+ try:
+ await self._publisher.publish_user(request.request_id, "agent", request.answer or "")
+ except Exception:
+ LOGGER.exception("failed to publish user event: request_id=%s", request.request_id)
+ await self._safe_publish_status(request.request_id, "runtime", "Обработка запроса завершена.")
def _complete_request(self, request: AgentRequest, session: AgentSession) -> None:
session.append_turn(user_message=request.message, assistant_message=request.answer or "")
@@ -92,7 +116,7 @@ class AgentRuntime:
request.error = self._build_error_payload(exc)
self._request_store.save(request)
self._trace_logger.fail_request(request)
- await self._publisher.publish_status(
+ await self._safe_publish_status(
request.request_id,
"runtime",
"Во время обработки запроса произошла ошибка.",
@@ -107,3 +131,14 @@ class AgentRuntime:
desc="Agent request failed unexpectedly.",
module=ModuleName.AGENT,
)
+
+ async def _safe_publish_status(self, request_id: str, source: str, text: str, payload: dict | None = None) -> None:
+ try:
+ await self._publisher.publish_status(request_id, source, text, payload)
+ except Exception:
+ LOGGER.exception(
+ "failed to publish status event: request_id=%s source=%s text=%s",
+ request_id,
+ source,
+ text,
+ )
diff --git a/src/app/core/agent/runtime/publisher.py b/src/app/core/agent/runtime/publisher.py
index c3d86b1..98ca8fa 100644
--- a/src/app/core/agent/runtime/publisher.py
+++ b/src/app/core/agent/runtime/publisher.py
@@ -1,10 +1,14 @@
from __future__ import annotations
+import logging
+
from app.core.api.domain.events.client_event import ClientEventRecord
from app.core.api.infrastructure.streaming.sse_event_channel import SseEventChannel
from app.infra.observability.request_trace_logger import RequestTraceLogger
from app.schemas.client_events import ClientEventType
+LOGGER = logging.getLogger(__name__)
+
class RuntimeEventPublisher:
def __init__(self, channel: SseEventChannel, trace_logger: RequestTraceLogger) -> None:
@@ -12,9 +16,23 @@ class RuntimeEventPublisher:
self._trace_logger = trace_logger
async def publish_status(self, request_id: str, source: str, text: str, payload: dict | None = None) -> None:
+ LOGGER.warning(
+ "publish status: request_id=%s source=%s text=%s payload_keys=%s",
+ request_id,
+ source,
+ text,
+ sorted(list((payload or {}).keys())),
+ )
await self._publish(request_id, ClientEventType.STATUS, source, text, payload)
async def publish_user(self, request_id: str, source: str, text: str, payload: dict | None = None) -> None:
+ LOGGER.warning(
+ "publish user: request_id=%s source=%s text_len=%s payload_keys=%s",
+ request_id,
+ source,
+ len(text or ""),
+ sorted(list((payload or {}).keys())),
+ )
await self._publish(request_id, ClientEventType.USER, source, text, payload)
async def _publish(
diff --git a/src/app/core/api/application/request_service.py b/src/app/core/api/application/request_service.py
index 8df37c7..c4a9fc8 100644
--- a/src/app/core/api/application/request_service.py
+++ b/src/app/core/api/application/request_service.py
@@ -1,6 +1,7 @@
from __future__ import annotations
import asyncio
+import logging
from app.core.api.domain.models.agent_request import AgentRequest
from app.core.api.infrastructure.ids.request_id_factory import RequestIdFactory
@@ -8,6 +9,8 @@ from app.core.api.infrastructure.stores.in_memory_request_store import InMemoryR
from app.core.api.application.session_service import SessionService
from app.core.agent.runtime import AgentRuntime
+LOGGER = logging.getLogger(__name__)
+
class RequestService:
def __init__(
@@ -31,8 +34,28 @@ class RequestService:
process_version=process_version,
)
self._request_store.save(request)
- asyncio.create_task(self._runtime.run(request, session))
+ LOGGER.warning(
+ "plugin request accepted: request_id=%s session_id=%s process_version=%s message=%s",
+ request.request_id,
+ session_id,
+ process_version,
+ (message or "").replace("\n", "\\n")[:500],
+ )
+ task = asyncio.create_task(self._runtime.run(request, session), name=f"agent-runtime:{request.request_id}")
+ task.add_done_callback(self._log_task_result)
return request
def get(self, request_id: str) -> AgentRequest | None:
return self._request_store.get(request_id)
+
+ def _log_task_result(self, task: asyncio.Task) -> None:
+ try:
+ exc = task.exception()
+ except asyncio.CancelledError:
+ LOGGER.warning("agent runtime task cancelled: task=%s", task.get_name())
+ return
+ except Exception:
+ LOGGER.exception("failed to inspect agent runtime task result: task=%s", task.get_name())
+ return
+ if exc is not None:
+ LOGGER.exception("agent runtime task crashed: task=%s", task.get_name(), exc_info=exc)
diff --git a/src/app/core/api/controllers/rag_public_controller.py b/src/app/core/api/controllers/rag_public_controller.py
index c1b9881..a2aa7f1 100644
--- a/src/app/core/api/controllers/rag_public_controller.py
+++ b/src/app/core/api/controllers/rag_public_controller.py
@@ -1,10 +1,14 @@
from __future__ import annotations
+import logging
+
from app.core.api.infrastructure.streaming.sse_response_builder import build_sse_response
from app.core.rag.module import RagModule
from app.core.shared.messaging import EventBus
from app.schemas.rag_sessions import RagSessionJobResponse
+LOGGER = logging.getLogger(__name__)
+
class RagPublicController:
def __init__(self, rag: RagModule) -> None:
@@ -12,6 +16,14 @@ class RagPublicController:
def get_job(self, rag_session_id: str, index_job_id: str) -> RagSessionJobResponse:
job = self._rag.get_session_job(rag_session_id, index_job_id)
+ LOGGER.warning(
+ "rag job polled: rag_session_id=%s job_id=%s status=%s indexed=%s failed=%s",
+ rag_session_id,
+ index_job_id,
+ job.status.value if hasattr(job.status, "value") else str(job.status),
+ job.indexed_files,
+ job.failed_files,
+ )
return RagSessionJobResponse(
rag_session_id=rag_session_id,
index_job_id=job.index_job_id,
@@ -25,6 +37,7 @@ class RagPublicController:
async def stream_job_events(self, rag_session_id: str, index_job_id: str):
channel_id, queue = await self._rag.subscribe_session_job_events(rag_session_id, index_job_id)
+ LOGGER.warning("rag job events subscribed: rag_session_id=%s job_id=%s", rag_session_id, index_job_id)
return build_sse_response(
queue,
encoder=EventBus.as_sse,
diff --git a/src/app/core/rag/embedding/gigachat_embedder.py b/src/app/core/rag/embedding/gigachat_embedder.py
index 48eec36..f31c479 100644
--- a/src/app/core/rag/embedding/gigachat_embedder.py
+++ b/src/app/core/rag/embedding/gigachat_embedder.py
@@ -7,5 +7,11 @@ class GigaChatEmbedder:
def __init__(self, client: GigaChatClient) -> None:
self._client = client
- def embed(self, texts: list[str]) -> list[list[float]]:
- return self._client.embed(texts)
+ def embed(
+ self,
+ texts: list[str],
+ *,
+ timeout_sec: int | None = None,
+ max_retries: int | None = None,
+ ) -> list[list[float]]:
+ return self._client.embed(texts, timeout_sec=timeout_sec, max_retries=max_retries)
diff --git a/src/app/core/rag/indexing/docs/document_builder.py b/src/app/core/rag/indexing/docs/document_builder.py
index 3884421..79c61f8 100644
--- a/src/app/core/rag/indexing/docs/document_builder.py
+++ b/src/app/core/rag/indexing/docs/document_builder.py
@@ -2,46 +2,33 @@ from __future__ import annotations
from app.core.rag.contracts import EvidenceLink, EvidenceType, RagDocument, RagLayer, RagSource
from app.core.rag.indexing.docs.chunkers.markdown_chunker import SectionChunk
+from app.core.rag.indexing.docs.frontmatter_metadata import merge_frontmatter_metadata
from app.core.rag.indexing.docs.frontmatter_view import DocsFrontmatterView
class DocsDocumentBuilder:
def build_document_catalog(self, source: RagSource, frontmatter: dict, summary_text: str, doc_kind: str, *, fallback_title: str) -> RagDocument:
view = DocsFrontmatterView(frontmatter)
- document_id = view.document_id or source.path
- metadata = {
- "document_id": document_id,
- "type": view.doc_type,
- "name": view.name,
- "title": view.title(fallback_title),
- "module": view.module,
- "domain": view.domain,
- "subdomain": view.subdomain,
- "layer": view.layer,
- "status": view.status,
- "updated_at": view.updated_at,
- "tags": view.tags,
- "entities": view.entities,
- "parent": view.parent,
- "children": view.children,
- "links": view.links,
- "source_path": source.path,
- "summary_text": summary_text[:4000],
- "doc_kind": doc_kind,
- "artifact_type": "DOCS",
- }
+ metadata = merge_frontmatter_metadata({}, frontmatter)
+ if view.document_id:
+ metadata["document_id"] = view.document_id
+ metadata["source_path"] = source.path
+ metadata["summary_text"] = summary_text[:4000]
+ metadata["doc_kind"] = doc_kind
+ row_title = str(frontmatter.get("title") or "").strip() or fallback_title or source.path
return RagDocument(
layer=RagLayer.DOCS_DOCUMENT_CATALOG,
source=source,
- title=metadata["title"] or document_id,
- text=summary_text[:4000] or metadata["title"] or document_id,
+ title=row_title,
+ text=summary_text[:4000] or row_title,
metadata=metadata,
)
def build_doc_chunk(self, source: RagSource, chunk: SectionChunk, frontmatter: dict, doc_kind: str) -> RagDocument:
view = DocsFrontmatterView(frontmatter)
document_id = view.document_id or source.path
- metadata = {
+ metadata = merge_frontmatter_metadata(
+ {
"document_id": document_id,
"type": view.doc_type,
"module": view.module,
@@ -54,7 +41,9 @@ class DocsDocumentBuilder:
"doc_kind": doc_kind,
"source_path": source.path,
"artifact_type": "DOCS",
- }
+ },
+ frontmatter,
+ )
return RagDocument(
layer=RagLayer.DOCS_DOC_CHUNKS,
source=source,
@@ -67,7 +56,8 @@ class DocsDocumentBuilder:
def build_entity_record(self, source: RagSource, frontmatter: dict, entity: str) -> RagDocument:
view = DocsFrontmatterView(frontmatter)
document_id = view.document_id or source.path
- metadata = {
+ metadata = merge_frontmatter_metadata(
+ {
"entity_name": entity,
"document_id": document_id,
"document_type": view.doc_type,
@@ -77,7 +67,9 @@ class DocsDocumentBuilder:
"tags": view.tags,
"source_path": source.path,
"artifact_type": "DOCS",
- }
+ },
+ frontmatter,
+ )
return RagDocument(
layer=RagLayer.DOCS_ENTITY_CATALOG,
source=source,
diff --git a/src/app/core/rag/indexing/docs/frontmatter_metadata.py b/src/app/core/rag/indexing/docs/frontmatter_metadata.py
new file mode 100644
index 0000000..e62af4b
--- /dev/null
+++ b/src/app/core/rag/indexing/docs/frontmatter_metadata.py
@@ -0,0 +1,13 @@
+from __future__ import annotations
+
+
+def merge_frontmatter_metadata(base: dict[str, object], frontmatter: dict) -> dict[str, object]:
+ merged = dict(base)
+ if not isinstance(frontmatter, dict):
+ return merged
+ for raw_key, value in frontmatter.items():
+ key = str(raw_key or "").strip()
+ if not key or key == "__frontmatter_parse_error__" or key in merged:
+ continue
+ merged[key] = value
+ return merged
diff --git a/src/app/core/rag/indexing/job_store.py b/src/app/core/rag/indexing/job_store.py
index 61480e4..8aeeaff 100644
--- a/src/app/core/rag/indexing/job_store.py
+++ b/src/app/core/rag/indexing/job_store.py
@@ -1,12 +1,17 @@
"""Хранилище задач индексации RAG (in-memory + persistence)."""
from dataclasses import dataclass
+from datetime import UTC, datetime
+import logging
+import os
from uuid import uuid4
from app.core.rag.persistence.repository import RagRepository
from app.schemas.common import ErrorPayload, ModuleName
from app.schemas.indexing import IndexJobStatus
+LOGGER = logging.getLogger(__name__)
+
@dataclass
class IndexJob:
@@ -46,7 +51,7 @@ class IndexJobStore:
desc=row.error_desc or "",
module=module,
)
- return IndexJob(
+ job = IndexJob(
index_job_id=row.index_job_id,
rag_session_id=row.rag_session_id,
status=IndexJobStatus(row.status),
@@ -56,6 +61,25 @@ class IndexJobStore:
cache_miss_files=row.cache_miss_files,
error=payload,
)
+ stale_timeout_sec = max(1, int(os.getenv("RAG_RUNNING_STALE_TIMEOUT_SEC", "8")))
+ if job.status == IndexJobStatus.RUNNING and self._is_stale(row.updated_at, stale_timeout_sec):
+ payload = ErrorPayload(
+ code="index_stalled",
+ desc="Indexing stalled in running state; likely blocked network call during embedding/auth.",
+ module=ModuleName.RAG,
+ )
+ job.status = IndexJobStatus.ERROR
+ job.error = payload
+ self.save(job)
+ LOGGER.error("rag index job marked stale->error: job_id=%s timeout_sec=%s", job.index_job_id, stale_timeout_sec)
+ return job
+
+ def _is_stale(self, updated_at: datetime | None, stale_timeout_sec: int) -> bool:
+ if updated_at is None:
+ return False
+ ts = updated_at if updated_at.tzinfo else updated_at.replace(tzinfo=UTC)
+ age = (datetime.now(UTC) - ts).total_seconds()
+ return age >= stale_timeout_sec
def save(self, job: IndexJob) -> None:
error_code = job.error.code if job.error else None
diff --git a/src/app/core/rag/indexing/orchestrator.py b/src/app/core/rag/indexing/orchestrator.py
index 85bdf73..28f0744 100644
--- a/src/app/core/rag/indexing/orchestrator.py
+++ b/src/app/core/rag/indexing/orchestrator.py
@@ -1,6 +1,8 @@
"""Оркестрация индексации RAG (очередь задач, события)."""
import asyncio
+import logging
+import os
from collections import defaultdict
from app.schemas.common import ErrorPayload, ModuleName
@@ -15,6 +17,8 @@ from app.core.rag.indexing.job_store import IndexJob, IndexJobStore
from app.core.shared.messaging import EventBus
from app.core.shared.resilience import RetryExecutor
+LOGGER = logging.getLogger(__name__)
+
class IndexingOrchestrator:
def __init__(
@@ -32,11 +36,23 @@ class IndexingOrchestrator:
async def enqueue_snapshot(self, rag_session_id: str, files: list[dict]) -> IndexJob:
job = self._store.create(rag_session_id)
+ LOGGER.warning(
+ "rag index snapshot queued: job_id=%s rag_session_id=%s files=%s",
+ job.index_job_id,
+ rag_session_id,
+ len(files),
+ )
asyncio.create_task(self._process_snapshot(job.index_job_id, rag_session_id, files))
return job
async def enqueue_changes(self, rag_session_id: str, changed_files: list[dict]) -> IndexJob:
job = self._store.create(rag_session_id)
+ LOGGER.warning(
+ "rag index changes queued: job_id=%s rag_session_id=%s changes=%s",
+ job.index_job_id,
+ rag_session_id,
+ len(changed_files),
+ )
asyncio.create_task(self._process_changes(job.index_job_id, rag_session_id, changed_files))
return job
@@ -71,9 +87,16 @@ class IndexingOrchestrator:
async with lock:
job = self._store.get(job_id)
if not job:
+ LOGGER.warning("rag index job missing in store before start: job_id=%s", job_id)
return
job.status = IndexJobStatus.RUNNING
self._store.save(job)
+ LOGGER.warning(
+ "rag index job running: job_id=%s rag_session_id=%s total_files=%s",
+ job_id,
+ rag_session_id,
+ total_files,
+ )
await self._events.publish(
job_id,
"index_status",
@@ -94,13 +117,25 @@ class IndexingOrchestrator:
},
)
- indexed, failed, cache_hits, cache_misses = await self._retry.run(lambda: operation(progress_cb))
+ timeout_sec = max(1, int(os.getenv("RAG_INDEX_JOB_TIMEOUT_SEC", "15")))
+ indexed, failed, cache_hits, cache_misses = await asyncio.wait_for(
+ operation(progress_cb),
+ timeout=timeout_sec,
+ )
job.status = IndexJobStatus.DONE
job.indexed_files = indexed
job.failed_files = failed
job.cache_hit_files = cache_hits
job.cache_miss_files = cache_misses
self._store.save(job)
+ LOGGER.warning(
+ "rag index job done: job_id=%s indexed=%s failed=%s cache_hits=%s cache_misses=%s",
+ job_id,
+ indexed,
+ failed,
+ cache_hits,
+ cache_misses,
+ )
await self._events.publish(
job_id,
"index_status",
@@ -129,12 +164,72 @@ class IndexingOrchestrator:
)
except (TimeoutError, ConnectionError, OSError) as exc:
job.status = IndexJobStatus.ERROR
+ job.failed_files = max(1, job.failed_files)
job.error = ErrorPayload(
- code="index_retry_exhausted",
- desc=f"Temporary indexing failure after retries: {exc}",
+ code="index_runtime_error",
+ desc=f"Indexing failed: {exc}",
module=ModuleName.RAG,
)
self._store.save(job)
+ LOGGER.exception("rag index job runtime-error: job_id=%s", job_id)
+ await self._events.publish(
+ job_id,
+ "index_status",
+ {"index_job_id": job_id, "status": job.status.value, "total_files": total_files},
+ )
+ await self._events.publish(
+ job_id,
+ "terminal",
+ {
+ "index_job_id": job_id,
+ "status": "error",
+ "total_files": total_files,
+ "error": {
+ "code": job.error.code,
+ "desc": job.error.desc,
+ "module": job.error.module.value,
+ },
+ },
+ )
+ except asyncio.TimeoutError as exc:
+ job.status = IndexJobStatus.ERROR
+ job.failed_files = max(1, job.failed_files)
+ job.error = ErrorPayload(
+ code="index_timeout",
+ desc=f"Indexing timed out while processing snapshot/changes: {exc}",
+ module=ModuleName.RAG,
+ )
+ self._store.save(job)
+ LOGGER.exception("rag index job timed out: job_id=%s", job_id)
+ await self._events.publish(
+ job_id,
+ "index_status",
+ {"index_job_id": job_id, "status": job.status.value, "total_files": total_files},
+ )
+ await self._events.publish(
+ job_id,
+ "terminal",
+ {
+ "index_job_id": job_id,
+ "status": "error",
+ "total_files": total_files,
+ "error": {
+ "code": job.error.code,
+ "desc": job.error.desc,
+ "module": job.error.module.value,
+ },
+ },
+ )
+ except Exception as exc:
+ job.status = IndexJobStatus.ERROR
+ job.failed_files = max(1, job.failed_files)
+ job.error = ErrorPayload(
+ code="index_unexpected_error",
+ desc=f"Unexpected indexing failure: {exc}",
+ module=ModuleName.RAG,
+ )
+ self._store.save(job)
+ LOGGER.exception("rag index job failed unexpectedly: job_id=%s", job_id)
await self._events.publish(
job_id,
"index_status",
diff --git a/src/app/core/rag/indexing/service.py b/src/app/core/rag/indexing/service.py
index e909be3..70a2513 100644
--- a/src/app/core/rag/indexing/service.py
+++ b/src/app/core/rag/indexing/service.py
@@ -32,6 +32,7 @@ class RagService:
self._repo = repository
self._docs = DocsIndexingPipeline()
self._code = CodeIndexingPipeline()
+ self._cache_enabled = os.getenv("RAG_DOCUMENT_CACHE_ENABLED", "false").strip().lower() in {"1", "true", "yes", "on"}
async def index_snapshot(
self,
@@ -39,8 +40,16 @@ class RagService:
files: list[dict],
progress_cb: Callable[[int, int, str], Awaitable[None] | None] | None = None,
) -> tuple[int, int, int, int]:
+ LOGGER.warning("rag index snapshot started: rag_session_id=%s files=%s", rag_session_id, len(files))
report = await self._index_files(rag_session_id, files, progress_cb=progress_cb)
self._repo.replace_documents(rag_session_id, report.documents_list)
+ LOGGER.warning(
+ "rag index snapshot persisted: rag_session_id=%s indexed=%s failed=%s docs=%s",
+ rag_session_id,
+ report.indexed_files,
+ report.failed_files,
+ len(report.documents_list),
+ )
return report.as_tuple()
async def index_changes(
@@ -49,6 +58,7 @@ class RagService:
changed_files: list[dict],
progress_cb: Callable[[int, int, str], Awaitable[None] | None] | None = None,
) -> tuple[int, int, int, int]:
+ LOGGER.warning("rag index changes started: rag_session_id=%s changes=%s", rag_session_id, len(changed_files))
delete_paths: list[str] = []
upserts: list[dict] = []
for item in changed_files:
@@ -58,6 +68,14 @@ class RagService:
upserts.append(item)
report = await self._index_files(rag_session_id, upserts, progress_cb=progress_cb)
self._repo.apply_document_changes(rag_session_id, delete_paths, report.documents_list)
+ LOGGER.warning(
+ "rag index changes persisted: rag_session_id=%s indexed=%s failed=%s docs=%s delete_paths=%s",
+ rag_session_id,
+ report.indexed_files,
+ report.failed_files,
+ len(report.documents_list),
+ len(delete_paths),
+ )
return report.as_tuple()
async def _index_files(
@@ -80,9 +98,18 @@ class RagService:
for index, file in enumerate(indexable_files, start=1):
path = str(file.get("path", ""))
try:
+ LOGGER.warning(
+ "rag index file started: rag_session_id=%s file=%s/%s path=%s",
+ rag_session_id,
+ index,
+ total_files,
+ path,
+ )
blob_sha = self._blob_sha(file)
- cached = await asyncio.to_thread(self._repo.get_cached_documents, repo_id, blob_sha)
pipelines = self._resolve_pipeline_names(path)
+ cached = []
+ if self._cache_enabled:
+ cached = await asyncio.to_thread(self._repo.get_cached_documents, repo_id, blob_sha)
if cached:
self._report_missing_or_partial_docs(path, cached)
report.documents_list.extend(self._with_file_metadata(cached, file, repo_id, blob_sha))
@@ -95,10 +122,33 @@ class RagService:
)
else:
built = self._build_documents(repo_id, path, file)
+ LOGGER.warning(
+ "rag index file built docs: rag_session_id=%s path=%s docs=%s",
+ rag_session_id,
+ path,
+ len(built),
+ )
self._report_missing_or_partial_docs(path, built)
- embedded = await asyncio.to_thread(self._embed_documents, built, file, repo_id, blob_sha)
+ embed_timeout_sec = max(1, int(os.getenv("RAG_EMBED_FILE_TIMEOUT_SEC", "8")))
+ LOGGER.warning(
+ "rag index file embedding started: rag_session_id=%s path=%s timeout_sec=%s",
+ rag_session_id,
+ path,
+ embed_timeout_sec,
+ )
+ embedded = await asyncio.wait_for(
+ asyncio.to_thread(self._embed_documents, built, file, repo_id, blob_sha),
+ timeout=embed_timeout_sec,
+ )
+ LOGGER.warning(
+ "rag index file embedded docs: rag_session_id=%s path=%s docs=%s",
+ rag_session_id,
+ path,
+ len(embedded),
+ )
report.documents_list.extend(embedded)
- await asyncio.to_thread(self._repo.cache_documents, repo_id, path, blob_sha, embedded)
+ if self._cache_enabled:
+ await asyncio.to_thread(self._repo.cache_documents, repo_id, path, blob_sha, embedded)
report.cache_miss_files += 1
LOGGER.warning(
"rag ingest file: rag_session_id=%s path=%s processing=embed pipeline=%s",
@@ -107,6 +157,13 @@ class RagService:
",".join(pipelines),
)
report.indexed_files += 1
+ LOGGER.warning(
+ "rag index file completed: rag_session_id=%s file=%s/%s path=%s",
+ rag_session_id,
+ index,
+ total_files,
+ path,
+ )
except Exception as exc:
report.failed_files += 1
report.warnings.append(f"{path}: {exc}")
@@ -116,6 +173,8 @@ class RagService:
path,
exc,
)
+ # Fail-fast: stop indexing immediately so caller can expose the exact error to plugin.
+ raise RuntimeError(f"RAG indexing failed for '{path}': {exc}") from exc
await self._notify_progress(progress_cb, index, total_files, path)
report.documents = len(report.documents_list)
return report
@@ -156,12 +215,32 @@ class RagService:
if not docs:
return []
batch_size = max(1, int(os.getenv("RAG_EMBED_BATCH_SIZE", "16")))
+ request_timeout_sec = max(1, int(os.getenv("RAG_EMBED_REQUEST_TIMEOUT_SEC", "5")))
+ request_retries = max(1, int(os.getenv("RAG_EMBED_REQUEST_MAX_RETRIES", "1")))
metadata = self._document_metadata(file, repo_id, blob_sha)
for doc in docs:
doc.metadata.update(metadata)
for start in range(0, len(docs), batch_size):
batch = docs[start : start + batch_size]
- vectors = self._embedder.embed([doc.text for doc in batch])
+ LOGGER.warning(
+ "rag embed batch start: path=%s batch_start=%s batch_size=%s timeout_sec=%s retries=%s",
+ file.get("path", ""),
+ start,
+ len(batch),
+ request_timeout_sec,
+ request_retries,
+ )
+ vectors = self._embedder.embed(
+ [doc.text for doc in batch],
+ timeout_sec=request_timeout_sec,
+ max_retries=request_retries,
+ )
+ LOGGER.warning(
+ "rag embed batch done: path=%s batch_start=%s vectors=%s",
+ file.get("path", ""),
+ start,
+ len(vectors),
+ )
for doc, vector in zip(batch, vectors):
doc.embedding = vector
return docs
diff --git a/src/app/core/rag/persistence/job_repository.py b/src/app/core/rag/persistence/job_repository.py
index ad20ceb..6dd59d1 100644
--- a/src/app/core/rag/persistence/job_repository.py
+++ b/src/app/core/rag/persistence/job_repository.py
@@ -1,6 +1,7 @@
from __future__ import annotations
from dataclasses import dataclass
+from datetime import datetime
from sqlalchemy import text
@@ -19,6 +20,7 @@ class RagJobRow:
error_code: str | None
error_desc: str | None
error_module: str | None
+ updated_at: datetime | None
class RagJobRepository:
@@ -85,7 +87,7 @@ class RagJobRepository:
text(
"""
SELECT index_job_id, rag_session_id, status, indexed_files, failed_files,
- cache_hit_files, cache_miss_files, error_code, error_desc, error_module
+ cache_hit_files, cache_miss_files, error_code, error_desc, error_module, updated_at
FROM rag_index_jobs
WHERE index_job_id = :jid
"""
diff --git a/src/app/core/shared/gigachat/client.py b/src/app/core/shared/gigachat/client.py
index 0127295..f3ea41e 100644
--- a/src/app/core/shared/gigachat/client.py
+++ b/src/app/core/shared/gigachat/client.py
@@ -1,4 +1,5 @@
import time
+import logging
import requests
@@ -6,6 +7,9 @@ from app.infra.constants import MAX_RETRIES
from app.core.shared.gigachat.errors import GigaChatError
from app.core.shared.gigachat.settings import GigaChatSettings
from app.core.shared.gigachat.token_provider import GigaChatTokenProvider
+from app.core.shared.network.hard_timeout import run_with_hard_timeout
+
+LOGGER = logging.getLogger(__name__)
class GigaChatClient:
@@ -30,13 +34,26 @@ class GigaChatClient:
message = choices[0].get("message") or {}
return str(message.get("content") or "")
- def embed(self, texts: list[str]) -> list[list[float]]:
+ def embed(
+ self,
+ texts: list[str],
+ *,
+ timeout_sec: int | None = None,
+ max_retries: int | None = None,
+ ) -> list[list[float]]:
token = self._tokens.get_access_token()
payload = {
"model": self._settings.embedding_model,
"input": texts,
}
- response = self._post_with_retry("/embeddings", payload, token=token, timeout=90, operation_name="embeddings")
+ response = self._post_with_retry(
+ "/embeddings",
+ payload,
+ token=token,
+ timeout=timeout_sec or 90,
+ operation_name="embeddings",
+ max_retries=max_retries,
+ )
data = response.json()
items = data.get("data")
if not isinstance(items, list):
@@ -51,21 +68,50 @@ class GigaChatClient:
token: str,
timeout: int,
operation_name: str,
+ max_retries: int | None = None,
):
last_error: Exception | None = None
- for attempt in range(1, MAX_RETRIES + 1):
+ retries = max(1, int(max_retries or MAX_RETRIES))
+ for attempt in range(1, retries + 1):
try:
- response = requests.post(
- f"{self._settings.api_url.rstrip('/')}{path}",
- json=payload,
- headers={
- "Authorization": f"Bearer {token}",
- "Content-Type": "application/json",
- },
- timeout=timeout,
- verify=self._settings.ssl_verify,
+ LOGGER.warning(
+ "gigachat request start: operation=%s path=%s attempt=%s/%s timeout_sec=%s",
+ operation_name,
+ path,
+ attempt,
+ retries,
+ timeout,
+ )
+ response = run_with_hard_timeout(
+ lambda: requests.post(
+ f"{self._settings.api_url.rstrip('/')}{path}",
+ json=payload,
+ headers={
+ "Authorization": f"Bearer {token}",
+ "Content-Type": "application/json",
+ },
+ timeout=timeout,
+ verify=self._settings.ssl_verify,
+ ),
+ timeout_sec=timeout,
+ operation_name=f"gigachat_{operation_name}",
+ )
+ LOGGER.warning(
+ "gigachat request done: operation=%s path=%s attempt=%s/%s status=%s",
+ operation_name,
+ path,
+ attempt,
+ retries,
+ response.status_code,
)
except requests.RequestException as exc:
+ LOGGER.exception(
+ "gigachat request failed: operation=%s path=%s attempt=%s/%s",
+ operation_name,
+ path,
+ attempt,
+ retries,
+ )
last_error = GigaChatError(f"GigaChat {operation_name} request failed: {exc}")
else:
if response.status_code < 400:
@@ -73,7 +119,7 @@ class GigaChatClient:
last_error = GigaChatError(f"GigaChat {operation_name} error {response.status_code}: {response.text}")
if not self._is_retryable_status(response.status_code):
raise last_error
- if attempt == MAX_RETRIES:
+ if attempt == retries:
break
time.sleep(0.1 * attempt)
if last_error is None:
diff --git a/src/app/core/shared/gigachat/token_provider.py b/src/app/core/shared/gigachat/token_provider.py
index 0d8adb6..98df2cf 100644
--- a/src/app/core/shared/gigachat/token_provider.py
+++ b/src/app/core/shared/gigachat/token_provider.py
@@ -1,11 +1,16 @@
import threading
import time
import uuid
+import logging
+import os
import requests
from app.core.shared.gigachat.errors import GigaChatError
from app.core.shared.gigachat.settings import GigaChatSettings
+from app.core.shared.network.hard_timeout import run_with_hard_timeout
+
+LOGGER = logging.getLogger(__name__)
class GigaChatTokenProvider:
@@ -30,6 +35,7 @@ class GigaChatTokenProvider:
def _fetch_token(self) -> tuple[str, float]:
if not self._settings.credentials:
raise GigaChatError("GIGACHAT_TOKEN is not set")
+ timeout_sec = max(1, int(os.getenv("GIGACHAT_AUTH_TIMEOUT_SEC", "5")))
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json",
@@ -37,14 +43,21 @@ class GigaChatTokenProvider:
"RqUID": str(uuid.uuid4()),
}
try:
- response = requests.post(
- self._settings.auth_url,
- headers=headers,
- data=f"scope={self._settings.scope}",
- timeout=30,
- verify=self._settings.ssl_verify,
+ LOGGER.warning("gigachat auth start: url=%s timeout_sec=%s", self._settings.auth_url, timeout_sec)
+ response = run_with_hard_timeout(
+ lambda: requests.post(
+ self._settings.auth_url,
+ headers=headers,
+ data=f"scope={self._settings.scope}",
+ timeout=timeout_sec,
+ verify=self._settings.ssl_verify,
+ ),
+ timeout_sec=timeout_sec,
+ operation_name="gigachat_auth",
)
+ LOGGER.warning("gigachat auth done: status=%s", response.status_code)
except requests.RequestException as exc:
+ LOGGER.exception("gigachat auth failed")
raise GigaChatError(f"GigaChat auth request failed: {exc}") from exc
if response.status_code >= 400:
diff --git a/src/app/core/shared/network/hard_timeout.py b/src/app/core/shared/network/hard_timeout.py
new file mode 100644
index 0000000..e484a50
--- /dev/null
+++ b/src/app/core/shared/network/hard_timeout.py
@@ -0,0 +1,31 @@
+from __future__ import annotations
+
+import queue
+import threading
+from collections.abc import Callable
+from typing import TypeVar
+
+T = TypeVar("T")
+
+
+def run_with_hard_timeout(operation: Callable[[], T], *, timeout_sec: int, operation_name: str) -> T:
+ result_queue: queue.Queue[tuple[bool, object]] = queue.Queue(maxsize=1)
+
+ def _runner() -> None:
+ try:
+ result_queue.put((True, operation()))
+ except BaseException as exc: # noqa: BLE001
+ result_queue.put((False, exc))
+
+ thread = threading.Thread(target=_runner, name=f"hard-timeout:{operation_name}", daemon=True)
+ thread.start()
+ thread.join(timeout=max(1, int(timeout_sec)))
+ if thread.is_alive():
+ raise TimeoutError(f"{operation_name} exceeded hard timeout ({timeout_sec}s)")
+ if result_queue.empty():
+ raise TimeoutError(f"{operation_name} finished without a result")
+ ok, value = result_queue.get_nowait()
+ if ok:
+ return value # type: ignore[return-value]
+ raise value # type: ignore[misc]
+
diff --git a/src/app/main.py b/src/app/main.py
index 3dcb41f..b06529a 100644
--- a/src/app/main.py
+++ b/src/app/main.py
@@ -2,6 +2,7 @@ import logging
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
+from starlette.requests import Request
from app.infra.logging_setup import configure_logging
from app.infra.error_handlers import register_error_handlers
@@ -19,6 +20,7 @@ def create_app() -> FastAPI:
app = FastAPI(title="Agent Backend MVP", version="0.1.0")
modules = ModularApplication()
app.state.modules = modules
+ logger = logging.getLogger("app.http")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
@@ -30,6 +32,22 @@ def create_app() -> FastAPI:
app.include_router(modules.api.public_router())
register_error_handlers(app)
+ @app.middleware("http")
+ async def log_http_requests(request: Request, call_next):
+ logger.warning("http request: method=%s path=%s query=%s", request.method, request.url.path, request.url.query)
+ try:
+ response = await call_next(request)
+ logger.warning(
+ "http response: method=%s path=%s status=%s",
+ request.method,
+ request.url.path,
+ response.status_code,
+ )
+ return response
+ except Exception:
+ logger.exception("http request failed: method=%s path=%s", request.method, request.url.path)
+ raise
+
@app.on_event("startup")
async def startup() -> None:
modules.startup()
diff --git a/tests/unit_tests/agent/test_api_endpoint_collector.py b/tests/unit_tests/agent/test_api_endpoint_collector.py
index 5bb8e44..62f3379 100644
--- a/tests/unit_tests/agent/test_api_endpoint_collector.py
+++ b/tests/unit_tests/agent/test_api_endpoint_collector.py
@@ -51,7 +51,7 @@ def test_collector_ignores_file_paths_from_content() -> None:
assert endpoints == ["GET /health"]
-def test_collector_uses_title_path_fallback_when_endpoint_metadata_missing() -> None:
+def test_collector_ignores_title_when_endpoint_metadata_missing() -> None:
rows = [
{
"metadata": {
@@ -65,4 +65,4 @@ def test_collector_uses_title_path_fallback_when_endpoint_metadata_missing() ->
endpoints = ApiEndpointCollector().collect(rows)
- assert endpoints == ["GET /actions/{action}"]
+ assert endpoints == []
diff --git a/tests/unit_tests/rag/test_docs_indexing_pipeline.py b/tests/unit_tests/rag/test_docs_indexing_pipeline.py
index 288556e..a7b5b1b 100644
--- a/tests/unit_tests/rag/test_docs_indexing_pipeline.py
+++ b/tests/unit_tests/rag/test_docs_indexing_pipeline.py
@@ -20,6 +20,8 @@ sub_domain: invoices
layer: application
status: draft
updated_at: 2026-03-23
+endpoint: POST /billing/invoices
+source_of_truth: analytics
tags: [billing, api]
entities: [Invoice]
parent: billing_api
@@ -125,9 +127,13 @@ Create invoice
catalog_doc = next(doc for doc in docs if doc.layer == RagLayer.DOCS_DOCUMENT_CATALOG)
assert catalog_doc.metadata["document_id"] == "api.billing.create_invoice"
+ assert catalog_doc.metadata["id"] == "api.billing.create_invoice"
assert catalog_doc.metadata["module"] == "billing"
assert catalog_doc.metadata["domain"] == "billing"
- assert catalog_doc.metadata["subdomain"] == "invoices"
+ assert catalog_doc.metadata["sub_domain"] == "invoices"
+ assert "subdomain" not in catalog_doc.metadata
+ assert catalog_doc.metadata["endpoint"] == "POST /billing/invoices"
+ assert catalog_doc.metadata["source_of_truth"] == "analytics"
assert catalog_doc.metadata["summary_text"] == "Creates an invoice in billing."
fact_texts = [doc.text for doc in docs if doc.layer == RagLayer.DOCS_FACT_INDEX]
@@ -335,3 +341,4 @@ Control actions endpoint.
catalog = next(doc for doc in docs if doc.layer == RagLayer.DOCS_DOCUMENT_CATALOG)
assert catalog.metadata["type"] == "api_method"
assert catalog.metadata["title"] == "HTTP API /actions/{action}"
+ assert catalog.metadata["endpoint"] == "GET|POST /actions/{action}"