feat(completeness): Regulatory Completeness Engine — auditable coverage, not confidence

Phase A½. The move from feature to product development: for every assessment, answer "how sure are
we that this answer is COMPLETE?" — different from confidence. The product never claims full coverage;
it makes its own knowledge state transparent and auditable. Shows what we do NOT know and why.

- compliance/completeness/: assess_completeness(identified, corpus_status, uncertain, assumptions,
  assessed_obligations) -> CompletenessReport. Separates IDENTIFIED from ASSESSED (validated corpus
  AND determined applicability) and justifies every gap. Two kinds of open: corpus gap (future_corpus)
  and applicability uncertainty (query_required + deciding question, e.g. Data Act / generates_usage_data).
- The metric is COUNTS, never a single percentage: "Identifiziert N · bewertet M · offen K ·
  Unsicherheiten U · Begründung ja" + an honest audit statement.
- ADR-007: auditable honesty; phase order A factory -> A½ Completeness -> B new domains; the
  transparency selling point. Deterministic, no LLM; corpus status + obligation count injected.
- reference suite: "Regulatory Completeness" section runs an industrial-dishwasher assessment
  (assessed CRA/MaschinenVO; open EMV/Environmental=future_corpus, Data Act=query_required) and notes
  Environmental flips open->validated automatically once the corpus lands.

11 completeness tests (54 with adjacent modules), mypy --strict clean (15 files), check-loc 0.
Product code with no app caller + ADR/reference = non-runtime -> no deploy (ADR-001). Freeze-safe.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-27 14:16:12 +02:00
parent 0b0d262462
commit aa99111a87
8 changed files with 389 additions and 3 deletions
@@ -0,0 +1,24 @@
"""Regulatory Completeness — auditable knowledge coverage, not confidence.
An internal quality machine: for an assessment it reports identified vs assessed regulations and
justifies every open or excluded domain (corpus gap -> future_corpus; applicability uncertain ->
query_required). The metric is counts, never a single percentage. The product never claims full
coverage — it makes its own knowledge state transparent and auditable. Deterministic, no LLM, no
new corpus/meta-model class (freeze v1.0).
"""
from __future__ import annotations
from .engine import assess_completeness
from .schemas import (
Assumption, CompletenessReport, CorpusStatus, DomainCoverage, Exclusion,
)
__all__ = [
"assess_completeness",
"CompletenessReport",
"CorpusStatus",
"DomainCoverage",
"Exclusion",
"Assumption",
]
@@ -0,0 +1,89 @@
"""Regulatory Completeness Engine — measure auditable knowledge coverage for an assessment.
Separates what we IDENTIFIED (triggered regulations) from what we ASSESSED (validated corpus AND
determined applicability), and justifies every gap. Two kinds of „open":
- corpus gap — no validated corpus yet (e.g. Environmental) -> future_corpus
- applicability open — corpus exists but applicability is uncertain (Data Act) -> query_required
The metric is COUNTS, never a single percentage. The audit statement says plainly „wir bewerteten M
von N Domänen; K sind nicht im validierten Korpus und wurden bewusst nicht bewertet".
Deterministic, computed-not-stored, no LLM, no new corpus/meta-model class (freeze v1.0). Python 3.9.
"""
from __future__ import annotations
from typing import Any, Dict, List, Optional
from .schemas import (
Assumption, CompletenessReport, CorpusStatus, DomainCoverage, Exclusion,
)
_VALID = {s.value for s in CorpusStatus}
def _status(corpus_status: Dict[str, str], reg: str) -> CorpusStatus:
raw = corpus_status.get(reg, "unknown")
return CorpusStatus(raw) if raw in _VALID else CorpusStatus.UNKNOWN
def assess_completeness(
identified_regulations: List[str],
corpus_status: Dict[str, str],
uncertain: Optional[List[Dict[str, Any]]] = None,
assumptions: Optional[List[Dict[str, Any]]] = None,
assessed_obligations: int = 0,
) -> CompletenessReport:
"""Build the auditable coverage report.
`identified_regulations`: triggered/identified for this product. `corpus_status`: regulation ->
one of validated/draft/unsupported/unknown (curated/injected corpus registry). `uncertain`:
applicability-uncertain regulations [{regulation, deciding_question, reason}]. `assumptions`:
[{key, value, note}]. `assessed_obligations`: count from Execution (injected, default 0).
"""
ids = sorted(set(identified_regulations))
unc = uncertain or []
unc_subjects = {str(u.get("regulation") or u.get("subject")) for u in unc if (u.get("regulation") or u.get("subject"))}
coverage = [DomainCoverage(regulation=r, status=_status(corpus_status, r)) for r in ids]
assessed = [r for r in ids if _status(corpus_status, r) == CorpusStatus.VALIDATED and r not in unc_subjects]
open_regs = [r for r in ids if r not in assessed]
open_corpora = [r for r in ids if _status(corpus_status, r) in (CorpusStatus.UNSUPPORTED, CorpusStatus.UNKNOWN)]
exclusions: List[Exclusion] = []
for u in unc:
subj = str(u.get("regulation") or u.get("subject") or "")
if not subj:
continue
exclusions.append(Exclusion(
subject=subj, reason=str(u.get("reason", "Anwendbarkeit unsicher")),
deciding_question=str(u.get("deciding_question", "")), resolution="query_required"))
for r in open_regs:
if r in unc_subjects:
continue
st = _status(corpus_status, r)
if st == CorpusStatus.DRAFT:
exclusions.append(Exclusion(subject=r, reason="Korpus in Bearbeitung (draft)", resolution="in_review"))
else:
exclusions.append(Exclusion(subject=r, reason="nicht im validierten Korpus", resolution="future_corpus"))
covered_subjects = {e.subject for e in exclusions}
justification = (not open_regs) or set(open_regs) <= covered_subjects
assumptions_m = [Assumption(key=str(a.get("key", "")), value=str(a.get("value", "")), note=str(a.get("note", ""))) for a in (assumptions or [])]
summary = "Identifiziert %d · bewertet %d · offen %d · Unsicherheiten %d · Begründung %s" % (
len(ids), len(assessed), len(open_regs), len(unc), "ja" if justification else "nein")
if open_regs:
audit = (
"Für dieses Produkt konnten wir %d von %d identifizierten regulatorischen Domänen vollständig "
"bewerten. %d weitere %s noch nicht Bestandteil des validierten Korpus bzw. anwendungsunsicher "
"und wurden deshalb bewusst nicht bewertet." % (
len(assessed), len(ids), len(open_regs), "ist" if len(open_regs) == 1 else "sind"))
else:
audit = "Für dieses Produkt konnten wir alle %d identifizierten regulatorischen Domänen vollständig bewerten." % len(ids)
return CompletenessReport(
identified_regulations=ids, assessed_regulations=assessed, open_regulations=open_regs,
open_corpora=open_corpora, coverage=coverage, assumptions=assumptions_m, exclusions=exclusions,
uncertainties_count=len(unc), assessed_obligations=assessed_obligations,
justification_present=justification, completeness_summary=summary, audit_statement=audit,
)
@@ -0,0 +1,62 @@
"""Schemas for the Regulatory Completeness Engine — auditable knowledge-coverage, not confidence.
For an assessment it answers „wie sicher sind wir, dass diese Antwort VOLLSTÄNDIG ist?" by separating
IDENTIFIED regulations from ASSESSED ones (those in the validated corpus) and listing every open or
excluded domain WITH a reason. The metric is counts, never a single „87%". This is an internal quality
machine: the product never claims full coverage — it makes its own knowledge state transparent.
Deterministic, computed-not-stored, no new meta-model class (freeze v1.0). Python 3.9 compatible.
"""
from __future__ import annotations
from enum import Enum
from typing import List
from pydantic import BaseModel, Field
class CorpusStatus(str, Enum):
"""The maturity of our knowledge corpus for a regulation/domain."""
VALIDATED = "validated" # we can fully assess this
DRAFT = "draft" # partial / under review
UNSUPPORTED = "unsupported" # triggered but no corpus yet
UNKNOWN = "unknown" # not in our registry at all
class DomainCoverage(BaseModel):
regulation: str
status: CorpusStatus = CorpusStatus.UNKNOWN
note: str = ""
class Exclusion(BaseModel):
"""A domain/regulation DELIBERATELY not assessed — always with a reason (the heart of the engine)."""
subject: str
reason: str
deciding_question: str = "" # what would resolve it (if a query)
resolution: str = "future_corpus" # query_required | future_corpus | not_applicable
class Assumption(BaseModel):
key: str
value: str = ""
note: str = ""
class CompletenessReport(BaseModel):
"""The auditable coverage report for one assessment — counts + justification, NO single percentage."""
identified_regulations: List[str] = Field(default_factory=list)
assessed_regulations: List[str] = Field(default_factory=list) # in the validated corpus
open_regulations: List[str] = Field(default_factory=list) # identified but not validated
open_corpora: List[str] = Field(default_factory=list) # missing domains worth building
coverage: List[DomainCoverage] = Field(default_factory=list)
assumptions: List[Assumption] = Field(default_factory=list)
exclusions: List[Exclusion] = Field(default_factory=list)
uncertainties_count: int = 0
assessed_obligations: int = 0 # injected (Execution-owned)
justification_present: bool = False
completeness_summary: str = "" # "Identifiziert N · bewertet M · offen K · ..."
audit_statement: str = "" # the honest narrative sentence