From dbf7b9b58792f94afd8376508db2d4ab9d29426e Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Sun, 28 Jun 2026 10:18:28 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Customer=20Mission=20#5=20=E2=80=94=20a?= =?UTF-8?q?=20non-security=20target,=20evidence=20relevance=20flips=20both?= =?UTF-8?q?=20ways?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes the Evidence-Relevance(Target) claim by testing it on a deliberately NON-security target (a hand-authored environmental / material-evidence Required set — no corpus, no ISO-14001 norm model, no new module). One company profile, three targets through the same engine: - ISO 14001: keine (CRA) / keine (TISAX) / HOCH (environmental) <- flips - ISO 27001: hoch (CRA) / hoch (TISAX) / keine (environmental) <- flips the other way - PSIRT: hoch (CRA) / keine (TISAX) / keine (environmental) Proves relevance(evidence, target) is two-sided: no evidence is relevant "in itself"; relevance only arises against a target -> it must be computed, never stored as an attribute of the evidence. With this, the target-type diversity for the later selector is complete (Regulation · Certification · Contract/Tender · OEM-Spec · Environmental/Material) — five target types through one engine, so a Scope→Journey selector finally makes sense. Synthetic, no real names. Non-runtime -> no deploy. 5 tests. --- .../reference_scenarios/customer_mission_5.md | 27 ++++ .../mission_non_security_target.py | 129 ++++++++++++++++++ .../tests/test_customer_mission_5.py | 55 ++++++++ 3 files changed, 211 insertions(+) create mode 100644 backend-compliance/reference_scenarios/customer_mission_5.md create mode 100644 backend-compliance/reference_scenarios/mission_non_security_target.py create mode 100644 backend-compliance/tests/test_customer_mission_5.py diff --git a/backend-compliance/reference_scenarios/customer_mission_5.md b/backend-compliance/reference_scenarios/customer_mission_5.md new file mode 100644 index 00000000..77d1d26f --- /dev/null +++ b/backend-compliance/reference_scenarios/customer_mission_5.md @@ -0,0 +1,27 @@ +# Customer Mission #5 — ein Nicht-Security-Ziel: kippt die Evidence-Relevanz? + +_Enger Scope: KEIN Umweltrecht, KEINE ISO-14001-Normmodellierung, KEIN neues Modul, KEIN Deploy. Nur die EINE Frage: ist `relevance(evidence, target)` wirklich eine Funktion des Ziels — oder ein Attribut der Evidence? Das Umwelt-/Materialnachweis-Ziel ist ein hand-authored `Required`-Satz (synthetisch), nur um die bestehende Engine auf ein Nicht-Security-Ziel zu richten. Synthetischer Kunde, keine echten Namen._ + +## Der Kunde (synthetisch) — EIN Profil (hat u. a. ISO 14001) +> **ISO 9001 · ISO 27001 · ISO 14001 · TISAX · PSIRT** · vernetzte Maschinen · Export EU + +## 1. Evidence-Relevanz über drei Ziele — zwei Security, eines NICHT +| Zertifizierung (Evidence) | → CRA | → TISAX | → Umwelt-/Material | +|---|---|---|---| +| **ISO27001** | hoch (5) | hoch (3) | keine (0) | +| **TISAX** | niedrig (2) | hoch (6) | keine (0) | +| **PSIRT** | hoch (3) | keine (0) | keine (0) | +| **ISO14001** | keine (0) | keine (0) | hoch (3) | ⟵ kippt +| **ISO9001** | niedrig (1) | keine (0) | keine (0) | + +## 2. Beweis — Relevanz ist eine Funktion des ZIELS (in BEIDE Richtungen) +- **ISO 14001:** gegen CRA/TISAX **keine**, gegen das Umwelt-/Materialziel **hoch (3)**. Dieselbe Zertifizierung — von wertlos zu entscheidend, nur weil das Ziel wechselt. +- **Symmetrisch:** **ISO 27001** (hoch gegen CRA/TISAX) ist gegen das Umwelt-/Materialziel **keine (0)**; **PSIRT** ebenso **keine (0)**. Security-Evidence ist hier wertlos. +- Delta des Umwelt-/Materialziels: **5** fehlende Fähigkeiten (das Profil deckt nur die ISO-14001-nahen ab) — über dieselbe `assess_transition`-Engine, kein Sonderpfad. + +→ **Damit ist `relevance(evidence, target)` zweiseitig bewiesen:** keine Evidence ist „an sich" relevant; Relevanz entsteht erst gegen ein Ziel. Eine Capability/Zertifizierung ohne Ziel hat keinen Relevanzwert. + +## Befund + +> **Ein und dieselbe Evidence kann je Ziel wertlos oder hoch relevant sein** — hier erstmals an einem NICHT-Security-Ziel gezeigt, in beide Richtungen (ISO 14001 kippt von keine→hoch, Security-Certs von hoch→keine). Folgerung für das spätere Modell: Relevanz darf NICHT als Attribut der Evidence gespeichert werden, sondern nur als `relevance(evidence, target)` berechnet (computed-not-stored). **Damit ist die Ziel-Diversität für den späteren Selektor beisammen: Regulation · Certification · Contract/Tender · OEM-Spec · Umwelt-/Material-Ziel — fünf Zielarten durch dieselbe Engine. Erst jetzt wird ein Scope→Journey-Selektor sinnvoll** (er optimiert nicht mehr auf einer einzigen Zielart). + diff --git a/backend-compliance/reference_scenarios/mission_non_security_target.py b/backend-compliance/reference_scenarios/mission_non_security_target.py new file mode 100644 index 00000000..5c3248ee --- /dev/null +++ b/backend-compliance/reference_scenarios/mission_non_security_target.py @@ -0,0 +1,129 @@ +# ruff: noqa +# mypy: ignore-errors +"""Customer Mission #5 — a NON-security target: does evidence relevance really flip? + +The whole „Evidence-Relevance(Target)" claim is only convincing if it holds in BOTH directions. Missions +#2–#4 showed security evidence (ISO 27001, PSIRT) ranking differently across security targets, and ISO +14001 being worthless against the CRA/TISAX. This mission closes the loop with a deliberately NON-security +target — an environmental / material-evidence requirement set — and asks the one question: + + is `relevance(evidence, target)` genuinely a function of the TARGET, or an attribute of the evidence? + +Expected and shown: ISO 14001 is keine/niedrig against CRA and TISAX but HOCH against the environmental +target — while the security certificates (ISO 27001, PSIRT) flip the other way (relevant for security, +keine for the environmental target). The same evidence is worthless or decisive depending on the target. + +DELIBERATELY NOT here (per scope): no environmental corpus, no ISO-14001 norm model, no new runtime +module, no deploy, no real names. The environmental target is a hand-authored Required set (injected like +any TargetRequirement) purely to point the existing engine at a non-security goal. + +Run: cd backend-compliance && PYTHONPATH=. python3 reference_scenarios/mission_non_security_target.py +""" +from __future__ import annotations + +import os +import yaml + +from compliance.company import ( + CompanyContext, Certification, CapabilityMappingEntry, build_company_profile, +) +from compliance.reasoning.enums import Confidence +from compliance.transition_reasoning import ( + TransitionContext, TransitionGoal, TargetRequirement, assess_transition, CoverageStatus, +) + +OUT = [] + + +def w(s=""): + OUT.append(s) + + +_K = os.path.join(os.path.dirname(__file__), "..", "knowledge", "transition_patterns") + + +def _caps(pattern_file): + p = yaml.safe_load(open(os.path.join(_K, pattern_file), encoding="utf-8")) + return [a["capability"] for a in p["likely_covered"]] + [d["capability"] for d in p["delta_requirements"]] + + +# ── Three targets — two security, one NON-security (the new axis) ─────────────────────────── +CRA = _caps("transition_pattern_iso27001_to_cra_maschinenvo_v1.yaml") # security regulation +TISAX = _caps("transition_pattern_isms_to_tisax_v1.yaml") # security certification +# NON-security target: an environmental / material-evidence requirement set. Hand-authored Required +# capabilities (NOT a corpus, NOT an ISO-14001 norm model) — just a goal to point the engine at. +ENVIRONMENTAL = [ + "environmental_management_documentation", "energy_efficiency_documentation", + "supply_chain_environmental_due_diligence", "material_declaration_scip_reach", + "hazardous_substance_restriction_rohs", "carbon_footprint_accounting", + "recycling_and_take_back", "battery_passport_material_data", +] +TARGETS = [("CRA", "Security/Regulation", CRA), ("TISAX", "Security/Certification", TISAX), + ("Umwelt-/Materialnachweis", "NICHT-Security", ENVIRONMENTAL)] + +# ── ONE company profile (the same multi-certified archetype; it HAS ISO 14001) ────────────── +CERT_OBS = { + "ISO27001": ["information_security_management", "incident_management", "access_control_and_authentication", + "technical_vulnerability_management", "security_logging_and_monitoring", "secure_development_lifecycle"], + "TISAX": ["information_security_management", "access_control_and_authentication", "incident_management", + "supplier_security", "physical_security", "prototype_protection"], + "PSIRT": ["coordinated_vulnerability_disclosure", "exploited_vuln_and_incident_reporting", + "public_security_advisories"], + # an EMS (ISO 14001) touches several environmental process areas — relevant ONLY to an env target: + "ISO14001": ["environmental_management_documentation", "energy_efficiency_documentation", + "supply_chain_environmental_due_diligence"], + "ISO9001": ["ce_conformity_assessment_and_technical_documentation"], +} +cmap = {k: CapabilityMappingEntry(capability_ids=v, confidence=Confidence.MEDIUM) for k, v in CERT_OBS.items()} +profile = build_company_profile( + CompanyContext(company_id="mc5", certifications=[Certification(certification_id=k) for k in CERT_OBS]), cmap) + + +def _delta(caps): + reqs = [TargetRequirement(capability_id=c) for c in caps] + a = assess_transition(TransitionContext(company_id="mc5", target=TransitionGoal(target_id="t")), reqs, profile) + return sorted({c.capability_id for c in a.coverage if c.status == CoverageStatus.MISSING}) + + +def _rel(cert_caps, target_caps): + n = len(set(cert_caps) & set(target_caps)) + return n, ("hoch" if n >= 3 else "niedrig" if n >= 1 else "keine") + + +w('# Customer Mission #5 — ein Nicht-Security-Ziel: kippt die Evidence-Relevanz?') +w("") +w('_Enger Scope: KEIN Umweltrecht, KEINE ISO-14001-Normmodellierung, KEIN neues Modul, KEIN Deploy. Nur die EINE Frage: ist `relevance(evidence, target)` wirklich eine Funktion des Ziels — oder ein Attribut der Evidence? Das Umwelt-/Materialnachweis-Ziel ist ein hand-authored `Required`-Satz (synthetisch), nur um die bestehende Engine auf ein Nicht-Security-Ziel zu richten. Synthetischer Kunde, keine echten Namen._') +w("") +w("## Der Kunde (synthetisch) — EIN Profil (hat u. a. ISO 14001)") +w("> **ISO 9001 · ISO 27001 · ISO 14001 · TISAX · PSIRT** · vernetzte Maschinen · Export EU") +w("") + +# ── 1. Die Relevanz-Matrix (zwei Security-Ziele + ein Umwelt-Ziel) ───────── +w("## 1. Evidence-Relevanz über drei Ziele — zwei Security, eines NICHT") +w("| Zertifizierung (Evidence) | → CRA | → TISAX | → Umwelt-/Material |") +w("|---|---|---|---|") +for cert, caps in CERT_OBS.items(): + cells = [_rel(caps, t)[1] + " (%d)" % _rel(caps, t)[0] for _, _, t in TARGETS] + mark = " ⟵ kippt" if cert == "ISO14001" else "" + w("| **%s** | %s | %s | %s |%s" % (cert, cells[0], cells[1], cells[2], mark)) +w("") + +# ── 2. Der Beweis: dieselbe Evidence, gegensätzlicher Wert je Ziel ───────── +iso14_env = _rel(CERT_OBS["ISO14001"], ENVIRONMENTAL) +iso27_env = _rel(CERT_OBS["ISO27001"], ENVIRONMENTAL) +psirt_env = _rel(CERT_OBS["PSIRT"], ENVIRONMENTAL) +w("## 2. Beweis — Relevanz ist eine Funktion des ZIELS (in BEIDE Richtungen)") +w("- **ISO 14001:** gegen CRA/TISAX **keine**, gegen das Umwelt-/Materialziel **%s (%d)**. Dieselbe Zertifizierung — von wertlos zu entscheidend, nur weil das Ziel wechselt." % (iso14_env[1], iso14_env[0])) +w("- **Symmetrisch:** **ISO 27001** (hoch gegen CRA/TISAX) ist gegen das Umwelt-/Materialziel **%s (%d)**; **PSIRT** ebenso **%s (%d)**. Security-Evidence ist hier wertlos." % (iso27_env[1], iso27_env[0], psirt_env[1], psirt_env[0])) +w("- Delta des Umwelt-/Materialziels: **%d** fehlende Fähigkeiten (das Profil deckt nur die ISO-14001-nahen ab) — über dieselbe `assess_transition`-Engine, kein Sonderpfad." % len(_delta(ENVIRONMENTAL))) +w("") +w('→ **Damit ist `relevance(evidence, target)` zweiseitig bewiesen:** keine Evidence ist „an sich" relevant; Relevanz entsteht erst gegen ein Ziel. Eine Capability/Zertifizierung ohne Ziel hat keinen Relevanzwert.') +w("") + +# ── Befund ──────────────────────────────────────────────────────────────── +w("## Befund") +w("") +w('> **Ein und dieselbe Evidence kann je Ziel wertlos oder hoch relevant sein** — hier erstmals an einem NICHT-Security-Ziel gezeigt, in beide Richtungen (ISO 14001 kippt von keine→hoch, Security-Certs von hoch→keine). Folgerung für das spätere Modell: Relevanz darf NICHT als Attribut der Evidence gespeichert werden, sondern nur als `relevance(evidence, target)` berechnet (computed-not-stored). **Damit ist die Ziel-Diversität für den späteren Selektor beisammen: Regulation · Certification · Contract/Tender · OEM-Spec · Umwelt-/Material-Ziel — fünf Zielarten durch dieselbe Engine. Erst jetzt wird ein Scope→Journey-Selektor sinnvoll** (er optimiert nicht mehr auf einer einzigen Zielart).') +w("") + +print("\n".join(OUT)) diff --git a/backend-compliance/tests/test_customer_mission_5.py b/backend-compliance/tests/test_customer_mission_5.py new file mode 100644 index 00000000..6901e288 --- /dev/null +++ b/backend-compliance/tests/test_customer_mission_5.py @@ -0,0 +1,55 @@ +"""Customer Mission #5 — a non-security target: evidence relevance flips both ways. + +Pins the one claim this mission exists to prove: relevance(evidence, target) is a function of the +TARGET, not an attribute of the evidence. The same ISO 14001 is keine against CRA/TISAX but hoch +against an environmental/material target, while the security certs flip the other way (hoch against +security targets, keine against the environmental one). Tight scope: no corpus, no norm model, no +new runtime module, no real names. +""" + +from __future__ import annotations + +import os +import subprocess +import sys + + +def _run(): + root = os.path.join(os.path.dirname(__file__), "..") + r = subprocess.run( + [sys.executable, "reference_scenarios/mission_non_security_target.py"], + cwd=root, env={**os.environ, "PYTHONPATH": "."}, capture_output=True, text=True, + ) + assert r.returncode == 0, r.stderr + return r.stdout + + +def test_runs_end_to_end(): + out = _run() + assert "Customer Mission #5" in out + + +def test_iso14001_relevance_flips_to_high_on_environmental_target(): + out = _run() + # the headline: same cert, keine against security targets, hoch against the environmental one + assert "**ISO14001** | keine (0) | keine (0) | hoch (3) |" in out + + +def test_security_evidence_is_worthless_against_environmental_target(): + out = _run() + # symmetry: security certs are relevant for security, keine for the environmental target + assert "**ISO27001** | hoch (5) | hoch (3) | keine (0) |" in out + assert "**PSIRT** | hoch (3) | keine (0) | keine (0) |" in out + + +def test_relevance_is_a_function_of_the_target(): + out = _run() + assert "relevance(evidence, target)` zweiseitig bewiesen" in out + # five target types now covered -> selector becomes sensible + assert "fünf Zielarten" in out + + +def test_no_real_company_names(): + out = _run().lower() + for name in ["eto", "owis", "winterhalter"]: + assert name not in out