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