feat(control-pipeline): add Document Compliance Engine — scope detection + document requirements

New service: document_scope_resolver.py with 28 document rules covering:
- Base (impressum, privacy_policy)
- Tracking (cookie_banner, cookie_policy)
- E-Commerce (AGB, withdrawal, shipping, pricing, payment)
- Digital (digital_content_terms, no_withdrawal_notice)
- SaaS (ToS, service_description, DPA, SLA)
- AI (transparency_notice, automated_decisions)
- Hardware (warranty, return, CE, safety)
- Environmental (WEEE, battery disposal)
- Marketplace (seller terms, ranking transparency)
- Subscription (cancellation terms)

API: POST /v1/document-compliance/required
Input: company flags + jurisdiction → Output: required documents + assessment

Includes confidence scoring, escalation detection (e.g. ecommerce
without distance_selling flag), and reasoning. 19 tests covering all
business model combinations including B2B-only exclusions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-24 08:39:55 +02:00
parent f1359d63ba
commit 3ffa3f5793
4 changed files with 711 additions and 0 deletions

View File

@@ -0,0 +1,190 @@
"""Tests for Document Scope Resolver — required documents per business model."""
import pytest
from services.document_scope_resolver import resolve_required_documents
class TestBasicWebsite:
def test_only_website(self):
result = resolve_required_documents({"has_website": True})
types = [d["document_type"] for d in result["required_documents"]]
assert "impressum" in types
assert "privacy_policy" in types
assert "withdrawal_policy" not in types
assert "terms_and_conditions" not in types
def test_website_with_tracking(self):
result = resolve_required_documents({"has_website": True, "uses_tracking": True})
types = [d["document_type"] for d in result["required_documents"]]
assert "cookie_banner" in types
assert "cookie_policy" in types
def test_no_cookie_banner_without_tracking(self):
result = resolve_required_documents({"has_website": True})
types = [d["document_type"] for d in result["required_documents"]]
assert "cookie_banner" not in types
class TestEcommerce:
def test_webshop_physical(self):
result = resolve_required_documents({
"has_website": True, "has_ecommerce": True,
"sells_physical_products": True, "distance_selling": True,
"has_checkout": True,
})
types = [d["document_type"] for d in result["required_documents"]]
assert "terms_and_conditions" in types
assert "withdrawal_policy" in types
assert "shipping_information" in types
assert "warranty_information" in types
assert "agb_checkout_summary" in types
assert "pricing_transparency" in types
assert "payment_terms" in types
def test_b2b_only_no_withdrawal(self):
result = resolve_required_documents({
"has_website": True, "has_ecommerce": True,
"sells_physical_products": True, "b2b_only": True,
"has_checkout": True,
})
types = [d["document_type"] for d in result["required_documents"]]
assert "terms_and_conditions" in types
assert "withdrawal_policy" not in types # B2B = kein Widerruf
assert "return_policy" not in types
def test_digital_products(self):
result = resolve_required_documents({
"has_website": True, "has_ecommerce": True,
"sells_digital_products": True, "distance_selling": True,
})
types = [d["document_type"] for d in result["required_documents"]]
assert "digital_content_terms" in types
assert "no_withdrawal_notice" in types
class TestSaaS:
def test_saas_basic(self):
result = resolve_required_documents({
"has_website": True, "has_saas": True, "has_user_accounts": True,
})
types = [d["document_type"] for d in result["required_documents"]]
assert "terms_of_service" in types
assert "data_processing_agreement" in types
assert "service_description" in types
def test_saas_with_ai(self):
result = resolve_required_documents({
"has_website": True, "has_saas": True, "uses_ai": True,
})
types = [d["document_type"] for d in result["required_documents"]]
assert "ai_transparency_notice" in types
def test_saas_with_automated_decisions(self):
result = resolve_required_documents({
"has_website": True, "has_saas": True, "automated_decisions": True,
})
types = [d["document_type"] for d in result["required_documents"]]
assert "automated_decision_explanation" in types
class TestHardware:
def test_regulated_products(self):
result = resolve_required_documents({
"has_website": True, "has_ecommerce": True,
"sells_regulated_products": True,
})
types = [d["document_type"] for d in result["required_documents"]]
assert "ce_conformity_declaration" in types
assert "product_safety_instructions" in types
def test_electronics_weee(self):
result = resolve_required_documents({
"has_website": True, "has_ecommerce": True,
"sells_electronics": True,
})
types = [d["document_type"] for d in result["required_documents"]]
assert "weee_information" in types
def test_battery_products(self):
result = resolve_required_documents({
"has_website": True, "sells_physical_products": True,
"contains_battery": True,
})
types = [d["document_type"] for d in result["required_documents"]]
assert "battery_disposal_information" in types
class TestMarketplace:
def test_marketplace(self):
result = resolve_required_documents({
"has_website": True, "operates_marketplace": True,
})
types = [d["document_type"] for d in result["required_documents"]]
assert "marketplace_seller_terms" in types
assert "marketplace_ranking_transparency" in types
class TestSubscription:
def test_subscription(self):
result = resolve_required_documents({
"has_website": True, "has_saas": True, "subscription_model": True,
})
types = [d["document_type"] for d in result["required_documents"]]
assert "subscription_cancellation_terms" in types
class TestAssessment:
def test_high_confidence_full_flags(self):
result = resolve_required_documents({
"has_website": True, "has_ecommerce": True,
"uses_tracking": True, "sells_physical_products": True,
"distance_selling": True,
})
assert result["assessment"]["confidence"] >= 0.85
def test_low_confidence_few_flags(self):
result = resolve_required_documents({"has_website": True})
assert result["assessment"]["confidence"] < 0.80
def test_escalation_ecommerce_without_distance_selling(self):
result = resolve_required_documents({
"has_website": True, "has_ecommerce": True,
})
assert result["assessment"]["escalation_flag"] is True
def test_no_escalation_b2b_explicit(self):
result = resolve_required_documents({
"has_website": True, "has_ecommerce": True, "b2b_only": True,
})
assert result["assessment"]["escalation_flag"] is False
class TestFullStack:
def test_full_stack_worst_case(self):
"""Enterprise with everything: website + webshop + SaaS + AI + hardware."""
result = resolve_required_documents({
"has_website": True, "has_ecommerce": True, "has_saas": True,
"has_checkout": True, "distance_selling": True,
"uses_tracking": True, "uses_ai": True,
"sells_physical_products": True, "sells_regulated_products": True,
"sells_electronics": True, "contains_battery": True,
"subscription_model": True, "has_user_accounts": True,
})
assert result["total_required"] >= 15
types = [d["document_type"] for d in result["required_documents"]]
# Must have all base docs
assert "impressum" in types
assert "privacy_policy" in types
assert "cookie_banner" in types
# Must have ecommerce docs
assert "terms_and_conditions" in types
assert "withdrawal_policy" in types
# Must have SaaS docs
assert "terms_of_service" in types
assert "data_processing_agreement" in types
# Must have AI docs
assert "ai_transparency_notice" in types
# Must have hardware docs
assert "ce_conformity_declaration" in types
assert "weee_information" in types
assert "battery_disposal_information" in types