Расширить proof matrix маржинальности follow-up replay
This commit is contained in:
@@ -259,6 +259,11 @@ GUARDED_INSUFFICIENCY_PRIMARY_MARKERS = (
|
||||
"\u043d\u0435 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430",
|
||||
"\u043d\u0435\u043b\u044c\u0437\u044f \u0447\u0435\u0441\u0442\u043d\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434",
|
||||
"\u043d\u0435\u043b\u044c\u0437\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b",
|
||||
"\u0447\u0435\u0441\u0442\u043d\u043e \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f",
|
||||
"\u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e\u0439 \u0431\u0430\u0437\u044b",
|
||||
"\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u043e\u0439 \u0441\u0435\u0431\u0435\u0441\u0442\u043e\u0438\u043c",
|
||||
"\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u0445 \u0441\u0442\u0440\u043e\u043a",
|
||||
"\u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e",
|
||||
)
|
||||
GUARDED_INSUFFICIENCY_LIMITATION_MARKERS = (
|
||||
"\u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d",
|
||||
@@ -2457,6 +2462,33 @@ def is_validated_guarded_insufficiency_answer(
|
||||
)
|
||||
|
||||
|
||||
def is_validated_clarification_answer(
|
||||
state: dict[str, Any],
|
||||
execution_status: str,
|
||||
business_review: dict[str, Any],
|
||||
violations: list[str],
|
||||
) -> bool:
|
||||
if normalize_identifier(state.get("expected_result_mode")) != "clarification_required":
|
||||
return False
|
||||
if execution_status != "partial":
|
||||
return False
|
||||
if violations:
|
||||
return False
|
||||
if str(state.get("reply_type") or "").strip() not in {"partial_coverage", "clarification_required"}:
|
||||
return False
|
||||
truth_mode = str(state.get("truth_mode") or "").strip()
|
||||
answer_shape = str(state.get("answer_shape") or "").strip()
|
||||
if truth_mode != "clarification_required" and answer_shape != "clarification_required":
|
||||
return False
|
||||
return (
|
||||
business_review.get("business_usefulness_ok") is True
|
||||
and business_review.get("direct_answer_first_ok") is True
|
||||
and business_review.get("answer_layering_ok") is True
|
||||
and business_review.get("technical_garbage_present") is False
|
||||
and business_review.get("next_action_present") is True
|
||||
)
|
||||
|
||||
|
||||
def _business_review_is_clean(step_state: dict[str, Any]) -> bool:
|
||||
business_review = step_state.get("business_first_review")
|
||||
if not isinstance(business_review, dict):
|
||||
@@ -2698,6 +2730,12 @@ def validate_step_contract(step_state: dict[str, Any]) -> dict[str, Any]:
|
||||
business_review,
|
||||
unique_violations,
|
||||
)
|
||||
clarification_validated = is_validated_clarification_answer(
|
||||
state,
|
||||
execution_status,
|
||||
business_review,
|
||||
unique_violations,
|
||||
)
|
||||
state["violated_invariants"] = unique_violations
|
||||
state["warnings"] = list(dict.fromkeys(warnings))
|
||||
state["hard_fail"] = hard_fail
|
||||
@@ -2705,10 +2743,17 @@ def validate_step_contract(step_state: dict[str, Any]) -> dict[str, Any]:
|
||||
state["memory_checkpoint_validated"] = memory_validated
|
||||
state["runtime_factual_answer_validated"] = runtime_factual_validated
|
||||
state["guarded_insufficiency_validated"] = guarded_insufficiency_validated
|
||||
state["clarification_answer_validated"] = clarification_validated
|
||||
state["acceptance_status"] = acceptance_status_from_execution(
|
||||
execution_status,
|
||||
hard_fail,
|
||||
bounded_validated or memory_validated or runtime_factual_validated or guarded_insufficiency_validated,
|
||||
(
|
||||
bounded_validated
|
||||
or memory_validated
|
||||
or runtime_factual_validated
|
||||
or guarded_insufficiency_validated
|
||||
or clarification_validated
|
||||
),
|
||||
)
|
||||
state["status"] = state["acceptance_status"]
|
||||
return state
|
||||
|
||||
@@ -804,6 +804,87 @@ class DomainCaseLoopStepStateTests(unittest.TestCase):
|
||||
self.assertTrue(step_state["guarded_insufficiency_validated"])
|
||||
self.assertEqual(step_state["acceptance_status"], "validated")
|
||||
|
||||
def test_expected_clarification_partial_answer_validates(self) -> None:
|
||||
answer_text = (
|
||||
"Для рейтинга прибыльности номенклатуры нужен период.\n\n"
|
||||
"Могу посчитать по номенклатуре: выручку без НДС, себестоимость реализации, "
|
||||
"валовую прибыль и маржинальность.\n\n"
|
||||
"Уточните период: месяц, квартал, год или весь доступный период."
|
||||
)
|
||||
step_state = dcl.validate_step_contract(
|
||||
{
|
||||
"execution_status": "partial",
|
||||
"reply_type": "partial_coverage",
|
||||
"expected_result_mode": "clarification_required",
|
||||
"required_answer_shape": "direct_answer_first",
|
||||
"response_type": "LIMITED_WITH_REASON",
|
||||
"truth_mode": "clarification_required",
|
||||
"answer_shape": "clarification_required",
|
||||
"assistant_text": answer_text,
|
||||
"actual_direct_answer": "Для рейтинга прибыльности номенклатуры нужен период.",
|
||||
"top_non_empty_lines": [
|
||||
"Для рейтинга прибыльности номенклатуры нужен период.",
|
||||
"Могу посчитать по номенклатуре: выручку без НДС, себестоимость реализации, валовую прибыль и маржинальность.",
|
||||
"Уточните период: месяц, квартал, год или весь доступный период.",
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(step_state["clarification_answer_validated"])
|
||||
self.assertEqual(step_state["acceptance_status"], "validated")
|
||||
|
||||
def test_inventory_margin_guarded_insufficiency_validates_without_exact_values(self) -> None:
|
||||
answer_text = (
|
||||
"За период 01.05.2020 - 31.05.2020 рейтинг прибыльности номенклатуры построить нельзя.\n\n"
|
||||
"Что нашлось:\n"
|
||||
"- Есть реализация по 1 номенклатурной позиции.\n"
|
||||
"- Подтвержденной себестоимости реализации по этой позиции не найдено.\n"
|
||||
"- Поэтому валовую прибыль и маржинальность честно посчитать нельзя.\n"
|
||||
"Вывод: за период 01.05.2020 - 31.05.2020 нет достаточной базы для рейтинга "
|
||||
"«высокая / низкая прибыль» по номенклатуре.\n\n"
|
||||
"Что можно сделать дальше:\n"
|
||||
"- показать найденные реализации за этот период;\n"
|
||||
"- расширить период до квартала или года;\n"
|
||||
"- попробовать строгий расчет по проводкам 90.01 / 90.02.\n\n"
|
||||
"Граница ответа:\n"
|
||||
"- Прибыльность номенклатуры считаю только когда есть реализация и подтвержденная себестоимость реализации."
|
||||
)
|
||||
step_state = dcl.validate_step_contract(
|
||||
{
|
||||
"execution_status": "partial",
|
||||
"reply_type": "partial_coverage",
|
||||
"expected_result_mode": "ranking_or_limited_accounting_answer",
|
||||
"required_answer_shape": "direct_answer_first",
|
||||
"detected_intent": "inventory_margin_ranking_for_nomenclature",
|
||||
"capability_id": "inventory_inventory_margin_ranking_for_nomenclature",
|
||||
"fallback_type": "none",
|
||||
"mcp_call_status": "matched_non_empty",
|
||||
"response_type": "FACTUAL_SUMMARY",
|
||||
"truth_mode": "limited",
|
||||
"answer_shape": "limited_with_reason",
|
||||
"balance_confirmed": False,
|
||||
"assistant_text": answer_text,
|
||||
"actual_direct_answer": "За период 01.05.2020 - 31.05.2020 рейтинг прибыльности номенклатуры построить нельзя.",
|
||||
"top_non_empty_lines": [
|
||||
"За период 01.05.2020 - 31.05.2020 рейтинг прибыльности номенклатуры построить нельзя.",
|
||||
"Что нашлось:",
|
||||
"- Есть реализация по 1 номенклатурной позиции.",
|
||||
"- Подтвержденной себестоимости реализации по этой позиции не найдено.",
|
||||
"- Поэтому валовую прибыль и маржинальность честно посчитать нельзя.",
|
||||
"Вывод: за период 01.05.2020 - 31.05.2020 нет достаточной базы для рейтинга «высокая / низкая прибыль» по номенклатуре.",
|
||||
"Что можно сделать дальше:",
|
||||
"- показать найденные реализации за этот период;",
|
||||
"- расширить период до квартала или года;",
|
||||
"- попробовать строгий расчет по проводкам 90.01 / 90.02.",
|
||||
"Граница ответа:",
|
||||
"- Прибыльность номенклатуры считаю только когда есть реализация и подтвержденная себестоимость реализации.",
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(step_state["guarded_insufficiency_validated"])
|
||||
self.assertEqual(step_state["acceptance_status"], "validated")
|
||||
|
||||
def test_heuristic_open_items_without_limitation_is_rejected(self) -> None:
|
||||
step_state = dcl.build_scenario_step_state(
|
||||
scenario_id="runtime_factual_demo",
|
||||
|
||||
Reference in New Issue
Block a user