From b4981ea9abd68275be787fb698d13361961ae91b Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Thu, 11 Jun 2026 16:32:52 +0200 Subject: [PATCH] feat(iace): benchmark distance panel (Thema 1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surface result.distances in the benchmark module: a DistanceComparison panel showing agreement %, covered values (green), GT-only gaps (amber) and engine-only extras — mirroring the RiskComparison panel. Co-Authored-By: Claude Opus 4.7 --- .../_components/DistanceComparison.tsx | 69 +++++++++++++++++++ .../benchmark/_hooks/useBenchmark.ts | 16 +++++ .../sdk/iace/[projectId]/benchmark/page.tsx | 4 ++ 3 files changed, 89 insertions(+) create mode 100644 admin-compliance/app/sdk/iace/[projectId]/benchmark/_components/DistanceComparison.tsx diff --git a/admin-compliance/app/sdk/iace/[projectId]/benchmark/_components/DistanceComparison.tsx b/admin-compliance/app/sdk/iace/[projectId]/benchmark/_components/DistanceComparison.tsx new file mode 100644 index 00000000..987ffe93 --- /dev/null +++ b/admin-compliance/app/sdk/iace/[projectId]/benchmark/_components/DistanceComparison.tsx @@ -0,0 +1,69 @@ +'use client' + +import type { DistanceComparison as DistanceComparisonData, DistanceToken } from '../_hooks/useBenchmark' + +function fmt(t: DistanceToken): string { + const v = Number.isInteger(t.value) ? t.value.toString() : t.value.toString().replace('.', ',') + return `${v} ${t.unit}` +} + +function TokenList({ tokens, tone }: { tokens: DistanceToken[]; tone: 'ok' | 'gap' | 'extra' }) { + if (!tokens.length) return + const cls = + tone === 'ok' + ? 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300' + : tone === 'gap' + ? 'bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300' + : 'bg-gray-100 text-gray-500 dark:bg-gray-700 dark:text-gray-400' + return ( +
+ {tokens.map((t, i) => ( + + {fmt(t)} + + ))} +
+ ) +} + +/** + * Distance/speed dimension comparison: do the engine's mm/mm-s values match the + * professional's (GT)? Confidence-aware tonality — green = covered, amber = gap. + */ +export function DistanceComparison({ data }: { data?: DistanceComparisonData }) { + if (!data || data.gt_count === 0) return null + + return ( +
+
+

Abstands-/Geschwindigkeits-Vergleich (Fachmann vs. Tool)

+

+ Deckt das Tool die konkreten mm-/mm-s-Werte des Fachmanns ab? Deterministischer Abgleich der + Maße aus den GT-Maßnahmen gegen die vom Tool vorgeschlagenen Maßnahmen. +

+
+ +
+ {Math.round(data.agreement_pct)}% + + {data.matched_count} von {data.gt_count} Fachmann-Maßen abgedeckt + +
+ +
+
+
Abgedeckt
+
+
+
+
Lücken (nur Fachmann)
+
+
+
+
Nur Tool
+
+
+
+
+ ) +} diff --git a/admin-compliance/app/sdk/iace/[projectId]/benchmark/_hooks/useBenchmark.ts b/admin-compliance/app/sdk/iace/[projectId]/benchmark/_hooks/useBenchmark.ts index f793dc81..8ac6b4a1 100644 --- a/admin-compliance/app/sdk/iace/[projectId]/benchmark/_hooks/useBenchmark.ts +++ b/admin-compliance/app/sdk/iace/[projectId]/benchmark/_hooks/useBenchmark.ts @@ -66,6 +66,21 @@ export interface RiskAgreement { high_confidence_pct: number } +export interface DistanceToken { + value: number + unit: string // "mm" | "mm/s" + raw: string +} + +export interface DistanceComparison { + gt_count: number + matched_count: number + agreement_pct: number + matched: DistanceToken[] + gt_only: DistanceToken[] + engine_only: DistanceToken[] +} + export interface BenchmarkResult { coverage_score: number measure_coverage: number @@ -78,6 +93,7 @@ export interface BenchmarkResult { risk_rank_pairs: { gt_rank: number; engine_rank: number; hazard_name: string; gt_risk_score: number }[] risk_comparison?: RiskComparisonPair[] risk_agreement?: RiskAgreement + distances?: DistanceComparison } interface UseBenchmarkReturn { diff --git a/admin-compliance/app/sdk/iace/[projectId]/benchmark/page.tsx b/admin-compliance/app/sdk/iace/[projectId]/benchmark/page.tsx index 2e507e8c..3fe5273e 100644 --- a/admin-compliance/app/sdk/iace/[projectId]/benchmark/page.tsx +++ b/admin-compliance/app/sdk/iace/[projectId]/benchmark/page.tsx @@ -7,6 +7,7 @@ import { GTImportForm } from './_components/GTImportForm' import { HazardComparisonTable } from './_components/HazardComparisonTable' import { CategoryBreakdown } from './_components/CategoryBreakdown' import { RiskComparison } from './_components/RiskComparison' +import { DistanceComparison } from './_components/DistanceComparison' export default function BenchmarkPage() { const { projectId } = useParams<{ projectId: string }>() @@ -106,6 +107,9 @@ export default function BenchmarkPage() { {/* Risk-number comparison (tool vs professional) with traffic lights */} + {/* Distance/speed dimension comparison */} + + {/* Hazard Comparison Table */}