Усилить reliability gate и принять margin semantic replay
This commit is contained in:
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user