80bf1993e0
The sanctioned last architectural building block. Reverses the order: not Goal -> Journey -> Delta but Goal -> Required -> Delta -> Journey. A Journey is the EXPLANATION of the Capability Delta, not its cause — so this is a Matcher/Explainer, not a Selector. New module compliance/journey_matcher/ = the third independent, interchangeable function of the pipeline, beside Company 2A (Evidence -> Capability) and RS-005 (Capability -> Delta): match_journeys(delta, journeys, context) -> ranked, auditable explanation - Looks ONLY at the Capability Delta — never at certificates, regulation, tenders or the goal. Journey signatures are certificate-agnostic capability clusters (Input -> Output pattern). - score = share of the delta a journey explains (recall over the missing capabilities); journey_only documents where a journey reaches beyond the delta so a broad journey is not silently preferred. - Deliberately dumb + deterministic (pure set overlap; NO ML/embeddings/LLM), fully auditable (matched / unexplained / journey_only / context signals); a learning ranker can sit on top later. - Signatures injected, engine hermetic. mypy --strict clean. Validated on the real patterns (demo): a CRA+MaschinenVO delta ranks the convergence journey 100%, "ISO27001 -> CRA" 56% (misses the machine-safety caps), "ISMS -> TISAX" 0%. This resolves the "Scope -> Journey" jump from Customer Mission #1. Freeze exception explicitly authorised; non-runtime -> no deploy. 12 tests pass, check-loc 0.
52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
"""Journey Matcher demo test — Delta -> Journey on the real transition patterns.
|
|
|
|
Pins that the matcher, given ONLY a real Capability Delta (a multi-cert company wanting CRA +
|
|
MaschinenVO), correctly ranks the known journeys by explanatory power: the convergence journey
|
|
explains the whole delta, the CRA-only journey explains the security part but misses the machine-
|
|
safety capabilities, and the TISAX journey is irrelevant. End-to-end through the real engines.
|
|
"""
|
|
|
|
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/journey_matcher_demo.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 "Journey Matcher" in out
|
|
assert "Goal → Required → Delta → Journey" in out
|
|
|
|
|
|
def test_convergence_journey_explains_the_whole_delta():
|
|
out = _run()
|
|
assert "**ISO27001 -> CRA + MaschinenVO** | 9 von 9 fehlenden Capabilities | 100% |" in out
|
|
|
|
|
|
def test_partial_journey_misses_machine_safety():
|
|
out = _run()
|
|
# CRA-only journey explains the security part but not the MaschinenVO capabilities
|
|
assert "**ISO27001 -> CRA** | 5 von 9 fehlenden Capabilities | 56% |" in out
|
|
|
|
|
|
def test_irrelevant_journey_scores_zero():
|
|
out = _run()
|
|
assert "**ISMS -> TISAX** | 0 von 9 fehlenden Capabilities | 0% |" in out
|
|
|
|
|
|
def test_match_is_auditable():
|
|
out = _run()
|
|
assert "auditierbar, keine Blackbox" in out
|
|
assert "Erklärte Capabilities" in out
|