feat(use-case-controls): Adressat-Achse — out-of-scope advisory + additiver GOV-Tag

2-Pass-Haiku-Klassifikation (konservativ + Re-Confirm jeder Nicht-unternehmen-
Einstufung) der Review-Tier-Atome: wer muss die Pflicht erfuellen?

- Migration 155: atom_classification.addressee (unternehmen/oeffentliche_stelle/
  aufsichtsbefugnis/staat_eu/dritter/meta), additiv, kein CHECK. [migration-approved]
- Service: addressee + applicable + is_gov pro Control; include_out_of_scope-Param
  (Default false -> out-of-scope advisory ausgeblendet, NIE geloescht); out_of_scope_count.
  Pure Helper addressee_applicable/addressee_is_gov (+ Tests).
- Route: optionaler include_out_of_scope-Query (contract-safe, additiv).
- Frontend: GOV-Chip (additiv) + "kein Kunden-Pruefaspekt"-Chip + 1-Klick-Toggle
  zum Einblenden der out-of-scope-Atome.

Daten: 40.859 Adressat-Tags auf macmini geladen (81% applicable, 19% advisory,
3.146 GOV). Konservativ: NULL/Unklar = applicable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-16 06:58:37 +02:00
parent f6fe592164
commit 0a6e57ac02
7 changed files with 181 additions and 12 deletions
@@ -7,6 +7,7 @@ import {
provenanceBadgeClass,
splitByTier,
severityBadgeClass,
addresseeLabel,
type UseCaseRow,
type ControlItem,
} from './_helpers'
@@ -17,6 +18,8 @@ const ctrl = (over: Partial<ControlItem>): ControlItem => ({
relevant: true,
tier: 'core',
source_type: 'derived',
applicable: true,
is_gov: false,
...over,
})
@@ -97,6 +100,14 @@ describe('coverage helpers', () => {
expect(severityBadgeClass(null)).toContain('gray')
})
it('addressee label maps keys to German labels', () => {
expect(addresseeLabel('oeffentliche_stelle')).toBe('Öffentliche Stelle')
expect(addresseeLabel('aufsichtsbefugnis')).toBe('Aufsichtsbehörde')
expect(addresseeLabel('staat_eu')).toBe('Mitgliedstaat/EU')
expect(addresseeLabel(null)).toBe('')
expect(addresseeLabel('unbekannt_neu')).toBe('unbekannt_neu')
})
it('splitByTier separates core (relevant) from review', () => {
const { core, review } = splitByTier([
ctrl({ id: 'a', relevant: true }),