From 05e5caa447266de31ba3a3dab86a079e453a9f69 Mon Sep 17 00:00:00 2001 From: Albrecht Degering Date: Sun, 23 Aug 2026 01:54:20 +0200 Subject: [PATCH] docs(risk-compliance): add German assurance guidance --- package.json | 2 +- pyproject.toml | 4 +- .../backend/manifest.py | 174 +++++++++++++++--- tests/test_documentation.py | 31 ++++ webui/package.json | 2 +- 5 files changed, 182 insertions(+), 31 deletions(-) create mode 100644 tests/test_documentation.py diff --git a/package.json b/package.json index 2907105..4a34caf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/risk-compliance-webui", - "version": "0.1.18", + "version": "0.1.19", "private": true, "type": "module", "main": "webui/src/index.ts", diff --git a/pyproject.toml b/pyproject.toml index b63bfe8..80e86c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "govoplan-risk-compliance" -version = "0.1.18" +version = "0.1.19" description = "GovOPlaN Risk Compliance platform module seed." readme = "README.md" requires-python = ">=3.12" @@ -12,7 +12,7 @@ license = { file = "LICENSE" } authors = [{ name = "GovOPlaN" }] dependencies = [ "defusedxml>=0.7.1", - "govoplan-core>=0.1.18", + "govoplan-core>=0.1.37", "govoplan-access>=0.1.18", ] diff --git a/src/govoplan_risk_compliance/backend/manifest.py b/src/govoplan_risk_compliance/backend/manifest.py index 3f6510f..f4da261 100644 --- a/src/govoplan_risk_compliance/backend/manifest.py +++ b/src/govoplan_risk_compliance/backend/manifest.py @@ -12,6 +12,7 @@ from govoplan_core.core.module_guards import ( ) from govoplan_core.core.modules import ( CapabilityDocumentation, + DocumentationCondition, DocumentationLink, DocumentationTopic, FrontendModule, @@ -68,7 +69,7 @@ from govoplan_risk_compliance.backend.permissions import ( MODULE_ID = "risk_compliance" MODULE_NAME = "Risk Compliance" -MODULE_VERSION = "0.1.18" +MODULE_VERSION = "0.1.19" OPTIONAL_DEPENDENCIES = ( "audit", "policy", @@ -314,10 +315,10 @@ def _tenant_summary(session, tenant_id: str) -> dict[str, int]: DOCUMENTATION = ( DocumentationTopic( id=f"{MODULE_ID}.module-boundary", - title=f"{MODULE_NAME} module boundary", + title="Screen sanctions and manage assurance evidence", summary=( - "Risk and compliance workflows own legal evaluation, immutable " - "screening evidence, review, and dispositions." + "Run version-pinned sanctions screening and connect risks, controls, " + "evidence, findings, and corrective measures without automating legal conclusions." ), body=( "Connectors may acquire source evidence, but Risk Compliance " @@ -336,6 +337,9 @@ DOCUMENTATION = ( "module_admin", "compliance_reviewer", ), + conditions=( + DocumentationCondition(any_scopes=(READ_SCOPE, SANCTIONS_READ_SCOPE)), + ), order=100, related_modules=OPTIONAL_DEPENDENCIES, links=( @@ -353,31 +357,38 @@ DOCUMENTATION = ( ), ), metadata={ - "domain_objects": [ - "sanctions list snapshots", - "screening runs", - "candidate evidence", - "review dispositions", - "time-bounded exceptions", - ], - "privacy": ( - "Queue and audit summaries contain stable references and " - "minimal subject data." + "kind": "workflow", + "purpose": ( + "Produce reproducible screening and assurance evidence while keeping legal review explicit and human-accountable." ), - "assurance_domain_model": [ - "obligation", - "governed object reference", - "risk", - "control", - "evidence", - "finding", - "corrective measure", - "effectiveness review", + "prerequisites": [ + "The actor can read the relevant assurance or sanctions area; import, screening, review, and editing use dedicated scopes.", + "A connector-provided source snapshot is available before sanctions-list import.", + "The minimum necessary screening subject data and an exact governed subject reference are available.", + ], + "steps": [ + "Import connector evidence into an immutable normalized sanctions-list snapshot.", + "Run screening against one pinned snapshot using only the required subject data.", + "Review every fuzzy candidate and record an evidence-backed disposition or time-bounded exception.", + "Create or revise assurance objects for obligations, risks, controls, evidence, findings, and corrective measures.", + "Connect assurance revisions through typed governed relationships and review effectiveness over time.", + ], + "fields": { + "source_snapshot": "An immutable normalized list revision with connector provenance and content fingerprint.", + "screening_run": "A version-pinned comparison of minimum subject data against one source snapshot.", + "candidate": "Potential matching evidence that requires human review and is never a confirmed match by itself.", + "disposition": "An append-only legal review outcome with reviewer, reason, evidence, and authority context.", + "exception": "A subject-and-entry decision bounded by explicit validity and expiry.", + "assurance_revision": "An effective-dated immutable revision of an obligation, risk, control, evidence, finding, measure, or review.", + }, + "limitations": [ + "Fuzzy matching only creates candidates and never confirms a sanctions match or legal prohibition.", + "Risk Compliance does not replace source acquisition, governed domain objects, Policy decisions, Audit evidence, or Records retention.", + ], + "privacy_notes": [ + "Queue and audit summaries use stable references and the minimum necessary subject data.", + "Governed domain objects are linked through opaque references rather than copied into the assurance graph.", ], - "assurance_graph": ( - "Every node and edge is effective-dated, revisioned, tenant-scoped, " - "and linked through opaque governed-object references." - ), "help_contexts": [ "risk_compliance.workspace", "risk_compliance.sanctions.sources", @@ -400,6 +411,77 @@ DOCUMENTATION = ( "revise_assurance_object": "append a new effective-dated revision while preserving prior evidence", "connect_assurance_objects": "append a governed typed relationship between assurance objects", }, + "verification": [ + "Every screening result names the exact list snapshot, subject fingerprint, policy provenance, and run revision.", + "Every candidate remains pending until an authorized reviewer appends a disposition or exception.", + "Every assurance node and edge is tenant-scoped, effective-dated, revisioned, and linked by governed references.", + ], + }, + translations={ + "de": { + "title": "Sanktionsprüfung und Assurance-Nachweise steuern", + "summary": ( + "Versionsgebundene Sanktionsprüfungen durchführen und Risiken, Kontrollen, " + "Nachweise, Feststellungen und Korrekturmaßnahmen verknüpfen, ohne rechtliche Schlüsse zu automatisieren." + ), + "body": ( + "Connectors können Quellnachweise beschaffen; Risk Compliance führt jedoch unveränderliche " + "normalisierte Sanktionslisten, versionsgebundene Prüfungen, Kandidatenbewertungen und rechtliche " + "Dispositionen. Unscharfer Abgleich erzeugt nur Kandidaten und bestätigt niemals einen Treffer. " + "Die weitergehende Modulrichtung verknüpft Verpflichtungen, gesteuerte Objektreferenzen, Risiken, " + "Kontrollen, Nachweise, Feststellungen, Korrekturmaßnahmen und Wirksamkeitsprüfungen, ohne das " + "gesteuerte Fachobjekt zu kopieren oder Policy und Audit zu ersetzen." + ), + } + }, + structured_translation_version="1", + structured_translations={ + "de": { + "purpose": ( + "Reproduzierbare Prüf- und Assurance-Nachweise erzeugen und rechtliche Bewertung ausdrücklich und menschlich verantwortet halten." + ), + "prerequisites": [ + "Die handelnde Person darf den jeweiligen Assurance- oder Sanktionsbereich lesen; Import, Prüfung, Bewertung und Bearbeitung verwenden eigene Berechtigungen.", + "Vor dem Import einer Sanktionsliste liegt ein von einem Connector bereitgestellter Quellsnapshot vor.", + "Die minimal erforderlichen Betroffenendaten und eine exakte gesteuerte Betroffenenreferenz sind verfügbar.", + ], + "steps": [ + "Connector-Nachweise in einen unveränderlichen normalisierten Sanktionslistensnapshot importieren.", + "Eine Prüfung mit nur den erforderlichen Betroffenendaten gegen genau einen fixierten Snapshot ausführen.", + "Jeden unscharfen Kandidaten prüfen und eine nachweisgestützte Disposition oder befristete Ausnahme aufzeichnen.", + "Assurance-Objekte für Verpflichtungen, Risiken, Kontrollen, Nachweise, Feststellungen und Korrekturmaßnahmen anlegen oder revidieren.", + "Assurance-Revisionen durch typisierte gesteuerte Beziehungen verbinden und ihre Wirksamkeit im Zeitverlauf prüfen.", + ], + "fields": { + "source_snapshot": "Eine unveränderliche normalisierte Listenrevision mit Connector-Provenienz und Inhaltsfingerabdruck.", + "screening_run": "Ein versionsgebundener Vergleich minimaler Betroffenendaten mit genau einem Quellsnapshot.", + "candidate": "Potenzieller Übereinstimmungsnachweis, der menschliche Prüfung erfordert und allein niemals ein bestätigter Treffer ist.", + "disposition": "Ein nur anfügbares rechtliches Prüfungsergebnis mit prüfender Person, Begründung, Nachweis und Zuständigkeitskontext.", + "exception": "Eine Entscheidung für Betroffenen- und Listeneintrag mit ausdrücklicher Gültigkeit und Ablaufzeit.", + "assurance_revision": "Eine zeitlich wirksame unveränderliche Revision von Verpflichtung, Risiko, Kontrolle, Nachweis, Feststellung, Maßnahme oder Prüfung.", + }, + "limitations": [ + "Unscharfer Abgleich erzeugt nur Kandidaten und bestätigt niemals einen Sanktionstreffer oder ein rechtliches Verbot.", + "Risk Compliance ersetzt weder Quellenbeschaffung noch gesteuerte Fachobjekte, Policy-Entscheidungen, Audit-Nachweise oder Records-Aufbewahrung.", + ], + "privacy_notes": [ + "Warteschlangen- und Auditübersichten verwenden stabile Referenzen und die minimal erforderlichen Betroffenendaten.", + "Gesteuerte Fachobjekte werden über opake Referenzen verknüpft und nicht in den Assurance-Graphen kopiert.", + ], + "consequence_classes": { + "import_snapshot": "Kopiert Connector-Nachweise in einen unveränderlichen normalisierten Sanktionslistensnapshot.", + "run_screening": "Erzeugt unveränderliche versionsgebundene Prüfnachweise aus den minimal erforderlichen Betroffenendaten.", + "record_disposition": "Fügt eine nachweisgestützte rechtliche Disposition an, die nicht an Ort und Stelle bearbeitet wird.", + "record_exception": "Fügt eine befristete Ausnahme für Betroffenen- und Listeneintrag mit ausdrücklichem Ablauf an.", + "revise_assurance_object": "Fügt eine neue zeitlich wirksame Revision an und bewahrt frühere Nachweise.", + "connect_assurance_objects": "Fügt eine gesteuerte typisierte Beziehung zwischen Assurance-Objekten an.", + }, + "verification": [ + "Jedes Prüfergebnis nennt exakten Listensnapshot, Betroffenenfingerabdruck, Richtlinienherkunft und Ausführungsrevision.", + "Jeder Kandidat bleibt offen, bis eine befugte prüfende Person eine Disposition oder Ausnahme anfügt.", + "Jeder Assurance-Knoten und jede Kante ist mandantenbegrenzt, zeitlich wirksam, revisioniert und durch gesteuerte Referenzen verknüpft.", + ], + } }, ), ) @@ -615,6 +697,7 @@ manifest = ModuleManifest( related_modules=("core", "access", "audit", "records", "policy"), order=90, metadata={ + "kind": "reference", "help_contexts": [ "risk_compliance.sanctions.screening", "privacy.data-subject-requests", @@ -631,6 +714,43 @@ manifest = ModuleManifest( ), }, }, + translations={ + "de": { + "title": "Datenschutzanfragen zu Risiko und Compliance", + "summary": ( + "Verifizierte Daten geprüfter Betroffener und verantwortbare Aktivitäten exportieren, " + "ohne Sanktions- oder Prüfungsnachweise Dritter offenzulegen." + ), + "body": ( + "Risk Compliance gleicht Daten geprüfter Betroffener nur über eine exakte, getrennt " + "verifizierte Betroffenenreferenz ab. Eine Konto- oder Mitgliedschaftskennung ermittelt " + "unabhängig eigene Zuschreibungen zu Bedienung, Prüfung, Import, Ausnahme und Assurance-Graph. " + "Suchen können auf eine Prüfungs- oder Assurance-Revision eingegrenzt werden; eine " + "Objektkennung allein begründet niemals Identität. Betroffenenexporte enthalten begrenzte " + "übermittelte Namen, Aliase, Kennungen, Daten, Adressen und das Lebenszyklusergebnis der Prüfung. " + "Sanktionsdaten Dritter, Kandidatenabgleichsnachweise, Fingerabdrücke, Prüfsummen, " + "Richtliniensnapshots, Begründungen prüfender Personen, Zuständigkeitskontext, Provenienz und " + "Nachweisreferenzen bleiben ausgeschlossen. Versionsgebundene Prüfungen, Dispositionen, Ausnahmen " + "und Assurance-Revisionen bleiben als rechtliche und verantwortungsbezogene Nachweise erhalten." + ), + } + }, + structured_translation_version="1", + structured_translations={ + "de": { + "consequence_classes": { + "export_screening_subject": ( + "Gibt begrenzte Betroffeneneingaben und Lebenszyklusdaten für eine exakte Referenz zurück." + ), + "exclude_third_party_evidence": ( + "Gibt niemals Sanktionslisteneinträge, Abgleichsnachweise oder geschützte Prüfungsinhalte zurück." + ), + "retain_compliance_evidence": ( + "Bewahrt versionsgebundene Rechts-, Audit- und Verantwortungsnachweise auf." + ), + } + } + }, ), *DOCUMENTATION, ), diff --git a/tests/test_documentation.py b/tests/test_documentation.py new file mode 100644 index 0000000..347a023 --- /dev/null +++ b/tests/test_documentation.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +import unittest + +from govoplan_core.core.modules import ( + documentation_structured_translation_issues, + user_workflow_scope_condition_issues, +) +from govoplan_risk_compliance.backend.manifest import manifest + + +class RiskComplianceDocumentationTests(unittest.TestCase): + def test_public_topics_have_complete_german_reference_content(self) -> None: + self.assertEqual(2, len(manifest.documentation)) + for topic in manifest.documentation: + translation = topic.translations.get("de", {}) + self.assertTrue( + all(translation.get(key) for key in ("title", "summary", "body")) + ) + self.assertEqual((), documentation_structured_translation_issues(topic)) + + def test_documentation_has_scope_conditioned_workflow_and_reference(self) -> None: + kinds = {topic.metadata.get("kind") for topic in manifest.documentation} + self.assertIn("workflow", kinds) + self.assertIn("reference", kinds) + for topic in manifest.documentation: + self.assertEqual((), user_workflow_scope_condition_issues(topic)) + + +if __name__ == "__main__": + unittest.main() diff --git a/webui/package.json b/webui/package.json index ffbbbbc..d1dbdcf 100644 --- a/webui/package.json +++ b/webui/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/risk-compliance-webui", - "version": "0.1.18", + "version": "0.1.19", "private": true, "type": "module", "main": "src/index.ts",