from __future__ import annotations from app.core.agent.intent_router import IntentRouterV2 from app.core.agent.runtime.docs_qa_pipeline import DocsQAPipelineRunner, DocsTaskPlanner from tests.docs_qa_eval.fixture_adapter import InMemoryDocsRetrievalAdapter from tests.unit_tests.rag.intent_router_testkit import repo_context def test_docs_pipeline_uses_synthesizer_for_explain() -> None: rows = [ { "layer": "D2_FACT_INDEX", "path": "docs/components/billing.md", "title": "Billing facts", "content": "Billing обновляет статус заказа после оплаты.", } ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Объясни модуль billing в документации", "docs-session") assert result.router_result.intent == "DOCUMENTATION_EXPLAIN" assert "Billing" in result.answer assert result.openapi_result is None assert result.diagnostics.facts_found == 1 def test_docs_pipeline_uses_openapi_branch() -> None: rows = [ { "layer": "D2_FACT_INDEX", "path": "docs/api/orders-create.md", "title": "POST /orders", "content": "Create order", "metadata": { "endpoint": "/orders", "http_method": "post", "request_schema": {"type": "object", "properties": {"customer_id": {}}}, "response_schema": {"type": "object", "properties": {"order_id": {}}}, }, } ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Сгенерируй openapi spec для создания заказа", "docs-session") assert result.router_result.intent == "OPENAPI_GENERATION" assert result.openapi_result is not None assert result.openapi_result.path == "/orders" assert result.openapi_result.method == "post" assert result.answer_mode != "degraded" assert result.diagnostics.gate_decision != "reject" assert "paths:" in result.answer assert "/orders" in result.answer def test_docs_pipeline_keeps_query_candidates_for_not_found_entity() -> None: runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter([]), repo_context=repo_context()) result = runner.run("Что такое сущность PaymentTransaction?", "docs-session") assert result.answer_mode == "degraded" assert "PaymentTransaction" in result.diagnostics.query_entity_candidates assert result.diagnostics.resolved_entity_candidates == [] assert result.diagnostics.degraded_reason == "not_found_exact_anchor" def test_docs_pipeline_reports_canonical_doc_ids_and_layers() -> None: rows = [ { "layer": "D5_RELATION_GRAPH", "path": "docs/api/health.md", "title": "Health relations", "content": "Health -> runtime health", "metadata": {"doc_id": "api.health_endpoint", "target_doc_id": "domain.runtime_health", "endpoint": "/health"}, }, { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/domain/runtime-health.md", "title": "Runtime health", "content": "Runtime health overview", "metadata": {"doc_id": "domain.runtime_health"}, }, ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Какие документы связаны с endpoint /health?", "docs-session") assert result.diagnostics.doc_ids[:2] == ["api.health_endpoint", "domain.runtime_health"] assert result.diagnostics.planned_layers == ["D5_RELATION_GRAPH", "D1_DOCUMENT_CATALOG", "D0_DOC_CHUNKS"] assert result.diagnostics.executed_layers == ["D5_RELATION_GRAPH", "D1_DOCUMENT_CATALOG", "D0_DOC_CHUNKS"] assert result.diagnostics.non_empty_layers == ["D5_RELATION_GRAPH"] assert result.diagnostics.relation_hits_count == 1 assert result.diagnostics.relation_targets == ["domain.runtime_health"] assert result.diagnostics.answer_mode == "answered" assert result.diagnostics.layer_diagnostics["D5_RELATION_GRAPH"]["hits"] == 1 assert result.diagnostics.gate_decision == "allow" def test_related_docs_uses_relation_graph_as_primary_layer() -> None: runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter([]), repo_context=repo_context()) result = runner.run("Что еще посмотреть по теме billing?", "docs-session") assert result.router_result.query_plan.sub_intent == "RELATED_DOCS_EXPLAIN" assert result.diagnostics.planned_layers[0] == "D5_RELATION_GRAPH" assert result.diagnostics.executed_layers[0] == "D5_RELATION_GRAPH" def test_openapi_partial_contract_returns_partial_mode() -> None: rows = [ { "layer": "D2_FACT_INDEX", "path": "docs/api/orders-create.md", "title": "POST /orders", "content": "Create order", "metadata": { "endpoint": "/orders", "http_method": "post", "request_schema": {"type": "object", "properties": {"customer_id": {}}}, "doc_id": "api.orders_create", }, } ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Сгенерируй openapi для /orders", "docs-session") assert result.answer_mode == "structured_spec_partial" assert result.degraded_reason == "answered_with_gaps" assert result.openapi_result is not None assert result.openapi_result.path == "/orders" assert result.diagnostics.gate_decision == "partial" assert "paths:" in result.answer assert "/orders" in result.answer def test_docs_pipeline_accepts_precomputed_task_plan_without_rerouting() -> None: rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/api/health.md", "title": "GET /health", "content": "/health returns runtime and component statuses.", "metadata": {"document_id": "api.health_endpoint", "type": "api_method", "endpoint": "/health"}, }, { "layer": "D2_FACT_INDEX", "path": "docs/api/health.md", "title": "api.health_endpoint:response", "content": "Returns health summary and component diagnostics.", "metadata": {"subject_id": "api.health_endpoint", "type": "api_method"}, }, ] route_result = IntentRouterV2().route( "Объясни API метод /health", repo_context=repo_context(), ) task_plan = DocsTaskPlanner().plan( "Объясни API метод /health", "docs-session", route_result=route_result, ) class FailingRouter: def route(self, *_args, **_kwargs): raise AssertionError("runner should use the precomputed task plan") runner = DocsQAPipelineRunner(FailingRouter(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run( "Объясни API метод /health", "docs-session", mode="pre_llm_only", task_plan=task_plan, ) assert result.router_result.intent == "DOCUMENTATION_EXPLAIN" assert result.router_result.query_plan.sub_intent == "API_METHOD_EXPLAIN" assert result.diagnostics.selected_primary_documents == ["api.health_endpoint"] assert result.diagnostics.gate_decision == "allow_exact" def test_pre_llm_mode_returns_diagnostic_only_without_answer_generation() -> None: rows = [ { "layer": "D2_FACT_INDEX", "path": "docs/components/runtime-manager.md", "title": "RuntimeManager", "content": "Coordinates runtime orchestration.", "metadata": {"doc_id": "architecture.runtime_manager", "component": "RuntimeManager"}, } ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Какую роль в системе играет RuntimeManager?", "docs-session", mode="pre_llm_only") assert result.mode == "pre_llm_only" assert result.answer == "" assert result.diagnostics.gate_decision == "allow" assert "RuntimeManager" in result.diagnostics.query_entity_candidates assert "RuntimeManager" in result.diagnostics.resolved_entity_candidates def test_pre_llm_mode_detects_path_anchor_candidates() -> None: rows = [ { "layer": "D2_FACT_INDEX", "path": "docs/api/health.md", "title": "GET /health", "content": "Health endpoint", "metadata": {"doc_id": "api.health_endpoint", "endpoint": "/health", "http_method": "get"}, } ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Объясни API метод /health", "docs-session", mode="pre_llm_only") assert "/health" in result.diagnostics.query_anchor_candidates assert "/health" in result.diagnostics.resolved_anchor_candidates assert result.diagnostics.planned_layers == ["D1_DOCUMENT_CATALOG", "D2_FACT_INDEX", "D0_DOC_CHUNKS", "D4_WORKFLOW_INDEX"] assert set(result.diagnostics.executed_layers) == {"D1_DOCUMENT_CATALOG", "D2_FACT_INDEX", "D4_WORKFLOW_INDEX", "D0_DOC_CHUNKS"} def test_pre_llm_openapi_gate_reports_missing_signals() -> None: rows = [ { "layer": "D2_FACT_INDEX", "path": "docs/api/orders.md", "title": "POST /orders", "content": "Create order", "metadata": {"doc_id": "api.orders_create", "endpoint": "/orders", "http_method": "post"}, } ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Сгенерируй openapi для /orders", "docs-session", mode="pre_llm_only") assert result.diagnostics.gate_decision == "partial" assert result.diagnostics.gate_decision_reason == "answered_with_gaps" assert result.answer_mode == "ready_partial" assert result.answer assert "paths:" in result.answer assert "path_found" in result.diagnostics.gate_satisfied_requirements assert "http_method_found" in result.diagnostics.gate_satisfied_requirements assert "contract_fields_found" in result.diagnostics.gate_missing_requirements assert result.diagnostics.evidence_summary["openapi_signals"]["path_found"] is True assert result.diagnostics.openapi_evidence["path_found"] is True assert result.diagnostics.layer_diagnostics["D2_FACT_INDEX"]["hits"] == 1 def test_related_docs_keeps_relation_hits_when_exact_anchor_is_missing() -> None: rows = [ { "layer": "D5_RELATION_GRAPH", "path": "docs/relations/health-links.md", "title": "Health relations", "content": "Runtime health and service overview", "metadata": { "document_id": "api.health_endpoint", "target_document_id": "domain.runtime_health", }, } ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Какие документы связаны с endpoint /health?", "docs-session", mode="pre_llm_only") assert result.router_result.query_plan.sub_intent == "RELATED_DOCS_EXPLAIN" assert result.diagnostics.doc_ids[:2] == ["api.health_endpoint", "domain.runtime_health"] assert result.diagnostics.relation_hits_count == 1 assert result.diagnostics.exact_anchor_match is False assert result.diagnostics.gate_decision == "allow" assert result.diagnostics.gate_decision_reason == "relation_evidence_available" def test_related_docs_exact_path_outranks_neighboring_api_doc() -> None: rows = [ { "layer": "D5_RELATION_GRAPH", "path": "docs/documentation/api/control-actions-endpoint.md", "title": "HTTP API /actions/{action}", "content": "Nearby API relation", "metadata": { "document_id": "api.control_actions_endpoint", "target_document_id": "architecture.telegram_notify_app", }, }, { "layer": "D5_RELATION_GRAPH", "path": "docs/documentation/api/health-endpoint.md", "title": "HTTP API /health", "content": "Health relation", "metadata": { "document_id": "api.health_endpoint", "target_document_id": "domain.runtime_health", "endpoint": "/health", }, }, ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Какие документы связаны с endpoint /health?", "docs-session", mode="pre_llm_only") assert result.diagnostics.anchor_candidates[0] == "api.health_endpoint" assert result.diagnostics.selected_anchor == "api.health_endpoint" assert result.diagnostics.anchor_match_type == "exact_path" assert result.diagnostics.anchor_selection_reason == "metadata.endpoint exact match" assert result.diagnostics.doc_ids[0] == "api.health_endpoint" def test_pre_llm_targeted_chunk_fallback_enriches_api_method_layers() -> None: rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/api/health.md", "title": "GET /health", "content": "Health endpoint", "metadata": {"doc_id": "api.health_endpoint"}, }, { "layer": "D0_DOC_CHUNKS", "path": "docs/api/health.md", "title": "api.health_endpoint:Scenario", "content": "request -> check runtime -> return status", "metadata": {"doc_id": "api.health_endpoint"}, }, ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Объясни API метод /health", "docs-session", mode="pre_llm_only") assert "D0_DOC_CHUNKS" in result.diagnostics.executed_layers assert "D0_DOC_CHUNKS" in result.diagnostics.non_empty_layers assert result.diagnostics.layer_diagnostics["D0_DOC_CHUNKS"]["hits"] == 1 assert result.diagnostics.selected_chunk_ids == ["api.health_endpoint"] def test_openapi_request_fragment_uses_fragment_aware_gate() -> None: rows = [ { "layer": "D2_FACT_INDEX", "path": "docs/api/send.md", "title": "POST /send", "content": "Request payload contains message and chat_id fields.", "metadata": { "document_id": "api.send_message_endpoint", "endpoint": "/send", "http_method": "post", }, } ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Сгенерируй request schema для endpoint /send", "docs-session", mode="pre_llm_only") assert result.router_result.query_plan.sub_intent == "OPENAPI_FRAGMENT_GENERATE" assert result.diagnostics.requested_fragment_type == "request_schema" assert "path" in result.diagnostics.fragment_evidence_found assert "payload_description" in result.diagnostics.fragment_evidence_found assert result.diagnostics.gate_decision in {"allow", "partial"} assert result.diagnostics.gate_decision_reason in {"evidence_sufficient", "fragment_payload_only"} assert result.diagnostics.fragment_missing_requirements == [] assert result.answer_mode in {"ready", "ready_partial"} assert result.answer assert "type: object" in result.answer def test_api_method_explain_prefers_api_method_primary_doc() -> None: rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/domain/runtime-health.md", "title": "Сущность runtime health", "content": "Runtime health describes overall service health.", "metadata": {"document_id": "domain.runtime_health", "type": "domain_entity"}, }, { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/api/health.md", "title": "GET /health", "content": "/health returns runtime and component statuses.", "metadata": {"document_id": "api.health_endpoint", "type": "api_method", "endpoint": "/health"}, }, { "layer": "D5_RELATION_GRAPH", "path": "docs/domain/runtime-health.md", "title": "Runtime health links", "content": "runtime health used by health endpoint", "metadata": {"document_id": "domain.runtime_health", "target_doc_id": "api.health_endpoint"}, }, ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Что делает метод health?", "docs-session", mode="pre_llm_only") assert result.router_result.query_plan.sub_intent == "API_METHOD_EXPLAIN" assert result.diagnostics.target_anchor in {"health", "/health"} assert result.diagnostics.api_method_match_found is True assert result.diagnostics.selected_primary_documents == ["api.health_endpoint"] assert "api.health_endpoint" in result.diagnostics.primary_doc_candidates assert result.diagnostics.evidence_gate_require_target_api_spec is True assert result.diagnostics.evidence_gate_target_api_spec_found is True assert result.answer_mode == "exact" assert result.diagnostics.gate_decision == "allow_exact" def test_api_method_explain_promotes_api_doc_via_links() -> None: rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/domain/runtime-health.md", "title": "Сущность runtime health", "content": "Runtime health is the domain model for observability.", "metadata": { "document_id": "domain.runtime_health", "type": "domain_entity", "links": [{"target": "api.health_endpoint", "type": "used_by"}], }, }, { "layer": "D0_DOC_CHUNKS", "path": "docs/api/health.md", "title": "api.health_endpoint:Overview", "content": "Endpoint /health returns overall runtime status and component diagnostics.", "metadata": {"document_id": "api.health_endpoint", "type": "api_method", "endpoint": "/health"}, }, ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Как работает health endpoint?", "docs-session", mode="pre_llm_only") assert result.diagnostics.promoted_via_links == ["api.health_endpoint"] assert result.diagnostics.selected_primary_documents == ["api.health_endpoint"] assert result.diagnostics.api_method_match_found is True def test_api_method_explain_rejects_cross_endpoint_primary_candidates() -> None: rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/documentation/api/control-actions-endpoint.md", "title": "HTTP API /actions/{action}", "content": "Endpoint for controlling actions.", "metadata": { "document_id": "api.control_actions_endpoint", "type": "api_method", "endpoint": "/actions/{action}", }, }, { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/documentation/api/health-endpoint.md", "title": "HTTP API /health", "content": "Health endpoint returns runtime health and component diagnostics.", "metadata": { "document_id": "api.health_endpoint", "type": "api_method", "endpoint": "/health", }, }, { "layer": "D0_DOC_CHUNKS", "path": "docs/documentation/api/actions-endpoint.md", "title": "api.control_actions_endpoint:Scenario", "content": "The /actions/{action} endpoint triggers runtime actions.", "metadata": { "document_id": "api.control_actions_endpoint", "type": "api_method", "endpoint": "/actions/{action}", }, }, ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Как работает метод health?", "docs-session", mode="pre_llm_only") assert result.router_result.query_plan.sub_intent == "API_METHOD_EXPLAIN" assert result.diagnostics.target_endpoint_identity["normalized_doc_id"] == "api.health_endpoint" assert result.diagnostics.selected_primary_documents == ["api.health_endpoint"] assert result.diagnostics.primary_api_documents_after_filter == ["api.health_endpoint"] assert "api.control_actions_endpoint" in result.diagnostics.rejected_endpoint_candidates assert result.diagnostics.cross_endpoint_leakage_detected is True assert result.diagnostics.evidence_gate_target_api_spec_found is True assert "api.control_actions_endpoint" not in result.diagnostics.selected_doc_ids def test_api_method_explain_without_exact_target_returns_insufficiency() -> None: rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/documentation/api/control-actions-endpoint.md", "title": "HTTP API /actions/{action}", "content": "Endpoint for controlling actions.", "metadata": { "document_id": "api.control_actions_endpoint", "type": "api_method", "endpoint": "/actions/{action}", }, }, { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/documentation/api/send-endpoint.md", "title": "HTTP API /send", "content": "Endpoint for sending messages.", "metadata": { "document_id": "api.send_message_endpoint", "type": "api_method", "endpoint": "/send", }, }, ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Что делает метод health?", "docs-session", mode="pre_llm_only") assert result.router_result.query_plan.sub_intent == "API_METHOD_EXPLAIN" assert result.diagnostics.target_endpoint_identity["normalized_doc_id"] == "api.health_endpoint" assert result.diagnostics.selected_primary_documents == [] assert "api.control_actions_endpoint" in result.diagnostics.rejected_endpoint_candidates assert "api.send_message_endpoint" in result.diagnostics.rejected_endpoint_candidates assert result.diagnostics.target_api_spec_found_exact is False assert result.diagnostics.evidence_gate_target_api_spec_found is False assert result.diagnostics.gate_decision == "reject" assert result.answer_mode == "insufficient" assert "api.control_actions_endpoint" not in result.diagnostics.selected_doc_ids assert "api.send_message_endpoint" not in result.diagnostics.selected_doc_ids def test_api_method_explain_uses_indirect_mode_from_target_linked_docs() -> None: rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/domain/runtime-health.md", "title": "Runtime health", "content": "Runtime health describes overall service state and component diagnostics.", "metadata": { "document_id": "domain.runtime_health", "type": "domain_entity", "links": [{"target": "api.health_endpoint", "type": "used_by"}], }, }, ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Как работает метод health?", "docs-session", mode="pre_llm_only") assert result.answer_mode == "indirect" assert result.diagnostics.gate_decision == "allow_indirect" assert result.diagnostics.raw_retrieval_non_empty is True assert result.diagnostics.target_primary_context_non_empty is False assert result.diagnostics.indirect_target_context_non_empty is True assert result.diagnostics.graph_promotion_attempted is True assert result.diagnostics.graph_promotion_hits == ["api.health_endpoint"] assert result.diagnostics.promoted_target_loaded is False assert result.diagnostics.materialization_failure_reason == "materialized_rows_empty" assert result.diagnostics.final_primary_document_ids == [] assert "domain.runtime_health" in result.diagnostics.final_secondary_document_ids def test_api_method_explain_skips_llm_when_no_exact_or_indirect_context() -> None: from tests.unit_tests.rag.test_docs_prompt_layer import FakeLlm rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/documentation/api/send-endpoint.md", "title": "HTTP API /send", "content": "Endpoint for sending messages.", "metadata": { "document_id": "api.send_message_endpoint", "type": "api_method", "endpoint": "/send", }, } ] llm = FakeLlm("should not be called") runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context(), llm=llm) result = runner.run("Что делает метод health?", "docs-session") assert llm.calls == [] assert result.answer_mode == "insufficient" assert result.diagnostics.llm_called is False assert result.diagnostics.llm_call_reason == "no_exact_or_indirect_target_context" assert result.diagnostics.gate_decision == "reject" def test_api_method_explain_materializes_promoted_target_into_primary_context() -> None: rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/domain/runtime-health.md", "title": "Runtime health", "content": "Runtime health describes service state and component diagnostics.", "metadata": { "document_id": "domain.runtime_health", "type": "domain_entity", "links": [{"target": "api.health_endpoint", "type": "used_by"}], }, } ] materialized_rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/api/health.md", "title": "GET /health", "content": "/health returns runtime and component statuses.", "metadata": {"document_id": "api.health_endpoint", "type": "api_method", "endpoint": "/health"}, }, { "layer": "D2_FACT_INDEX", "path": "docs/api/health.md", "title": "api.health_endpoint:response", "content": "Returns health summary and component diagnostics.", "metadata": {"subject_id": "api.health_endpoint", "type": "api_method"}, }, { "layer": "D0_DOC_CHUNKS", "path": "docs/api/health.md", "title": "api.health_endpoint:Overview", "content": "Endpoint /health returns overall runtime health.", "metadata": {"document_id": "api.health_endpoint", "type": "api_method", "endpoint": "/health"}, }, ] runner = DocsQAPipelineRunner( IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows, materialized_rows=materialized_rows), repo_context=repo_context(), ) result = runner.run("Как работает метод health?", "docs-session", mode="pre_llm_only") assert result.answer_mode == "exact" assert result.diagnostics.graph_promotion_hits == ["api.health_endpoint"] assert result.diagnostics.graph_promotion_materialized == ["api.health_endpoint"] assert result.diagnostics.promoted_target_loaded is True assert result.diagnostics.promoted_target_chunks_loaded == 1 assert result.diagnostics.promoted_target_facts_loaded == 1 assert result.diagnostics.pinned_document_ids == ["api.health_endpoint"] assert result.diagnostics.final_primary_document_ids == ["api.health_endpoint"] assert "domain.runtime_health" in result.diagnostics.final_secondary_document_ids assert result.diagnostics.materialized_target_primary_context_non_empty is True assert result.diagnostics.gate_decision == "allow_exact" def test_entity_question_does_not_prefer_api_method_primary_doc() -> None: rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/domain/runtime-health.md", "title": "Сущность runtime health", "content": "Runtime health describes service state.", "metadata": {"document_id": "domain.runtime_health", "type": "domain_entity"}, }, { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/api/health.md", "title": "GET /health", "content": "/health returns runtime status.", "metadata": {"document_id": "api.health_endpoint", "type": "api_method", "endpoint": "/health"}, }, ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Что такое runtime health?", "docs-session", mode="pre_llm_only") assert result.router_result.query_plan.sub_intent == "ENTITY_EXPLAIN" assert result.diagnostics.selected_primary_documents == [] assert result.diagnostics.api_method_match_found is False assert result.answer == "" def test_openapi_method_with_only_path_is_rejected() -> None: rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/api/health.md", "title": "/health", "content": "", "metadata": {"endpoint": "/health", "doc_id": "api.health_endpoint"}, } ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Сгенерируй OpenAPI для endpoint /health", "docs-session", mode="pre_llm_only") assert result.diagnostics.gate_decision == "reject" assert result.answer_mode == "degraded" def test_openapi_response_fragment_does_not_require_request_payload() -> None: rows = [ { "layer": "D2_FACT_INDEX", "path": "docs/api/health.md", "title": "GET /health", "content": "Returns 200 with status and uptime fields.", "metadata": { "endpoint": "/health", "http_method": "get", "response_schema": {"type": "object", "properties": {"status": {}, "uptime": {}}}, }, } ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Сгенерируй response schema для endpoint /health", "docs-session", mode="pre_llm_only") assert result.diagnostics.requested_fragment_type == "response_schema" assert result.diagnostics.gate_decision != "reject" assert result.answer_mode != "degraded" assert "properties:" in result.answer def test_system_flow_evidence_prefers_workflows_and_relations() -> None: rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/workflows/checkout.md", "title": "Checkout overview", "content": "Overview doc", "metadata": {"doc_id": "workflow.checkout"}, }, { "layer": "D4_WORKFLOW_INDEX", "path": "docs/workflows/checkout.md", "title": "Checkout steps", "content": "cart -> payment -> confirm", "metadata": {"workflow_id": "workflow.checkout"}, }, { "layer": "D5_RELATION_GRAPH", "path": "docs/workflows/checkout.md", "title": "Checkout relations", "content": "Related to payment entity", "metadata": {"doc_id": "workflow.checkout", "target_doc_id": "domain.payment"}, }, { "layer": "D0_DOC_CHUNKS", "path": "docs/workflows/checkout.md", "title": "workflow.checkout:chunk", "content": "payment step persists order", "metadata": {"chunk_id": "chunk.checkout.1", "doc_id": "workflow.checkout"}, }, ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Объясни как работает checkout workflow", "docs-session", mode="pre_llm_only") assert result.diagnostics.planned_layers == ["D4_WORKFLOW_INDEX", "D5_RELATION_GRAPH", "D1_DOCUMENT_CATALOG", "D0_DOC_CHUNKS"] assert result.diagnostics.selected_workflow_ids == ["workflow.checkout"] assert result.diagnostics.selected_relation_ids == ["domain.payment"] assert result.diagnostics.selected_chunk_ids == ["chunk.checkout.1"] def test_component_evidence_prefers_facts_and_targeted_chunks() -> None: rows = [ { "layer": "D1_DOCUMENT_CATALOG", "path": "docs/components/runtime-manager.md", "title": "Runtime manager", "content": "Overview", "metadata": {"doc_id": "architecture.runtime_manager"}, }, { "layer": "D2_FACT_INDEX", "path": "docs/components/runtime-manager.md", "title": "Runtime facts", "content": "Coordinates runtime orchestration", "metadata": {"fact_id": "fact.runtime_manager.role", "doc_id": "architecture.runtime_manager"}, }, { "layer": "D0_DOC_CHUNKS", "path": "docs/components/runtime-manager.md", "title": "RuntimeManager chunk", "content": "Starts worker loops and supervises control channels", "metadata": {"chunk_id": "chunk.runtime_manager.1", "doc_id": "architecture.runtime_manager"}, }, ] runner = DocsQAPipelineRunner(IntentRouterV2(), InMemoryDocsRetrievalAdapter(rows), repo_context=repo_context()) result = runner.run("Какую роль в системе играет RuntimeManager?", "docs-session", mode="pre_llm_only") assert result.diagnostics.planned_layers == ["D2_FACT_INDEX", "D5_RELATION_GRAPH", "D1_DOCUMENT_CATALOG", "D0_DOC_CHUNKS"] assert result.diagnostics.selected_fact_ids == ["fact.runtime_manager.role"] assert result.diagnostics.selected_doc_ids == ["architecture.runtime_manager"] assert result.diagnostics.selected_chunk_ids == ["chunk.runtime_manager.1"]