Merge pull request 'Customer Mission #5 — a non-security target (evidence relevance flips)' (#33) from feat/customer-mission-5-non-security into main
This commit is contained in:
@@ -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).
|
||||||
|
|
||||||
@@ -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))
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user