feat: Anti-Fake-Evidence System (Phase 1-4b)

Implement full evidence integrity pipeline to prevent compliance theater:
- Confidence levels (E0-E4), truth status tracking, assertion engine
- Four-Eyes approval workflow, audit trail, reject endpoint
- Evidence distribution dashboard, LLM audit routes
- Traceability matrix (backend endpoint + Compliance Hub UI tab)
- Anti-fake badges, control status machine, normative patterns
- 2 migrations, 4 test suites, MkDocs documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-23 17:15:45 +01:00
parent 48ca0a6bef
commit e6201d5239
36 changed files with 5627 additions and 189 deletions

View File

@@ -43,6 +43,7 @@ class ControlStatus(str):
FAIL = "fail"
NOT_APPLICABLE = "n/a"
PLANNED = "planned"
IN_PROGRESS = "in_progress"
class RiskLevel(str):
@@ -209,12 +210,14 @@ class ControlUpdate(BaseModel):
owner: Optional[str] = None
status: Optional[str] = None
status_notes: Optional[str] = None
status_justification: Optional[str] = None
class ControlResponse(ControlBase):
id: str
status: str
status_notes: Optional[str] = None
status_justification: Optional[str] = None
last_reviewed_at: Optional[datetime] = None
next_review_at: Optional[datetime] = None
created_at: datetime
@@ -291,7 +294,8 @@ class EvidenceBase(BaseModel):
class EvidenceCreate(EvidenceBase):
pass
confidence_level: Optional[str] = None
truth_status: Optional[str] = None
class EvidenceResponse(EvidenceBase):
@@ -304,6 +308,20 @@ class EvidenceResponse(EvidenceBase):
uploaded_by: Optional[str] = None
collected_at: datetime
created_at: datetime
# Anti-Fake-Evidence fields
confidence_level: Optional[str] = None
truth_status: Optional[str] = None
generation_mode: Optional[str] = None
may_be_used_as_evidence: Optional[bool] = None
reviewed_by: Optional[str] = None
reviewed_at: Optional[datetime] = None
# Anti-Fake-Evidence Phase 2: Four-Eyes
approval_status: Optional[str] = None
first_reviewer: Optional[str] = None
first_reviewed_at: Optional[datetime] = None
second_reviewer: Optional[str] = None
second_reviewed_at: Optional[datetime] = None
requires_four_eyes: Optional[bool] = None
class Config:
from_attributes = True
@@ -435,6 +453,25 @@ class AISystemListResponse(BaseModel):
# Dashboard & Export Schemas
# ============================================================================
class MultiDimensionalScore(BaseModel):
"""Multi-dimensional compliance score (Anti-Fake-Evidence)."""
requirement_coverage: float = 0.0 # % requirements with linked control
evidence_strength: float = 0.0 # Weighted avg of evidence confidence (E0=0..E4=1)
validation_quality: float = 0.0 # % evidence with truth_status >= validated_internal
evidence_freshness: float = 0.0 # % evidence not expired + reviewed < 90 days
control_effectiveness: float = 0.0 # Existing formula (pass + partial*0.5)
overall_readiness: float = 0.0 # Weighted composite
hard_blocks: List[str] = [] # Blocking issues preventing audit-readiness
class StatusTransitionError(BaseModel):
"""Error detail for forbidden control status transitions."""
allowed: bool = False
current_status: str
requested_status: str
violations: List[str] = []
class DashboardResponse(BaseModel):
compliance_score: float
total_regulations: int
@@ -447,6 +484,7 @@ class DashboardResponse(BaseModel):
total_risks: int
risks_by_level: Dict[str, int]
recent_activity: List[Dict[str, Any]]
multi_score: Optional[MultiDimensionalScore] = None
class ExportRequest(BaseModel):
@@ -1939,3 +1977,111 @@ class TOMStatsResponse(BaseModel):
implemented: int = 0
partial: int = 0
not_implemented: int = 0
# ============================================================================
# Assertion Schemas (Anti-Fake-Evidence Phase 2)
# ============================================================================
class AssertionCreate(BaseModel):
entity_type: str
entity_id: str
sentence_text: str
assertion_type: Optional[str] = "assertion"
evidence_ids: Optional[List[str]] = []
normative_tier: Optional[str] = None
class AssertionUpdate(BaseModel):
sentence_text: Optional[str] = None
assertion_type: Optional[str] = None
evidence_ids: Optional[List[str]] = None
normative_tier: Optional[str] = None
confidence: Optional[float] = None
class AssertionResponse(BaseModel):
id: str
tenant_id: Optional[str] = None
entity_type: str
entity_id: str
sentence_text: str
sentence_index: int = 0
assertion_type: str = "assertion"
evidence_ids: Optional[List[str]] = []
confidence: float = 0.0
normative_tier: Optional[str] = None
verified_by: Optional[str] = None
verified_at: Optional[datetime] = None
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
class Config:
from_attributes = True
class AssertionListResponse(BaseModel):
assertions: List[AssertionResponse]
total: int
class AssertionSummaryResponse(BaseModel):
total_assertions: int = 0
total_facts: int = 0
total_rationale: int = 0
unverified_count: int = 0
class AssertionExtractRequest(BaseModel):
entity_type: str
entity_id: str
text: str
class EvidenceRejectRequest(BaseModel):
reviewed_by: str
rejection_reason: Optional[str] = None
# ============================================================================
# Traceability Matrix (Anti-Fake-Evidence Phase 4a)
# ============================================================================
class TraceabilityAssertion(BaseModel):
"""Single assertion linked to an evidence item."""
id: str
sentence_text: str
assertion_type: str = "assertion"
confidence: float = 0.0
verified: bool = False
class TraceabilityEvidence(BaseModel):
"""Evidence item with nested assertions."""
id: str
title: str
evidence_type: str
confidence_level: str = "E1"
status: str = "valid"
assertions: List[TraceabilityAssertion] = []
class TraceabilityCoverage(BaseModel):
"""Coverage flags for a single control."""
has_evidence: bool = False
has_assertions: bool = False
all_assertions_verified: bool = False
min_confidence_level: Optional[str] = None
class TraceabilityControl(BaseModel):
"""Control with nested evidence and coverage info."""
id: str
control_id: str
title: str
status: str = "planned"
domain: str = "unknown"
evidence: List[TraceabilityEvidence] = []
coverage: TraceabilityCoverage = TraceabilityCoverage()
class TraceabilityMatrixResponse(BaseModel):
"""Full traceability matrix: Controls → Evidence → Assertions."""
controls: List[TraceabilityControl]
summary: Dict[str, int]