feat(agent): Impressum-Tab auf Haupt-Engine + Profil/§36-Fixes

Ergebnis-Tab rendert jetzt result.results (Haupt-Doc-Check) statt des
abweichenden v3-Agenten — BMW korrekt statt False Positives:
- DocResultView: ein Dokument als Pflichtangaben-Tabelle (Label + gefundener
  Text + 3-Tier-Status), KEINE MC-IDs. ComplianceResultTabs speist Tabs aus
  result.results; ChecklistView-Bausteine exportiert + wiederverwendet.
- profile_extractor: Firmenname/Rechtsform = fruehester Treffer + ausge-
  schriebene Formen (Aktiengesellschaft) -> BMW AG statt "juris GmbH".
- 36 VSBG (MC-010): reines b2c -> POSSIBLY_APPLICABLE (Pruef-Hinweis) statt
  MEDIUM-FAIL; hart nur bei ecommerce. possibly_hint pro MC.
- McCoverage traegt label + found (Snippet); mc_possibly-Aggregat.
- AgentFindingCard/Methodik: interne check_id/mc_id nicht mehr angezeigt.

Tests: test_four_status (16) + Frontend-Vitest gruen; CI-Suite 206, v3/GT
unveraendert. Nur eigene Dateien (geteilter Tree).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-10 23:44:01 +02:00
parent a7dc12f30f
commit 3f23a64d5f
15 changed files with 450 additions and 187 deletions
@@ -10,21 +10,16 @@
import React, { useState } from 'react'
import type { SlotOutput } from './_agentTypes'
import { AgentResultTab } from './AgentResultTab'
import { ChecklistView } from './ChecklistView'
import { ChecklistView, DOC_TYPE_LABELS, type DocResult } from './ChecklistView'
import { DocResultView } from './DocResultView'
import { MigrationPanel } from './MigrationPanel'
const TOPIC_LABELS: Record<string, string> = {
impressum: 'Impressum',
cookie: 'Cookie-Banner',
}
export function ComplianceResultTabs({ results }: { results: any }) {
const agentOutputs: Record<string, SlotOutput> = results.agent_outputs || {}
const topicKeys = Object.keys(agentOutputs)
const tabs = [...topicKeys, 'raw']
const [active, setActive] = useState<string>(tabs[0])
// Themen-Tabs aus der HAUPT-Engine (result.results) — nicht aus dem
// v3-Agent. Jedes Dokument = ein Tab mit der genauen Pflichtangaben-Tabelle.
const docs: DocResult[] = results.results || []
const tabs = docs.map((_: DocResult, i: number) => String(i)).concat('raw')
const [active, setActive] = useState<string>(tabs[0] ?? 'raw')
return (
<div className="bg-white border border-gray-200 rounded-xl p-6 shadow-sm space-y-4">
@@ -112,26 +107,30 @@ export function ComplianceResultTabs({ results }: { results: any }) {
</div>
)}
{/* Tab-Leiste — Themen-Agenten + Roh-Checkliste */}
{/* Tab-Leiste — ein Tab je Dokument (Haupt-Engine) + Übersicht */}
<div className="flex gap-1 border-b border-gray-200 flex-wrap">
{tabs.map(t => {
const count = t !== 'raw' ? (agentOutputs[t]?.findings?.length ?? 0) : 0
const tabClass = `px-3 py-1.5 text-sm font-medium border-b-2 -mb-px transition-colors flex items-center gap-1.5 ${
active === t
? 'border-purple-500 text-purple-700'
: 'border-transparent text-gray-500 hover:text-gray-700'
}`
if (t === 'raw') {
return (
<button key={t} onClick={() => setActive(t)} className={tabClass}>
Alle Checks
</button>
)
}
const doc = docs[Number(t)]
const dot = doc.error ? 'bg-gray-300'
: doc.scenario === 'import' ? 'bg-green-500'
: doc.scenario === 'fix' ? 'bg-amber-500'
: doc.scenario === 'regenerate' ? 'bg-red-500' : 'bg-gray-400'
return (
<button
key={t}
onClick={() => setActive(t)}
className={`px-3 py-1.5 text-sm font-medium border-b-2 -mb-px transition-colors ${
active === t
? 'border-purple-500 text-purple-700'
: 'border-transparent text-gray-500 hover:text-gray-700'
}`}
>
{t === 'raw' ? 'Alle Checks (roh)' : (TOPIC_LABELS[t] || t)}
{count > 0 && (
<span className="ml-1.5 text-xs bg-gray-100 text-gray-600 rounded-full px-1.5">
{count}
</span>
)}
<button key={t} onClick={() => setActive(t)} className={tabClass}>
<span className={`w-2 h-2 rounded-full ${dot}`} />
{DOC_TYPE_LABELS[doc.doc_type] || doc.doc_type}
</button>
)
})}
@@ -140,11 +139,8 @@ export function ComplianceResultTabs({ results }: { results: any }) {
{/* Tab-Inhalt */}
{active === 'raw' ? (
<ChecklistView results={results.results} />
) : agentOutputs[active] ? (
<AgentResultTab
topicLabel={TOPIC_LABELS[active] || active}
output={agentOutputs[active]}
/>
) : docs[Number(active)] ? (
<DocResultView doc={docs[Number(active)]} />
) : null}
{/* Check-Footer (themenübergreifend) */}