Files

125 lines
4.7 KiB
Python

from datetime import date
import pytest
from pydantic import ValidationError
from yuqei_sdk.ai_platform import ContractReviewRequest
from yuqei_sdk.review_material_preflight import (
REVIEW_MATERIAL_PREFLIGHT_VERSION,
build_review_material_preflight,
preflight_prompt_context,
verify_review_material_preflight,
)
REFERENCE = "甲方:华北设备有限公司\n乙方:远航租赁有限公司\n双方签署设备租赁合同。"
def test_signing_preflight_detects_types_parties_expiry_duplicates_and_versions():
text = """【材料一:授权委托书 版本 V1】
甲方:华北设备有限公司
有效期至:2025年12月31日
授权代表张三签署设备租赁合同。
【材料二:授权委托书 版本 V2】
甲方:华北设备有限公司
有效期至:2027年12月31日
授权代表李四签署设备租赁合同。
【材料三:重复扫描件】
甲方:华北设备有限公司
有效期至:2027年12月31日
授权代表李四签署设备租赁合同。"""
result = build_review_material_preflight(
review_target="signing_package",
source_title="签署材料包.txt",
source_text=text,
reference_contract_text=REFERENCE,
source_content_type="text/plain",
as_of_date=date(2026, 8, 29),
)
assert result.policy_version == REVIEW_MATERIAL_PREFLIGHT_VERSION
assert result.status == "needs_attention" and not result.blocks_submission
assert "power_of_attorney" in result.detected_document_types
assert result.version_labels == ["V1", "V2"]
codes = {item.code for item in result.issues}
assert {"EXPIRED_MATERIAL", "MULTIPLE_MATERIAL_VERSIONS", "DUPLICATE_MATERIAL"}.issubset(codes)
assert result.items[2].duplicate_of == result.items[1].id
assert verify_review_material_preflight(
result,
review_target="signing_package",
source_text=text,
reference_contract_text=REFERENCE,
)
def test_unreadable_material_blocks_before_model_but_unclear_readable_material_does_not():
blocked = build_review_material_preflight(
review_target="performance_evidence",
source_title="空材料.txt",
source_text="",
reference_contract_text=REFERENCE,
as_of_date=date(2026, 8, 29),
)
assert blocked.status == "blocked" and blocked.blocks_submission
assert "MATERIAL_TEXT_EMPTY" in {item.code for item in blocked.issues}
unclear = build_review_material_preflight(
review_target="performance_evidence",
source_title="说明.txt",
source_text="甲方:华北设备有限公司\n现场情况已经记录,待进一步核对。",
reference_contract_text=REFERENCE,
as_of_date=date(2026, 8, 29),
)
assert unclear.status == "needs_attention" and not unclear.blocks_submission
assert "MATERIAL_TYPE_UNCLEAR" in {item.code for item in unclear.issues}
def test_contract_text_preflight_is_explicitly_not_applicable_and_hash_stable():
first = build_review_material_preflight(
review_target="contract_text",
source_title="合同正文",
source_text=REFERENCE,
as_of_date=date(2026, 8, 29),
)
second = build_review_material_preflight(
review_target="contract_text",
source_title="合同正文",
source_text=REFERENCE,
as_of_date=date(2026, 8, 29),
)
assert first.status == "not_applicable"
assert first.evidence_sha256 == second.evidence_sha256
assert preflight_prompt_context(first) == ""
def test_review_request_rejects_tampered_or_rebound_preflight():
text = "甲方:华北设备有限公司\n签署页由授权代表签字并加盖合同章。"
preflight = build_review_material_preflight(
review_target="signing_package",
source_title="签署页.txt",
source_text=text,
reference_contract_text=REFERENCE,
as_of_date=date(2026, 8, 29),
)
request = ContractReviewRequest(
contract_title="设备租赁合同",
contract_text=text,
reference_contract_text=REFERENCE,
review_target="signing_package",
review_profile="scene_evaluation_v3",
material_preflight=preflight,
)
assert request.material_preflight.evidence_sha256 == preflight.evidence_sha256
tampered = preflight.model_copy(update={"status": "blocked"})
with pytest.raises(ValidationError, match="immutable review inputs"):
ContractReviewRequest(
contract_title="设备租赁合同",
contract_text=text,
reference_contract_text=REFERENCE,
review_target="signing_package",
review_profile="scene_evaluation_v3",
material_preflight=tampered,
)