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` строится в формате `<type-group>.<name>`.\\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- `# <title>`\\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>`, совпадающий со значением `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` строится в формате `<type-group>.<name>`.\\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- `# <title>`\\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>`, совпадающий со значением `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` строится в формате `<type-group>.<name>`.\\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- `# <title>`\\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>`, совпадающий со значением `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` строится в формате `<type-group>.<name>`.\\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- `# <title>`\\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>`, совпадающий со значением `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` строится в формате `<type-group>.<name>`.\\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- `# <title>`\\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>`, совпадающий со значением `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` строится в формате `<type-group>.<name>`.\\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- `# <title>`\\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>`, совпадающий со значением `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` строится в формате `<type-group>.<name>`.\\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- `# <title>`\\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>`, совпадающий со значением `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` строится в формате `<type-group>.<name>`.\\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- `# <title>`\\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>`, совпадающий со значением `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` строится в формате `<type-group>.<name>`.\\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- `# <title>`\\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- имя файла всегда формировать строго как <id>.md.\n- для существующего документа (если это видно из контекста и индекса) путь не менять.\n- для нового документа путь формировать строго как docs/<application>/<platform>/<page_type>/<id>.md.\n- platform использовать только из допустимых значений: web, ufs, pprb.\n- page_type выбирать по doc_type (например ui_page -> ui, api_method -> api, logic_block -> logic).\n- последний сегмент path обязан совпадать с <id>.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>`, совпадающий со значением `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` строится в формате `<type-group>.<name>`.\\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- `# <title>`\\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>`, совпадающий со значением `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` строится в формате `<type-group>.<name>`.\\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- `# <title>`\\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 и по аналогии с существующей документацией. + - имя файла всегда формировать строго как <id>.md. + - для существующего документа (если это видно из контекста и индекса) путь не менять. + - для нового документа путь формировать строго как docs/<application>/<platform>/<page_type>/<id>.md. + - platform использовать только из допустимых значений: web, ufs, pprb. + - page_type выбирать по doc_type (например ui_page -> ui, api_method -> api, logic_block -> logic). + - последний сегмент path обязан совпадать с <id>.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}"