PMFlow/backend/tests/test_pmflow_ai_verification...

93 lines
3.6 KiB
Python

from app.schemas.rag import RAGAskRequest
from app.services.pmflow_ai_answer_verifier_registry import PMFlowAIAnswerVerifierRegistry
from app.services.pmflow_ai_turn_runtime_service import (
PMFlowAITurnRuntimeService,
_verification_failure_allows_retry,
)
from app.services.pmflow_ai_turn_state_reviser import PMFlowAITurnStateReviser
def _service() -> PMFlowAITurnRuntimeService:
return PMFlowAITurnRuntimeService(object(), tenant_id=1)
def _protected_internal_state():
return _service().build_initial_turn_state(
request=RAGAskRequest(question="你们是什么技术架构"),
route_plan={},
turn_hypothesis={
"normalized_goal": "request_pmflow_internal_architecture",
"desired_outcome": "判断 PMFlow 内部技术架构是否可以披露",
"answer_shape": "general_answer",
"goal_frames": [
{
"frame_id": "internal-disclosure-boundary",
"operation_kind": "explain_assistant",
"target_scope": {"scope_type": "current_space", "binding_strength": "surface"},
"target_object_requirement": "none",
"source_policy": "none",
"answer_shape": "general_answer",
"confidence": 0.9,
}
],
"operation_gaps": [],
"disclosure_policy": {
"visibility_class": "protected_pmflow_internal",
"protected_categories": ["internal_architecture", "source_code", "model_provider"],
"allowed_response_mode": "protected_refusal",
"contract_key": "protected_internal_refusal.v1",
},
},
)
def _mismatched_static_payload() -> dict:
return {
"_runtime_payload_kind": "final_answer",
"answer": "我按内部合同回答。",
"answer_runtime_packet": {"objective": {}, "plan": {}, "draft": {}},
"customer_evidence_packet": {"source_summary": []},
}
def test_packet_av_verifier_failure_carries_verification_delta() -> None:
state = _protected_internal_state()
failure = PMFlowAIAnswerVerifierRegistry().verify_payload(
turn_state=state,
payload=_mismatched_static_payload(),
)
assert failure is not None
assert failure.verification_delta["packet_version"] == "pmflow_ai_verification_delta.v1"
assert failure.verification_delta["verification_ok"] is False
assert failure.verification_delta["retry_would_change_state"] is False
assert failure.verification_delta["customer_safe_effect"]["blocked_claims"]
assert "Static contract" in failure.verification_delta["internal_diagnostic"]
def test_packet_av_retry_gate_blocks_same_state_static_contract_retry() -> None:
state = _protected_internal_state()
failure = PMFlowAIAnswerVerifierRegistry().verify_payload(
turn_state=state,
payload=_mismatched_static_payload(),
)
assert failure is not None
assert _verification_failure_allows_retry(failure) is False
def test_packet_av_reviser_does_not_create_synthesize_gap_when_retry_would_not_change_state() -> None:
state = _protected_internal_state()
failure = PMFlowAIAnswerVerifierRegistry().verify_payload(
turn_state=state,
payload=_mismatched_static_payload(),
)
assert failure is not None
PMFlowAITurnStateReviser().revise_from_verification(turn_state=state, failure=failure)
assert not any(gap.system_action_hint == "synthesize_answer" for gap in state.operation_gaps)
assert state.state_revisions
assert "Static contract" not in state.state_revisions[-1].reason