Merge pull request 'Capability Convergence Explanation + Core/Domain (Phase Omega)' (#40) from feat/capability-families-and-core-domain into main
This commit is contained in:
@@ -0,0 +1,48 @@
|
|||||||
|
# Capability Families — the curated WHY behind convergence (Phase Ω: understand the core, not add domains).
|
||||||
|
#
|
||||||
|
# Medical proved the registry CONVERGES: completely different worlds (clinical/MDR/patient safety) still
|
||||||
|
# surface the same capabilities at the top. The question is no longer "which MCAPs?" but "WHY do they
|
||||||
|
# recur?". The answer is that ~60-70 MCAPs reduce to a small set of FAMILIES — and each family has a
|
||||||
|
# reason it is universal. That reason is the moat: not "MCAP-0017 exists" but "why MCAP-0017 must exist".
|
||||||
|
#
|
||||||
|
# This file is CURATED INSIGHT (the reason), not computed. Assignment of a capability to a family is by
|
||||||
|
# token match, FIRST family in this order wins — so cross-cutting CORE families are checked before
|
||||||
|
# DOMAIN-specific ones. Core vs Domain itself is NOT stored here; it is COMPUTED from the data (a cap is
|
||||||
|
# Core when it recurs across independent domains + source types). `kind` below is only the family's
|
||||||
|
# expected nature, used as a hint in the report. No new runtime, no new architecture.
|
||||||
|
|
||||||
|
families:
|
||||||
|
# ── CORE families (expected to recur across domains) ──────────────────────────────────────
|
||||||
|
- {id: risk, label: "Risk", kind: core, tokens: [risk, hazard, threat],
|
||||||
|
reason: "Universeller Prozess — jede Regulierung verlangt eine Risikobeurteilung."}
|
||||||
|
- {id: update, label: "Update", kind: core, tokens: [update],
|
||||||
|
reason: "Softwareprodukt — jedes vernetzte Produkt muss sicher aktualisierbar sein."}
|
||||||
|
- {id: vulnerability, label: "Vulnerability", kind: core, tokens: [vulnerability, vuln],
|
||||||
|
reason: "Produktbetrieb — Schwächen über die Lebensdauer behandeln."}
|
||||||
|
- {id: identity_access, label: "Identity & Access", kind: core, tokens: [access, authentication, identification, credentials],
|
||||||
|
reason: "Wer/was darf — Identität und Zugriff."}
|
||||||
|
- {id: inventory, label: "Inventory & Composition", kind: core, tokens: [sbom, inventory, material, substance, substances, rxswin],
|
||||||
|
reason: "Lieferkette/Stoffstrom — was steckt im Produkt? (SBOM = Software, Stoffliste = Material)."}
|
||||||
|
- {id: supplier, label: "Supplier", kind: core, tokens: [supplier, suppliers],
|
||||||
|
reason: "Lieferantensteuerung — Verantwortung über die Kette."}
|
||||||
|
- {id: incident, label: "Incident & Reporting", kind: core, tokens: [incident, advisories, disclosure],
|
||||||
|
reason: "Vorfälle erkennen, behandeln und melden."}
|
||||||
|
- {id: monitoring, label: "Monitoring & Audit", kind: core, tokens: [monitoring, logging, surveillance, audits, audit],
|
||||||
|
reason: "Beobachtung — Betrieb und Umfeld überwachen."}
|
||||||
|
- {id: lifecycle, label: "Lifecycle & Development", kind: core, tokens: [lifecycle, development, engineer, versions],
|
||||||
|
reason: "Produkt-/Software-Lebenszyklus."}
|
||||||
|
- {id: evidence_docs, label: "Documentation & Evidence", kind: core, tokens: [document, documentation, declaration, conformity, technical],
|
||||||
|
reason: "Nachweisführung — Konformität dokumentieren."}
|
||||||
|
- {id: configuration, label: "Configuration & Asset", kind: core, tokens: [configuration, asset],
|
||||||
|
reason: "Konfiguration und Asset-Kontrolle."}
|
||||||
|
# ── DOMAIN families (expected to stay within one domain) ──────────────────────────────────
|
||||||
|
- {id: environmental, label: "Environmental/Material", kind: domain, tokens: [environmental, water, wastewater, energy, waste, emission, emissions, chemical, rohs, reach, battery, recycling, passport],
|
||||||
|
reason: "Umwelt-/Stoff-spezifisch."}
|
||||||
|
- {id: medical, label: "Medical", kind: domain, tokens: [clinical, medical, benefit, safety, classify, udi, device, capa],
|
||||||
|
reason: "Medizin-/Patientensicherheit-spezifisch."}
|
||||||
|
- {id: automotive, label: "Automotive", kind: domain, tokens: [aspice, csms, sums, cybersecurity, prototype, campaigns, ppap, apqp, functional],
|
||||||
|
reason: "Automotive-/Funktionssicherheit-spezifisch."}
|
||||||
|
- {id: machine_safety, label: "Machine Safety", kind: domain, tokens: [machine, mechanical, guards, operating, corruption],
|
||||||
|
reason: "Maschinensicherheit-spezifisch."}
|
||||||
|
- {id: process_qms, label: "Process & QMS", kind: domain, tokens: [release, change, capability, improvement, aspects, compliance, verify, design, ce]
|
||||||
|
,reason: "QM-/Prozessdisziplin."}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# Capability Convergence Explanation — WARUM konvergieren diese Capabilities?
|
||||||
|
|
||||||
|
_Nicht „welche MCAPs?", sondern „warum verlangen völlig verschiedene Welten immer wieder DIESELBEN?". Drei abgeleitete Sichten über vorhandene Daten (kein ML, keine neue Architektur). Der eigentliche Burggraben ist nicht „MCAP-X existiert", sondern „warum MCAP-X existieren MUSS"._
|
||||||
|
|
||||||
|
## 1. Warum konvergieren sie? — Domänen-Matrix + Grund
|
||||||
|
| Capability | Industrial | Automotive | Medical | Environmental | Grund (Familie) |
|
||||||
|
|---|---|---|---|---||---|
|
||||||
|
| `access_control_and_authentication` | ✓ | ✓ | ✓ | – | Wer/was darf — Identität und Zugriff. |
|
||||||
|
| `sbom_creation` | ✓ | ✓ | ✓ | – | Lieferkette/Stoffstrom — was steckt im Produkt? (SBOM = Software, Stoffliste = Material). |
|
||||||
|
| `secure_signed_update_distribution` | ✓ | ✓ | ✓ | – | Softwareprodukt — jedes vernetzte Produkt muss sicher aktualisierbar sein. |
|
||||||
|
| `technical_vulnerability_management` | ✓ | ✓ | ✓ | – | Produktbetrieb — Schwächen über die Lebensdauer behandeln. |
|
||||||
|
| `asset_and_configuration_management` | ✓ | ✓ | – | – | Konfiguration und Asset-Kontrolle. |
|
||||||
|
| `coordinated_vulnerability_disclosure` | ✓ | ✓ | – | – | Produktbetrieb — Schwächen über die Lebensdauer behandeln. |
|
||||||
|
| `cryptography` | ✓ | ✓ | – | – | — |
|
||||||
|
| `document_and_change_control` | ✓ | ✓ | – | – | Nachweisführung — Konformität dokumentieren. |
|
||||||
|
| `incident_management` | ✓ | ✓ | – | – | Vorfälle erkennen, behandeln und melden. |
|
||||||
|
| `product_cyber_risk_assessment` | ✓ | ✓ | – | – | Universeller Prozess — jede Regulierung verlangt eine Risikobeurteilung. |
|
||||||
|
|
||||||
|
→ Das ist keine Statistik mehr, sondern **Erkenntnis**: dieselbe Fähigkeit kehrt wieder, weil ein universelles Prinzip dahinter steht (Softwareprodukt · Lieferkette · Produktbetrieb · universeller Prozess).
|
||||||
|
|
||||||
|
## 2. Capability Families — 75 MCAPs reduzieren sich auf 15 Familien
|
||||||
|
| Familie | Art | MCAPs | Domänen | Warum universell / spezifisch |
|
||||||
|
|---|---|---:|---:|---|
|
||||||
|
| **Risk** | core | 6 | 3 | Universeller Prozess — jede Regulierung verlangt eine Risikobeurteilung. |
|
||||||
|
| **Update** | core | 4 | 3 | Softwareprodukt — jedes vernetzte Produkt muss sicher aktualisierbar sein. |
|
||||||
|
| **Vulnerability** | core | 3 | 3 | Produktbetrieb — Schwächen über die Lebensdauer behandeln. |
|
||||||
|
| **Identity & Access** | core | 3 | 3 | Wer/was darf — Identität und Zugriff. |
|
||||||
|
| **Inventory & Composition** | core | 6 | 4 | Lieferkette/Stoffstrom — was steckt im Produkt? (SBOM = Software, Stoffliste = Material). |
|
||||||
|
| **Supplier** | core | 3 | 3 | Lieferantensteuerung — Verantwortung über die Kette. |
|
||||||
|
| **Incident & Reporting** | core | 2 | 2 | Vorfälle erkennen, behandeln und melden. |
|
||||||
|
| **Monitoring & Audit** | core | 3 | 3 | Beobachtung — Betrieb und Umfeld überwachen. |
|
||||||
|
| **Lifecycle & Development** | core | 3 | 3 | Produkt-/Software-Lebenszyklus. |
|
||||||
|
| **Documentation & Evidence** | core | 6 | 4 | Nachweisführung — Konformität dokumentieren. |
|
||||||
|
| **Configuration & Asset** | core | 2 | 2 | Konfiguration und Asset-Kontrolle. |
|
||||||
|
| **Environmental/Material** | domain | 9 | 1 | Umwelt-/Stoff-spezifisch. |
|
||||||
|
| **Medical** | domain | 7 | 3 | Medizin-/Patientensicherheit-spezifisch. |
|
||||||
|
| **Automotive** | domain | 4 | 1 | Automotive-/Funktionssicherheit-spezifisch. |
|
||||||
|
| **Process & QMS** | domain | 4 | 3 | QM-/Prozessdisziplin. |
|
||||||
|
| _(nicht zugeordnet)_ | — | 10 | — | Review: Familie fehlt oder Name untypisch |
|
||||||
|
|
||||||
|
→ Die Familien **erklären** die Konvergenz: unterschiedliche Regelwerke brauchen dieselben MCAPs, weil sie dieselbe FAMILIE adressieren. Vermutete Langzeit-Reduktion: ~15 Familien statt 75 Einzel-MCAPs.
|
||||||
|
|
||||||
|
## 3. Core vs Domain — eine BERECHNETE Eigenschaft (keine neue Klasse, keine Architektur)
|
||||||
|
- **Core (6):** kehren über ≥2 unabhängige Domänen UND ≥2 Quelltypen wieder — z. B. `access_control_and_authentication`, `incident_management`, `secure_development_lifecycle`, `secure_signed_update_distribution`, `supplier_security`, `technical_vulnerability_management` ….
|
||||||
|
- **Domain (61):** überwiegend EINE Fachdomäne — z. B. `account_energy_consumption`, `analyze_water_discharge`, `approve_production_parts_ppap`, `assess_software_process_capability`, `assign_unique_device_identification`, `ce_conformity_assessment_and_technical_documentation` ….
|
||||||
|
- **Bridging (8):** dazwischen (mehrere Domänen, aber 1 Quelltyp).
|
||||||
|
|
||||||
|
> **Befund:** Medical machte es offensichtlich — die neuen medizinischen Capabilities sind fast alle **Domain**, während Update/SBOM/Access/Logging **Core** sind. Die Zweiteilung ist eine **abgeleitete Eigenschaft** aus (Domänen × Quelltypen), kein neues Modell. Der eigentliche Burggraben ist die Erklärung, WARUM die Core-Familien existieren: sie sind die wenigen universellen Prinzipien (Risiko · Update · Identität · Inventar · Nachweis · Lieferant · Lebenszyklus), auf die sehr unterschiedliche Anforderungswelten immer wieder zurückfallen. Reine Aggregation, 0 Runtime, 0 neue Architektur.
|
||||||
|
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
# ruff: noqa
|
||||||
|
# mypy: ignore-errors
|
||||||
|
"""Capability Convergence Explanation — WHY do these capabilities converge? (Phase Ω, understand the core)
|
||||||
|
|
||||||
|
Medical proved the registry converges. The mature next step is NOT the next domain but understanding WHY:
|
||||||
|
not "which MCAPs?" but "why do different worlds keep needing the SAME ones?". Three derived views over
|
||||||
|
the existing data (no new runtime, no new architecture):
|
||||||
|
1. Why converge? — a domain matrix per core MCAP + a curated REASON (the moat: why it must exist)
|
||||||
|
2. Capability Families — the ~60 MCAPs reduce to a small set of families, each with a reason
|
||||||
|
3. Core vs Domain — a COMPUTED property (not stored): Core recurs across independent domains+types;
|
||||||
|
Domain stays within one. The split that Medical made obvious.
|
||||||
|
|
||||||
|
Non-runtime -> no deploy.
|
||||||
|
Run: cd backend-compliance && PYTHONPATH=. python3 reference_scenarios/capability_convergence_explanation.py
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
OUT = []
|
||||||
|
|
||||||
|
|
||||||
|
def w(s=""):
|
||||||
|
OUT.append(s)
|
||||||
|
|
||||||
|
|
||||||
|
_HERE = os.path.dirname(__file__)
|
||||||
|
_TP = os.path.join(_HERE, "..", "knowledge", "transition_patterns")
|
||||||
|
FAM = yaml.safe_load(open(os.path.join(_HERE, "..", "knowledge", "capability_families", "families.yaml"), encoding="utf-8"))["families"]
|
||||||
|
|
||||||
|
PATTERN_META = {
|
||||||
|
"transition_pattern_iso27001_to_cra_maschinenvo_v1.yaml": ("industrial_automation", "regulation", ["CRA", "MaschinenVO"]),
|
||||||
|
"transition_pattern_iso27001_to_cra_v1.yaml": ("industrial_automation", "regulation", ["CRA"]),
|
||||||
|
"transition_pattern_iso9001_to_cra_v1.yaml": ("industrial_automation", "regulation", ["CRA"]),
|
||||||
|
"transition_pattern_isms_to_tisax_v1.yaml": ("automotive", "certification", ["TISAX"]),
|
||||||
|
"transition_pattern_iso14001_to_environmental_v1.yaml": ("environmental", "regulation", ["ENV"]),
|
||||||
|
"transition_pattern_iso13485_to_medical_v1.yaml": ("medical", "regulation", ["MDR"]),
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = {}
|
||||||
|
|
||||||
|
|
||||||
|
def _e(c):
|
||||||
|
return idx.setdefault(c, {"domains": set(), "types": set(), "sources": set()})
|
||||||
|
|
||||||
|
|
||||||
|
for fname, (domain, ttype, default_sources) in PATTERN_META.items():
|
||||||
|
p = yaml.safe_load(open(os.path.join(_TP, fname), encoding="utf-8"))
|
||||||
|
cert = (p.get("transition_goal", {}).get("from", {}) or {}).get("standard", fname)
|
||||||
|
for a in p.get("likely_covered", []):
|
||||||
|
e = _e(a["capability"]); e["domains"].add(domain); e["types"].add("certification"); e["sources"].add(cert)
|
||||||
|
for d in p.get("delta_requirements", []):
|
||||||
|
e = _e(d["capability"]); e["domains"].add(domain); e["types"].add(ttype); e["sources"] |= set(d.get("covers_targets") or default_sources)
|
||||||
|
|
||||||
|
A = yaml.safe_load(open(os.path.join(_HERE, "..", "knowledge", "domains", "automotive", "source_capabilities.yaml"), encoding="utf-8"))
|
||||||
|
for s in A["sources"]:
|
||||||
|
for cap in s["requires"]:
|
||||||
|
e = _e(cap); e["domains"].add("automotive"); e["types"].add(s["type"]); e["sources"].add(s["id"])
|
||||||
|
|
||||||
|
|
||||||
|
def family_of(cap):
|
||||||
|
toks = set(cap.split("_"))
|
||||||
|
for f in FAM: # first family (core first) sharing a token wins
|
||||||
|
if toks & set(f["tokens"]):
|
||||||
|
return f
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
DOMAINS = ["industrial_automation", "automotive", "medical", "environmental"]
|
||||||
|
DLAB = {"industrial_automation": "Industrial", "automotive": "Automotive", "medical": "Medical", "environmental": "Environmental"}
|
||||||
|
|
||||||
|
w("# Capability Convergence Explanation — WARUM konvergieren diese Capabilities?")
|
||||||
|
w("")
|
||||||
|
w('_Nicht „welche MCAPs?", sondern „warum verlangen völlig verschiedene Welten immer wieder DIESELBEN?". Drei abgeleitete Sichten über vorhandene Daten (kein ML, keine neue Architektur). Der eigentliche Burggraben ist nicht „MCAP-X existiert", sondern „warum MCAP-X existieren MUSS"._')
|
||||||
|
w("")
|
||||||
|
|
||||||
|
# ── 1. Why converge? ──────────────────────────────────────────────────────
|
||||||
|
cross = sorted((c for c, e in idx.items() if len(e["domains"]) >= 2), key=lambda c: (-len(idx[c]["domains"]), c))
|
||||||
|
w("## 1. Warum konvergieren sie? — Domänen-Matrix + Grund")
|
||||||
|
w("| Capability | %s | Grund (Familie) |" % " | ".join(DLAB[d] for d in DOMAINS))
|
||||||
|
w("|---|%s|---|" % ("---|" * len(DOMAINS)))
|
||||||
|
for c in cross[:10]:
|
||||||
|
cells = ["✓" if d in idx[c]["domains"] else "–" for d in DOMAINS]
|
||||||
|
f = family_of(c)
|
||||||
|
w("| `%s` | %s | %s |" % (c, " | ".join(cells), (f["reason"] if f else "—")))
|
||||||
|
w("")
|
||||||
|
w("→ Das ist keine Statistik mehr, sondern **Erkenntnis**: dieselbe Fähigkeit kehrt wieder, weil ein universelles Prinzip dahinter steht (Softwareprodukt · Lieferkette · Produktbetrieb · universeller Prozess).")
|
||||||
|
w("")
|
||||||
|
|
||||||
|
# ── 2. Capability Families ─────────────────────────────────────────────────
|
||||||
|
fam_members = {f["id"]: [] for f in FAM}
|
||||||
|
unassigned = []
|
||||||
|
for c in idx:
|
||||||
|
f = family_of(c)
|
||||||
|
(fam_members[f["id"]] if f else unassigned).append(c)
|
||||||
|
w("## 2. Capability Families — %d MCAPs reduzieren sich auf %d Familien" % (len(idx), len([f for f in FAM if fam_members[f['id']]])))
|
||||||
|
w("| Familie | Art | MCAPs | Domänen | Warum universell / spezifisch |")
|
||||||
|
w("|---|---|---:|---:|---|")
|
||||||
|
for f in FAM:
|
||||||
|
ms = fam_members[f["id"]]
|
||||||
|
if not ms:
|
||||||
|
continue
|
||||||
|
doms = set()
|
||||||
|
for c in ms:
|
||||||
|
doms |= idx[c]["domains"]
|
||||||
|
w("| **%s** | %s | %d | %d | %s |" % (f["label"], f["kind"], len(ms), len(doms), f["reason"]))
|
||||||
|
if unassigned:
|
||||||
|
w("| _(nicht zugeordnet)_ | — | %d | — | Review: Familie fehlt oder Name untypisch |" % len(unassigned))
|
||||||
|
w("")
|
||||||
|
w("→ Die Familien **erklären** die Konvergenz: unterschiedliche Regelwerke brauchen dieselben MCAPs, weil sie dieselbe FAMILIE adressieren. Vermutete Langzeit-Reduktion: ~%d Familien statt %d Einzel-MCAPs." % (len([f for f in FAM if fam_members[f['id']]]), len(idx)))
|
||||||
|
w("")
|
||||||
|
|
||||||
|
# ── 3. Core vs Domain (COMPUTED, not stored) ──────────────────────────────
|
||||||
|
core = sorted(c for c, e in idx.items() if len(e["domains"]) >= 2 and len(e["types"]) >= 2)
|
||||||
|
domain_caps = sorted(c for c, e in idx.items() if len(e["domains"]) == 1)
|
||||||
|
bridging = [c for c in idx if c not in core and c not in domain_caps]
|
||||||
|
w("## 3. Core vs Domain — eine BERECHNETE Eigenschaft (keine neue Klasse, keine Architektur)")
|
||||||
|
w("- **Core (%d):** kehren über ≥2 unabhängige Domänen UND ≥2 Quelltypen wieder — z. B. %s." % (
|
||||||
|
len(core), ", ".join("`%s`" % c for c in core[:6]) + " …"))
|
||||||
|
w("- **Domain (%d):** überwiegend EINE Fachdomäne — z. B. %s." % (
|
||||||
|
len(domain_caps), ", ".join("`%s`" % c for c in domain_caps[:6]) + " …"))
|
||||||
|
w("- **Bridging (%d):** dazwischen (mehrere Domänen, aber 1 Quelltyp)." % len(bridging))
|
||||||
|
w("")
|
||||||
|
w('> **Befund:** Medical machte es offensichtlich — die neuen medizinischen Capabilities sind fast alle **Domain**, während Update/SBOM/Access/Logging **Core** sind. Die Zweiteilung ist eine **abgeleitete Eigenschaft** aus (Domänen × Quelltypen), kein neues Modell. Der eigentliche Burggraben ist die Erklärung, WARUM die Core-Familien existieren: sie sind die wenigen universellen Prinzipien (Risiko · Update · Identität · Inventar · Nachweis · Lieferant · Lebenszyklus), auf die sehr unterschiedliche Anforderungswelten immer wieder zurückfallen. Reine Aggregation, 0 Runtime, 0 neue Architektur.')
|
||||||
|
w("")
|
||||||
|
|
||||||
|
print("\n".join(OUT))
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
"""Capability Convergence Explanation — why the registry converges (Phase Ω, understand the core).
|
||||||
|
|
||||||
|
Pins the three derived views: the why-converge domain matrix (cross-domain core caps + a reason), the
|
||||||
|
family reduction (~60-70 MCAPs collapse to a small set of families), and the COMPUTED Core-vs-Domain
|
||||||
|
split (Core recurs across independent domains+types; Domain stays in one — which Medical made obvious).
|
||||||
|
"""
|
||||||
|
|
||||||
|
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/capability_convergence_explanation.py"],
|
||||||
|
cwd=root, env={**os.environ, "PYTHONPATH": "."}, capture_output=True, text=True,
|
||||||
|
)
|
||||||
|
assert r.returncode == 0, r.stderr
|
||||||
|
return r.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_runs_and_explains_why():
|
||||||
|
out = _run()
|
||||||
|
assert "WARUM konvergieren" in out
|
||||||
|
assert "Universeller Prozess" in out # a reason, not just a count
|
||||||
|
|
||||||
|
|
||||||
|
def test_cross_domain_core_caps_in_matrix():
|
||||||
|
out = _run()
|
||||||
|
for cap in ["secure_signed_update_distribution", "sbom_creation", "technical_vulnerability_management"]:
|
||||||
|
assert cap in out
|
||||||
|
|
||||||
|
|
||||||
|
def test_families_reduce_the_registry():
|
||||||
|
out = _run()
|
||||||
|
assert "Capability Families" in out
|
||||||
|
assert "reduzieren sich auf" in out
|
||||||
|
for fam in ["Risk", "Update", "Identity & Access", "Inventory & Composition"]:
|
||||||
|
assert fam in out
|
||||||
|
|
||||||
|
|
||||||
|
def test_core_vs_domain_is_computed():
|
||||||
|
out = _run()
|
||||||
|
assert "BERECHNETE Eigenschaft" in out
|
||||||
|
assert "**Core (" in out and "**Domain (" in out
|
||||||
Reference in New Issue
Block a user