From 80f2e2f61962d8611890e9e3b71829b442c9ab25 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Sun, 28 Jun 2026 12:09:52 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Medical=20stress=20test=20(safety+secur?= =?UTF-8?q?ity=20coupled)=20+=20Missing=20Convergence=20report=20(Phase=20?= =?UTF-8?q?=CE=A9=20#3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Medical before Payment: the harder scientific test (safety AND security coupled, full lifecycle, deep risk/evidence demands). ISO 13485 runs through the SAME engine as ISO 27001 -> CRA, only new data, 0 runtime. The key result: IEC 81001-5-1 (health-software security) pulls in the SAME security MCAPs as the CRA, so Medical REUSES cyber capabilities (the safety/security coupling appears as capability reuse) while adding 7 genuinely new medical caps (clinical evaluation, software safety classification, ISO 14971 risk file, benefit-risk). rejected_assumptions intact. Effect on the convergence core: secure_signed_update_distribution 18 -> 24 and technical_vulnerability_management 17 -> 23, now spanning 3 domains (cyber + industrial + medical) — the core visibly GROWS, exactly the convergence signal. New 5th report: MISSING CONVERGENCE — deterministic (no ML) token-cluster detector for potential structural duplications: a name token shared by >=3 MCAPs across >=2 distinct sources is flagged for EXPERT REVIEW (never auto-merged). Surfaces e.g. the `risk` cluster (6 risk MCAPs across 6 sources) and `security`/`software`; single-source decompositions are filtered out. Complements Suspicious by looking at cross-source duplication, not single MCAPs. Also records the durable modelling rule extracted from the frequency fix: evidence is attributed to its ORIGIN; its value against a target is computed later (relevance(evidence,target)). Ledger now 8 sources, Architecture Stability 8/8 = 100%. Non-runtime -> no deploy. 29 tests pass, check-loc 0. --- .../integration_ledger.yaml | 10 +++ ...sition_pattern_iso13485_to_medical_v1.yaml | 82 ++++++++++++++++++ .../architecture_stability_kpi.md | 13 +-- .../mcap_convergence_analysis.md | 38 ++++++--- .../mcap_convergence_analysis.py | 36 +++++++- .../medical_stress_test.md | 26 ++++++ .../medical_stress_test.py | 83 +++++++++++++++++++ .../tests/test_mcap_convergence_analysis.py | 23 +++-- .../tests/test_medical_stress_test.py | 58 +++++++++++++ 9 files changed, 343 insertions(+), 26 deletions(-) create mode 100644 backend-compliance/knowledge/transition_patterns/transition_pattern_iso13485_to_medical_v1.yaml create mode 100644 backend-compliance/reference_scenarios/medical_stress_test.md create mode 100644 backend-compliance/reference_scenarios/medical_stress_test.py create mode 100644 backend-compliance/tests/test_medical_stress_test.py diff --git a/backend-compliance/knowledge/architecture_stability/integration_ledger.yaml b/backend-compliance/knowledge/architecture_stability/integration_ledger.yaml index 0b0c18a4..21971c68 100644 --- a/backend-compliance/knowledge/architecture_stability/integration_ledger.yaml +++ b/backend-compliance/knowledge/architecture_stability/integration_ledger.yaml @@ -86,6 +86,16 @@ sources: integration_kind: data_only family: cyber # convergence test: same capability fed by many sources, model stayed stable exercised_by: "automotive_convergence_stress_test" + - source: "ISO 13485 -> Medical device (MDR / IEC 62304 / ISO 14971 / IEC 81001-5-1)" + domain: medical + target_type: regulation + integrated_as: transition_pattern_data + new_runtime_classes: 0 + new_pipeline: false + new_capability_types: 7 # of 11 delta caps, 4 REUSE cyber MCAPs (IEC 81001-5-1 = CRA security coupling) + integration_kind: data_only + family: non_cyber # safety/clinical domain WITH a security coupling — the harder joint test + exercised_by: "medical_stress_test" # --- One-time, domain-AGNOSTIC pipeline functions (built once, now FROZEN per Phase Ω). --- # Listed for honesty so the stability KPI cannot be gamed: these are NOT per-domain costs. The last diff --git a/backend-compliance/knowledge/transition_patterns/transition_pattern_iso13485_to_medical_v1.yaml b/backend-compliance/knowledge/transition_patterns/transition_pattern_iso13485_to_medical_v1.yaml new file mode 100644 index 00000000..9273b1b5 --- /dev/null +++ b/backend-compliance/knowledge/transition_patterns/transition_pattern_iso13485_to_medical_v1.yaml @@ -0,0 +1,82 @@ +# Transition KNOWLEDGE Pattern (TKP) — ISO 13485 (Medical QMS) -> Medical device compliance +# The HARDER scientific test (Phase Ω, test #3). Medical brings, at once, properties not yet jointly +# tested: safety and security TIGHTLY COUPLED, a full product lifecycle, very strong risk-management + +# evidence demands, and high regulatory depth. Sources: MDR, IEC 62304 (software lifecycle), +# ISO 14971 (risk management), IEC 81001-5-1 (health-software security). +# +# KEY for the convergence analysis: IEC 81001-5-1 (health-software security) REQUIRES the same security +# capabilities the CRA does (secure update, vulnerability management, access control, SBOM). So Medical +# REUSES the cyber MCAPs — the safety/security coupling shows up as capability reuse, growing the core +# into a 3rd domain. Alongside that, Medical adds genuinely new caps (clinical evaluation, software +# safety classification, the ISO 14971 risk file, benefit-risk). Capabilities are VERBS. Expert L1 draft. + +id: TP-ISO13485-MEDICAL-v1 +status: draft +version: 1 + +transition_goal: + from: + standard: "ISO 13485" + edition: "2016" + nature: organizational_medical_qms + to: + domain: "Medical device compliance (software-containing device)" + nature: product_safety_and_security + sources: ["MDR", "IEC_62304", "ISO_14971", "IEC_81001_5_1"] + one_line: "Move a manufacturer whose management system is ISO 13485 toward placing a software-containing medical device on the EU market." + +provenance: + author: "Claude (Reasoning session) — AI first draft (L1)" + basis: "ISO 13485:2016 (4.2 documentation, 7.3 design, 7.1/risk, 8.2.1 feedback/PMS, 8.5 CAPA) vs MDR + IEC 62304 + ISO 14971 + IEC 81001-5-1." + reviewed_by: null + validated_by: null + +disclaimer: > + Curated expert knowledge, NOT a normative proof. KEY INSIGHT: ISO 13485 is a medical QUALITY + management system — it gives QMS + design-control + risk-process + PMS discipline, but not the + concrete clinical, software-lifecycle, risk-file or product-security EVIDENCE. Safety and security + are coupled: IEC 81001-5-1 pulls in the SAME security capabilities the CRA requires. Welt-1. + +source_state_variants: + certified: "ISO 13485 certified -> QMS/design/risk-process assumptions hold; concrete evidence still missing." + qms_introduced: "QMS implemented but not certified -> downgrade 'partially_supports' to needs_confirmation." + +# ── A) LIKELY COVERED — medical QMS management discipline (partially_supports), NOT evidence. ── +likely_covered: + - {capability: manage_document_control, iso13485_basis: "4.2", relationship: partially_supports, confidence_source: relationship, verification: required, expected_evidence: [document_control_procedure], rationale: "ISO 13485 document control maintains records but creates no clinical/safety content.", reviewable_claim: "Document control maintains, not creates, medical evidence."} + - {capability: operate_capa_process, iso13485_basis: "8.5", relationship: partially_supports, confidence_source: relationship, verification: required, expected_evidence: [capa_procedure], rationale: "CAPA gives corrective/preventive discipline, not product safety evidence.", reviewable_claim: "CAPA does not establish device safety."} + - {capability: conduct_design_controls, iso13485_basis: "7.3", relationship: partially_supports, confidence_source: relationship, verification: required, expected_evidence: [design_history_file], rationale: "Design controls structure development but do not by themselves produce IEC 62304 software-lifecycle records.", reviewable_claim: "Design controls do not produce the IEC 62304 lifecycle records."} + - {capability: run_risk_management_process, iso13485_basis: "7.1", relationship: partially_supports, confidence_source: relationship, verification: required, expected_evidence: [risk_management_procedure], rationale: "ISO 13485 requires a risk-management PROCESS, but the ISO 14971 risk FILE with concrete analyses is separate.", reviewable_claim: "A risk-management process is not a completed ISO 14971 risk file."} + - {capability: control_suppliers_medical, iso13485_basis: "7.4", relationship: partially_supports, confidence_source: relationship, verification: required, expected_evidence: [supplier_controls], rationale: "Supplier controls give purchasing discipline, not component security.", reviewable_claim: "Medical supplier control does not establish component security."} + - {capability: operate_post_market_surveillance, iso13485_basis: "8.2.1", relationship: partially_supports, confidence_source: relationship, verification: required, expected_evidence: [pms_procedure], rationale: "Feedback/PMS process exists, but MDR PMS + vigilance reporting evidence is separate.", reviewable_claim: "A feedback process is not MDR post-market surveillance evidence."} + +# ── B) DELTA — concrete medical evidence + (coupled) product security. ── +delta_requirements: + # B1) safety/security COUPLING — IEC 81001-5-1 reuses the SAME cyber MCAPs as the CRA: + - {capability: secure_signed_update_distribution, missing_because: "QMS has no secure update.", why_asked: "IEC 81001-5-1 requires authenticity/integrity-protected health-software updates (= CRA).", dropped_if: ["Updates are signed and verified."], needed_information: verify_existence, covers_targets: [IEC_81001_5_1, MDR], expected_evidence: [config_export], priority: high, reviewable_claim: "ISO 13485 does not establish signed update distribution."} + - {capability: technical_vulnerability_management, missing_because: "QMS has no vulnerability management.", why_asked: "IEC 81001-5-1 requires handling health-software vulnerabilities (= CRA).", dropped_if: ["A vulnerability management process exists."], needed_information: verify_existence, covers_targets: [IEC_81001_5_1, MDR], expected_evidence: [vulnerability_management_procedure], priority: high, reviewable_claim: "ISO 13485 does not establish vulnerability management."} + - {capability: access_control_and_authentication, missing_because: "QMS has no product access control.", why_asked: "IEC 81001-5-1 requires authentication/access control for health software (= CRA).", dropped_if: ["Authentication is documented + tested."], needed_information: verify_existence, covers_targets: [IEC_81001_5_1], expected_evidence: [access_control_policy], priority: medium, reviewable_claim: "ISO 13485 does not establish product authentication."} + - {capability: sbom_creation, missing_because: "QMS produces no SBOM.", why_asked: "IEC 81001-5-1 expects a software bill of materials (= CRA).", dropped_if: ["A machine-readable SBOM is produced per release."], needed_information: determine_sbom_maturity, covers_targets: [IEC_81001_5_1], expected_evidence: [sbom], priority: high, reviewable_claim: "ISO 13485 does not produce an SBOM."} + # B2) genuinely NEW medical-specific evidence: + - {capability: conduct_clinical_evaluation, missing_because: "QMS produces no clinical evidence.", why_asked: "The MDR requires a clinical evaluation / clinical evidence.", dropped_if: ["A clinical evaluation report exists."], needed_information: request_evidence, covers_targets: [MDR], expected_evidence: [clinical_evaluation_report], priority: high, reviewable_claim: "ISO 13485 does not produce clinical evidence."} + - {capability: classify_software_safety_iec62304, missing_because: "QMS does not classify software safety.", why_asked: "IEC 62304 requires a software safety classification (Class A/B/C) driving the lifecycle.", dropped_if: ["A software safety classification exists."], needed_information: request_evidence, covers_targets: [IEC_62304], expected_evidence: [software_safety_classification], priority: high, reviewable_claim: "ISO 13485 does not classify software safety per IEC 62304."} + - {capability: maintain_risk_management_file_iso14971, missing_because: "QMS has a process, not the file.", why_asked: "ISO 14971 requires a maintained risk management file with concrete analyses + controls.", dropped_if: ["An ISO 14971 risk management file exists."], needed_information: request_evidence, covers_targets: [ISO_14971, MDR], expected_evidence: [risk_management_file], priority: high, reviewable_claim: "An ISO 13485 risk process is not a completed ISO 14971 risk file."} + - {capability: perform_benefit_risk_analysis, missing_because: "QMS does not weigh benefit vs risk.", why_asked: "The MDR + ISO 14971 require a documented benefit-risk determination.", dropped_if: ["A benefit-risk analysis exists."], needed_information: request_evidence, covers_targets: [MDR, ISO_14971], expected_evidence: [benefit_risk_analysis], priority: medium, reviewable_claim: "ISO 13485 does not document a benefit-risk analysis."} + - {capability: implement_software_lifecycle_iec62304, missing_because: "QMS has design controls, not the IEC 62304 lifecycle.", why_asked: "IEC 62304 requires a defined software development + maintenance lifecycle.", dropped_if: ["IEC 62304 lifecycle records exist."], needed_information: request_evidence, covers_targets: [IEC_62304], expected_evidence: [software_lifecycle_records], priority: high, reviewable_claim: "ISO 13485 does not produce IEC 62304 lifecycle records."} + - {capability: assign_unique_device_identification, missing_because: "QMS has no UDI.", why_asked: "The MDR requires UDI assignment + registration.", dropped_if: ["UDI is assigned and registered."], needed_information: verify_existence, covers_targets: [MDR], expected_evidence: [udi_record], priority: medium, reviewable_claim: "ISO 13485 does not assign UDI."} + - {capability: compile_medical_technical_documentation, missing_because: "QMS has no MDR technical documentation.", why_asked: "The MDR (Annex II/III) requires complete technical documentation + DoC.", dropped_if: ["MDR technical documentation exists."], needed_information: request_evidence, covers_targets: [MDR], expected_evidence: [technical_documentation, declaration_of_conformity], priority: high, reviewable_claim: "ISO 13485 does not satisfy MDR technical documentation."} + +rejected_assumptions: + - "ISO 13485 does NOT produce clinical evidence or a clinical evaluation." + - "ISO 13485 does NOT produce the ISO 14971 risk management FILE (only the process)." + - "ISO 13485 does NOT produce IEC 62304 software-lifecycle records or a software safety classification." + - "ISO 13485 does NOT establish health-software security (IEC 81001-5-1 = the same security caps as the CRA)." + +determinism_goal: > + Two independent auditors should agree that an ISO-13485-only manufacturer has medical QMS discipline + but is missing the clinical, software-lifecycle, risk-file and product-security evidence — and that the + security part is the SAME capability set as the CRA (safety/security coupling). + +review_checklist: + - "Confirm delta + rejected_assumptions with a medical regulatory expert." + - "Replace capability ids with Capability Registry MCAP ids once assigned." diff --git a/backend-compliance/reference_scenarios/architecture_stability_kpi.md b/backend-compliance/reference_scenarios/architecture_stability_kpi.md index 6d7534a4..098f24b0 100644 --- a/backend-compliance/reference_scenarios/architecture_stability_kpi.md +++ b/backend-compliance/reference_scenarios/architecture_stability_kpi.md @@ -13,11 +13,12 @@ _Der Fokus hat sich verschoben: nicht mehr „kann die Architektur das?", sonder | OEM Specification (Lastenheft) | cyber | 0 | 0 | 4 | ✅ | | ISO 14001 -> Environmental/Material (REACH/RoHS/Batterie/Wasser/Energie/Abfall) | non_cyber | 0 | 0 | 16 | ✅ | | Automotive ECU for OEM X (CRA / UNECE R155+R156 / IATF 16949 / TISAX / ASPICE / OEM spec) | cyber | 0 | 0 | 14 | ✅ | +| ISO 13485 -> Medical device (MDR / IEC 62304 / ISO 14971 / IEC 81001-5-1) | non_cyber | 0 | 0 | 7 | ✅ | -- **Architecture Stability: 7/7 = 100%** der Quellen ohne neue Runtime-Klasse und ohne neue Pipeline. -- **Knowledge Velocity: 7/7 = 100%** der Quellen **data-only** integriert (kein Entwickler nötig). -- **Generalität über Cyber hinaus: 1/7 Quellen NICHT-Cyber** (Umwelt) — trugen die Pipeline ebenfalls 0/0. Das ist der eigentliche Test (ein anderes Denkmodell, nicht noch ein Cyber-Regelwerk). -- **Capability-Modell-Frühindikator: 59 neue Typen gesamt, Maximum 16** (Umwelt, erste Nicht-Cyber-Domäne) — in Range, KEIN Granularitätsalarm (Alarm ≈ eine Domäne braucht plötzlich ~80 neue Typen bei 0 Runtime-Change → Modell zu grob/fein). +- **Architecture Stability: 8/8 = 100%** der Quellen ohne neue Runtime-Klasse und ohne neue Pipeline. +- **Knowledge Velocity: 8/8 = 100%** der Quellen **data-only** integriert (kein Entwickler nötig). +- **Generalität über Cyber hinaus: 2/8 Quellen NICHT-Cyber** (Umwelt) — trugen die Pipeline ebenfalls 0/0. Das ist der eigentliche Test (ein anderes Denkmodell, nicht noch ein Cyber-Regelwerk). +- **Capability-Modell-Frühindikator: 66 neue Typen gesamt, Maximum 16** (Umwelt, erste Nicht-Cyber-Domäne) — in Range, KEIN Granularitätsalarm (Alarm ≈ eine Domäne braucht plötzlich ~80 neue Typen bei 0 Runtime-Change → Modell zu grob/fein). ## Ehrlichkeit: die Pipeline-Funktionen sind EINMALIG (jetzt eingefroren) - 6 domänen-AGNOSTISCHE Funktionen, einmal gebaut, nicht je Domäne: `transition_reasoning (RS-005)`, `optimization`, `journey_matcher (ADR-011)`, `playbook`, `completeness`, `company (2A)`. @@ -31,8 +32,8 @@ _Der Fokus hat sich verschoben: nicht mehr „kann die Architektur das?", sonder | **Produktion** (wie TUN/BEWEISEN) | Playbooks, Verification, Reference Scenarios | ## Die drei Erfolgsfragen ab jetzt (statt Coverage) -1. **Musste für eine neue Domäne Runtime-Code geändert werden?** → bisher: **nein** (7/7). -2. **Knowledge Velocity** — neues Wissen ohne Entwickler aufnehmbar? → bisher: **ja** (7/7 data-only). +1. **Musste für eine neue Domäne Runtime-Code geändert werden?** → bisher: **nein** (8/8). +2. **Knowledge Velocity** — neues Wissen ohne Entwickler aufnehmbar? → bisher: **ja** (8/8 data-only). 3. **Architecture Stability** — bestehende Capability/Journey strukturell ändern oder nur Daten ergänzen? → bisher: **nur Daten**. > **Befund:** Über fünf Zielarten und sechs Quellen blieb `Reality → Evidence → Capability → Required → Delta → Journey → Roadmap → Playbooks → Verification` unverändert. Das ist der eigentliche Nachweis: keine Compliance-Architektur, sondern eine allgemeine Requirements-Verifikationsarchitektur, die ihre Generalität UNTER realer fachlicher Belastung behält. Der nächste Test ist nicht ein Feature, sondern die nächste echte Domäne (Umwelt-Cluster · Automotive · Medizintechnik · Payment) — jede als neue Ledger-Zeile, bei stabilem KPI. diff --git a/backend-compliance/reference_scenarios/mcap_convergence_analysis.md b/backend-compliance/reference_scenarios/mcap_convergence_analysis.md index 244df7e0..18a8a402 100644 --- a/backend-compliance/reference_scenarios/mcap_convergence_analysis.md +++ b/backend-compliance/reference_scenarios/mcap_convergence_analysis.md @@ -1,47 +1,59 @@ # Cross-Domain MCAP Convergence Analysis — wo konvergiert das Wissensmodell? -_Nicht „welche MCAPs kommen am häufigsten vor?" (Häufigkeit täuscht), sondern „welche MCAPs TRAGEN den größten Teil des Systems?". Deterministischer **Impact-Score** (kein ML), internes Engineering-Werkzeug, reine Aggregation über vorhandene Daten (5 Transition Patterns + 7 Automotive-Quellen). Non-runtime, keine echten Namen._ +_Nicht „welche MCAPs kommen am häufigsten vor?" (Häufigkeit täuscht), sondern „welche MCAPs TRAGEN den größten Teil des Systems?". Deterministischer **Impact-Score** (kein ML), internes Engineering-Werkzeug, reine Aggregation über vorhandene Daten (6 Transition Patterns inkl. Medical + 7 Automotive-Quellen). Non-runtime, keine echten Namen._ ## Impact-Score (deterministisch) > `Impact = distinct Sources + distinct Target-Types + distinct Domains + distinct Journeys + Regulatory Leverage + Business Leverage` -- 62 distinct Capabilities (MCAP-Kandidaten) über alle Quellen aggregiert. +- 75 distinct Capabilities (MCAP-Kandidaten) über alle Quellen aggregiert. ## 1. Core MCAPs — höchster Impact (die tragenden Knoten) | Capability | Impact | Sources | Types | Domains | Journeys | |---|---:|---:|---:|---:|---:| -| `secure_signed_update_distribution` | **18** | 5 | 2 | 2 | 4 | -| `technical_vulnerability_management` | **17** | 5 | 3 | 2 | 4 | -| `access_control_and_authentication` | **15** | 4 | 2 | 2 | 5 | +| `secure_signed_update_distribution` | **24** | 7 | 2 | 3 | 5 | +| `technical_vulnerability_management` | **23** | 7 | 3 | 3 | 5 | +| `access_control_and_authentication` | **19** | 5 | 2 | 3 | 6 | | `incident_management` | **14** | 4 | 2 | 2 | 4 | | `product_cyber_risk_assessment` | **13** | 3 | 1 | 2 | 4 | +| `sbom_creation` | **13** | 2 | 1 | 3 | 5 | | `secure_development_lifecycle` | **11** | 2 | 2 | 2 | 4 | | `supplier_security` | **11** | 3 | 2 | 2 | 3 | | `ce_conformity_assessment_and_technical_documentation` | **9** | 2 | 1 | 1 | 3 | | `coordinated_vulnerability_disclosure` | **9** | 1 | 1 | 2 | 4 | -| `sbom_creation` | **9** | 1 | 1 | 2 | 4 | → Hoher Impact = ein Knoten verbindet viele Quellen ÜBER Typen/Domänen/Journeys hinweg — nicht „in 40 Dokumenten einer Normenfamilie". ## 2. Emerging MCAPs — verbinden ≥2 Domänen (Brücken zwischen Anforderungswelten) -- `secure_signed_update_distribution` — 2 Domänen (automotive, industrial_automation), 2 Typen. -- `technical_vulnerability_management` — 2 Domänen (automotive, industrial_automation), 3 Typen. -- `access_control_and_authentication` — 2 Domänen (automotive, industrial_automation), 2 Typen. +- `secure_signed_update_distribution` — 3 Domänen (automotive, industrial_automation, medical), 2 Typen. +- `technical_vulnerability_management` — 3 Domänen (automotive, industrial_automation, medical), 3 Typen. +- `access_control_and_authentication` — 3 Domänen (automotive, industrial_automation, medical), 2 Typen. - `incident_management` — 2 Domänen (automotive, industrial_automation), 2 Typen. - `product_cyber_risk_assessment` — 2 Domänen (automotive, industrial_automation), 1 Typen. +- `sbom_creation` — 3 Domänen (automotive, industrial_automation, medical), 1 Typen. - `secure_development_lifecycle` — 2 Domänen (automotive, industrial_automation), 2 Typen. - `supplier_security` — 2 Domänen (automotive, industrial_automation), 2 Typen. -- `coordinated_vulnerability_disclosure` — 2 Domänen (automotive, industrial_automation), 1 Typen. - _(Echtes „Wachstum über Zeit" braucht historische Snapshots — hier Proxy = Domänen-Spannweite jetzt.)_ ## 3. Isolated MCAPs — nur 1 Quelle/Journey (Review: spezialisiert ODER Konvergenz übersehen?) -- 36 Stück, u. a.: `account_energy_consumption`, `cybersecurity_management_system`, `document_update_campaigns`, `document_waste_streams`, `issue_battery_passport`, `machine_safety_risk_assessment`, `measure_air_emissions`, `mechanical_safety_and_guards`. +- 47 Stück, u. a.: `account_energy_consumption`, `assign_unique_device_identification`, `classify_software_safety_iec62304`, `compile_medical_technical_documentation`, `conduct_clinical_evaluation`, `cybersecurity_management_system`, `document_update_campaigns`, `document_waste_streams`. ## 4. Suspicious MCAPs — Abstraktionsgrad-Verdacht (Experten-Review) - **Evtl. zu grob** (generisches Verb, breit aber nur 1 Typ): `document_and_change_control`, `manage_chemical_substances`. -- **Evtl. zu fein** (isoliert + sehr spezifischer Name): `operating_instructions_and_safety_information`, `provide_dedicated_security_contact`, `provide_functional_safety_evidence`, `restrict_hazardous_substances_rohs`, `secure_by_default_no_default_credentials`, `threat_analysis_and_risk_assessment`. +- **Evtl. zu fein** (isoliert + sehr spezifischer Name): `assign_unique_device_identification`, `compile_medical_technical_documentation`, `implement_software_lifecycle_iec62304`, `operating_instructions_and_safety_information`, `provide_dedicated_security_contact`, `provide_functional_safety_evidence`. - Die Analyse sagt damit nicht nur WELCHE MCAPs wichtig sind, sondern auch, ob sie auf dem **richtigen Abstraktionsniveau** definiert sind. +## 5. Missing Convergence — mögliche strukturelle Doppelungen (Experten-Review, KEIN Auto-Merge) +> Nicht „welche MCAPs existieren?", sondern „welche hätte ich aufgrund der Daten ERWARTET, existieren aber als GETRENNTE MCAPs?". Deterministische Heuristik (kein ML): geteiltes Namens-Token über ≥3 MCAPs UND ≥2 verschiedene Quellen = Konvergenz-Kandidat (eine Einzelquelle-Zerlegung zählt NICHT). Nur anzeigen, nie automatisch zusammenführen. + +- **Token `secure` → 3 MCAPs / 8 Quellen:** `secure_by_default_no_default_credentials`, `secure_development_lifecycle`, `secure_signed_update_distribution` — _Review: eine Fähigkeit in mehreren Facetten?_ +- **Token `update` → 4 MCAPs / 7 Quellen:** `document_update_campaigns`, `secure_signed_update_distribution`, `security_update_support_period`, `software_update_management_system` — _Review: eine Fähigkeit in mehreren Facetten?_ +- **Token `risk` → 6 MCAPs / 6 Quellen:** `machine_safety_risk_assessment`, `maintain_risk_management_file_iso14971`, `perform_benefit_risk_analysis`, `product_cyber_risk_assessment`, `run_risk_management_process`, `threat_analysis_and_risk_assessment` — _Review: eine Fähigkeit in mehreren Facetten?_ +- **Token `document` → 5 MCAPs / 6 Quellen:** `document_and_change_control`, `document_update_campaigns`, `document_waste_streams`, `manage_document_control`, `treat_and_document_wastewater` — _Review: eine Fähigkeit in mehreren Facetten?_ +- **Token `security` → 8 MCAPs / 4 Quellen:** `information_security_management`, `physical_security`, `provide_dedicated_security_contact`, `public_security_advisories`, `security_awareness_training`, `security_logging_and_monitoring`, `security_update_support_period`, `supplier_security` — _Review: eine Fähigkeit in mehreren Facetten?_ +- **Token `safety` → 6 MCAPs / 4 Quellen:** `classify_software_safety_iec62304`, `machine_safety_risk_assessment`, `mechanical_safety_and_guards`, `operating_instructions_and_safety_information`, `protection_against_corruption_of_safety_functions`, `provide_functional_safety_evidence` — _Review: eine Fähigkeit in mehreren Facetten?_ + +→ Ergänzt `Suspicious`: dieser Report schaut nicht auf einzelne MCAPs, sondern auf **strukturelle Doppelungen** über Quellen hinweg — der häufigste systematische Modellierungsfehler. + ## Befund -> **Ein Kern beginnt sich zu zeigen:** 11 von 62 Capabilities erreichen Impact ≥ 8 (tragende Knoten), 14 verbinden ≥2 Domänen. Bislang ist das Wissensmodell noch jung (5 Patterns + 1 Automotive-Profil), aber die Methode steht: sobald Medical/Payment/weitere Domänen als DATEN hinzukommen, zeigt dieselbe Aggregation, ob sich der erwartete stabile Kern von 30–50 hochkonvergenten MCAPs bildet — der gemeinsame Strukturkern hinter sehr unterschiedlichen Anforderungswelten. Das ist ein tieferer Wertnachweis als „eine weitere Norm unterstützt". Reine Aggregation, 0 Runtime, 0 neue Architektur. +> **Ein Kern beginnt sich zu zeigen:** 11 von 75 Capabilities erreichen Impact ≥ 8 (tragende Knoten), 14 verbinden ≥2 Domänen. Mit Medical (6 Patterns inkl. ISO 13485 + Automotive) zeigt sich erstmals die **Safety/Security-Kopplung als Capability-REUSE**: IEC 81001-5-1 zieht dieselben Security-MCAPs wie die CRA herein → diese Knoten spannen jetzt Cyber + Maschinenbau + Automotive + Medizin. Die Methode steht; sobald Payment/weitere Domänen als DATEN kommen, zeigt dieselbe Aggregation (+ der neue Missing-Convergence-Report), ob sich der erwartete stabile Kern von 30–50 hochkonvergenten MCAPs bildet — der gemeinsame Strukturkern hinter sehr unterschiedlichen Anforderungswelten. Tieferer Wertnachweis als „eine weitere Norm unterstützt". Reine Aggregation, 0 Runtime, 0 neue Architektur. diff --git a/backend-compliance/reference_scenarios/mcap_convergence_analysis.py b/backend-compliance/reference_scenarios/mcap_convergence_analysis.py index d6a47a59..b4974451 100644 --- a/backend-compliance/reference_scenarios/mcap_convergence_analysis.py +++ b/backend-compliance/reference_scenarios/mcap_convergence_analysis.py @@ -42,6 +42,8 @@ PATTERN_META = { "transition_pattern_isms_to_tisax_v1.yaml": ("automotive", "certification", ["TISAX"]), "transition_pattern_iso14001_to_environmental_v1.yaml": ("environmental", "regulation", ["REACH", "RoHS", "Batterieverordnung", "Wasserrecht", "Abwasservorschriften", "Energiemanagement", "Kreislaufwirtschaft", "Emissionsschutz"]), + "transition_pattern_iso13485_to_medical_v1.yaml": ("medical", "regulation", + ["MDR", "IEC_62304", "ISO_14971", "IEC_81001_5_1"]), } # capability -> dict of sets we aggregate @@ -95,7 +97,7 @@ GENERIC = ("document_", "manage_", "control_", "conduct_", "operate_", "run_", " w("# Cross-Domain MCAP Convergence Analysis — wo konvergiert das Wissensmodell?") w("") -w('_Nicht „welche MCAPs kommen am häufigsten vor?" (Häufigkeit täuscht), sondern „welche MCAPs TRAGEN den größten Teil des Systems?". Deterministischer **Impact-Score** (kein ML), internes Engineering-Werkzeug, reine Aggregation über vorhandene Daten (5 Transition Patterns + 7 Automotive-Quellen). Non-runtime, keine echten Namen._') +w('_Nicht „welche MCAPs kommen am häufigsten vor?" (Häufigkeit täuscht), sondern „welche MCAPs TRAGEN den größten Teil des Systems?". Deterministischer **Impact-Score** (kein ML), internes Engineering-Werkzeug, reine Aggregation über vorhandene Daten (6 Transition Patterns inkl. Medical + 7 Automotive-Quellen). Non-runtime, keine echten Namen._') w("") w("## Impact-Score (deterministisch)") w("> `Impact = distinct Sources + distinct Target-Types + distinct Domains + distinct Journeys + Regulatory Leverage + Business Leverage`") @@ -135,12 +137,42 @@ w("- **Evtl. zu fein** (isoliert + sehr spezifischer Name): %s." % (", ".join("` w("- Die Analyse sagt damit nicht nur WELCHE MCAPs wichtig sind, sondern auch, ob sie auf dem **richtigen Abstraktionsniveau** definiert sind.") w("") +# ── 5. Missing Convergence — potential structural duplications (token clusters) ────────────── +STOP = {"and", "of", "the", "for", "to", "a", "an", "no", "on", "in", "by", "with", "per"} +GENERIC_TOK = {"management", "process", "control", "distribution", "documentation", "technical", + "internal", "continual", "assessment", "evidence"} +tok2caps = {} +for cap in idx: + for t in cap.split("_"): + if len(t) >= 4 and t not in STOP and t not in GENERIC_TOK: + tok2caps.setdefault(t, set()).add(cap) +# cross-source signal only: a token shared by >=3 MCAPs that span >=2 distinct sources (one source's +# own decomposition is NOT a duplication candidate — that is intended granularity). +clusters = [] +for t, cs in tok2caps.items(): + if len(cs) >= 3: + srcs = set() + for c in cs: + srcs |= idx[c]["sources"] + if len(srcs) >= 2: + clusters.append((t, sorted(cs), len(srcs))) +clusters.sort(key=lambda x: (-x[2], -len(x[1]), x[0])) +w("## 5. Missing Convergence — mögliche strukturelle Doppelungen (Experten-Review, KEIN Auto-Merge)") +w('> Nicht „welche MCAPs existieren?", sondern „welche hätte ich aufgrund der Daten ERWARTET, existieren aber als GETRENNTE MCAPs?". Deterministische Heuristik (kein ML): geteiltes Namens-Token über ≥3 MCAPs UND ≥2 verschiedene Quellen = Konvergenz-Kandidat (eine Einzelquelle-Zerlegung zählt NICHT). Nur anzeigen, nie automatisch zusammenführen.') +w("") +for t, cs, ns in clusters[:6]: + w("- **Token `%s` → %d MCAPs / %d Quellen:** %s — _Review: eine Fähigkeit in mehreren Facetten?_" % ( + t, len(cs), ns, ", ".join("`%s`" % c for c in cs))) +w("") +w("→ Ergänzt `Suspicious`: dieser Report schaut nicht auf einzelne MCAPs, sondern auf **strukturelle Doppelungen** über Quellen hinweg — der häufigste systematische Modellierungsfehler.") +w("") + # ── Befund ───────────────────────────────────────────────────────────────── core_cut = [c for c, e in scored if impact(e) >= 8] cross = [c for c, e in scored if len(e["domains"]) >= 2] w("## Befund") w("") -w('> **Ein Kern beginnt sich zu zeigen:** %d von %d Capabilities erreichen Impact ≥ 8 (tragende Knoten), %d verbinden ≥2 Domänen. Bislang ist das Wissensmodell noch jung (5 Patterns + 1 Automotive-Profil), aber die Methode steht: sobald Medical/Payment/weitere Domänen als DATEN hinzukommen, zeigt dieselbe Aggregation, ob sich der erwartete stabile Kern von 30–50 hochkonvergenten MCAPs bildet — der gemeinsame Strukturkern hinter sehr unterschiedlichen Anforderungswelten. Das ist ein tieferer Wertnachweis als „eine weitere Norm unterstützt". Reine Aggregation, 0 Runtime, 0 neue Architektur.' % (len(core_cut), len(idx), len(cross))) +w('> **Ein Kern beginnt sich zu zeigen:** %d von %d Capabilities erreichen Impact ≥ 8 (tragende Knoten), %d verbinden ≥2 Domänen. Mit Medical (6 Patterns inkl. ISO 13485 + Automotive) zeigt sich erstmals die **Safety/Security-Kopplung als Capability-REUSE**: IEC 81001-5-1 zieht dieselben Security-MCAPs wie die CRA herein → diese Knoten spannen jetzt Cyber + Maschinenbau + Automotive + Medizin. Die Methode steht; sobald Payment/weitere Domänen als DATEN kommen, zeigt dieselbe Aggregation (+ der neue Missing-Convergence-Report), ob sich der erwartete stabile Kern von 30–50 hochkonvergenten MCAPs bildet — der gemeinsame Strukturkern hinter sehr unterschiedlichen Anforderungswelten. Tieferer Wertnachweis als „eine weitere Norm unterstützt". Reine Aggregation, 0 Runtime, 0 neue Architektur.' % (len(core_cut), len(idx), len(cross))) w("") print("\n".join(OUT)) diff --git a/backend-compliance/reference_scenarios/medical_stress_test.md b/backend-compliance/reference_scenarios/medical_stress_test.md new file mode 100644 index 00000000..231f5aff --- /dev/null +++ b/backend-compliance/reference_scenarios/medical_stress_test.md @@ -0,0 +1,26 @@ +# Medical Stress Test — Safety + Security gekoppelt, der härtere Test (Phase Ω #3) + +_Medical prüft erstmals gemeinsam: Safety UND Security gekoppelt, voller Produktlebenszyklus, sehr starke Risikomanagement-/Nachweispflichten, hohe regulatorische Tiefe. ISO 13485 als Company Profile durch DIESELBE Engine — nur neue Daten, 0 Runtime. Synthetisch, keine echten Namen._ + +## 1. ISO 13485 als Profil → Delta über dieselbe Engine +- ISO 13485 liefert medizinische QMS-Disziplin (Welt-1): `manage_document_control`, `operate_capa_process`, `conduct_design_controls`, `run_risk_management_process`. … +- Delta (fehlt): **11** Capabilities — über dieselbe `assess_transition`, **0 neue Runtime-Klassen**. + +## 2. Safety/Security-KOPPLUNG — Medical REUSED Cyber-MCAPs (IEC 81001-5-1 = CRA-Security) +- **Wiederverwendete Cyber-Capabilities (4):** `access_control_and_authentication`, `sbom_creation`, `secure_signed_update_distribution`, `technical_vulnerability_management`. +- → Genau das ist die Kopplung: die Gesundheitssoftware-Security (IEC 81001-5-1) fordert **dieselben** Fähigkeiten wie die CRA. Diese MCAPs wandern damit in eine **dritte Domäne** und werden im Convergence-Core noch zentraler. + +## 3. Genuin neue, medizin-spezifische Capabilities +- **Neu (7):** `assign_unique_device_identification`, `classify_software_safety_iec62304`, `compile_medical_technical_documentation`, `conduct_clinical_evaluation`, `implement_software_lifecycle_iec62304`, `maintain_risk_management_file_iso14971`, `perform_benefit_risk_analysis`. +- Capabilities als Verben: `conduct_clinical_evaluation`, `classify_software_safety_iec62304`, `maintain_risk_management_file_iso14971`, `perform_benefit_risk_analysis`. + +## 4. Was ISO 13485 typischerweise NICHT erzeugt _(rejected_assumptions, Welt-1/Welt-2)_ +- ISO 13485 does NOT produce clinical evidence or a clinical evaluation. +- ISO 13485 does NOT produce the ISO 14971 risk management FILE (only the process). +- ISO 13485 does NOT produce IEC 62304 software-lifecycle records or a software safety classification. +- ISO 13485 does NOT establish health-software security (IEC 81001-5-1 = the same security caps as the CRA). + +## Befund + +> **Die härteste Domäne bisher (Safety+Security gekoppelt, voller Lebenszyklus, tiefe Risiko-/Nachweispflicht) lief durch die unveränderte Pipeline — 0 neue Runtime-Klassen, nur ein Pattern-YAML.** Das stärkste Einzelsignal: **4 Security-Capabilities werden aus dem Cyber-Bestand WIEDERVERWENDET** (IEC 81001-5-1 = CRA), während **7 medizin-spezifische** neu hinzukommen. Genau so wächst ein Kern: gemeinsame Fähigkeiten verbinden Cyber, Maschinenbau, Automotive UND Medizin; das Domänenspezifische bleibt am Rand. Architecture Stability bleibt stabil; der Engpass ist jetzt die Qualität der Wissensmodellierung, nicht die Architektur. + diff --git a/backend-compliance/reference_scenarios/medical_stress_test.py b/backend-compliance/reference_scenarios/medical_stress_test.py new file mode 100644 index 00000000..09598109 --- /dev/null +++ b/backend-compliance/reference_scenarios/medical_stress_test.py @@ -0,0 +1,83 @@ +# ruff: noqa +# mypy: ignore-errors +"""Medical stress test — the harder scientific test: safety + security coupled (Phase Ω #3). + +Medical jointly tests properties not yet tested together: safety and security TIGHTLY COUPLED, a full +product lifecycle, very strong risk-management/evidence demands, high regulatory depth. ISO 13485 (a +medical QMS) is run as a Company Profile through the SAME engine as before — only new DATA, 0 runtime. + +The interesting result: IEC 81001-5-1 (health-software security) requires the SAME security capabilities +as the CRA, so Medical REUSES cyber MCAPs (the coupling shows up as capability reuse, growing the core), +while ALSO adding genuinely new medical caps (clinical evaluation, software safety classification, the +ISO 14971 risk file, benefit-risk). Synthetic, no real names. Non-runtime -> no deploy. +Run: cd backend-compliance && PYTHONPATH=. python3 reference_scenarios/medical_stress_test.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) + + +_TP = os.path.join(os.path.dirname(__file__), "..", "knowledge", "transition_patterns") +MED = yaml.safe_load(open(os.path.join(_TP, "transition_pattern_iso13485_to_medical_v1.yaml"), encoding="utf-8")) + +# existing capability universe (everything modelled before Medical) — to detect reuse vs new +known = set() +for f in os.listdir(_TP): + if f.endswith(".yaml") and "iso13485" not in f: + p = yaml.safe_load(open(os.path.join(_TP, f), encoding="utf-8")) + known |= {a["capability"] for a in p.get("likely_covered", [])} + known |= {d["capability"] for d in p.get("delta_requirements", [])} + +mgmt = [a["capability"] for a in MED["likely_covered"]] +delta_caps = [d["capability"] for d in MED["delta_requirements"]] +profile = build_company_profile( + CompanyContext(company_id="med", certifications=[Certification(certification_id="ISO13485")]), + {"ISO13485": CapabilityMappingEntry(capability_ids=mgmt, confidence=Confidence.MEDIUM)}) +assess = assess_transition(TransitionContext(company_id="med", target=TransitionGoal(target_id="Medical")), + [TargetRequirement(capability_id=c) for c in mgmt + delta_caps], profile) +delta = sorted({c.capability_id for c in assess.coverage if c.status == CoverageStatus.MISSING}) + +reused = sorted(c for c in delta if c in known) # safety/security coupling: cyber caps reused +fresh = sorted(c for c in delta if c not in known) # genuinely new medical caps + +w("# Medical Stress Test — Safety + Security gekoppelt, der härtere Test (Phase Ω #3)") +w("") +w('_Medical prüft erstmals gemeinsam: Safety UND Security gekoppelt, voller Produktlebenszyklus, sehr starke Risikomanagement-/Nachweispflichten, hohe regulatorische Tiefe. ISO 13485 als Company Profile durch DIESELBE Engine — nur neue Daten, 0 Runtime. Synthetisch, keine echten Namen._') +w("") +w("## 1. ISO 13485 als Profil → Delta über dieselbe Engine") +w("- ISO 13485 liefert medizinische QMS-Disziplin (Welt-1): %s." % ", ".join("`%s`" % c for c in mgmt[:4]) + " …") +w("- Delta (fehlt): **%d** Capabilities — über dieselbe `assess_transition`, **0 neue Runtime-Klassen**." % len(delta)) +w("") +w("## 2. Safety/Security-KOPPLUNG — Medical REUSED Cyber-MCAPs (IEC 81001-5-1 = CRA-Security)") +w("- **Wiederverwendete Cyber-Capabilities (%d):** %s." % (len(reused), ", ".join("`%s`" % c for c in reused))) +w("- → Genau das ist die Kopplung: die Gesundheitssoftware-Security (IEC 81001-5-1) fordert **dieselben** Fähigkeiten wie die CRA. Diese MCAPs wandern damit in eine **dritte Domäne** und werden im Convergence-Core noch zentraler.") +w("") +w("## 3. Genuin neue, medizin-spezifische Capabilities") +w("- **Neu (%d):** %s." % (len(fresh), ", ".join("`%s`" % c for c in fresh))) +w("- Capabilities als Verben: `conduct_clinical_evaluation`, `classify_software_safety_iec62304`, `maintain_risk_management_file_iso14971`, `perform_benefit_risk_analysis`.") +w("") +w("## 4. Was ISO 13485 typischerweise NICHT erzeugt _(rejected_assumptions, Welt-1/Welt-2)_") +for r in MED["rejected_assumptions"]: + w("- %s" % r) +w("") +w("## Befund") +w("") +w('> **Die härteste Domäne bisher (Safety+Security gekoppelt, voller Lebenszyklus, tiefe Risiko-/Nachweispflicht) lief durch die unveränderte Pipeline — 0 neue Runtime-Klassen, nur ein Pattern-YAML.** Das stärkste Einzelsignal: **%d Security-Capabilities werden aus dem Cyber-Bestand WIEDERVERWENDET** (IEC 81001-5-1 = CRA), während **%d medizin-spezifische** neu hinzukommen. Genau so wächst ein Kern: gemeinsame Fähigkeiten verbinden Cyber, Maschinenbau, Automotive UND Medizin; das Domänenspezifische bleibt am Rand. Architecture Stability bleibt stabil; der Engpass ist jetzt die Qualität der Wissensmodellierung, nicht die Architektur.' % (len(reused), len(fresh))) +w("") + +print("\n".join(OUT)) diff --git a/backend-compliance/tests/test_mcap_convergence_analysis.py b/backend-compliance/tests/test_mcap_convergence_analysis.py index 1fff521a..b9b18a44 100644 --- a/backend-compliance/tests/test_mcap_convergence_analysis.py +++ b/backend-compliance/tests/test_mcap_convergence_analysis.py @@ -38,23 +38,36 @@ def test_runs_end_to_end(): def test_core_is_cross_cutting_not_frequency(): out = _run() core = _section(out, "## 1. Core MCAPs") - # the most cross-cutting capability tops the Core report - assert "`secure_signed_update_distribution` | **18** |" in core + # the most cross-cutting capability tops the Core report; with Medical it now spans 3 domains + assert "`secure_signed_update_distribution` | **24** |" in core assert "technical_vulnerability_management" in core # a high-frequency BUT single-domain management cap must NOT be in Core (frequency != impact) assert "conduct_internal_environmental_audits" not in core -def test_all_four_reports_present(): +def test_all_five_reports_present(): out = _run() - for header in ["## 1. Core MCAPs", "## 2. Emerging MCAPs", "## 3. Isolated MCAPs", "## 4. Suspicious MCAPs"]: + for header in ["## 1. Core MCAPs", "## 2. Emerging MCAPs", "## 3. Isolated MCAPs", + "## 4. Suspicious MCAPs", "## 5. Missing Convergence"]: assert header in out +def test_missing_convergence_flags_cross_source_duplication(): + out = _run() + mc = _section(out, "## 5. Missing Convergence") + # the 'risk' token clusters several distinct risk MCAPs across many sources -> a review candidate + assert "Token `risk`" in mc + assert "maintain_risk_management_file_iso14971" in mc and "product_cyber_risk_assessment" in mc + assert "KEIN Auto-Merge" in out + # single-source decompositions (all-environmental) must be filtered out (>=2 sources required) + assert "Token `environmental`" not in mc + + def test_isolated_and_suspicious_are_review_tools(): out = _run() iso = _section(out, "## 3. Isolated MCAPs") - assert "issue_battery_passport" in iso or "measure_air_emissions" in iso + assert "Review: spezialisiert ODER Konvergenz übersehen" in iso + assert "conduct_clinical_evaluation" in iso or "cybersecurity_management_system" in iso susp = _section(out, "## 4. Suspicious MCAPs") assert "zu grob" in susp and "zu fein" in susp diff --git a/backend-compliance/tests/test_medical_stress_test.py b/backend-compliance/tests/test_medical_stress_test.py new file mode 100644 index 00000000..3d06caa3 --- /dev/null +++ b/backend-compliance/tests/test_medical_stress_test.py @@ -0,0 +1,58 @@ +"""Medical stress test — safety + security coupled (Phase Ω #3). + +Pins the harder joint test: ISO 13485 runs through the SAME engine (0 runtime, data only), and IEC +81001-5-1 (health-software security) pulls in the SAME security MCAPs as the CRA — so Medical REUSES +cyber capabilities (the safety/security coupling shows up as capability reuse) while adding genuinely +new medical-specific caps (clinical evaluation, software safety classification, ISO 14971 risk file). +""" + +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/medical_stress_test.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_zero_runtime(): + out = _run() + assert "Medical Stress Test" in out + assert "0 neue Runtime-Klassen" in out + + +def test_safety_security_coupling_reuses_cyber_caps(): + out = _run() + assert "Wiederverwendete Cyber-Capabilities (4)" in out + for cap in ["secure_signed_update_distribution", "technical_vulnerability_management", + "access_control_and_authentication", "sbom_creation"]: + assert cap in out + assert "IEC 81001-5-1" in out + + +def test_genuinely_new_medical_capabilities(): + out = _run() + assert "Neu (7)" in out + for cap in ["conduct_clinical_evaluation", "classify_software_safety_iec62304", + "maintain_risk_management_file_iso14971", "perform_benefit_risk_analysis"]: + assert cap in out + + +def test_rejected_assumptions_present(): + out = _run() + assert "ISO 13485 does NOT produce clinical evidence" in out + assert "the same security caps as the CRA" in out + + +def test_no_real_company_names(): + out = _run().lower() + for name in ["eto", "owis", "winterhalter", "medtronic", "siemens"]: + assert name not in out