Усилить reliability gate и принять margin semantic replay

This commit is contained in:
2026-05-24 10:34:20 +03:00
parent 7f797e5346
commit 9957f82c21
35 changed files with 2963 additions and 67 deletions
@@ -0,0 +1,79 @@
{
"schema_version": "domain_scenario_pack_v1",
"pack_id": "agent_margin_profitability_reliability_20260524",
"domain": "margin_profitability",
"title": "AGENT | margin profitability wrong-domain traps",
"description": "Минимальный reliability pack для проверки, что вопросы про маржинальность номенклатуры не утекают в ОС, амортизацию, банк, оплаты или взаиморасчёты.",
"source_contract_id": "margin_profitability_v1",
"bindings": {
"period": "2020 год",
"item": "товар"
},
"analysis_context": {
"expected_business_answer_contract": "margin_profitability_v1",
"semantic_focus": [
"direct_answer_first",
"margin_domain_purity",
"honest_unknowns",
"wrong_domain_traps"
]
},
"scenarios": [
{
"scenario_id": "margin_root_wrong_domain_trap",
"title": "Root margin question must not leak into accounting domains",
"steps": [
{
"step_id": "step_01",
"title": "Маржинальность номенклатуры",
"question": "Какая номенклатура была самой маржинальной за {{bindings.period}}?",
"semantic_tags": ["margin_profitability", "inventory", "wrong_domain_trap"],
"expected_result_mode": "ranking_or_limited_accounting_answer",
"expected_business_answer_contract": "margin_profitability_v1",
"required_answer_shape": "direct_answer_first",
"required_answer_patterns_any": [
"(?i)(марж|прибыл|выруч|себестоим|не могу подтвердить|не хватает)"
],
"forbidden_answer_patterns": [
"(?i)(амортизац|основн(ые|ых)? средств|объект ОС|оплат[аы]|банк|settlement|payment_document)"
],
"notes": "Если точного расчёта нет, допустим честный limited answer, но не уход в ОС/банк/оплаты."
}
]
},
{
"scenario_id": "margin_followup_contract_boundary",
"title": "Follow-up must keep margin contract and state limitations",
"steps": [
{
"step_id": "step_01",
"title": "Запрос маржинальности",
"question": "Покажи топ товаров по марже за {{bindings.period}}.",
"semantic_tags": ["margin_profitability", "inventory"],
"expected_result_mode": "ranking_or_limited_accounting_answer",
"expected_business_answer_contract": "margin_profitability_v1",
"required_answer_shape": "direct_answer_first",
"forbidden_answer_patterns": [
"(?i)(амортизац|объект ОС|payment_document|settlement)"
]
},
{
"step_id": "step_02",
"title": "Почему именно так",
"question": "А из чего ты это посчитал и чего не хватает для точной маржи?",
"depends_on": ["step_01"],
"semantic_tags": ["margin_profitability", "evidence", "scope_guard"],
"expected_result_mode": "evidence_or_honest_boundary",
"expected_business_answer_contract": "margin_profitability_v1",
"required_answer_shape": "direct_answer_first",
"required_answer_patterns_any": [
"(?i)(выруч|себестоим|валов|марж|не хватает|не подтвержден)"
],
"forbidden_answer_patterns": [
"(?i)(route_id|capability_id|runtime_|debug|амортизац|объект ОС)"
]
}
]
}
]
}
@@ -0,0 +1,77 @@
{
"schema_version": "business_answer_contract_v1",
"contract_id": "margin_profitability_v1",
"domain": "margin_profitability",
"title": "Маржинальность номенклатуры",
"purpose": "Зафиксировать минимальную форму честного бизнес-ответа для вопросов о выручке, себестоимости, валовой прибыли и марже по товарам/номенклатуре.",
"answer_surface": {
"must_start_with": "direct_answer_first",
"required_fields": [
{
"field": "period",
"meaning": "Период расчёта или честное указание, что период не задан/не подтверждён."
},
{
"field": "revenue_ex_vat",
"meaning": "Выручка без НДС или честное unknown, если контур не может доказать сумму."
},
{
"field": "cogs",
"meaning": "Себестоимость или честное unknown, если нет подтверждённой основы."
},
{
"field": "gross_profit",
"meaning": "Валовая прибыль как revenue_ex_vat - cogs или честное unknown."
},
{
"field": "margin_pct",
"meaning": "Процент маржи или честное unknown при недостаточной базе."
},
{
"field": "evidence_basis",
"meaning": "Какие документы/регистры/цепочки подтверждают расчёт."
}
],
"must_not_contain": [
"route ids",
"capability ids",
"debug ids",
"fixed assets / ОС leak",
"amortization / амортизация leak",
"payment document as margin source"
],
"limited_answer_rule": "Если точный расчёт невозможен, ответ должен сказать, что подтверждено, что неизвестно, и предложить следующий проверяемый шаг."
},
"root_layers": [
"intent",
"route",
"capability",
"field_mapping",
"answer_surface"
],
"detectors": [
"margin_domain_leak_accounting_route",
"margin_required_fields_missing",
"margin_next_action_missing",
"margin_payment_document_false_source",
"margin_os_amortization_leak"
],
"acceptance": {
"must_have": [
"direct_answer_first",
"period",
"revenue_ex_vat_or_honest_unknown",
"cogs_or_honest_unknown",
"gross_profit_or_honest_unknown",
"margin_pct_or_honest_unknown",
"evidence_basis_or_honest_boundary",
"next_action_if_limited"
],
"must_not_have": [
"fixed assets leak",
"amortization leak",
"payment document as margin source",
"technical garbage"
]
}
}
+221
View File
@@ -0,0 +1,221 @@
{
"schema_version": "agent_issue_catalog_v1",
"updated_at": "2026-05-24",
"principles": [
"No accepted save without effective_runtime.json.",
"No auto-coder without allowed issue_code, root_layers, allowed/forbidden targets, rerun_matrix, and answer contract.",
"Subagents are read-only reviewers; Lead/Orchestrator owns final verdict and repair decision."
],
"issues": {
"runtime_manifest_missing": {
"severity": "P0",
"business_meaning": "Прогон нельзя воспроизвести, поэтому audit/repair/acceptance нельзя считать доказанными.",
"root_layers": ["run_reproducibility"],
"detectors": ["missing_effective_runtime_json"],
"allowed_patch_targets": [
"scripts/domain_case_loop.py",
"scripts/domain_truth_harness.py",
"scripts/stage_agent_loop.py",
"scripts/save_agent_semantic_run.py",
"scripts/agent_runtime_manifest.py"
],
"forbidden_patch_targets": [
"business routing",
"MCP runtime",
"domain contracts"
],
"rerun_matrix": [
"same_spec_direct_runner",
"same_spec_stage_runner",
"accepted_smoke_pack"
],
"acceptance": {
"must_have": [
"effective_runtime.json",
"git_sha",
"runner",
"llm_model",
"temperature",
"prompt_source",
"prompt_hash"
]
}
},
"prompt_registry_opaque": {
"severity": "P0",
"business_meaning": "Неясно, какой normalizer prompt реально исполняется.",
"root_layers": ["prompt_registry", "runtime_config"],
"detectors": [
"default_prompt_version_missing_files",
"silent_prompt_fallback",
"preset_version_mismatch"
],
"allowed_patch_targets": [
"llm_normalizer/backend/src/services/promptBuilder.ts",
"llm_normalizer/backend/src/config.ts",
"llm_normalizer/data/presets/*.json",
"scripts/prompt_registry_healthcheck.py",
"scripts/agent_runtime_manifest.py"
],
"forbidden_patch_targets": [
"domain routing rewrites",
"business answer heuristics"
],
"rerun_matrix": [
"prompt_healthcheck",
"normalizer_smoke",
"accepted_smoke_pack"
]
},
"margin_domain_leak_accounting_route": {
"severity": "P0",
"business_meaning": "Запрос про маржинальность номенклатуры ушёл в чужой бухгалтерский домен вместо выручки, себестоимости, валовой прибыли и процента маржи.",
"root_layers": ["intent", "route", "capability", "domain_contract"],
"expected_answer_contract": "margin_profitability_v1",
"detectors": [
"forbidden_margin_terms",
"missing_revenue_cogs_margin_fields",
"wrong_capability_family"
],
"allowed_patch_targets": [
"llm_normalizer/backend/src/services/addressIntentResolver.ts",
"llm_normalizer/backend/src/services/addressCapabilityPolicy.ts",
"llm_normalizer/backend/src/services/addressFilterExtractor.ts",
"llm_normalizer/backend/src/services/address_runtime/**",
"docs/orchestration/contracts/margin_profitability_v1.json"
],
"forbidden_patch_targets": [
"fake data",
"silent heuristic masking",
"global orchestration rewrite",
"MCP protocol rewrite"
],
"rerun_matrix": [
"failed_margin_scenario",
"margin_neighbor_pack",
"wrong_domain_trap_pack",
"selected_object_followup_pack",
"accepted_smoke_pack"
],
"acceptance": {
"must_have": [
"direct_answer_first",
"period",
"revenue_ex_vat_or_honest_unknown",
"cogs_or_honest_unknown",
"gross_profit_or_honest_unknown",
"margin_pct_or_honest_unknown",
"next_action_if_limited"
],
"must_not_have": [
"route ids",
"debug ids",
"fixed assets leak",
"amortization leak",
"payment document as margin source"
]
}
},
"business_direct_answer_missing": {
"severity": "P0",
"business_meaning": "Ответ не начинает с прямого бизнес-вывода, хотя пользователь задал прямой вопрос.",
"root_layers": ["answer_surface", "business_utility"],
"detectors": ["first_line_not_direct_answer", "top_level_scaffold_before_answer"],
"allowed_patch_targets": [
"llm_normalizer/backend/src/services/address_runtime/composeStage.ts",
"llm_normalizer/backend/src/services/assistantMcpDiscoveryResponseCandidate.ts",
"llm_normalizer/backend/src/services/assistantService.ts"
],
"forbidden_patch_targets": [
"routing rewrites",
"fake evidence",
"global runtime rewrite"
],
"rerun_matrix": [
"failed_scenario",
"direct_answer_surface_pack",
"accepted_smoke_pack"
]
},
"technical_garbage_in_answer": {
"severity": "P0",
"business_meaning": "Финальный ответ протащил debug/runtime/MCP-механику в пользовательскую поверхность.",
"root_layers": ["answer_surface", "business_utility"],
"detectors": ["runtime_tokens_in_user_answer", "capability_ids_in_user_answer"],
"allowed_patch_targets": [
"llm_normalizer/backend/src/services/address_runtime/composeStage.ts",
"llm_normalizer/backend/src/services/assistantMcpDiscoveryResponseCandidate.ts",
"llm_normalizer/backend/src/services/assistantService.ts"
],
"forbidden_patch_targets": [
"route masking",
"debug deletion from artifacts"
],
"rerun_matrix": [
"failed_scenario",
"technical_garbage_canary_pack",
"accepted_smoke_pack"
]
},
"accounting_contract_missing": {
"severity": "P1",
"business_meaning": "Ответ не раскрыл обязательный бухгалтерский/доказательный контракт для запрошенного расчёта.",
"root_layers": ["domain_contract", "answer_surface", "evidence"],
"detectors": ["required_contract_fields_missing"],
"allowed_patch_targets": [
"docs/orchestration/contracts/*.json",
"llm_normalizer/backend/src/services/address_runtime/composeStage.ts",
"llm_normalizer/backend/src/services/assistantMcpDiscoveryResponseCandidate.ts"
],
"forbidden_patch_targets": [
"fake data",
"silent heuristic masking"
],
"rerun_matrix": [
"failed_scenario",
"contract_field_pack",
"accepted_smoke_pack"
]
},
"business_next_step_missing": {
"severity": "P2",
"business_meaning": "Ограниченный ответ не предлагает полезный следующий шаг.",
"root_layers": ["answer_surface", "business_utility"],
"detectors": ["limited_answer_without_next_action"],
"allowed_patch_targets": [
"llm_normalizer/backend/src/services/address_runtime/composeStage.ts",
"llm_normalizer/backend/src/services/assistantMcpDiscoveryResponseCandidate.ts"
],
"forbidden_patch_targets": [
"evidence fabrication",
"route masking"
],
"rerun_matrix": [
"failed_scenario",
"limited_answer_pack",
"accepted_smoke_pack"
]
},
"route_candidate_enablement_gap": {
"severity": "P1",
"business_meaning": "Планировщик понял бизнес-запрос, но route candidate ещё не исполняется как точная возможность.",
"root_layers": ["route_candidate", "runtime_capability"],
"detectors": ["route_candidate_needs_enablement"],
"allowed_patch_targets": [
"llm_normalizer/backend/src/services/assistantMcpDiscoveryRuntimeBridge.ts",
"llm_normalizer/backend/src/services/assistantMcpDiscoveryPlanner.ts",
"llm_normalizer/backend/src/services/assistantMcpDiscoveryPilotExecutor.ts",
"llm_normalizer/backend/src/services/addressRecipeCatalog.ts"
],
"forbidden_patch_targets": [
"global orchestration rewrite",
"fake fixtures"
],
"rerun_matrix": [
"failed_scenario",
"route_candidate_pack",
"accepted_smoke_pack"
]
}
}
}