# Umsetzungsauftrag: Report A (Management) und Report B (Technical) > Hinweis 2026-09-30: Historischer Auftrag. Die hier genannten Report-Dateien liegen seit der Verschiebung ohne Logikaenderung in `src/reporting/` (siehe `docs/REPORT_STRATEGY.md`, Report Engine boundary). Adressat: Codex. Dieser Auftrag ist verbindlich und abschließend formuliert. Wo dieser Auftrag schweigt, gelten `AGENTS.md`, `docs/REPORT_STRATEGY.md`, `docs/SCORING_MODEL.md` und `.claude/skills/assessor-ui/SKILL.md` unverändert weiter. Bei einem Widerspruch zwischen diesem Auftrag und einer dieser Quellen: **anhalten und den Widerspruch melden, nicht eigenmächtig auflösen.** Plan-Zuordnung: Die Artefakte A–D sind in `docs/REPORT_STRATEGY.md` als Deliverable ohne zugewiesene Plan-Phase festgehalten. Dieser Auftrag setzt A und B um und ändert die Strategie inhaltlich nicht. ## 0. Ausgangszustand im Code (verifiziert) | Baustein | Zustand | | --- | --- | | `src/domain/report-projection.ts` | vorhanden, `REPORT_PROJECTION_VERSION = '1.0.0'`, getestet | | `src/exports/management-overview-report.ts` | vorhanden, `buildManagementOverviewHtml`, Renderer-Version `'1.0.0'`, getestet | | Produktiver Aufrufer von `buildReportProjection` | **existiert nicht** — nur Tests | | Produktiver Aufrufer von `buildManagementOverviewHtml` | **existiert nicht** — nur Tests | | Report B (Technical) | **existiert nicht** | | Security-Domain-Zuordnung über `UnifiedResultProjection` | **existiert nicht** (Katalog arbeitet auf `FindingRecord`) | | Framework-Referenzen (MITRE ATT&CK / D3FEND) in der Unified-Projektion | **nicht enthalten** (nur `targetRole === 'category'` wird übernommen) | Die beiden vorhandenen Bausteine sind korrekt und werden **nicht neu geschrieben**, sondern additiv erweitert. ## 1. Lieferumfang Acht Arbeitspakete, in dieser Reihenfolge. Jedes Paket ist einzeln lauffähig, getestet und wird einzeln committet. ### AP1 — Security-Domain-Zuordnung für `UnifiedResultProjection` **Datei:** `src/features/dashboard/security-domains.ts` (erweitern, nicht ersetzen) Neue Funktion: ```ts export function securityDomainIdForUnifiedResult(result: UnifiedResultProjection): string ``` Bindende Semantik: - Es gilt **derselbe** `securityDomainCatalog` in **derselben** Reihenfolge. Kein zweiter Katalog, keine zweite Regex-Menge, keine report-eigene Zuordnung. - Evidenztext ist: `title`, `description` sowie `categoryLabel` aller Einträge aus `result.categories`. - Die explizite GPO-Erkennung geht wie bisher der Regex-Prüfung vor: erfüllt, wenn `result.sourceKind` einer von `'policy-evaluation' | 'policy-observation'` ist **oder** ein `categoryLabel` exakt `GPO`/`GPOs` lautet (case-insensitiv). - Kein Treffer ⇒ `unclassifiedSecurityDomain.id`. **Akzeptanzkriterium (Pflichttest):** Für einen synthetischen Fall, der sowohl als `FindingRecord` als auch als `UnifiedResultProjection` gebaut wird, liefern `securityDomainIdForRecord` und `securityDomainIdForUnifiedResult` **dieselbe** Domain — für alle acht Katalogeinträge, für den GPO-Sonderfall und für `unclassified`. Grund: Client-Info-Drilldown und Reports müssen dieselben Datensatzidentitäten auswählen (`AGENTS.md`, Abschnitt *UI Work filter context*). ### AP2 — Framework-Referenzen in der Unified-Projektion sichtbar machen **Datei:** `src/domain/unified-result.ts` Neu: ```ts export interface UnifiedResultFrameworkReference { namespace: string; // Tool-ID der Quelle value: string; // normalizedValue der Mapping-Eintragung, unverändert sourceFieldKey?: string; // sourceFieldKeys[0], falls vorhanden sourceLabel?: string; // Original-Spaltenüberschrift, falls vorhanden } ``` und additiv auf `UnifiedResultProjection`: ```ts frameworkReferences: UnifiedResultFrameworkReference[]; ``` Befüllung analog zu `scannerResultCategories`, aber aus den Mappings mit `targetRole === 'framework-reference'`. Leere Werte werden verworfen, alle übrigen **unverändert und unnormalisiert** übernommen. Bindende Randbedingungen: - Die Ableitung erfolgt **zur Projektionszeit aus bereits persistierten `fieldMappings`**. Es wird **keine** neue Spalte, Tabelle oder Migration angelegt und **kein** Parsing geändert. - Damit ist dies presentation-only über bereits gespeicherte Fakten: **kein** neuer Processing-Manifest-Eintrag, **keine** Reimport-Markierung (`docs/REIMPORT_POLICY.md`). - Sollte sich beim Umsetzen zeigen, dass eine Persistenzänderung nötig wäre: **anhalten und melden**, nicht persistieren. **Akzeptanzkriterium:** Synthetische Occurrence mit zwei `framework-reference`-Mappings und einem `category`-Mapping ⇒ zwei `frameworkReferences`, eine `category`, keine Vermischung, Originalwerte identisch. ### AP3 — Korrelationsmodul (Domain, plattformneutral) **Neue Datei:** `src/domain/report-correlation.ts` **Konstante:** `export const REPORT_CORRELATION_VERSION = '1.0.0';` Kein Storage, keine Uhr, kein Netzwerk, keine Präsentationstypen. Drei Ergebnisse: **(a) Quellenkonvergenz je Security Domain** ```ts export interface ReportDomainConvergence { domainId: string; sources: Array<{ toolId: string; assessed: number; deviations: number }>; sourceCount: number; // Quellen mit mindestens einer Abweichung evidence: 'shared-framework-reference' | 'domain-only'; } ``` `evidence` ist `'shared-framework-reference'` **nur dann**, wenn mindestens zwei Quellen in dieser Domain eine **exakt gleiche, nicht leere** `frameworkReferences`-Zeichenkette tragen. Andernfalls `'domain-only'`. **(b) Maßnahmenbündel** ```ts export interface ReportRemediationBundle { key: string; // die Framework-Referenz, unverändert namespace: string; members: string[]; // resultProjectionIds toolIds: string[]; domainIds: string[]; } ``` Gebildet über identische `frameworkReferences`-Werte von Abweichungen. Bündel mit weniger als zwei Mitgliedern entfallen. Sortierung: Mitgliederzahl absteigend, danach `key` alphabetisch — stabil, damit Ausgaben reproduzierbar sind. **(c) GPO-Einzelquellen-Maßnahmen** ```ts export interface ReportSingleSourcePolicyAction { policyEntryId: string; backupInstanceId: string; } ``` Genau die `ReportPolicyEntry` mit `verdict === 'Fail'`, `conflict === false`, `duplicate === false` und **exakt einem** Eintrag in `backupInstanceIds`. Bindende Verbote für AP3: - **Keine** Titel-, Wort-, Fuzzy- oder Ähnlichkeitsheuristik über Quellen hinweg. - **Kein** quellenübergreifender Score, Rang oder normalisierter Schweregrad. - **Keine** Aussage „gleicher Befund" — die Aussage lautet ausschließlich „dieselbe Domain" bzw. „dieselbe Framework-Referenz". - **Keine** Aufwands-, Kosten- oder Quick-Win-Schätzung. Ein Bündel trägt eine Mitgliederzahl, keine Bewertung. ### AP4 — Projektion erweitern **Datei:** `src/domain/report-projection.ts` **Version:** `REPORT_PROJECTION_VERSION` von `'1.0.0'` auf `'1.1.0'`. Additiv auf `ReportProjection`: ```ts convergence: ReportDomainConvergence[]; bundles: ReportRemediationBundle[]; singleSourcePolicyActions: ReportSingleSourcePolicyAction[]; ``` Bestehende Felder, Typen und Semantiken bleiben unverändert. Die bestehenden Zusicherungen in `tests/domain/report-projection.test.ts` müssen ohne Änderung grün bleiben; neue Tests kommen hinzu. ### AP5 — Report-Eingabe zusammenstellen **Neue Datei:** `src/features/reports/report-input-assembler.ts` ```ts export async function assembleReportProjectionInput( repository: AssessorRepository, scope: { projectId: string; assessmentId?: string; generatedAt: string } ): Promise ``` Quellen, ausschließlich: - Ergebnisse: `repository.queryUnifiedResults` über den Scope. - `domainOf`: `securityDomainIdForUnifiedResult` aus AP1. - `priorityBases`: `reportPriorityBases(...)` über die registrierten Profile. - `scoreSources` / `overallScore`: die vorhandene Scoring-Schicht (`src/domain/security-scoring.ts`, `src/features/dashboard/dashboard-security-score.ts`). **Keine eigene Score-Arithmetik.** - `environment`: normalisierte Fakten aus dem Environment-Snapshot. Fehlende Fakten bleiben **absent** und werden nie zu `0`. - `policyEntries` / `policyScopeLimited`: aus der Evaluations- und Aggregationsschicht mit dem **autoritativen, hochgerollten** Verdict. **Kein** Verdict wird hier neu abgeleitet. - `reviews`, `diagnostics`, `provenance`: aus den vorhandenen Repository-Pfaden. - `delta`: nur, wenn ein **gespeicherter** Timeslot-Vergleich existiert. Es wird **keine** Referenzlauf-Auswahl und **keine** Paarung im Export gebildet. Die Zusammenstellung läuft **nur beim Export**, nie beim Laden eines Workspace. ### AP6 — Management-Renderer erweitern **Datei:** `src/exports/management-overview-report.ts` **Version:** `MANAGEMENT_OVERVIEW_RENDERER_VERSION` auf `'1.1.0'`. Bestehende Abschnitte bleiben unverändert. Zwei neue Abschnitte: 1. **„Konvergenz der Quellen"** — direkt nach `Security Domains`. Je Domain: Anzahl unabhängiger Quellen mit Abweichungen, die Quellen namentlich, und eine sichtbare Unterscheidung zwischen belegter Konvergenz (`shared-framework-reference`) und thematischer Nähe (`domain-only`). Letztere trägt im Fließtext ausdrücklich den Hinweis auf **Validierungsbedarf**. 2. **„Maßnahmenbündel"** — direkt nach `Priority Findings`. Die Bündel aus AP3(b) mit Referenz und Mitgliederzahl sowie die Anzahl der Einzelquellen-GPO- Maßnahmen aus AP3(c). **Keine** Aufwands- oder Nutzenaussage. Der Abschnitt „Abdeckung und Lücken" wird **vor** „Priority Findings" gezogen und zeigt zusätzlich je Quelle den Anteil `not_run` an der Gesamtzahl. Begründung: Die Aussagegrenze muss vor der Priorisierung stehen. Unverändert bindend: keine Registry-Keys, SIDs, Evidenzpfade, Parser- oder Manifest-Versionen in Report A. ### AP7 — Report B (Technical) **Neue Datei:** `src/exports/technical-report.ts` **Konstante:** `export const TECHNICAL_REPORT_RENDERER_VERSION = '1.0.0';` **Signatur:** `export function buildTechnicalReportHtml(projection: ReportProjection): string` Abschnitte in dieser Reihenfolge, gemäß `docs/REPORT_STRATEGY.md` Report B: 1. Scope und Provenance — Importe, Processing-, Analyzer- und Manifest-Versionen, Reimport-Status, Aggregations- und Evaluations-Run-IDs. 2. Ergebnisinventar — Totals je Status, Severity, Domain und Tool, inklusive der score-neutralen Klassen; Passed erscheint als Zahl. 3. Findings im Detail — gruppiert je Domain, innerhalb der Gruppe nach Severity. 4. GPO-Policy-Register — alle sieben Verdicts vollständig; die score-neutralen sind **am Ort der Anzeige** als score-neutral gekennzeichnet. 5. Konvergenz-Nachweis — die Paare aus AP3(a) mit ihrer Begründung, damit die Managementaussage aus AP6 nachprüfbar ist. 6. Scope-Grenzen — ausdrücklich: kein RSoP, keine Aussage über wirksame Endpoint-Konfiguration, GPO-Aussagen gelten für das importierte Backup-Set, `not_run` ist kein Pass. 7. Diagnostik — jede Beobachtung **einmal**, mit ihrem autoritativen Resolver-Grund. 8. Anhang — vollständiger Ergebnisindex. ### AP8 — Auslösung in der Anwendung Zwei Aktionen in der bestehenden Oberfläche, die den Scope des aktuellen Projekts bzw. Assessments verwenden und über `src/exports/download-adapter.ts` bzw. `src/exports/text-download.ts` ausliefern. Keine neue Navigationsebene, keine neue Shell, keine neuen Farb- oder Geometrie-Tokens. Es gilt `.claude/skills/assessor-ui/SKILL.md` und der 20px-Panel-Inset. ## 2. Gestaltungsvorgaben für beide Dateien - Sprache: Deutsch. Etablierte englische Fachbegriffe bleiben englisch (`Deviation`, `Passed`, `Not configured`, `No baseline rule`, `Not comparable`, `Conflicts`, `Duplicates`, `Finding`, `Baseline`, `Score`, `Pass Rate`, Security-Domain-Namen, `Group Policy`, `Registry`, `Domain Controller`). - Zahlen und Daten in deutscher Formatierung. Unbekanntes ist ein Geviertstrich, niemals eine `0`. - Getrennte Dateien. Report A enthält keine technischen Identifikatoren. - Vollständig eigenständig: alle Styles inline, kein CDN, keine externe Font, kein Skript, kein Bild, kein Netzwerkzugriff beim Öffnen. Druckbar nach PDF ohne Layoutverlust. - Typografie-Rollen, Donut-Geometrie, Tile- und Segment-Grammatik, Statusfarbregeln und Panel-Inset wie in der Anwendung. Statusfarbe nur in Akzentlinie, Marker, Arc oder Score-Node — nie als Flächenfüllung. ## 3. Harte Verbote Nicht verhandelbar, auch dann nicht, wenn sie eine Lücke schließen würden: 1. Kein quellenübergreifender, normalisierter Schweregrad, Rang oder Risiko-Score. 2. Keine Aussage über wirksame Endpoint-Konfiguration aus einem Backup-Vergleich. 3. Kein GPO-Verdict aus Vergleichsprosa, Historie, Baseline-Text, Guidance oder Evidenz — ausschließlich das autoritative hochgerollte Verdict plus die expliziten Conflict- und Duplicate-Flags. 4. Ein selbst gemeldeter Review-Status wird nie zu einem gelösten Finding. 5. Kein Delta ohne gespeicherten Vergleich; keine Referenzlauf-Auswahl im Export. 6. Keine Score-Arithmetik, kein quellenspezifisches Parsing und kein Datenbankzugriff in einem Renderer. 7. `Not configured`, `No baseline rule` und `Not comparable` bleiben score-neutral und erscheinen nie in den Priority Findings. 8. Keine Titel- oder Ähnlichkeitsheuristik als Beleg für „gleicher Befund". 9. Keine echten Kunden-, Mandanten- oder Scan-Inhalte in Tests, Fixtures, Logs oder Commit-Nachrichten. Ausschließlich synthetische Fixtures. ## 4. Tests (Pflicht, synthetisch) | Paket | Testdatei | Muss nachweisen | | --- | --- | --- | | AP1 | `tests/features/security-domain-unified.test.ts` | Gleichstand beider Klassifizierer über alle acht Domains, GPO-Sonderfall, `unclassified` | | AP2 | `tests/domain/unified-result-framework-references.test.ts` | Trennung `category` / `framework-reference`, Originalwerte unverändert, leere Werte verworfen | | AP3 | `tests/domain/report-correlation.test.ts` | `shared-framework-reference` nur bei exakter Übereinstimmung über mindestens zwei Quellen; Bündel unter zwei Mitgliedern entfallen; stabile Sortierung; GPO-Einzelquelle schließt Conflict, Duplicate und Mehrfach-Backups aus | | AP4 | Erweiterung `tests/domain/report-projection.test.ts` | Neue Felder vorhanden, bestehende Zusicherungen unverändert grün | | AP5 | `tests/features/report-input-assembler.test.ts` | Kein Verdict wird neu abgeleitet; fehlende Fakten bleiben absent; `delta` bleibt ohne gespeicherten Vergleich `undefined`; Zusammenstellung nur beim Export | | AP6 | Erweiterung `tests/exports/management-overview-report.test.ts` | Beide neuen Abschnitte vorhanden; `domain-only` trägt den Validierungshinweis; keine Registry-Keys, SIDs, Pfade oder Versionen im Output; Abdeckung steht vor Priority Findings | | AP7 | `tests/exports/technical-report.test.ts` | Alle acht Abschnitte; score-neutrale Verdicts als solche gekennzeichnet; Diagnostik je Beobachtung genau einmal; Scope-Grenzen-Abschnitt vorhanden | | AP8 | Verhaltenstest der Auslösung | Export läuft nur auf Klick, nicht beim Laden des Workspace | Zusätzlich für Report A und B je ein Selbstgenügsamkeits-Test: der erzeugte HTML-String enthält kein `