From 8ea4c4be4fcac772bb32026f4bdf48f50be43b07 Mon Sep 17 00:00:00 2001 From: muraschal Date: Fri, 26 Jun 2026 09:00:21 +0200 Subject: [PATCH] feat(web): native de-CH copy across the site + locale regression guards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-ran the optimized content audit (C15 native-language lens, LOCALE de-CH, native-rewrite) on this repo's own German and applied the full rewrite set — sentences COMPLETELY re-modeled into original Swiss-German product copy, not word-level swaps. Meaning, claims and every protected technical term (CI/CD, OWASP, Trust Boundary, Prompt-Injection, file:line, SBOM, RAG, …) preserved; only the German sentence architecture changed. English strings untouched. - web/lib/i18n.ts — hero, value-prop, CTAs, nav, trust block, principles, phases, proof, reports prose: causative "lässt … laufen" and "point-at" calques rebuilt; terminology canon (kartieren/zuordnen, Prüfbereich, Befund, Durchlauf, einsetzen, Rechner, Selbst-); "live exposure" → "keine akute Gefährdung im Betrieb" (claim-faithful, not "rechtliches Risiko"). - web/lib/audit-details.ts — all 13 audits' de blocks re-modeled; jargon-density chains broken into native sentences with the precise terms kept; genus fixed ("das Audit"); 6 ß→ss. - 14 ß→ss total, 3 ASCII quote-closers → „…", consistent terminology. Guards so it can't drift back: - web/lib/locale-de-ch.test.ts (new) — hard-fails any ß + a morphology-aware Denglish denylist (mappen/laufen-lassen/deduplizieren/Linse/"der Audit"/…), scanning both copy files; English source is immune (German inflections only). - web/lib/i18n.test.ts — replaced the de!==en principle assertion (which institutionalized translationese) with a presence + locale-validity check. Verified: typecheck · 48 tests (5 files) · lint · production build all green. Co-Authored-By: Claude Opus 4.8 (1M context) --- web/lib/audit-details.ts | 134 +++++++++++++++++------------------ web/lib/i18n.test.ts | 8 ++- web/lib/i18n.ts | 108 ++++++++++++++-------------- web/lib/locale-de-ch.test.ts | 59 +++++++++++++++ 4 files changed, 186 insertions(+), 123 deletions(-) create mode 100644 web/lib/locale-de-ch.test.ts diff --git a/web/lib/audit-details.ts b/web/lib/audit-details.ts index be63b20..a41871e 100644 --- a/web/lib/audit-details.ts +++ b/web/lib/audit-details.ts @@ -31,23 +31,23 @@ export const AUDIT_DETAILS: Record "output": "A priority-sorted GitHub tracking issue plus one issue per confirmed finding — each with a management summary, OWASP/CWE/MITRE mapping, redacted evidence, CVSS, and a before/after fix." }, "de": { - "tagline": "Ein Security-Review über 14 Domains — jeder Befund evidenzbasiert und nach Exploitability bewertet.", - "approach": "Ein Spezialisten-Swarm prüft die 14 Security-Domains parallel: Injection, Authentication, Authorization, Secrets und Crypto, Supply Chain, Konfiguration, IaC, CI/CD, API, Business Logic, Frontend, Privacy, Logging und LLM. Phase 0 mappt zuerst die Angriffsfläche und die Trust Boundaries; jeder Befund zitiert eine file:line oder einen Config-Artefakt, mappt auf OWASP, CWE, MITRE oder CIS und trägt eine P0–P3-Severity mit CVSS-Schätzung. Jeder P0/P1 wird von unabhängigen Skeptikern angegriffen, bevor er es in den Report schafft.", + "tagline": "Ein Security-Review über 14 Domains — jeder Befund belegt, jede Ausnutzbarkeit eingestuft.", + "approach": "Ein Spezialisten-Swarm prüft die 14 Security-Domains parallel: Injection, Authentication, Authorization, Secrets und Crypto, Supply Chain, Konfiguration, IaC, CI/CD, API, Business Logic, Frontend, Privacy, Logging und LLM. Zuerst kartiert Phase 0 die Angriffsfläche und die Trust Boundaries. Jeder Befund zitiert eine file:line oder ein Config-Artefakt, ordnet ihn OWASP, CWE, MITRE oder CIS zu und trägt eine Severity von P0 bis P3 samt CVSS-Schätzung. Jeden P0/P1 nehmen unabhängige Skeptiker auseinander, bevor er es in den Bericht schafft.", "useCases": [ { "title": "Vor dem Production-Launch", - "body": "Du bist kurz vor dem Release und willst wissen, was ein Angreifer erreichen kann. Der Audit mappt Entry Points und Trust Boundaries und legt unauthentifizierte mutierende Endpoints, IDOR/BOLA-Lücken und exponierte Secrets als P0 offen — je mit konkretem Exploitation-Pfad und Before/After-Fix." + "body": "Du stehst kurz vor dem Release und willst wissen, was ein Angreifer erreichen kann. Das Audit kartiert Entry Points und Trust Boundaries und legt unauthentifizierte, verändernde Endpoints, IDOR/BOLA-Lücken und offengelegte Secrets als P0 offen — jeweils mit konkretem Exploit-Pfad und Vorher/Nachher-Fix." }, { "title": "Übernommene Codebase prüfen", - "body": "Du hast einen Service ohne Security-Historie übernommen. Der Swarm baut ein Attack-Surface-Inventory von Grund auf und benotet alle 14 Domains A–F, damit du die echte Exposure siehst — schwache JWT-Validierung, zu breite IAM, Dependencies mit bekannten CVEs — statt zu raten." + "body": "Du hast einen Service ohne Security-Historie übernommen. Der Swarm baut von Grund auf ein Inventar der Angriffsfläche und benotet alle 14 Domains von A bis F, damit du siehst, wo du wirklich angreifbar bist — schwache JWT-Validierung, zu breite IAM, Dependencies mit bekannten CVEs — statt zu raten." }, { "title": "CI/CD und IaC härten", - "body": "Deine Pipelines und Terraform sind organisch gewachsen. Der Audit prüft auf Secrets in CI, pull_request_target-Risiken, public Buckets, fehlende Encryption at Rest und zu breite Rollen und mappt jede Lücke auf ein CIS-Control mit konkreter Remediation." + "body": "Deine Pipelines und dein Terraform sind organisch gewachsen. Das Audit sucht nach Secrets in der CI, pull_request_target-Risiken, öffentlichen Buckets, fehlender Encryption at Rest und zu breiten Rollen — und ordnet jede Lücke einem CIS-Control samt konkreter Korrekturmassnahme zu." } ], - "output": "Ein priorisiertes GitHub-Tracking-Issue plus ein Issue je bestätigtem Befund — jeweils mit Management-Summary, OWASP/CWE/MITRE-Mapping, redacted Evidence, CVSS und Before/After-Fix." + "output": "Ein priorisiertes GitHub-Tracking-Issue plus ein Issue je bestätigtem Befund — jeweils mit Management-Summary, OWASP/CWE/MITRE-Zuordnung, geschwärztem Beleg, CVSS und Vorher/Nachher-Fix." } }, "repo": { @@ -72,22 +72,22 @@ export const AUDIT_DETAILS: Record }, "de": { "tagline": "Ein Engineering-Review fürs ganze Repo, gemessen an Google Eng, SRE und SLSA.", - "approach": "Ein Review auf Principal-Engineer-Niveau, das zehn Spezialisten parallel über Architektur, Stack-Konsistenz, Docs, Code-Qualität, Tests, Security, Dependencies, CI/CD, Observability und Git-/Release-Hygiene laufen lässt. Die Linse ist innere Kohärenz: deklarierter Standard gegen tatsächliche Praxis — Doc-Code-Drift, .env-vs-Code und Lint-Config-vs-Realität werden aktiv geprüft, nicht angenommen. Jeder Befund nennt file:line, wird gegen benannte Referenz-Repos benchmarkt und muss unabhängige Skeptiker überstehen, bevor er in den Bericht kommt.", + "approach": "Ein Review auf Principal-Engineer-Niveau: Zehn Spezialisten prüfen parallel Architektur, Stack-Konsistenz, Docs, Code-Qualität, Tests, Security, Dependencies, CI/CD, Observability und Git- und Release-Hygiene. Im Fokus steht die innere Kohärenz — der deklarierte Standard gegenüber der gelebten Praxis. Doc-Code-Drift, .env gegen Code und Lint-Config gegen Realität werden aktiv geprüft, nicht angenommen. Jeder Befund nennt seine file:line, wird an benannten Referenz-Repos gemessen und muss unabhängige Skeptiker überstehen, bevor er in den Bericht kommt.", "useCases": [ { "title": "Ein fremdes Repo übernehmen", - "body": "Du hast gerade ein Repo geerbt und das README ist deine einzige Karte. Das Audit geht clone-to-running durch und markiert genau den Schritt, an dem das Setup bricht — plus dokumentierte Befehle und Env-Vars, die nicht mehr zu dem passen, was der Code liest." + "body": "Du hast gerade ein Repo geerbt, und das README ist deine einzige Karte. Das Audit geht den Weg vom Clone bis zum laufenden Service durch und markiert genau den Schritt, an dem das Setup bricht — dazu dokumentierte Befehle und Env-Variablen, die nicht mehr zu dem passen, was der Code tatsächlich liest." }, { - "title": "Nachdem zwei Teams einen Code zusammenführten", - "body": "Ein Merger oder Reorg hat ein Repo mit zwei von allem zurückgelassen. Die Stack-Dimension listet konkurrierende Libraries (zwei HTTP-Clients, zwei Date-Libs), Version-Drift über Workspaces und gemischte Paradigmen — mit Usage-Counts und einem Konsolidierungspfad." + "title": "Nachdem zwei Teams eine Codebase zusammengeführt haben", + "body": "Eine Fusion oder Reorganisation hat ein Repo hinterlassen, in dem alles doppelt vorhanden ist. Der Prüfbereich Stack listet konkurrierende Libraries (zwei HTTP-Clients, zwei Date-Libs), Versions-Drift über die Workspaces hinweg und gemischte Paradigmen — mit Nutzungszahlen und einem Pfad zur Konsolidierung." }, { "title": "Due Diligence vor einer Übergabe", - "body": "Du kaufst ein Repo oder gibst Ownership ab und brauchst eine ehrliche Baseline statt Bauchgefühl. Du bekommst eine board-taugliche Scorecard über alle zehn Dimensionen, eine Gesamtnote und das größte Konsistenz-Risiko gleich vorneweg benannt." + "body": "Du kaufst ein Repo oder gibst die Ownership ab und brauchst eine ehrliche Ausgangslage statt Bauchgefühl. Du erhältst eine board-taugliche Scorecard über alle zehn Dimensionen, eine Gesamtnote und — gleich vorneweg — das grösste Konsistenz-Risiko klar benannt." } ], - "output": "Eine benotete Zehn-Dimensionen-Scorecard plus verifizierte Befunde als prioritätssortierte GitHub-Issues, jeder mit file:line-Beleg und einem Vorher/Nachher-Fix." + "output": "Eine benotete Scorecard über zehn Dimensionen plus verifizierte Befunde als prioritätssortierte GitHub-Issues, jeder mit file:line-Beleg und einem Vorher/Nachher-Fix." } }, "frontend": { @@ -112,22 +112,22 @@ export const AUDIT_DETAILS: Record }, "de": { "tagline": "Sechzehn Frontend-Spezialisten prüfen ein UI — jeder Befund verifiziert, bevor er eingereicht wird.", - "approach": "Phase 0 kartiert das Produkt, seine Surfaces und die kritischen User Journeys, dann laufen 16 Spezialisten-Agenten parallel über Usability, Verhaltenspsychologie, Visual Design, WCAG-2.2-Accessibility, Core Web Vitals, technisches SEO, Microcopy, Conversion, IA, Responsive-Verhalten, Interaction States, Formulare, Code-Qualität, Trust, i18n und den ersten Eindruck. Jeder Befund nennt die verletzte Regel oder Guideline, belegt sie konkret — mit DOM-Selektor, file:line, gemessener Metrik oder zitiertem String — und übersteht nur, wenn mindestens zwei von drei unabhängigen Skeptikern ihn nicht widerlegen. Liegen Live-URL und Repo beide vor, gleichen die Agenten ab, was der Code behauptet, gegen das, was die Seite tatsächlich rendert.", + "approach": "Zuerst kartiert Phase 0 das Produkt, seine Oberflächen und die kritischen User Journeys. Danach prüfen 16 Spezialisten-Agenten parallel: Usability, Verhaltenspsychologie, Visual Design, WCAG-2.2-Accessibility, Core Web Vitals, technisches SEO, Microcopy, Conversion, IA, Responsive-Verhalten, Interaction States, Formulare, Code-Qualität, Trust, i18n und den ersten Eindruck. Jeder Befund nennt die verletzte Regel oder Guideline und belegt sie konkret — mit DOM-Selektor, file:line, gemessener Metrik oder zitiertem String. Er übersteht nur, wenn ihn mindestens zwei von drei unabhängigen Skeptikern nicht widerlegen können. Liegen Live-URL und Repo beide vor, gleichen die Agenten ab, was der Code behauptet, mit dem, was die Seite tatsächlich rendert.", "useCases": [ { "title": "Review vor dem Launch", - "body": "Du bist Tage von einem Redesign entfernt und musst wissen, was wirklich kaputt ist — nicht, was in der Demo gut aussieht. Das Audit geht jede kritische Journey von Anfang bis Ende durch und legt die WCAG-A-Fehler, Dark Patterns und Conversion-Lecks offen, die den Launch blockieren — jedes mit Severity und konkretem Fix." + "body": "Du bist nur noch Tage von einem Redesign entfernt und musst wissen, was wirklich kaputt ist — nicht, was in der Demo gut aussieht. Das Audit geht jede kritische Journey von Anfang bis Ende durch und legt die WCAG-A-Fehler, Dark Patterns und Conversion-Verluste offen, die den Launch blockieren — jeweils mit Severity und konkretem Fix." }, { "title": "Signup-Funnel mit Leck", - "body": "Traffic kommt an, aber kaum jemand schließt den Signup ab, und die Analytics zeigen dir nur, wo abgesprungen wird, nicht warum. Die CRO- und Formular-Agenten zählen jedes Feld, jeden Klick und jede Entscheidung zwischen Ankunft und Erfolgsereignis und markieren die Friction, fehlende Validierung und schwachen Trust-Signale genau an dem Schritt, an dem Nutzer abbrechen." + "body": "Traffic kommt an, aber kaum jemand schliesst den Signup ab, und die Analytics zeigen dir nur, wo die Leute abspringen, nicht warum. Die CRO- und Formular-Agenten zählen jedes Feld, jeden Klick und jede Entscheidung zwischen Ankunft und Erfolgsereignis — und benennen Reibung, fehlende Validierung und schwache Trust-Signale genau an dem Schritt, an dem die Nutzer abbrechen." }, { "title": "Accessibility und rechtliches Risiko", - "body": "Die EAA-Frist rückt näher und du musst wissen, wo das Produkt die Konformität verfehlt, bevor ein Prüfer oder eine Beschwerde es findet. Der Accessibility-Agent fährt einen vollständigen WCAG-2.2-AA-Sweep — Semantik, Keyboard-Bedienbarkeit, Focus-Management, Kontrast, Target Size — und ordnet jedem Fehler seine Success-Criterion-Nummer und den rechtlichen Kontext zu." + "body": "Die EAA-Frist rückt näher, und du musst wissen, wo das Produkt die Konformität verfehlt, bevor ein Prüfer oder eine Beschwerde es aufdeckt. Der Accessibility-Agent führt einen vollständigen WCAG-2.2-AA-Durchlauf durch — Semantik, Bedienbarkeit per Tastatur, Focus-Management, Kontrast, Target Size — und ordnet jedem Fehler seine Success-Criterion-Nummer und den rechtlichen Kontext zu." } ], - "output": "Eine 0-100-Scorecard pro Dimension plus nach Priorität sortierte GitHub-Issues, jedes mit Management-Summary, Beleg, Before/After-Fix und einer 30/60/90-Roadmap." + "output": "Eine Scorecard von 0 bis 100 pro Dimension plus nach Priorität sortierte GitHub-Issues, jedes mit Management-Summary, Beleg, Vorher/Nachher-Fix und einer 30/60/90-Roadmap." } }, "api": { @@ -152,19 +152,19 @@ export const AUDIT_DETAILS: Record }, "de": { "tagline": "Prüfe deine API gegen ihren veröffentlichten Contract — und gegen das, was der Code tatsächlich tut.", - "approach": "Zwölf Spezialisten-Agenten prüfen eine API-Oberfläche über Resource-Modeling, HTTP-Semantik und Status-Codes, das Error-Envelope, Auth und Authorization auf Objektebene, Versioning, Pagination, Idempotency, Rate-Limits, Schema-Rigorosität, Docs, Webhooks und Observability. Jeder Befund nennt eine Handler-file:line, einen Schema-Pfad oder ein Request/Response-Paar und die verletzte Regel — RFC 9110, RFC 9457, OpenAPI 3.1, GraphQL-Spec oder gRPC-Konventionen. Jede Abweichung zwischen veröffentlichtem Contract und Implementierung wird als eigener Befund mit beiden Fundstellen erfasst.", + "approach": "Zwölf Spezialisten-Agenten prüfen eine API-Oberfläche entlang von Resource-Modeling, HTTP-Semantik und Status-Codes, dem Error-Envelope, Auth und Authorization auf Objektebene, Versioning, Pagination, Idempotency, Rate-Limits, Schema-Strenge, Docs, Webhooks und Observability. Jeder Befund nennt eine Handler-file:line, einen Schema-Pfad oder ein Request-Response-Paar und dazu die verletzte Regel — RFC 9110, RFC 9457, OpenAPI 3.1, GraphQL-Spec oder gRPC-Konventionen. Jede Abweichung zwischen veröffentlichtem Contract und Implementierung wird als eigener Befund mit beiden Fundstellen erfasst.", "useCases": [ { "title": "Interne API für Partner öffnen", - "body": "Ein internes Endpoint-Set wird zum öffentlichen Contract. Das Audit gleicht jede Operation mit ihrer OpenAPI oder SDL ab, markiert Verben im Pfad und inkonsistente Collection-Patterns und deckt fehlende Page-Size-Limits und unauthentifizierte mutierende Endpoints auf, bevor externe Entwickler darauf bauen." + "body": "Ein internes Endpoint-Set wird zum öffentlichen Contract. Das Audit gleicht jede Operation mit ihrer OpenAPI oder SDL ab, markiert Verben im Pfad und inkonsistente Collection-Patterns und deckt fehlende Page-Size-Limits und unauthentifizierte, verändernde Endpoints auf, bevor externe Entwickler darauf bauen." }, { "title": "Nachdem ein Payments-Endpoint doppelt abgebucht hat", - "body": "Ein Retry hat in Produktion eine zweite Charge erzeugt. Das Audit prüft Idempotency-Keys auf Money- und Side-Effect-POSTs, Optimistic Concurrency auf Read-Modify-Write-Pfaden und die Webhook-Delivery-Semantik und liefert das Idempotency-Key-Handling samt Storage als Vorher/Nachher-Fix." + "body": "Ein Retry hat in der Produktion eine zweite Abbuchung ausgelöst. Das Audit prüft Idempotency-Keys auf Money- und Side-Effect-POSTs, Optimistic Concurrency auf Read-Modify-Write-Pfaden und die Webhook-Delivery-Semantik — und liefert das Idempotency-Key-Handling samt Storage als Vorher/Nachher-Fix." }, { "title": "Spec-Drift vor der SDK-Generierung bereinigen", - "body": "Du generierst Client-SDKs aus einer OpenAPI-Spec, die nicht mehr zu den Handlern passt. Das Audit lintet die Spec und erstellt eine Contract-Drift-Matrix pro Operation — entfernte Felder, verengte Typen, geänderte Defaults, falsche Status-Codes — damit die generierten Clients nicht länger an echten Responses brechen." + "body": "Du generierst Client-SDKs aus einer OpenAPI-Spec, die nicht mehr zu den Handlern passt. Das Audit lintet die Spec und erstellt eine Contract-Drift-Matrix pro Operation — entfernte Felder, verengte Typen, geänderte Defaults, falsche Status-Codes — damit die generierten Clients nicht länger an echten Responses scheitern." } ], "output": "Eine pro Dimension benotete Scorecard plus ein nach Priorität sortiertes Tracking-Issue und pro Befund ein GitHub-Issue, jedes mit Management-Summary und Vorher/Nachher-Fix." @@ -192,19 +192,19 @@ export const AUDIT_DETAILS: Record }, "de": { "tagline": "Finde, wo das System langsam ist, wo es unter Last umkippt und wo es Ressourcen verschwendet.", - "approach": "Elf Spezialisten laufen parallel über serverseitige Latenz, Throughput und Skalierungsverhalten: algorithmische Hot Paths, Query-Effizienz und N+1-Muster, Caching, Concurrency, Leaks, Netzwerk-I/O, Resilienz und Kosten. Jeder Befund nennt ein konkretes Artefakt — eine Hot-Path-file:line, einen Query-Plan, eine gemessene Latenz, einen Profiler-Frame —, kennzeichnet sich als measured oder reasoned und übersteht die adversarielle Verifikation, bevor er landet. Jeder bestätigte Fix kommt mit geschätzter Metrik-Verbesserung und dem Lastniveau, ab dem der Pfad heute bricht.", + "approach": "Elf Spezialisten prüfen parallel die serverseitige Latenz, den Throughput und das Skalierungsverhalten: algorithmische Hot Paths, Query-Effizienz und N+1-Muster, Caching, Concurrency, Leaks, Netzwerk-I/O, Resilienz und Kosten. Jeder Befund nennt ein konkretes Artefakt — eine Hot-Path-file:line, einen Query-Plan, eine gemessene Latenz, einen Profiler-Frame — und kennzeichnet sich als gemessen oder hergeleitet. Er übersteht die adversarielle Verifikation, bevor er Bestand hat. Jeder bestätigte Fix kommt mit geschätzter Metrik-Verbesserung und dem Lastniveau, ab dem der Pfad heute bricht.", "useCases": [ { "title": "Ein Endpoint wurde nach einem Release langsam", - "body": "Ein Request-Pfad, der früher schnell war, hängt jetzt, und der Trace zeigt auf die Datenbank. Das Audit jagt N+1-Muster pro Endpoint, liest den Query-Plan auf Full Scans und fehlende Indizes und quantifiziert jeden: Queries pro Request, p95 vorher gegen nachher und den Index oder die gebündelte Query, die es behebt." + "body": "Ein Request-Pfad, der früher schnell war, hängt jetzt — und der Trace zeigt auf die Datenbank. Das Audit jagt N+1-Muster pro Endpoint, liest im Query-Plan Full Scans und fehlende Indizes ab und quantifiziert jeden Fall: Queries pro Request, p95 vorher und nachher sowie den Index oder die gebündelte Query, die ihn behebt." }, { "title": "Dimensionierung für 10x mehr Traffic", - "body": "Vor einem Launch oder einer Kampagne musst du wissen, ob das System hält. Das Audit denkt jeden kritischen Pfad bei 2x und 10x aktueller Last durch, benennt den ersten Bottleneck, der saturiert — eine Hot Row, ein globaler Lock, ein zu kleiner Connection-Pool —, und nennt das Lastniveau, ab dem es bricht, plus die realistische Decke nach der Behebung." + "body": "Vor einem Launch oder einer Kampagne musst du wissen, ob das System hält. Das Audit denkt jeden kritischen Pfad bei 2x und 10x der aktuellen Last durch, benennt den ersten Bottleneck, der an die Grenze kommt — eine Hot Row, ein globaler Lock, ein zu kleiner Connection-Pool — und nennt das Lastniveau, ab dem es bricht, samt der realistischen Obergrenze nach der Behebung." }, { "title": "Eine langsame Dependency löste eine Kaskade aus", - "body": "Ein langsamer Downstream-Call staute Threads und riss den Service mit. Das Audit prüft Timeout-Disziplin bei jedem externen Call, jagt Retries ohne Backoff und Jitter und markiert fehlende Circuit Breaker, Backpressure und Load Shedding — und zeigt den Failure Mode, wenn eine Dependency langsam ist, nicht nur tot." + "body": "Ein langsamer Downstream-Call staute die Threads und riss den Service mit. Das Audit prüft die Timeout-Disziplin bei jedem externen Call, jagt Retries ohne Backoff und Jitter und markiert fehlende Circuit Breaker, fehlende Backpressure und fehlendes Load Shedding — und zeigt das Fehlerbild, wenn eine Dependency langsam ist, nicht nur tot." } ], "output": "Eine pro Dimension benotete Scorecard plus ein nach Priorität sortierter Backlog aus GitHub-Issues, jedes mit Beleg, quantifizierten Kosten und einem Vorher/Nachher-Fix samt geschätzter Metrik-Verbesserung." @@ -231,23 +231,23 @@ export const AUDIT_DETAILS: Record "output": "A scorecard graded per dimension plus prioritized GitHub issues, each with evidence, severity, a before/after fix, and migrations sequenced with their safety plan." }, "de": { - "tagline": "Prüft, ob deine Daten falsch, verloren oder geleakt werden können — und belegt es mit Queries.", - "approach": "Ein engine-agnostischer Swarm prüft den Data Layer über elf Dimensionen: Schema und Normalisierung, Datentypen und Präzision, Constraints und referenzielle Integrität, Keys und Identity, Migrationssicherheit, Transaktionen und Concurrency, Integrität in der Praxis, Datenschutz, Lifecycle und Löschung, Pipelines sowie Backup/Recovery. Der Fokus liegt auf Korrektheit, nicht auf Query-Speed — jede Stelle, an der die Datenbank ungültigen, verwaisten oder inkonsistenten State zulässt, ist ein Befund, belegt an einer Migrationsdatei, einem Constraint oder einem geschwärzten Row-Pattern. P0/P1-Befunde benennen einen konkreten Datenverlust-, Korruptions- oder Leak-Pfad und überstehen die adversariale Verifikation, bevor sie ausgeliefert werden.", + "tagline": "Prüft, ob deine Daten verfälscht, verloren oder geleakt werden können — und belegt es mit Queries.", + "approach": "Unabhängig von der Datenbank-Engine prüft ein Swarm den Data Layer über elf Dimensionen: Schema und Normalisierung, Datentypen und Präzision, Constraints und referenzielle Integrität, Keys und Identity, Migrationssicherheit, Transaktionen und Concurrency, Integrität in der Praxis, Datenschutz, Lifecycle und Löschung, Pipelines sowie Backup/Recovery. Der Fokus liegt auf Korrektheit, nicht auf Query-Speed: Jede Stelle, an der die Datenbank ungültigen, verwaisten oder inkonsistenten State zulässt, ist ein Befund — belegt an einer Migrationsdatei, einem Constraint oder einem geschwärzten Row-Pattern. P0/P1-Befunde benennen einen konkreten Pfad zu Datenverlust, Korruption oder Leak und überstehen die adversariale Verifikation, bevor sie ausgeliefert werden.", "useCases": [ { "title": "Vor einer riskanten Produktiv-Migration", - "body": "Du willst eine NOT-NULL-Spalte hinzufügen, eine große Tabelle umschreiben oder einen destruktiven Backfill fahren. Der Audit prüft jede Migration auf Locking- und Blocking-Risiko, Reversibilität und einen Rollback-Pfad und markiert jede destruktive Operation ohne Sicherheitsnetz — und sequenziert den Fix als Expand/Contract-Plan mit Backfill und Rollback." + "body": "Du willst eine NOT-NULL-Spalte hinzufügen, eine grosse Tabelle umschreiben oder einen destruktiven Backfill ausführen. Das Audit prüft jede Migration auf Locking- und Blocking-Risiko, Reversibilität und einen Rollback-Pfad und markiert jede destruktive Operation ohne Sicherheitsnetz — und sequenziert den Fix als Expand/Contract-Plan mit Backfill und Rollback." }, { "title": "Wenn falsche Rows im Reporting auftauchen", - "body": "Die Billing-Reconciliation bricht oder ein Join liefert Rows, die es nicht geben dürfte. Der Audit prüft per Reasoning — und mit Read-only-Zugriff stichprobenartig — auf Orphans, Duplikate und Nulls in Pflichtfeldern, führt sie auf einen fehlenden FK-, UNIQUE- oder NOT-NULL-Constraint zurück und liefert die Cleanup-Query plus den Constraint, der es künftig verhindert." + "body": "Die Billing-Reconciliation bricht, oder ein Join liefert Rows, die es nicht geben dürfte. Das Audit prüft per Reasoning — und mit Read-only-Zugriff stichprobenartig — auf Orphans, Duplikate und Nulls in Pflichtfeldern, führt sie auf einen fehlenden FK-, UNIQUE- oder NOT-NULL-Constraint zurück und liefert die Cleanup-Query samt dem Constraint, der es künftig verhindert." }, { "title": "Multi-Tenant-SaaS mit PII", - "body": "Vor einem Compliance-Push oder Security-Review prüft der Audit, ob Tenant-Isolation im Data Layer erzwungen wird statt dem App-Code zu vertrauen, ob sensible Spalten nicht im Klartext liegen und ob ein GDPR-Recht-auf-Löschung eine Person wirklich überall löschen kann — inklusive Backups, Logs und Analytics." + "body": "Vor einem Compliance-Push oder Security-Review prüft das Audit, ob die Tenant-Isolation im Data Layer erzwungen wird, statt dem App-Code zu vertrauen, ob sensible Spalten nicht im Klartext liegen und ob das DSGVO-Recht auf Löschung eine Person wirklich überall entfernt — auch in Backups, Logs und Analytics." } ], - "output": "Eine Scorecard mit Note pro Dimension plus priorisierte GitHub-Issues, jedes mit Evidence, Severity, einem Before/After-Fix und Migrationen, die mit ihrem Safety-Plan sequenziert sind." + "output": "Eine Scorecard mit einer Note pro Dimension plus priorisierte GitHub-Issues, jedes mit Beleg, Severity, einem Vorher/Nachher-Fix und Migrationen, die mit ihrem Safety-Plan sequenziert sind." } }, "infrastructure": { @@ -271,23 +271,23 @@ export const AUDIT_DETAILS: Record "output": "A dimension-graded scorecard with a DORA snapshot, a blast-radius map, and a priority-sorted backlog of verified findings — each filed as a GitHub issue with evidence, a before/after fix, and a re-audit criterion." }, "de": { - "tagline": "Prüft, wie dein System gebaut, ausgeliefert und betrieben wird — fragil, exponiert oder nicht wiederherstellbar, gefunden und behoben.", - "approach": "Zwölf Spezialisten-Durchläufe decken IaC-Qualität und Drift, Cloud-Security und Netzwerk-Exposure, IAM, Secrets, Container, Kubernetes, CI/CD, High Availability, Backup/DR, Observability, Cost und Environment-Parität ab. Jeder Befund belegt ein konkretes Artefakt — IaC file:line, eine Manifest- oder Pipeline-Stanza, eine CIS- oder Well-Architected-Control — und die zentrale Frage lautet immer: Was passiert, wenn das ausfällt, und kannst du dich erholen? P0–P1-Befunde werden danach von unabhängigen Skeptikern angegriffen, bevor sie es in den Report schaffen.", + "tagline": "Prüft, wie dein System gebaut, ausgeliefert und betrieben wird — und findet und behebt, was fragil, exponiert oder nicht wiederherstellbar ist.", + "approach": "Zwölf Spezialisten-Durchläufe decken IaC-Qualität und Drift, Cloud-Security und Netzwerk-Exposure, IAM, Secrets, Container, Kubernetes, CI/CD, High Availability, Backup/DR, Observability, Cost und Environment-Parität ab. Jeder Befund nennt ein konkretes Artefakt — eine IaC file:line, eine Manifest- oder Pipeline-Stanza, eine CIS- oder Well-Architected-Control. Die zentrale Frage lautet immer: Was passiert, wenn das ausfällt, und kannst du den Zustand wiederherstellen? Danach nehmen unabhängige Skeptiker jeden P0- und P1-Befund auseinander, bevor er es in den Bericht schafft.", "useCases": [ { "title": "Vor einem Production-Launch", - "body": "Du bringst einen Service ins öffentliche Internet und willst wissen, was tatsächlich exponiert ist. Das Audit verfolgt Public-Exposure-Pfade — Security Groups offen auf 0.0.0.0/0 an sensiblen Ports, öffentliche Buckets und Datenbanken, fehlendes TLS oder Edge-Schutz — und meldet jeden mit der exakten IaC-Zeile und der verletzten CIS-Control." + "body": "Du bringst einen Service ins öffentliche Internet und willst wissen, was tatsächlich exponiert ist. Das Audit verfolgt die Public-Exposure-Pfade — Security Groups, die auf 0.0.0.0/0 an sensiblen Ports offen stehen, öffentliche Buckets und Datenbanken, fehlendes TLS oder fehlender Edge-Schutz — und meldet jeden mit der exakten IaC-Zeile und der verletzten CIS-Control." }, { "title": "Nach einem Beinahe-Ausfall", - "body": "Ein Incident hat dich fragen lassen, ob du wirklich aus Code und Backups neu aufbauen kannst. Das Audit prüft Single Points of Failure auf Tier-0-Pfaden und ob Backups verschlüsselt und restore-getestet sind — nicht bloß vorhanden — und legt die nicht wiederherstellbaren Zustände und fehlenden DR-Runbooks offen, bevor es der nächste Ausfall tut." + "body": "Ein Incident hat dich fragen lassen, ob du wirklich aus Code und Backups neu aufbauen kannst. Das Audit prüft Single Points of Failure auf Tier-0-Pfaden und ob Backups verschlüsselt und restore-getestet sind — nicht bloss vorhanden — und legt die nicht wiederherstellbaren Zustände und fehlenden DR-Runbooks offen, bevor es der nächste Ausfall tut." }, { "title": "Deploy-Pipeline härten", - "body": "Dein Team liefert schnell aus und du vermutest, dass die Gates nur Deko sind. Das Audit prüft, ob Build-, Test-, Scan- und Approval-Schritte wirklich blocken, kontrolliert Branch Protection und den Scope der Pipeline-Credentials und markiert Injection-Pfade wie pull_request_target — und zeigt, wo ein kaputter oder ungescannter Build in Prod landen kann." + "body": "Dein Team liefert schnell aus, und du vermutest, dass die Gates nur Deko sind. Das Audit prüft, ob Build-, Test-, Scan- und Approval-Schritte wirklich blockieren, kontrolliert die Branch Protection und den Scope der Pipeline-Credentials und markiert Injection-Pfade wie pull_request_target — und zeigt, wo ein kaputter oder ungescannter Build in der Prod landen kann." } ], - "output": "Eine nach Dimensionen benotete Scorecard mit DORA-Snapshot, eine Blast-Radius-Map und ein nach Priorität sortiertes Backlog verifizierter Befunde — jeder als GitHub-Issue mit Beleg, Before/After-Fix und Re-Audit-Kriterium." + "output": "Eine nach Dimensionen benotete Scorecard mit DORA-Snapshot, eine Blast-Radius-Map und ein nach Priorität sortiertes Backlog verifizierter Befunde — jeder als GitHub-Issue mit Beleg, Vorher/Nachher-Fix und Re-Audit-Kriterium." } }, "ai-llm": { @@ -312,22 +312,22 @@ export const AUDIT_DETAILS: Record }, "de": { "tagline": "Prüfe deine LLM-Features so, wie es ein Angreifer und ein ehrlicher Nutzer tun würden.", - "approach": "Provider- und Framework-agnostisch kartiert dieses Audit zuerst jede Stelle, an der ein LLM aufgerufen wird, und jede Trust-Boundary, an der untrusted Input — Nutzertext, abgerufene Dokumente, Tool-Ergebnisse — in einen Prompt gelangt. Zwölf Spezialisten prüfen dann Prompt-Injection, Jailbreaks, System-Prompt- und Secret-Leakage, Output-Handling, Tool-/Agent-Agency, RAG-Grounding, Halluzination, Evals und Kosten — jeder Befund auf die OWASP LLM Top 10 gemappt und P0–P3 bewertet. Jede Aussage ist auf ein konkretes Artefakt zurückgeführt und übersteht unabhängige Skeptiker, bevor sie eingereicht wird.", + "approach": "Unabhängig von Provider und Framework kartiert dieses Audit zuerst jede Stelle, an der ein LLM aufgerufen wird — und jede Trust Boundary, an der untrusted Input in einen Prompt gelangt: Nutzertext, abgerufene Dokumente, Tool-Ergebnisse. Danach prüfen zwölf Spezialisten Prompt-Injection, Jailbreaks, System-Prompt- und Secret-Leakage, Output-Handling, Tool- und Agent-Agency, RAG-Grounding, Halluzination, Evals und Kosten. Jeden Befund ordnen sie der OWASP LLM Top 10 zu und bewerten ihn von P0 bis P3. Jede Aussage ist auf ein konkretes Artefakt zurückgeführt und übersteht unabhängige Skeptiker, bevor sie eingereicht wird.", "useCases": [ { "title": "RAG-Support-Bot ausliefern", - "body": "Dein Assistent antwortet aus internen Docs und einer geteilten Knowledge-Base. Das Audit prüft, ob das Retrieval die Berechtigungen pro Nutzer respektiert, ob der Bot bei fehlendem Kontext abbricht oder halluziniert und ob in einem abgerufenen Dokument versteckte Anweisungen den System-Prompt überschreiben können (indirekte Injection)." + "body": "Dein Assistent antwortet aus internen Docs und einer geteilten Knowledge-Base. Das Audit prüft, ob das Retrieval die Berechtigungen pro Nutzer respektiert, ob der Bot sich bei fehlendem Kontext zurückhält oder halluziniert und ob in einem abgerufenen Dokument versteckte Anweisungen den System-Prompt überschreiben können (indirekte Injection)." }, { "title": "Einem Agenten echte Tools geben", - "body": "Dein Agent kann auf Modell-Geheiß E-Mails senden, die Datenbank abfragen oder interne APIs aufrufen. Das Audit prüft den Blast-Radius jedes Tools — kann es eine destruktive oder irreversible Aktion ohne Human-Gate auslösen? —, validiert die vom Modell erzeugten Argumente und verfolgt jeden Output-Sink auf XSS, SQL oder eval-Injection." + "body": "Dein Agent kann auf Geheiss des Modells E-Mails senden, die Datenbank abfragen oder interne APIs aufrufen. Das Audit prüft den Blast-Radius jedes Tools — kann es eine destruktive oder irreversible Aktion ohne Human-Gate auslösen? —, validiert die Argumente, die das Modell erzeugt, und verfolgt jeden Output-Sink auf XSS, SQL oder eval-Injection." }, { "title": "Vor dem Skalieren eines öffentlichen LLM-Endpoints", - "body": "Du öffnest ein KI-Feature gleich für untrusted Traffic. Das Audit sucht die Cost-Caps pro Nutzer und global, die Runaway-Spend und Missbrauch stoppen, die Evals, die deine High-Stakes-Pfade absichern, und das Provider-Retention- und PII-Handling, das du brauchst, bevor Nutzerdaten deine Maschine verlassen." + "body": "Du öffnest ein KI-Feature gleich für untrusted Traffic. Das Audit sucht nach den Cost-Caps pro Nutzer und global, die ausufernde Kosten und Missbrauch stoppen, nach den Evals, die deine High-Stakes-Pfade absichern, und nach dem Provider-Retention- und PII-Handling, das du brauchst, bevor Nutzerdaten deine Maschine verlassen." } ], - "output": "Eine Scorecard pro Dimension, eine Trust-Boundary- und Data-Flow-Map und verifizierte Befunde als nach Priorität sortierte GitHub-Issues — jedes mit OWASP-LLM-Mapping, redigiertem Repro und konkretem Vorher/Nachher-Fix." + "output": "Eine Scorecard pro Dimension, eine Trust-Boundary- und Data-Flow-Map und verifizierte Befunde als nach Priorität sortierte GitHub-Issues — jedes mit OWASP-LLM-Zuordnung, geschwärztem Repro und konkretem Vorher/Nachher-Fix." } }, "compliance-privacy": { @@ -352,22 +352,22 @@ export const AUDIT_DETAILS: Record }, "de": { "tagline": "Findet, wo du personenbezogene Daten ohne Rechtsgrundlage, Consent oder Löschmöglichkeit verarbeitest.", - "approach": "Primäre Linse ist die DSGVO, erweitert um ePrivacy, den EU AI Act und CCPA, wo sie greifen. Ein Schwarm spezialisierter Agents baut eine verifizierte Data-Flow- / RoPA-Karte und prüft dann Rechtsgrundlage, Consent und Cookies, Transparenz, Betroffenenrechte, Aufbewahrung, Drittlandtransfers, Auftragsverarbeiter-Verträge und Breach-Readiness. Consent wird per Network-Trace geprüft, nicht über das Banner-UI, und Lösch- und Auskunftsrechte werden End-to-End im Code verifiziert; jeder Befund zitiert einen konkreten Artikel und ein File, eine Tabelle, ein Cookie oder eine Policy-Klausel.", + "approach": "Im Zentrum steht die DSGVO, erweitert um ePrivacy, den EU AI Act und CCPA, wo sie greifen. Ein Schwarm spezialisierter Agenten baut eine verifizierte Data-Flow- und RoPA-Karte und prüft dann Rechtsgrundlage, Consent und Cookies, Transparenz, Betroffenenrechte, Aufbewahrung, Drittlandtransfers, Auftragsverarbeiter-Verträge und Breach-Readiness. Den Consent prüft das Audit per Network-Trace, nicht über das Banner-UI; Lösch- und Auskunftsrechte verifiziert es End-to-End im Code. Jeder Befund zitiert einen konkreten Artikel und dazu ein File, eine Tabelle, ein Cookie oder eine Policy-Klausel.", "useCases": [ { "title": "Cookie-Banner, das lügt", - "body": "Marketing liefert ein Consent-Banner aus, aber Analytics- und Ad-Pixel feuern trotzdem beim ersten Laden. Ein Network-Trace fängt jeden nicht-essenziellen Tag, der vor dem Opt-in läuft, benennt die Zeile, die ihn injiziert, und mappt ihn auf ePrivacy und Art. 6 mit einem Gate-before-Consent-Fix." + "body": "Marketing liefert ein Consent-Banner aus, aber Analytics- und Ad-Pixel feuern trotzdem schon beim ersten Laden. Ein Network-Trace fängt jeden nicht-essenziellen Tag, der vor dem Opt-in lädt, benennt die Zeile, die ihn einschleust, und ordnet ihn ePrivacy und Art. 6 zu — mit einem Gate-before-Consent-Fix." }, { "title": "Ein Nutzer stellt einen Löschantrag", - "body": "Der Support verspricht Löschung in der Datenschutzerklärung, aber niemand hat verfolgt, wo die Daten wirklich liegen. Das Audit folgt jeder Kategorie personenbezogener Daten und zeigt, wo die Löschung nicht bis in Backups, Logs oder Drittanbieter durchschlägt, gemessen an Art. 17." + "body": "Der Support verspricht in der Datenschutzerklärung die Löschung, aber niemand hat verfolgt, wo die Daten wirklich liegen. Das Audit folgt jeder Kategorie personenbezogener Daten und zeigt — gemessen an Art. 17 —, wo die Löschung nicht bis in Backups, Logs oder zu Drittanbietern durchschlägt." }, { "title": "AI-Feature-Launch in der EU", - "body": "Ein neues Profiling- oder LLM-Feature geht ohne DPIA und ohne EU-AI-Act-Risikoklasse live. Das Audit klassifiziert das Feature, prüft Art.-22-Schutzmaßnahmen und AI-Transparenzpflichten und verfolgt, ob die Daten ohne gültigen Transfermechanismus den EWR verlassen." + "body": "Ein neues Profiling- oder LLM-Feature geht ohne DPIA und ohne EU-AI-Act-Risikoklasse live. Das Audit klassifiziert das Feature, prüft die Schutzmassnahmen nach Art. 22 und die AI-Transparenzpflichten und verfolgt, ob die Daten ohne gültigen Transfermechanismus den EWR verlassen." } ], - "output": "Eine Scorecard je Dimension, eine verifizierte Data-Flow- / RoPA-Karte und ein nach Priorität sortiertes Befundregister, in dem jeder Befund seinen Artikel zitiert und einen konkreten Before/After-Fix liefert, überführt in GitHub-Issues unter einem Tracking-Issue." + "output": "Eine Scorecard je Dimension, eine verifizierte Data-Flow- und RoPA-Karte und ein nach Priorität sortiertes Befundregister, in dem jeder Befund seinen Artikel zitiert und einen konkreten Vorher/Nachher-Fix liefert — überführt in GitHub-Issues unter einem Tracking-Issue." } }, "accessibility": { @@ -392,22 +392,22 @@ export const AUDIT_DETAILS: Record }, "de": { "tagline": "Prüfe dein Produkt gegen WCAG 2.2 AA — mit Belegen und einem Konformitätsurteil.", - "approach": "Ein Schwarm von Spezialisten übernimmt je einen Ausschnitt der Disability-Experience — Tastatur, Screenreader, Fokus, Kontrast, Formulare, Zoom und Reflow, Target-Size, Motion und kognitive Last. Jeder Befund nennt ein konkretes Artefakt (einen DOM-Selektor, den berechneten Accessible Name, ein Kontrastverhältnis mit beiden Hex-Werten, eine Tastatur-Sequenz) und ist auf ein konkretes WCAG-Success-Criterion samt Level gemappt. Es laufen automatische Scanner und manuelle Checks, dann entsteht eine VPAT-fertige Konformitätstabelle, die benennt, was Automatisierung nicht findet.", + "approach": "Ein Schwarm von Spezialisten übernimmt je einen Ausschnitt der Erfahrung von Menschen mit Behinderung — Tastatur, Screenreader, Fokus, Kontrast, Formulare, Zoom und Reflow, Target Size, Motion und kognitive Last. Jeder Befund nennt ein konkretes Artefakt (einen DOM-Selektor, den berechneten Accessible Name, ein Kontrastverhältnis mit beiden Hex-Werten, eine Tastatur-Sequenz) und ist einem konkreten WCAG-Success-Criterion samt Level zugeordnet. Automatische Scanner und manuelle Checks kommen zum Einsatz; daraus entsteht eine VPAT-fertige Konformitätstabelle, die benennt, was die Automatisierung nicht findet.", "useCases": [ { "title": "Deadline European Accessibility Act", - "body": "Der EAA ist in Kraft und du brauchst ein Konformitätsurteil für die Barrierefreiheitserklärung, keine vage To-do-Liste. Dieses Audit liefert ein WCAG-2.2-AA-Urteil (pass/partial/fail) mit VPAT-fertiger Konformitätstabelle und benennt deine konkrete rechtliche Exposition unter EAA, ADA und EN 301 549." + "body": "Der EAA ist in Kraft, und du brauchst ein Konformitätsurteil für die Barrierefreiheitserklärung, keine vage To-do-Liste. Dieses Audit liefert ein WCAG-2.2-AA-Urteil (pass/partial/fail) mit VPAT-fertiger Konformitätstabelle und benennt dein konkretes rechtliches Risiko unter EAA, ADA und EN 301 549." }, { "title": "Design-System-Komponente prüfen", - "body": "Ein geteilter Button oder Modal, der bei Barrierefreiheit durchfällt, bricht jede Seite, die ihn nutzt. Das Audit dedupliziert auf die Wurzel-Komponente, statt dasselbe Issue 40-mal einzureichen, und markiert Compound-Barrieren — etwa fehlender Fokus-Indikator kombiniert mit Fokus-Verlust beim SPA-Routenwechsel — die Tastatur- und Screenreader-User stranden lassen." + "body": "Ein geteilter Button oder ein Modal, der bei der Barrierefreiheit durchfällt, bricht jede Seite, die ihn nutzt. Das Audit bündelt den Befund auf die Wurzel-Komponente, statt dasselbe Issue 40-mal einzureichen, und markiert Compound-Barrieren — etwa einen fehlenden Fokus-Indikator kombiniert mit Fokus-Verlust beim SPA-Routenwechsel —, die Tastatur- und Screenreader-User stranden lassen." }, { "title": "Tastatur- und Screenreader-Pfade", - "body": "Mit der Maus sieht deine App gut aus, aber du bist sie nie mit Tastatur oder Screenreader durchgegangen. Dieses Audit prüft die Tab-Reihenfolge gegen die visuelle Ordnung, findet Keyboard-Traps und unbeschriftete Controls, checkt, dass Fokus in Modals und bei Routenwechseln gesetzt und zurückgegeben wird, und bestätigt, dass async Updates und Fehler tatsächlich announced werden." + "body": "Mit der Maus sieht deine App gut aus, aber du bist sie nie mit Tastatur oder Screenreader durchgegangen. Dieses Audit gleicht die Tab-Reihenfolge mit der visuellen Ordnung ab, findet Keyboard-Traps und unbeschriftete Controls, prüft, ob der Fokus in Modals und bei Routenwechseln gesetzt und zurückgegeben wird, und bestätigt, dass asynchrone Updates und Fehler tatsächlich angesagt werden." } ], - "output": "Ein Konformitätsurteil plus VPAT-fertige WCAG-2.2-Tabelle, eine Scorecard pro Dimension und nach Priorität sortierte GitHub-Issues — jedes auf sein Success Criterion gemappt, mit Vorher/Nachher-Fix und Re-Audit-Kriterium." + "output": "Ein Konformitätsurteil plus VPAT-fertige WCAG-2.2-Tabelle, eine Scorecard pro Dimension und nach Priorität sortierte GitHub-Issues — jedes seinem Success Criterion zugeordnet, mit Vorher/Nachher-Fix und Re-Audit-Kriterium." } }, "documentation": { @@ -432,20 +432,20 @@ export const AUDIT_DETAILS: Record }, "de": { "tagline": "Prüft deine Doku gegen den Standard und gegen den Code, der sie bestätigt oder widerlegt.", - "approach": "Spezialisten-Agents gehen jede kritische Leser-Journey nur mit der Doku durch und verifizieren dann jede Aussage gegen die Realität: dokumentierte Commands laufen gegen die Scripts, Env-Variablen werden gegen den lesenden Code geprüft, Code-Beispiele werden nachvollzogen oder ausgeführt. Bewertet werden Repo-Kopf, Onboarding, Doc-Code-Drift, Schreibstil und Diátaxis-Passung auf einer 0-100-Rubrik — jede Seite gemessen an dem Job, den sie erfüllen soll.", + "approach": "Spezialisten-Agenten gehen jede kritische Leser-Journey nur mit der Doku durch und prüfen dann jede Aussage an der Realität: Dokumentierte Commands werden gegen die Scripts ausgeführt, Env-Variablen mit dem Code abgeglichen, der sie liest, Code-Beispiele nachvollzogen oder ausgeführt. Bewertet werden Repo-Kopf, Onboarding, Doc-Code-Drift, Schreibstil und Diátaxis-Passung auf einer Rubrik von 0 bis 100 — jede Seite gemessen an dem Job, den sie erfüllen soll.", "output": "Eine Rubrik-Scorecard mit Notenband plus ein Drift-Register und priorisierte GitHub-Issues, jedes mit einem Vorher/Nachher-Fix.", "useCases": [ { "title": "Vor dem Open-Sourcing", - "body": "Du machst ein Repo öffentlich, und das README ist die Eingangstür. Das Audit geht Clone bis erster grüner Test als neuer Leser durch, nennt den genauen Schritt, an dem er hängenbleibt, und markiert fehlende Value-Line, Badge-Reihe, Management-Summary und Architektur-Diagramm." + "body": "Du machst ein Repo öffentlich, und das README ist die Eingangstür. Das Audit geht als neuer Leser den Weg vom Clone bis zum ersten grünen Test durch, nennt den genauen Schritt, an dem er hängenbleibt, und markiert fehlende Value-Line, Badge-Reihe, Management-Summary und Architektur-Diagramm." }, { "title": "Nach einem Refactor mit Umbenennungen", - "body": "Ein Refactor hat Scripts, Env-Variablen und Modulpfade umbenannt, die Doku beschreibt aber noch die alten Namen. Das Audit testet dokumentierte Commands gegen die package.json, Env-Variablen gegen den lesenden Code und .env.example gegen die Realität — und liefert ein Drift-Register, das für jeden Treffer Doku- und Code-Zeile zitiert." + "body": "Ein Refactor hat Scripts, Env-Variablen und Modulpfade umbenannt, aber die Doku beschreibt noch die alten Namen. Das Audit testet dokumentierte Commands gegen die package.json, gleicht Env-Variablen mit dem Code ab, der sie liest, und .env.example mit der Realität — und liefert ein Drift-Register, das für jeden Treffer die Doku- und die Code-Zeile zitiert." }, { "title": "Übergabe eines Service an On-Call", - "body": "Du gibst einem anderen Team den Pager für einen Service, den es nicht gebaut hat. Das Audit prüft Runbooks, Rollback-Schritte und Referenz-Doku gegen die echte Infra und API-Oberfläche, sodass ein falscher Rollback-Schritt oder eine undokumentierte Pflicht-Config als P0/P1 auftaucht, bevor es um 3 Uhr nachts der Alarm tut." + "body": "Du gibst einem anderen Team den Pager für einen Service, den es nicht gebaut hat. Das Audit prüft Runbooks, Rollback-Schritte und Referenz-Doku an der echten Infra und der API-Oberfläche, sodass ein falscher Rollback-Schritt oder eine undokumentierte Pflicht-Config als P0/P1 auftaucht, bevor es um 3 Uhr nachts der Alarm tut." } ] } @@ -472,22 +472,22 @@ export const AUDIT_DETAILS: Record }, "de": { "tagline": "Prüft die Idee, nicht nur die Prosa — und schreibt um, was nicht trägt.", - "approach": "Es schickt deine Landing-Page, deinen Essay, Launch-Post oder deine Docs-Prosa durch vierzehn Linsen, die eine Sache testen: hält die Idee stand. Es steelmant das stärkste Gegenargument zu deiner These, prüft, ob der Text den Leser auf seiner tatsächlichen Awareness-Stage abholt, misst den Information Gain gegen Best-in-class-Content und verifiziert jede überprüfbare Aussage. Jeder bestätigte Befund liefert ein konkretes Before/After-Rewrite, kein „mach es knackiger“.", + "approach": "Das Audit schickt deine Landing-Page, deinen Essay, Launch-Post oder deine Docs-Prosa durch vierzehn Prüfbereiche, die alle eine Frage stellen: Hält die Idee stand? Es bildet den stärksten Gegenpunkt zu deiner These, prüft, ob der Text den Leser auf seiner tatsächlichen Awareness-Stage abholt, misst den Information Gain an Best-in-class-Content und verifiziert jede überprüfbare Aussage. Jeder bestätigte Befund liefert ein konkretes Vorher/Nachher-Rewrite, kein „mach es knackiger“.", "useCases": [ { "title": "Vor einem Produkt-Launch-Post", - "body": "Du willst die Ankündigung veröffentlichen, und ein unbelegter Superlativ oder ein Versprechen, das das Produkt nicht hält, würde am ersten Tag Glaubwürdigkeit kosten. Das Audit markiert unbelegte Behauptungen als P0, verifiziert die Zahlen und Fähigkeiten, die du nennst, und gibt dir alles Unüberprüfbare zurück, damit du es vor dem Launch klärst." + "body": "Du willst die Ankündigung veröffentlichen, und ein unbelegter Superlativ oder ein Versprechen, das das Produkt nicht hält, kostet dich am ersten Tag Glaubwürdigkeit. Das Audit markiert unbelegte Behauptungen als P0, verifiziert die Zahlen und Fähigkeiten, die du nennst, und gibt dir alles Unüberprüfbare zurück, damit du es vor dem Launch klärst." }, { "title": "Eine Landing-Page, die nicht konvertiert", - "body": "Traffic kommt an, springt aber ab, und du siehst nicht warum. Das Audit zeigt die Value Proposition unter drei Sätzen Throat-Clearing begraben, Copy auf der falschen Awareness-Stage und einen fehlenden oder unklaren Call-to-Action — jeden mit Fundstelle zitiert und direkt umgeschrieben." + "body": "Traffic kommt an, springt aber wieder ab, und du siehst nicht, warum. Das Audit zeigt die Value Proposition, begraben unter drei Sätzen Vorgeplänkel, Copy auf der falschen Awareness-Stage und einen fehlenden oder unklaren Call-to-Action — jeden mit Fundstelle zitiert und direkt umgeschrieben." }, { "title": "Ein Essay, der sauber liest, aber nichts Neues sagt", - "body": "Jeder Satz stimmt, doch der Leser kann jeden Punkt aus dem Titel vorhersagen. Das Audit misst den Information Gain gegen die besten existierenden Texte für diesen Leser, markiert den Commodity-Content und benennt, wo dein einziger echter, nicht-offensichtlicher Insight zu wenig genutzt ist." + "body": "Jeder Satz stimmt, doch der Leser kann jeden Punkt schon aus dem Titel ableiten. Das Audit misst den Information Gain an den besten existierenden Texten für diesen Leser, markiert den Commodity-Content und benennt, wo dein einziger echter, nicht offensichtlicher Insight zu wenig genutzt wird." } ], - "output": "Eine 0–100-Content-Scorecard, ein expliziter Thesen-Verdict und nach Priorität sortierte GitHub-Issues — jedes mit zitierter Passage, Before/After-Rewrite und Re-Audit-Kriterium." + "output": "Eine Content-Scorecard von 0 bis 100, ein explizites Thesen-Urteil und nach Priorität sortierte GitHub-Issues — jedes mit zitierter Passage, Vorher/Nachher-Rewrite und Re-Audit-Kriterium." } }, "lean": { @@ -511,20 +511,20 @@ export const AUDIT_DETAILS: Record "output": "A leanness scorecard plus prioritized GitHub issues, each with a removal class, the reachability proof, and a before/after fix with a revert note." }, "de": { - "tagline": "Finde Bloat, dead code und ungenutzte Dependencies — ohne etwas Tragendes zu löschen.", - "approach": "Ein read-only Schlankheits-Audit über fünf Dimensionen: Dependency-Transparenz und Supply Chain, dead code und Orphan-Files, Duplikation, AI-Slop und defensives Boilerplate, sowie Over-Engineering. Es baut zuerst eine SBOM und eine Reachability-Map, dann gated es jede Entfernung hinter Chesterton's Fence und einem Resurrector-Skeptiker — jeder Schnitt landet in remove-now, investigate, deprecate oder protected, nie ein blindes Löschen.", + "tagline": "Finde Bloat, Dead Code und ungenutzte Dependencies — ohne etwas Tragendes zu löschen.", + "approach": "Ein read-only Schlankheits-Audit über fünf Dimensionen: Dependency-Transparenz und Supply Chain, Dead Code und Orphan-Files, Duplikation, AI-Slop und defensives Boilerplate sowie Over-Engineering. Das Audit baut zuerst eine SBOM und eine Reachability-Map und sichert dann jede Entfernung hinter Chesterton's Fence und einem Resurrector-Skeptiker ab — jeder Schnitt wird als remove-now, investigate, deprecate oder protected eingestuft, nie blind gelöscht.", "useCases": [ { "title": "Du übernimmst eine AI-generierte Codebase", - "body": "Nach Monaten agent-geschriebenem Code vermutest du duplizierte Utilities, Code-wiederholende Kommentare und über-defensives Boilerplate, kannst es aber nicht belegen. Das Audit meldet die Duplikations-Dichte mit beiden Clone-Stellen, markiert log-and-continue Catch-Blöcke und benennt, welche Vereinfachungen verhaltens-äquivalent sind." + "body": "Nach Monaten von agentgeschriebenem Code vermutest du duplizierte Utilities, Kommentare, die nur den Code wiederholen, und übermässig defensives Boilerplate, kannst es aber nicht belegen. Das Audit meldet die Duplikations-Dichte mit beiden Clone-Stellen, markiert log-and-continue-Catch-Blöcke und benennt, welche Vereinfachungen verhaltensäquivalent sind." }, { "title": "Dependency-Surface vor einem Release verschlanken", - "body": "Du willst Install- und Supply-Chain-Risiko senken, fürchtest aber einen kaputten Fresh-Install. Es trennt declared-but-unused Dependencies von Phantom-Deps (used-but-undeclared), erklärt, warum jedes transitive Package da ist, und prüft Lockfile und Lizenzen gegen Policy." + "body": "Du willst das Install- und Supply-Chain-Risiko senken, fürchtest aber einen kaputten Fresh-Install. Das Audit trennt deklarierte, aber ungenutzte Dependencies von Phantom-Deps (genutzt, aber nicht deklariert), erklärt, warum jedes transitive Package vorhanden ist, und prüft Lockfile und Lizenzen gegen die Policy." }, { - "title": "Entscheiden, ob dead code wirklich tot ist", - "body": "Ein statisches Tool hat unused Exports und Orphan-Files markiert, aber Reflection, dynamische Imports und Out-of-Repo-Consumer lassen dich zögern. Das Audit verfolgt die Reachability-Map, nennt die ausgeschlossenen dynamischen Kanäle und labelt jeden Kandidaten als proven-dead oder nur suspected-dead." + "title": "Entscheiden, ob Dead Code wirklich tot ist", + "body": "Ein statisches Tool hat ungenutzte Exports und Orphan-Files markiert, aber Reflection, dynamische Imports und Out-of-Repo-Consumer lassen dich zögern. Das Audit verfolgt die Reachability-Map, nennt die ausgeschlossenen dynamischen Kanäle und kennzeichnet jeden Kandidaten als proven-dead oder nur suspected-dead." } ], "output": "Eine Schlankheits-Scorecard plus priorisierte GitHub-Issues, jedes mit Removal-Klasse, dem Reachability-Beleg und einem Vorher/Nachher-Fix samt Revert-Note." diff --git a/web/lib/i18n.test.ts b/web/lib/i18n.test.ts index 2f66938..d9303d5 100644 --- a/web/lib/i18n.test.ts +++ b/web/lib/i18n.test.ts @@ -64,8 +64,12 @@ describe("principles translation coverage", () => { const en = principles("en"); expect(de.length).toBe(en.length); for (let i = 0; i < en.length; i++) { - // German must differ from English (i.e. a translation was actually applied)… - expect(de[i].title, `principle "${en[i].title}" not translated`).not.toBe(en[i].title); + // German title + body must be present. We deliberately do NOT assert + // de !== en: a legitimately protected English term (a standard, a code + // identifier) may stay identical, and forcing a difference would + // institutionalize translationese. de-CH locale validity (no ß, native + // phrasing, no Denglish) is enforced comprehensively in locale-de-ch.test.ts. + expect(de[i].title, `principle "${en[i].title}" has no German title`).toBeTruthy(); expect(de[i].body).toBeTruthy(); // …and the shared, non-localized field (icon) must be preserved. expect(de[i].icon).toBe(en[i].icon); diff --git a/web/lib/i18n.ts b/web/lib/i18n.ts index e3bb7bd..0411be4 100644 --- a/web/lib/i18n.ts +++ b/web/lib/i18n.ts @@ -14,10 +14,10 @@ const proofRowsByIssue: Record> = { 122: 'Hero badge "copy & paste" duplicates the subhead', }, de: { - 100: 'Kein sichtbarer Output-Beweis — predigt „Evidence“, liefert Prosa', - 103: "Aktivierungs-Befehl ist nicht kopierbar", + 100: 'Kein sichtbarer Ergebnis-Beleg — predigt „Evidence“, liefert Prosa', + 103: "Aktivierungsbefehl lässt sich nicht kopieren", 104: '„any AI agent“ — unbelegte Universalbehauptung', - 107: "End-CTA wiederholt den Hero statt zu schließen", + 107: "End-CTA wiederholt den Hero, statt abzuschliessen", 113: '„Google-grade“ — unbelegter Superlativ', 122: 'Hero-Badge „copy & paste“ doppelt den Subhead', }, @@ -181,13 +181,13 @@ export const ui = { footerChangelog: "Changelog", }, de: { - nav: { use: "Nutzen", audits: "Audits", how: "Ablauf", standards: "Standards", reports: "Berichte" }, + nav: { use: "Einsetzen", audits: "Audits", how: "Ablauf", standards: "Standards", reports: "Berichte" }, skip: "Zum Inhalt springen", langToggle: "Auf Englisch wechseln", newTab: "(öffnet in neuem Tab)", ghRepo: "GitHub-Repository", menuOpen: "Menü öffnen", - menuClose: "Menü schließen", + menuClose: "Menü schliessen", navMobile: "Mobile Navigation", themeLight: "Zu hellem Design wechseln", themeDark: "Zu dunklem Design wechseln", @@ -195,15 +195,15 @@ export const ui = { heroBadge: "Audits · MIT", heroTitle: "Mach aus jedem KI-Agenten einen Schwarm spezialisierter Auditoren", heroSub: - "Kopiere einen Master-Prompt in deinen KI-Coding-Agenten. Er lässt viele Spezialisten parallel laufen und jeden Befund von unabhängigen Skeptikern auf die Probe stellen — nur was standhält, landet als GitHub-Issue in einem nach Priorität sortierten Backlog.", + "Kopiere einen Master-Prompt in deinen KI-Coding-Agenten. Er setzt viele Spezialisten parallel ein, lässt jeden Befund von unabhängigen Skeptikern anfechten und reicht nur ein, was standhält — als nach Priorität sortierte GitHub-Issues.", heroContrast: "Kein weiterer „audit my code“-Prompt — diese zwingen deinen Agenten, jeden Befund zu belegen, bevor er ihn einreicht.", heroCtaCopy: "Befehl kopieren", - heroCtaProof: "Echten Lauf ansehen", + heroCtaProof: "Echten Durchlauf ansehen", heroCtaHint: "Kopiert eine Vorlage — ersetze die Repo-URL, bevor du sie ausführst.", heroMeta: "belegbasiert · ≥2-von-3 adversariell verifiziert · 30/60/90-Roadmap", agentEyebrow: "Loslegen", - agentTitle: "Richte deinen KI-Agenten auf auditor.rapold.io", + agentTitle: "Nutze auditor.rapold.io mit deinem KI-Agenten", agentLead: "Keine Installation — funktioniert mit jedem Agenten, der eine URL abrufen und Tools ausführen kann (läuft mit Claude Code). Sag ihm, er soll ein Repo mit auditor.rapold.io auditieren: er holt den Audit-Prompt — einen einzigen Einstiegspunkt, der Sprache und Umfang erfragt — und legt dann die Issues an.", agentCmdVerb: "Audit", @@ -215,7 +215,7 @@ export const ui = { agentCopyHint: "Kopiere ihn, setze deine Repo-URL ein, füge ihn in deinen Agenten ein.", agentCtaSeeAudits: "Alle {count} Audits ansehen", agentExplain: - "Er fragt dann: Ausgabesprache (Deutsch / English), welche der {count} Audits (oder das ganze Repo) und ob Issues erstellt werden dürfen — dann führt er sie aus und öffnet einen nach Priorität sortierten Tracker.", + "Er fragt dann nach: Ausgabesprache (Deutsch / English), welche der {count} Audits (oder das ganze Repo) und ob er Issues erstellen darf — dann führt er sie aus und öffnet einen nach Priorität sortierten Tracker.", agentNotePre: "KI-Agenten: hole", agentNotePost: "und agiere als Audit-Orchestrator (Sprache + Umfang erfragen, dann ausführen).", trustTitle: "Ehrliche Antworten auf die naheliegenden Fragen", @@ -225,20 +225,20 @@ export const ui = { a: "Jede file:line wird in der adversariellen Verifikation (Phase 3) anhand der echten Datei nachgeprüft; nicht verifizierbare Aussagen werden verworfen.", }, { - q: "Verlässt mein Code meine Maschine?", + q: "Verlässt mein Code meinen Rechner?", a: "Nein — dein Agent holt nur den Prompt; dein Repo berührt unsere Domain nie.", }, { - q: "Was kostet ein Lauf?", - a: "Nur die Tokens deines Agenten — beschränke dich auf einige Audits, um die Kosten zu steuern.", + q: "Was kostet ein Durchlauf?", + a: "Nur die Tokens deines Agenten — grenz den Umfang auf ein paar Audits ein, um die Kosten zu steuern.", }, ], prinEyebrow: "Warum es anders ist", prinTitle: "Die meisten Audit-Prompts liefern unverifizierte Meinungen. Diese erzwingen Disziplin.", proofEyebrow: "Beweise statt Behauptungen", - proofTitle: "Wir haben die ganze Suite auf das eigene Repo gerichtet", + proofTitle: "Wir haben die ganze Suite auf das eigene Repo angesetzt", proofLead: - "Die Bibliothek wird auf sich selbst angewendet — auf genau dieses Repo gerichtet, das Backlog als öffentliche GitHub-Issues. Diese Seite bekam ihr eigenes Content-Audit; über das ganze Repo erreichte jede Linse A− bis A. Unten: der echte Backlog, die Noten und ein Finding in voller Tiefe.", + "Die Bibliothek prüft sich selbst — angesetzt auf genau dieses Repo, mit dem Backlog als öffentliche GitHub-Issues. Diese Seite bekam ihr eigenes Content-Audit; über das ganze Repo erreichte jeder Prüfbereich A− bis A. Unten: der echte Backlog, die Noten und ein Befund in voller Tiefe.", proofAnnotation: "Der echte Backlog aus dem Audit genau dieser Seite — 23 Befunde, jeder davon jetzt behoben.", proofVerifyHint: "Öffne ein Issue und prüfe den Beleg auf GitHub.", @@ -246,19 +246,19 @@ export const ui = { proofEvidence: "Beleg", proofBefore: "Vorher", proofAfter: "Nachher", - proofCta: "Ganzen Lauf ansehen (#97)", + proofCta: "Ganzen Durchlauf ansehen (#97)", apKicker: "Audit-Vorlage", - apApproach: "Wie dieses Audit arbeitet", + apApproach: "So funktioniert dieses Audit", apUseCases: "Wann du es einsetzt", apOutput: "Was du bekommst", - apMaps: "Mappt auf", + apMaps: "Zugeordnet zu", apViewPrompt: "Vollständigen Prompt ansehen", apAllAudits: "Alle Audits", apOthers: "Die anderen Audits ansehen", audEyebrow: "Die Bibliothek", audTitle: "{count} stack-agnostische Audits, eine gemeinsame Methodik", audLead: - "Jedes ist ein eigenständiger Master-Prompt: eine mehrphasige Spezifikation, keine einmalige „review my code“-Frage. Mehrere gegen dasselbe Repo laufen lassen — ihre Befunde fließen ohne Duplikate in einen einzigen, prioritätssortierten Tracker, weil jedes Audit denselben Issue-Kontrakt liefert.", + "Jedes ist ein eigenständiger Master-Prompt: eine mehrphasige Spezifikation, keine einmalige „review my code“-Frage. Setz mehrere auf dasselbe Repo an — ihre Befunde fliessen ohne Doppelungen in einen einzigen, nach Priorität sortierten Tracker, weil jedes Audit demselben Issue-Vertrag folgt.", howEyebrow: "Die Methode", howTitle: "Sechs Phasen, jedes Mal", howLead: @@ -267,26 +267,26 @@ export const ui = { howOutput: "Du bekommst — nach Priorität sortierte GitHub-Issues.", howParallel: "parallel", howGate: "übersteht ≥2 von 3", - stdEyebrow: "Die Maßstäbe", - stdTitle: "Zwei Maßstäbe. Jeder Bericht daran gemessen.", + stdEyebrow: "Die Massstäbe", + stdTitle: "Zwei Massstäbe. Jeder Bericht daran gemessen.", stdLead: - "Für sich allein nutzbar. Der eine bewertet 0–100 anhand einer Rubrik; der andere legt die exakte Issue-Form fest — so bleiben zwei Läufe vergleichbar, auch wenn die generierte Formulierung abweicht.", + "Für sich allein nutzbar. Der eine bewertet 0–100 anhand einer Rubrik; der andere legt die exakte Issue-Form fest — so bleiben zwei Durchläufe vergleichbar, auch wenn die generierte Formulierung abweicht.", ctaTitle: "Sieh, was dein KI-Agent findet, wenn er jede Aussage belegen muss.", ctaLead: - "Es ist kostenlos und MIT-lizenziert. Lass es auf einem Wegwerf-Branch laufen, lies Befunde, die 2-von-3 Skeptikern standhalten mussten, und behalte nur die Fixes, denen du zustimmst.", + "Es ist kostenlos und MIT-lizenziert. Setz es auf einem Wegwerf-Branch ein, lies Befunde, die 2-von-3 Skeptikern standhalten mussten, und behalte nur die Fixes, denen du zustimmst.", proofStrip: "Jede Aussage hier hat dasselbe Audit überstanden — lies das öffentliche Backlog (#97).", ctaBtnGet: "Prompts ansehen", ctaBtnQuick: "Quickstart", // Berichte-Galerie. repIndexKicker: "Beispiel-Berichte", - repIndexTitle: "Echte Audit-Läufe — jeder Befund auf ein öffentliches Issue zurückführbar", + repIndexTitle: "Echte Audit-Durchläufe — jeder Befund auf ein öffentliches Issue zurückführbar", repIndexLead: - "Keine erfundenen Demos. Jeder Bericht unten ist ein echter Lauf der Suite, gerendert aus denselben Daten, die als öffentliche GitHub-Issues eingereicht wurden — öffne jeden Link und prüfe den Beleg selbst. Wir starten die Galerie mit dem Self-Audit dieses Repos; weitere echte Läufe kommen dazu, sobald sie laufen.", + "Keine erfundenen Demos. Jeder Bericht unten ist ein echter Durchlauf der Suite, gerendert aus denselben Daten, die als öffentliche GitHub-Issues eingereicht wurden — öffne jeden Link und prüfe den Beleg selbst. Wir starten die Galerie mit dem Selbst-Audit dieses Repos; weitere echte Durchläufe kommen dazu, sobald sie vorliegen.", repIndexWhyTitle: "Warum diese echt und nicht inszeniert sind", repIndexWhy: [ { t: "Belegbasiert", - d: "Jeder Befund nennt ein konkretes Artefakt (file:line, einen Config-Wert) und verlinkt das GitHub-Issue, in dem er lebt.", + d: "Jeder Befund nennt ein konkretes Artefakt (file:line, einen Config-Wert) und verlinkt das GitHub-Issue, in dem er steht.", }, { t: "Adversariell verifiziert", @@ -294,30 +294,30 @@ export const ui = { }, { t: "Öffentlich prüfbar", - d: "Die Scorecard, die begründeten Nicht-anwendbar-Entscheide und die Cross-Audit-Dedupe führen alle auf einen Master-Tracker.", + d: "Die Scorecard, die begründeten Nicht-anwendbar-Entscheide und das audit-übergreifende Bereinigen von Doppelungen führen alle auf einen Master-Tracker zurück.", }, ], repViewReport: "Bericht ansehen", repTracker: "Master-Tracker", repTarget: "Ziel", - repDate: "Lauf-Datum", + repDate: "Datum des Durchlaufs", repBackToReports: "Alle Berichte", repScorecardTitle: "Scorecard", - repScorecardLead: "Phase 0 wählte {n} anwendbare Audits; jede Linse wurde unabhängig benotet.", + repScorecardLead: "Phase 0 wählte {n} anwendbare Audits; jeder Prüfbereich wurde unabhängig benotet.", repNotApplicableTitle: "Als nicht anwendbar deklariert", repNotApplicableLead: - "Phase 0 erklärte diese — mit Begründung — als außerhalb des Umfangs, statt sie still zu überspringen.", + "Phase 0 erklärte diese — mit Begründung — als ausserhalb des Umfangs, statt sie still zu überspringen.", repFindingsTitle: "Wichtigste Befunde", repFindingsLead: "Ein Ausschnitt des Backlogs, nativ gerendert. Öffne ein Issue und prüfe den Beleg auf GitHub.", - repDedupTitle: "Cross-Audit-Dedupe", + repDedupTitle: "Audit-übergreifende Doppelbefunde", repDedupLead: - "Der Mehrwert, die Audits zusammen laufen zu lassen: dieselbe Lücke von mehreren Linsen gefunden, zu einem Backlog-Item gemergt — jedes Zitat erhalten.", + "Der Mehrwert, die Audits gemeinsam einzusetzen: dieselbe Lücke, von mehreren Prüfbereichen gefunden und zu einem Backlog-Item zusammengeführt — jedes Zitat bleibt erhalten.", repDedupFoundBy: "Unabhängig gefunden von", - repMethodTitle: "Wie dieser Lauf arbeitete", + repMethodTitle: "Wie dieser Durchlauf ablief", repMethodLead: - "Recon wählte die anwendbaren Audits, ein Spezialisten-Schwarm führte sie parallel aus, Befunde wurden zusammengeführt und dedupliziert, und jeder P0/P1 musste unabhängige Skeptiker überstehen, bevor er in den Bericht kam.", + "Recon wählte die anwendbaren Audits, ein Spezialisten-Schwarm führte sie parallel aus, die Befunde wurden zusammengeführt und um Doppelungen bereinigt, und jeder P0/P1 musste unabhängige Skeptiker überstehen, bevor er in den Bericht kam.", repViewIssue: "Issue ansehen", - repFullRun: "Ganzen Lauf ansehen", + repFullRun: "Ganzen Durchlauf ansehen", repEvidence: "Beleg", repBefore: "Vorher", repAfter: "Nachher", @@ -333,9 +333,9 @@ export const ui = { // German prose for the data that lives in content.ts (icons/files/names stay shared). const auditBlurbDe: Record = { - security: "14 Domänen: Injection, AuthN/Z, Secrets, Supply Chain, IaC, CI/CD, Business-Logik, Datenschutz, LLM.", + security: "14 Domänen: Injection, AuthN/Z, Secrets, Supply Chain, IaC, CI/CD, Business Logic, Datenschutz, LLM.", repo: "Repo-Engineering: Architektur, Stack-Konsistenz, Docs, Tests, Deps, CI/CD, Git-Hygiene.", - frontend: "16-Agenten-Frontend-Sweep: Usability, Psychologie, Visual Design, A11y, Performance, SEO, Copy, CRO.", + frontend: "16-Agenten-Frontend-Durchlauf: Usability, Psychologie, Visual Design, A11y, Performance, SEO, Copy, CRO.", api: "API-Design: Ressourcen-Modell, HTTP-Semantik, Error-Model, Versionierung, Idempotenz, Rate-Limits, DX.", performance: "Performance & Skalierung: Hotspots, N+1, Caching, Concurrency, Leaks, Lastverhalten, Resilienz, FinOps.", data: "Daten & Datenbank: Modellierung, Typen, Constraints, Migrations-Sicherheit, Transaktionen, Integrität, Backup/DR.", @@ -345,7 +345,7 @@ const auditBlurbDe: Record = { accessibility: "Tiefes A11y: Semantik, Tastatur, Fokus, Screenreader, Kontrast, Formulare, Zoom, Motorik, Motion, Kognition.", documentation: "Doku-Qualität vs. Standard: Repo-Kopf, Onboarding, Doc-Code-Drift, Schreibstil, Diátaxis, Repo-Health.", content: "Inhalt & Botschaft: These hinterfragen, Zielgruppen-Fit, Belege & Originalität, Struktur, Stimme, konkrete Umformulierungen.", - lean: "Schlankheit: toter Code, ungenutzte/Phantom-Deps, Duplikation, AI-Slop, Dependency-Transparenz — sicherer Strip-down ohne Über-Löschen.", + lean: "Schlankheit: toter Code, ungenutzte/Phantom-Deps, Duplikation, AI-Slop, Dependency-Transparenz — sicheres Verschlanken ohne Über-Löschen.", }; // German prose for each principle, keyed by the principle's English `title` (stable), @@ -356,7 +356,7 @@ const principleDe: Record = { body: "Jeder Befund nennt ein konkretes Artefakt — file:line, einen Query-Plan, einen Request, einen Config-Wert, eine gemessene Metrik. Kein Beleg, kein Befund.", }, "Adversarial self-challenge": { - title: "Adversarielle Selbst-Challenge", + title: "Adversarielle Selbstprüfung", body: "Kein Befund überlebt, bevor unabhängige Skeptiker-Agenten ihn zu widerlegen versucht haben — er muss mindestens zwei von drei überstehen, sonst wird er verworfen. Wer eine feindselige Lesart nicht übersteht, ist kein Befund.", }, "Blind-spot hunting": { @@ -370,9 +370,9 @@ const principleDe: Record = { }; const phaseDe: Record = { - "0": { title: "Reconnaissance", body: "Faktisches Inventar + Surface-Map. Noch keine Meinungen." }, + "0": { title: "Reconnaissance", body: "Faktisches Inventar + Oberflächen-Karte. Noch keine Meinungen." }, "1": { title: "Spezialisten-Schwarm", body: "Viele Domänen-Experten parallel, jeder belegpflichtig." }, - "2": { title: "Cross-Pollination", body: "Mergen, deduplizieren, Compound-Findings sichtbar machen." }, + "2": { title: "Cross-Pollination", body: "Zusammenführen, Doppelungen entfernen, Verbund-Befunde sichtbar machen." }, "3": { title: "Adversarielle Verifikation", body: "Unabhängige Skeptiker widerlegen jeden P0/P1; ≥2 von 3 zum Überleben." }, "4": { title: "Benchmark", body: "Vergleich gegen benannte Best-in-Class-Referenzen und Standards." }, "5": { title: "Synthese", body: "Bericht, Scorecard, Issues und eine 30/60/90-Roadmap." }, @@ -380,7 +380,7 @@ const phaseDe: Record = { const standardBlurbDe: Record = { "Documentation standard": - "Ein Dokumentationsstandard mit fünf Repo-Profilen und einer 0–100-Rubrik — derselbe Maßstab, an dem das Documentation-Audit misst.", + "Ein Dokumentationsstandard mit fünf Repo-Profilen und einer 0–100-Rubrik — derselbe Massstab, an dem das Documentation-Audit misst.", "Issue-output standard": "Der verbindliche Vertrag, dem jedes Audit folgt: zuerst ein nach Priorität sortiertes Tracking-Issue, dann pro Befund ein Issue mit eigener Management-Summary.", }; @@ -407,7 +407,7 @@ const reportProse: Record> = { "self-audit": { title: "Dieses Repo auditieren", summary: - "Die Suite auf das eigene Repository gerichtet — 7 anwendbare Audits, 4 mit Begründung als nicht anwendbar deklariert, null P0, ein P1.", + "Die Suite auf das eigene Repository angesetzt — 7 anwendbare Audits, 4 mit Begründung als nicht anwendbar deklariert, null P0, ein P1.", }, }, }; @@ -419,7 +419,7 @@ const reportVerdicts: Record> = { }, de: { selfAudit: - "Production-ready. Alle sieben anwendbaren Audits liegen bei A− bis A (90–94), null P0, genau ein P1; die einzigen echten Restrisiken betreffen das Supply-Chain-Vertrauensmodell, das das Produkt verkauft, nicht eine Live-Exposition.", + "Production-ready. Alle sieben anwendbaren Audits liegen bei A− bis A (90–94), null P0, genau ein P1; die einzigen echten Restrisiken betreffen das Supply-Chain-Vertrauensmodell, das das Produkt vermarktet — keine akute Gefährdung im Betrieb.", }, }; @@ -434,7 +434,7 @@ const reportReasons: Record> = { api: "Keine route.ts / Server-Actions — voll statisch.", data: "Keine Datenbank, kein Schema, kein ORM.", aiLlm: "Prompts laufen im externen Agenten; kein In-Repo-Runtime.", - compliancePrivacy: "Keine Formulare, kein Auth, keine PII außer Vercel Analytics.", + compliancePrivacy: "Keine Formulare, kein Auth, keine PII ausser Vercel Analytics.", }, }; @@ -477,20 +477,20 @@ const reportFindings: Record> = { checksums: { title: "CHECKSUMS.txt wird in CI nicht verifiziert", evidence: "CHECKSUMS.txt · .github/workflows", - before: 'Verspricht „verify-before-execute" — nicht erzwungen', - after: "Ein CI-Gate verifiziert die Checksummen bei jedem Lauf", + before: 'Verspricht „verify-before-execute“ — nicht erzwungen', + after: "Ein CI-Gate verifiziert die Checksummen bei jedem Durchlauf", }, pins: { - title: "~17 hand-gepflegte Versions-Pins ohne Single Source of Truth", + title: "~17 von Hand gepflegte Versions-Pins ohne Single Source of Truth", evidence: "verstreute v0.5.0-Pins im Repo", - before: "Jeder Pin von Hand editiert, driftanfällig", - after: "Eine Single Source of Truth, per Skript gebumpt", + before: "Jeder Pin von Hand bearbeitet, anfällig für Abweichungen", + after: "Eine Single Source of Truth, per Skript hochgezählt", }, enMeta: { - title: 'EN-Metadaten hartcodieren „German GitHub issues"', + title: 'EN-Metadaten waren fest auf „German GitHub issues“ verdrahtet', evidence: "web/lib/site.ts", - before: "Englische Copy behauptete nur deutsche Ausgabe", - after: "Copy spiegelt deutsche oder englische Ausgabe", + before: "Der englische Text behauptete, die Ausgabe erfolge nur auf Deutsch", + after: "Der Text spiegelt deutsche oder englische Ausgabe wider", }, }, }; @@ -504,8 +504,8 @@ const reportDedup: Record> }, de: { checksums: { - title: '„CHECKSUMS.txt wird in CI nicht verifiziert"', - body: "Unabhängig von der repo-, infrastructure- und security-Linse gefunden und zu einem einzigen Backlog-Item gemergt — alle drei Zitate erhalten. Die Versions-Pin-Hälfte wurde als eigener Fix abgespalten.", + title: '„CHECKSUMS.txt wird in CI nicht verifiziert“', + body: "Unabhängig vom repo-, infrastructure- und security-Prüfbereich gefunden und zu einem einzigen Backlog-Item zusammengeführt — alle drei Zitate bleiben erhalten. Der Teil zu den Versions-Pins wurde als eigener Fix abgespalten.", }, }, }; diff --git a/web/lib/locale-de-ch.test.ts b/web/lib/locale-de-ch.test.ts new file mode 100644 index 0000000..d0450e4 --- /dev/null +++ b/web/lib/locale-de-ch.test.ts @@ -0,0 +1,59 @@ +import { describe, it, expect } from "vitest"; +import { readFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +/** + * de-CH locale guard. These files carry the German product copy. Two invariants + * that a future edit must not silently break: + * 1. No `ß` — Swiss orthography uses `ss`. English strings have no `ß`, so a + * whole-file scan is safe; tagged immutable exceptions go in SS_ALLOW. + * 2. No German-inflected Denglish / translationese the content audit removed. + * The denylist is morphology-aware (German inflections only), so it never + * fires on the English source strings (e.g. EN "steelman" vs DE "steelmant"). + */ +const HERE = dirname(fileURLToPath(import.meta.url)); +const FILES = ["i18n.ts", "audit-details.ts"]; + +// Immutable proper names / code / legal titles / verbatim quotes that may keep a ß. (None today.) +const SS_ALLOW: RegExp[] = []; + +// German „…" must close with the U+201C closer, never an ASCII straight quote. +const BAD_QUOTE = /„[^“”\n]*"/; // „ opener directly closed by ASCII " + +const DENGLISH: { label: string; re: RegExp }[] = [ + { label: 'mappen → use kartieren/zuordnen', re: /\bge?mapp(t|en|te|st)\b/i }, + { label: 'laufen lassen → use einsetzen/ausführen/prüfen', re: /\blauf(en|t)\s+(zu\s+)?(lassen|lässt|gelassen)\b/i }, + { label: 'deduplizieren → use Doppelungen entfernen', re: /\bdedupliz/i }, + { label: 'gemergt → use zusammengeführt', re: /\bgemergt\b/i }, + { label: 'gebumpt → use hochgezählt', re: /\bgebumpt\b/i }, + { label: 'Linse (lens calque) → use Prüfbereich', re: /\bLinsen?\b/ }, + { label: '"der Audit" (genus) → "das Audit"', re: /\b[Dd]er Audit\b/ }, + { label: 'steelmann-inflected → "den stärksten Gegenpunkt bilden"', re: /\bsteelman(nt?|en)\b/i }, +]; + +describe("de-CH locale guard", () => { + for (const file of FILES) { + const text = readFileSync(join(HERE, file), "utf8"); + + it(`[${file}] uses Swiss orthography (no ß)`, () => { + const offenders = text + .split("\n") + .map((line, i) => ({ line, n: i + 1 })) + .filter(({ line }) => line.includes("ß") && !SS_ALLOW.some((re) => re.test(line))) + .map((o) => `${file}:${o.n}`); + expect(offenders).toEqual([]); + }); + + it(`[${file}] closes German „…" with the correct curly quote`, () => { + expect(BAD_QUOTE.test(text), `straight-quote closer after a „ opener in ${file}`).toBe(false); + }); + + for (const { label, re } of DENGLISH) { + it(`[${file}] no Denglish: ${label}`, () => { + const m = text.match(re); + expect(m, m ? `found "${m[0]}" in ${file}` : "").toBeNull(); + }); + } + } +});