Quality Gates Reference (Deutsch)
Gate-Inventar (~90 Skripte)
Abschnitt betitelt „Gate-Inventar (~90 Skripte)“Die Skripte befinden sich unter scripts/check/ (Richtlinien-Gates) und scripts/quality/ (Ratchet-Engine).
Die maßgebliche CI-Quelle ist .github/workflows/ci.yml.
Schnellpfad für Release-PRs (quality.yml)
Abschnitt betitelt „Schnellpfad für Release-PRs (quality.yml)“.github/workflows/quality.yml wird für PRs ausgeführt, deren Ziel release/** ist. Der Workflow hält
Contributor-Branches mit pfadgefilterten schnellen Gates in Bewegung und liefert bei Codeänderungen
zusätzlich ein nicht blockierendes Signal für den Produktions-Build:
| Job | Umfang | Blockierend |
|---|---|---|
Build (advisory) |
Nicht als Entwurf markierte Code-PRs und Mergify-Queue-Branches; Node 24, npm-ci-retry, check:node-runtime, npm run build mit OMNIROUTE_USE_TURBOPACK=1; kein Artefakt-Upload, da kein nachgelagerter Qualitätsjob ihn verwendet |
Nicht blockierend (continue-on-error: true; nach einer Woche stabiler Release-PR-Läufe entfernen) |
Docs Gates (fast-path) |
Dokumentations-/Code-PRs; API-Dokumentationsreferenzen und docs-all | Ja |
Fast Quality Gates |
Code-PRs; statische Prüfungen, Typprüfung, Dashboard-Typprüfung, betroffene Unit-Tests | Ja |
Forgotten sibling tests |
Code-PRs; geänderte Module werden bis zu statischen Konsumenten und infrage kommenden benachbarten Tests nachverfolgt; Barrel- und Dynamic-Import-Pfade werden als nicht blockierende Diagnosen gemeldet, einschließlich referenzierter Ausnahmen aus der Positivliste | Nicht blockierend |
Vitest (fast-path) |
Code-PRs; schnelle Vitest-Suite | Ja |
Unit Tests fast-path |
Code-PRs; Unit-Test-Suite mit 4 Shards | Ja |
No new ESLint warnings |
Code-PRs; unterdrückungsabhängiger Lint-Schutz | Ja für eigenen Ursprung, nicht blockierend für Forks |
Merge integrity (changelog + generated skills) |
Nicht als Entwurf markierte PRs; Synchronisierung von Changelog und generierten Skills | Ja für eigenen Ursprung, nicht blockierend für Forks |
Bericht zu vergessenen benachbarten Tests
Abschnitt betitelt „Bericht zu vergessenen benachbarten Tests“npm run check:forgotten-sibling-tests verwendet den Import-Resolver wieder, der auch der Testauswirkungsübersicht zugrunde liegt.
Für jedes geänderte Produktionsmodul meldet er deterministische
Ketten nach dem Muster geändertes Modul/Symbol -> statischer Konsument -> infrage kommender benachbarter Test, wenn der betreffende
Test nicht im Pull-Request-Diff enthalten ist. Die Markdown-Zusammenfassung und das JSON-Ergebnis werden
zur Kalibrierung vor einer blockierenden Einführung als Workflow-Artefakt forgotten-sibling-tests aufbewahrt.
Barrel-Re-Exporte und dynamische Importe dienen ausschließlich als Auflösungsdiagnosen; sie führen niemals zu einem
blockierenden Befund. Geprüfte Ausnahmen befinden sich in
config/quality/forgotten-sibling-allowlist.json. Jeder Eintrag muss den Konsumenten und den infrage kommenden
Test benennen, eine konkrete Begründung angeben und auf ein GitHub-Issue oder einen Pull Request verweisen. Fehlerhafte Einträge führen
standardmäßig zu einem Fehlschlag. Ausnahmen können weder einen gelöschten infrage kommenden Test noch einen Diff unterdrücken, der .skip/.todo
hinzufügt; abgeschwächte Assertions und andere Verschleierungen bleiben Aufgabe des unabhängig blockierenden
Gates check:test-masking.
Job: lint
Abschnitt betitelt „Job: lint“Wird bei jedem PR auf main ausgeführt. Blockiert bei einem Fehlschlag den Merge.
Skript (npm run ...) |
Validiert | Blockierend |
|---|---|---|
check:node-runtime |
Die Node.js-Version liegt innerhalb des unterstützten Bereichs | Ja |
check:cycles |
Zirkuläre Importe — alle Module in src/ + open-sse/ |
Ja |
check:route-validation:t06 |
Zod-Schemas sind für alle Routen vorhanden (Tier-6-Richtlinie) | Ja |
check:any-budget:t11 |
Die Anzahl von @ts-expect-error // any überschreitet das Budget nicht (Tier-11-Catraca) |
Ja |
check:provider-consistency |
Jeder Provider in providers.ts hat einen entsprechenden Eintrag in providerRegistry.ts (und umgekehrt, innerhalb der Allowlist) |
Ja |
check:model-lifecycle |
Die drei manuell gepflegten Routingtabellen bleiben mit dem eingecheckten Lifecycle-Snapshot (#11503) konsistent: FITNESS_TABLE (taskFitness.ts) bewertet keine eingestellte ID, die REGISTRY routen kann; jedes Ziel aus BUILT_IN_ALIASES ist in REGISTRY vorhanden und fehlt im Snapshot der eingestellten IDs; jede eingestellte ID, die noch in REGISTRY enthalten ist, wird weitergeleitet oder in allowedRetiredInCatalog aufgeführt; und weder Quelle noch Ziel aus DEFAULT_DEGRADATION_MAP sind in diesem Snapshot als eingestellt verzeichnet. Dies beweist nicht, dass ein Modell derzeit von einem aktiven Upstream bereitgestellt wird. Offline — Vergleich mit config/quality/model-lifecycle.json, das manuell mit npm run quality:refresh-model-lifecycle aktualisiert wird (Netzwerkzugriff; nicht in CI eingebunden). allowedRetiredInCatalog ist eine schrittweise abzubauende Sperrklinke: Einen Eintrag nur zusammen mit einem Tracking-Issue hinzufügen. |
Ja |
check:fetch-targets |
Jeder Aufruf von fetch("/api/...") im clientseitigen src/ wird zu einer vorhandenen route.ts aufgelöst |
Ja |
check:deps |
Alle mit npm install installierbaren Abhängigkeiten in jeder package.json im Repository sind in dependency-allowlist.json enthalten; neue nicht fixierte oder durch Slopsquatting entstandene Pakete werden gemeldet |
Ja |
audit:deps |
npm audit (Root + Electron) — keine Warnungen mit hohem/kritischem Schweregrad (überschneidet sich mit OSV-check:vuln-ratchet; siehe Rationalisierungs-Backlog) |
Ja |
check:lockfile |
Integrität von package-lock.json — HTTPS-Registry, Integritäts-Hashes, keine Host-Überschreibungen |
Ja |
check:licenses |
SPDX-Lizenz-Zulassungsliste für Produktionsabhängigkeiten | Ja |
check:tracked-artifacts |
Keine Build-Artefakte / eingecheckten node_modules-Symlinks (wird auch beim Husky-Pre-Commit ausgeführt; Pre-Push ist absichtlich schlank gehalten — #6716) |
Ja |
check:ai-attribution |
Keine KI-/Bot-Co-Authored-By-Trailer oder Hinweise auf KI-Generierung in PR-Commits, Titel oder Text — Harte Regel Nr. 16 (in der Fast-Gates-Schleife von quality.yml für PR→release/** — liest die Event-Nutzlast, außerhalb von PRs keine Aktion — sowie ein reiner PR-Schritt im Lint-Job von ci.yml für PR→main; außerdem der Husky-Hook commit-msg; menschliche Co-Autoren sind zulässig; #14436) |
|
check:vitest-exclusions |
Jeder Vitest-Ausschluss nennt ein Tracking-Issue und ist in config/quality/vitest-exclusions.json aufgeführt (#13204) |
Ja |
check:file-size |
Keine Quelldatei überschreitet die Obergrenze der jeweiligen Dateierweiterung (Ratsche: eingefrorene große Dateien in der Liste frozen) |
Ja |
check:error-helper |
Fehlerantworten in Executors/Handlern verwenden buildErrorBody() / sanitizeErrorMessage() (Harte Regel Nr. 12) |
Ja |
check:migration-numbering |
Migration-SQL-Dateien sind fortlaufend nummeriert, ohne Lücken oder Duplikate | Ja |
check:public-creds |
Keine literalen OAuth-client_id-/client_secret- oder Firebase-Webschlüssel außerhalb von publicCreds.ts (Strikte Regel Nr. 11) |
Ja |
check:db-rules |
Kein direktes SQL außerhalb der Module in src/lib/db/; keine Barrel-Imports aus localDb.ts (Strikte Regeln Nr. 2/Nr. 5) |
Ja |
check:known-symbols |
In ihren Dispatch-Tabellen registrierte Provider-Executors, Routing-Strategien und Übersetzer stimmen mit den Dateien auf dem Datenträger überein – keine verwaisten oder nicht deklarierten Symbole | Ja |
check:route-guard-membership |
Jede Route, die einen untergeordneten Prozess startet, wird durch isLocalOnlyPath() klassifiziert (Strikte Regeln Nr. 15/Nr. 17) |
Ja |
check:test-discovery |
Jede *.test.ts- / *.spec.ts-Datei im Repository wird von mindestens einem Test-Runner erfasst (Ratchet-Prinzip: Die Liste verwaister Dateien in test-discovery-baseline.json darf nur kürzer werden) |
Ja |
check:agent-skills-sync |
Generierte Agent-Skills-Artefakte stimmen mit ihrem Quellkatalog überein (keine Abweichung) | |
check:provider-asset-provenance |
Anbieterlogos/-Assets verfügen über einen dokumentierten Herkunftsnachweis | |
lint:json |
JSON-Konfigurationsdateien können geparst werden und erfüllen die Lint-Regeln des Repositories | |
typecheck:core |
TypeScript-Kompilierung ohne Fehler (nur informative Warnungen) | Ja |
typecheck:noimplicit:core |
Striktes noImplicitAny — zukunftsorientiert; viele bereits vorhandene Aufrufstellen benötigen weiterhin Annotationen |
Informativ (continue-on-error: true) |
check:dashboard-typecheck |
Auf src/app/(dashboard)/** beschränktes tsc (#7033) — die kuratierte Positivliste mit 27 Dateien von typecheck:core enthält keine Dashboard-TSX-Dateien, und next build führt dafür ebenfalls nie eine Typprüfung durch (next.config.mjs setzt ignoreBuildErrors: true), sodass Regressionen durch verwaiste Bezeichner dort (#6625/#6909) für CI unsichtbar waren. Abgleich mit einer eingefrorenen Baseline der Anzahl pro Datei und TS-Code (config/quality/dashboard-typecheck-baseline.json, dasselbe Muster zur Erzwingung der Aktualität wie bei check:known-symbols) — nur NEUE Fehler, die über die in der Baseline festgelegte Anzahl hinausgehen, lassen das Gate fehlschlagen; mit --update schrittweise reduzieren, wenn ein bereits vorhandener Fehler behoben wird. |
Ja |
Job: quality-gate
Abschnitt betitelt „Job: quality-gate“Wird nach test-coverage ausgeführt. Blockiert das Zusammenführen bei einem Fehler.
| Skript | Validiert | Blockierend |
|---|---|---|
quality:collect |
Erzeugt quality-metrics.json (Anzahl der ESLint-Warnungen, Abdeckung aus dem zusammengeführten Shard-Bericht) |
Ja (vorgelagert zum Ratchet) |
quality:ratchet |
Keine Metrik in quality-baseline.json hat sich verschlechtert (ESLint-Warnungen ≤ Baseline; Abdeckung ≥ Baseline) |
Ja |
check:duplication |
Codeduplizierung (jscpd@4) überschreitet die Baseline in quality-baseline.json nicht |
Ja |
check:complexity |
Zyklomatische Komplexität auf Dateiebene überschreitet den Grenzwert nicht (ESLint-Kernregeln complexity + max-lines-per-function) |
Ja |
check:cognitive-complexity |
Ratchet für kognitive Komplexität (eslint-plugin-sonarjs) — separater ESLint-Durchlauf; CI führt beide zusammengeführt als einzelnen Schritt check:complexity-ratchets aus |
Ja |
check:dead-code |
Ratchet für ungenutzte Exporte/Dateien (knip) verschlechtert sich gegenüber der Baseline nicht | Ja |
check:compression-budget |
Budget für den Komprimierungs-Benchmark — Mindestwerte für Token-Einsparungen pro Engine dürfen sich nicht verschlechtern | Ja |
check:type-coverage |
Ratchet für den typisierten Prozentanteil (type-coverage) verschlechtert sich nicht; ersetzt typecheck:noimplicit:core weitgehend |
Ja |
check:codeql-ratchet |
Anzahl offener CodeQL-Warnungen verschlechtert sich nicht (liest über gh api; kontrolliertes Überspringen ohne Token) — Aktualisierungsintervall und manueller Auslöser: siehe „CodeQL-Ratchet“ unten |
Ja |
Job: quality-extended
Abschnitt betitelt „Job: quality-extended“Der gesamte Job ist nur informativ (continue-on-error: true). Die npm-basierten Ratchets werden
tatsächlich ausgeführt; die externen Scanner werden über gh release download installiert und überspringen sich selbst (Exit-Code 0),
wenn eine Binärdatei weiterhin fehlt.
| Skript | Validiert | Blockierend |
|---|---|---|
check:circular-deps |
Keine zirkulären Abhängigkeiten (dpdm) | Nur informativ |
check:bundle-size |
Bundle-Größe überschreitet den Grenzwert nicht | Nur informativ |
check:secrets |
Suche nach Geheimnissen (gitleaks) — wird übersprungen, wenn die Binärdatei fehlt | Nur informativ |
check:vuln-ratchet |
Sicherheitslücken in Abhängigkeiten (osv-scanner) verschlechtern sich nicht — wird übersprungen, wenn die Binärdatei fehlt | Nur informativ |
check:workflows |
Workflow-Linting (actionlint + zizmor) — wird übersprungen, wenn Binärdateien fehlen | Nur informativ |
check:openapi-breaking |
Inkompatible Änderungen am öffentlichen API-Vertrag (openapi.yaml) gegenüber dem Basis-Branch (oasdiff) — erzeugt openapiBreaking=N; wird übersprungen, wenn oasdiff fehlt oder die Basisspezifikation nicht aufgelöst werden kann |
Nur informativ |
Job: docs-sync-strict
Abschnitt betitelt „Job: docs-sync-strict“Wird bei jedem PR an main ausgeführt. Blockiert bei einem Fehler das Zusammenführen.
| Skript | Validiert | Blockierend |
|---|---|---|
check:docs-all |
Meta-Gate, das die 6 nachfolgenden Sub-Gates nacheinander ausführt | Ja |
↳ check:docs-sync |
Versionskonsistenz zwischen CHANGELOG / OpenAPI / llm.txt | Ja |
↳ check:docs-counts |
Zahlen im Fließtext (Anbieteranzahl, Migrationsanzahl usw.) liegen innerhalb des Ratchet-Fensters der tatsächlichen Zahlen | Ja |
↳ check:env-doc-sync |
Jede Umgebungsvariable in .env.example ist in einer Dokumentationstabelle dokumentiert und umgekehrt |
Ja |
↳ check:deprecated-versions |
Keine veralteten Versionsangaben in der Dokumentation | Ja |
↳ check:doc-links |
Interne Markdown-Links in der Dokumentation verweisen auf vorhandene Dateien (Form [text]/(path)) |
Ja |
↳ check:fabricated-docs |
In der Dokumentation erwähnte Routen, Umgebungsvariablen, CLI-Befehle, Hook-Namen und Dateipfade sind in der Codebasis vorhanden. Striktes Gate mit --strict; ohne Flag weicher Fehler. |
Ja (über --strict in CI) |
check:cli-i18n |
Zeichenfolgen für CLI-Befehle sind in allen i18n-Locale-Dateien vorhanden | Ja |
check:openapi-coverage |
Die OpenAPI-Spezifikation deckt mindestens einen per Ratchet festgelegten Mindestwert der tatsächlichen Routen ab | Ja |
check:openapi-security-tiers |
Sicherheitsebenen-Anmerkungen in openapi.yaml stimmen mit den Klassifizierungen in routeGuard.ts überein |
Hinweis |
check:openapi-routes |
Jeder Pfad in openapi.yaml verweist auf eine tatsächlich vorhandene route.ts (Halluzinationsschutz) |
Ja |
check:docs-symbols |
Jede /api/...-Referenz in docs/**/*.md verweist auf eine tatsächlich vorhandene route.ts (Halluzinationsschutz) |
Ja |
i18n translation drift |
Nicht übersetzte Schlüssel in i18n-Locale-Dateien — nur Warnung | Hinweis |
Job: i18n-ui-coverage
Abschnitt betitelt „Job: i18n-ui-coverage“| Skript | Validiert | Blockierend |
|---|---|---|
check-ui-keys-coverage (inline) |
Die Abdeckung der UI-i18n-Schlüssel beträgt ≥ 65 % | Ja |
check-ui-value-drift (inline) |
Ein neu formulierter englischer Wert hinterlässt keine veraltete Übersetzung | Ja |
check-new-key-coverage (inline) |
Ein neuer englischer Schlüssel ist in jeder Locale übersetzt — eine __MISSING__:-Markierung wird abgelehnt |
Ja |
check-translation-ratio |
Der Anteil echter Übersetzungen pro Locale (mit dem Englischen identische / Platzhalter- / fehlende Einträge außerhalb der Positivliste) darf config/quality/i18n-translation-baseline.json + Toleranz nicht überschreiten |
Hinweis |
Benötigt fetch-depth: 0 — das Value-Drift-Gate vergleicht en.json per Diff mit der Merge-Basis.
check-ui-value-drift — Gate gegen veraltete Übersetzungen
Abschnitt betitelt „check-ui-value-drift — Gate gegen veraltete Übersetzungen“Erkennt die eine i18n-Regression, die die anderen Gates strukturell nicht erkennen können: Ein englischer Wert wird neu formuliert, während die aus dem vorherigen englischen Text abgeleiteten Übersetzungen bestehen bleiben, sodass nicht englischsprachige Benutzer weiterhin einen selbstsicher formulierten, aber inzwischen falschen Text lesen.
Dies wurde tatsächlich so veröffentlicht. oauthModal.googleOAuthWarning wurde neu formuliert, als der Antigravity-
Anmeldehelfer eingeführt wurde (#5203); 39 von 43 Locales behielten einen Text bei, der Betreiber anwies, „die
vollständige URL zu kopieren und unten einzufügen“ — ein Ablauf, der für diesen Anbieter nicht abgeschlossen werden kann. Dies blieb
bis #8463 unbemerkt, weil:
sync-ui-keysnur fehlende Schlüssel ergänzt, niemals veraltete;check-ui-keys-coveragedie Anwesenheit von Schlüsseln zählt, sodass eine veraltete Übersetzung als abgedeckt gewertet wird;check-translation-driftdie Dokumentationsspiegel unterdocs/i18n/<locale>/**.mdverfolgt —src/i18n/messages/*.jsonwird nie gelesen. Seit der erneuten Synchronisierung 2026-09 im Jobdocs-sync-strictblockierend: Kerndokument bearbeiten →npm run i18n:run -- --files=<doc>(abschnittsweise, kostengünstig).
Diff-bewusst, nicht durch eine Baseline gestützt. Es vergleicht en.json am Merge-Base mit dem
Arbeitsbaum; für jeden Schlüssel, dessen englischer Wert geändert wurde, gilt jede Locale, die noch eine
unveränderte Übersetzung enthält, als veraltet. Dadurch werden bereits bestehende Altlasten bewusst eingefroren — aus einem Diff
lässt sich nicht erkennen, von welchem alten englischen Text eine seit Langem bestehende Übersetzung stammt, daher bewertet das Gate
nur, was von der aktuellen Änderung betroffen ist. Die Alternative (eine Hash-Baseline pro Schlüssel) würde eine
generierte Datei von ca. 600 KB erfordern, dreimal so groß wie die größte bestehende Baseline, die sich bei jedem i18n-PR ändern würde.
Es gibt zwei Möglichkeiten, die Prüfung zu erfüllen:
- die betroffenen Übersetzungen aktualisieren oder
- sie auf
__MISSING__:<new english>setzen — zur Laufzeit wird dann der korrigierte englische Text ausgeliefert (src/i18n/request.ts::deepMergeFallback, #7258) und der Schlüssel zur Übersetzung vorgemerkt.
Wenn sich die Bedeutung des Textes geändert hat, sollte der Schlüssel umbenannt werden: Ein neuer Schlüssel kann keine veraltete Übersetzung übernehmen. Dieses Muster wurde in #8463 verwendet.
npm run i18n:check-value-drift # strikt (wird von CI ausgeführt)npm run i18n:check-value-drift:warn # nur BerichtBASE_REF=origin/release/vX.Y.Z npm run i18n:check-value-driftWird der Basiskatalog nicht gefunden, endet die Prüfung mit Code 0 und SKIP reason=base-unresolved (flacher
Klon ohne den Basis-Ref), analog zu check-openapi-breaking.
Job: i18n
Abschnitt betitelt „Job: i18n“Vollständige i18n-Validierungsmatrix (ein Job pro Locale). Der gesamte Job ist unverbindlich.
| Skript | Validiert | Blockierend |
|---|---|---|
validate_translation.py quick |
Vollständigkeit der Übersetzung je Locale | Unverbindlich (continue-on-error: true für den gesamten Job) |
Job: pr-test-policy
Abschnitt betitelt „Job: pr-test-policy“Wird nur bei Pull Requests ausgeführt.
| Skript | Validiert | Blockierend |
|---|---|---|
check:pr-test-policy |
PRs, die Produktionscode in src/, open-sse/, electron/ oder bin/ ändern, müssen Tests enthalten oder aktualisieren (feste Regel Nr. 8) |
Ja |
check:test-masking |
Geänderte Testdateien verringern nicht die Nettoanzahl der Assertions und fügen keine assert.ok(true)-Tautologien hinzu |
Ja |
check:pr-evidence |
Der PR-Text nennt Test-/VPS-Nachweise für die Änderung (automatisiert feste Regel Nr. 18 durch Durchsuchen des PR-Textes — fragil, siehe Backlog) | Ja |
Job: test-vitest
Abschnitt betitelt „Job: test-vitest“Wird nach build ausgeführt. Blockiert bei einem Fehler den Merge.
| Suite | Validiert | Blockierend |
|---|---|---|
test:vitest |
MCP-Server (110 Tools), autoCombo, Cache — vitest-Test-Runner | Ja |
test:vitest:ui |
UI-Komponententests — vitest-Test-Runner | Blockierend — bereits bestehende Fehler sind in vitest.config.ts ausdrücklich ausgeschlossen; neue Fehler lassen den Job fehlschlagen |
Nächtliche Workflows (geplant, unverbindlich)
Abschnitt betitelt „Nächtliche Workflows (geplant, unverbindlich)“Diese werden nach einem Cron-Zeitplan (und über workflow_dispatch) ausgeführt, niemals bei PRs. Sie sind alle unverbindlich.
| Workflow | Validiert | Blockierend |
|---|---|---|
nightly-property |
fast-check-Property-Tests mit zufälligem Seed und hoher Anzahl von Durchläufen | Unverbindlich |
nightly-resilience |
Heap-Wachstums-Gate, Chaos-Fehlerinjektion, k6-Last-/Dauertests | Unverbindlich |
nightly-llm-security |
promptfoo-Injection-Guard (Blockiermodus) + garak-Probes (werden ohne Provider-Secret übersprungen) | Unverbindlich |
nightly-schemathesis |
OpenAPI-Vertrags-Fuzzing (schemathesis) gegen eine aktive OmniRoute-Instanz unter Verwendung von docs/openapi.yaml — deckt Spezifikationsverletzungen/unbehandelte 500-Fehler auf (Phase 8 B.4) |
Unverbindlich |
nightly-mutation |
Stryker-Mutationstestbewertung für die schnelle Unit-Test-Strecke — überlebende Mutanten zeigen schwache Assertions auf | Unverbindlich |
nightly-compat |
Kompatibilitätsmatrix der Node-Engine über die unterstützten engines.node-Bereiche hinweg |
Unverbindlich |
Velocity-Phase (2026-08-30 → v4.0 LTS): Alle Baselines um 20 % gelockert
Abschnitt betitelt „Velocity-Phase (2026-08-30 → v4.0 LTS): Alle Baselines um 20 % gelockert“Entscheidung des Owners (2026-08-30): Bis zur Modularisierung in v4.0 ist die
Auslieferungsgeschwindigkeit wichtiger als die Einhaltung der technischen Schuldengrenze. Jede
numerische Ratchet-Baseline wurde in einem einzigen auditierbaren Durchgang um 20 % gelockert,
und die Phase ist in config/quality/quality-baseline.json deklariert:
"_policy": { "phase": "velocity", "since": "2026-08-30", "until": "4.0.0", "relaxPct": 20, "requireTighten": false }| Was geändert wurde | Wo |
|---|---|
metrics.*.value — Werte, bei denen niedriger besser ist, ×1,2; Prozentsätze, bei denen höher besser ist, ÷1,2 (Coverage-Untergrenze bleibt 60, eslintErrors bleibt 0, eslintWarnings 0 → 20 % der eingefrorenen Anzahl an Unterdrückungen) |
quality-baseline.json (Hinweis _relax_velocity_2026_08_30 listet alle Vorher- → Nachher-Werte auf) |
count ×1,2 / percentage ×1,2 |
complexity-baseline.json, duplication-baseline.json |
cap, testCap, jede Zeilenobergrenze in frozen[*] / testFrozen[*] ×1,2 |
file-size-baseline.json |
| Anzahl pro Datei / pro TS-Code ×1,2 | api-typecheck-baseline.json, dashboard-typecheck-baseline.json, open-sse-typecheck-baseline.json |
THRESHOLD 36 → 30 |
scripts/check/check-openapi-coverage.mjs |
--require-tighten wird nur noch als Hinweis behandelt, solange _policy.requireTighten === false |
scripts/quality/check-quality-ratchet.mjs |
Das nächtliche bank-ratchet-shrinks wird pausiert (es würde die gemessene Verringerung festschreiben und den Spielraum wieder aufheben) |
.github/workflows/nightly-release-green.yml |
Allowlists (eslint-suppressions.json, test-masking-allowlist.json, test-discovery-baseline.json,
…) sind keine Budgets und wurden nicht verändert. Richtlinien-Gates mit Bestehen/Fehlschlagen
(Secrets, SQL-Regeln, Dokumentations-/Umgebungsvertrag, i18n-Parität, Unit-Tests) bleiben unverändert
— ein fehlgeschlagener Test bleibt ein fehlgeschlagener Test.
Werkzeuge
npm run quality:relax-baselines -- --pct 20 --note velocity_YYYY_MM_DD [--dry-run]— die einmalige Lockerung (scripts/quality/relax-baselines.mjs); eine zweite Ausführung mit demselben Hinweis wird abgelehnt.npm run quality:headroom [-- --only deadExports,fileSize] [--json out.json --md out.md]— misst jedes numerische Gate auf dieselbe Weise wie CI und gibt den verbleibenden Spielraum pro Gate aus (scripts/quality/baseline-headroom.mjs). Der nächtliche Jobbaseline-headroomveröffentlicht die Tabelle im fortlaufend gepflegten Issue 📈 Baseline-Spielraum (Velocity-Phase) und fügt das Labelheadroom-alerthinzu, wenn ein Gate höchstens noch 10 % von seiner Obergrenze entfernt ist oder diese bereits überschritten hat. Dieses Issue dient als Frühwarnung: Ein Budget, das innerhalb weniger Tage aufgebraucht ist, bedeutet, dass die Lockerung von wenigen PRs statt vom gesamten Team verbraucht wird — prüfen Sie die_rebaseline_*-Hinweise des betreffenden Gates.
Neucode-Modus (Clean-as-You-Code) — seit 2026-08-30, nur PR-Schnellpfad
Bei pull_request-Ereignissen übergibt quality.yml die Option --base-ref <PR base SHA> an
check:file-size, check:complexity-ratchets und check:dead-code. In diesem Modus vergleicht
das Gate HEAD mit der Merge-Base, beschränkt auf die vom PR geänderten Dateien
(scripts/check/newCodeMode.mjs: Die Merge-Base wird in einem temporären git worktree
materialisiert, ESLint/knip werden dort und auf HEAD ausgeführt und die Anzahl pro Datei wird
differenziert):
- blockierend — der PR hat zyklomatische/kognitive Verstöße oder ungenutzte Exporte in von ihm
geänderten Dateien hinzugefügt (
complexityNewCode=,cognitiveComplexityNewCode=,deadExportsNewCode=im Protokoll); - hinweisend — die globale Gesamtzahl im Vergleich zur eingefrorenen Baseline. Übernommene Abweichungen lassen einen unbeteiligten PR niemals fehlschlagen; die Abweichung wird beim Release-Abgleich erneut eingefroren und vom Headroom-Job überwacht.
workflow_dispatch-Ausführungen, der Release-Green-Durchlauf und der nächtliche Headroom-Job
haben keine PR-Basis und behalten den absoluten (globalen) Vergleich bei. Coverage, Duplizierung
und Type-Coverage bleiben vorerst global (ihre Werkzeuge erzeugen nicht ohne Weiteres einen
kostengünstigen Diff pro Datei) — sie sind Kandidaten für dieselbe Behandlung.
**Abschluss der Phase mit v4.0 (LTS = strenger als zuvor, nicht „zurück zum Normalzustand“)
- Auf dem unveränderten Stand von
release/v4.0.0:npm run quality:headroom --jsonzur Dokumentation ausführen, dannnpm run quality:ratchet -- --update,check:file-size --update,check:complexity-ratchets --update,check:dead-code --updatesowie--updatefür jedes Typecheck-Gate — jede Baseline wird auf den gemessenen Wert abgesenkt. _policyausquality-baseline.jsonlöschen (aktiviert--require-tightenund das nächtliche Banking erneut),THRESHOLD = 36(oder höher) incheck-openapi-coverage.mjswiederherstellen.- Über die Messwerte hinaus verschärfen, wo sich die Modularisierung ausgezahlt hat: den File-Size-
capwieder auf 1000 (oder 800) setzen, die Coverage-Untergrenzen um 5 erhöhen und für die modularisierten Pakete 0 ungenutzte Exporte festlegen.
Ratchet-Baseline (quality-baseline.json)
Abschnitt betitelt „Ratchet-Baseline (quality-baseline.json)“Die Ratchet-Engine (scripts/quality/check-quality-ratchet.mjs) liest quality-baseline.json
und vergleicht sie mit der neu erfassten quality-metrics.json. Jede Metrik, die sich
über ihren Epsilonwert hinaus verschlechtert, lässt den Build fehlschlagen.
Derzeit erfasste Metriken:
| Metrik | Richtung | Bedeutung |
|---|---|---|
eslintWarnings |
down |
Die Anzahl der ESLint-Warnungen darf nicht steigen |
coverage.statements |
up |
Die Statement-Abdeckung darf nicht sinken |
coverage.lines |
up |
Die Zeilenabdeckung darf nicht sinken |
coverage.functions |
up |
Die Funktionsabdeckung darf nicht sinken |
coverage.branches |
up |
Die Zweigabdeckung darf nicht sinken |
So aktualisieren Sie die Baseline nach einer tatsächlichen Verbesserung:
npm run quality:ratchet -- --updategit add quality-baseline.jsonDas Flag --update schreibt die aktuell gemessenen Werte in quality-baseline.json.
Committen Sie diese Datei zusammen mit der Änderung, durch die die Metrik verbessert wurde. Ein PR, der eine
Metrik verbessert, ohne die Baseline zu aktualisieren, wird von --require-tighten erkannt (Phase 6A.5,
Implementierung ausstehend).
CodeQL-Ratchet: Aktualisierungsintervall und manuelle Auslösung
Abschnitt betitelt „CodeQL-Ratchet: Aktualisierungsintervall und manuelle Auslösung“check:codeql-ratchet liest den Repository-Status, der nach einem Zeitplan aktualisiert wird — nicht pro PR.
gh api repos/diegosouzapw/OmniRoute/code-scanning/default-setup meldet
state: configured, schedule: weekly: GitHubs Scan mit Standardkonfiguration, keine Analyse
bei jedem Push. Folge: Nachdem ein PR, der Warnungen BEHEBT, gemergt wurde, liest das Ratchet
weiterhin die alte, höhere Anzahl, bis der nächste geplante Scan ausgeführt wird — daher meldet es
bei jedem offenen PR eine Regression, einschließlich der Folge-PRs des Korrektur-PRs selbst, bis der Scan den aktuellen Stand erfasst.
Manuelle Aktualisierung: gh workflow run codeql.yml --ref release/vX.Y.Z führt die
Analyse erneut aus und veröffentlicht die Warnungen innerhalb weniger Minuten neu. Lesen Sie zuerst
.github/workflows/codeql.yml — der Header erklärt, dass sie ausschließlich für workflow_dispatch
vorgesehen ist, weil sie mit GitHubs „Standardkonfiguration“ kollidiert (CodeQL analyses from advanced configurations cannot be processed when the default setup is enabled). Das Wiederherstellen der Trigger push/pull_request/
schedule erfordert zuerst eine Aktion des Eigentümers: Settings → Code security →
CodeQL: Default → Advanced. Fügen Sie ohne diese Umstellung keinen schedule:-Trigger hinzu — er
würde lediglich fehlschlagende Läufe erzeugen.
Verschärfen Sie die Baseline, nachdem die Anzahl gesunken ist — node scripts/check/check-codeql-ratchet.mjs --update schreibt die neu gemessene Anzahl in quality-baseline.json →
metrics.codeqlAlerts.value, damit das Ratchet nicht stillschweigend eine Regression zurück
auf den alten Grenzwert zulässt. Praxisbeispiel (2026-09-02/03): PR #12502 behob 7 echte Warnungen
(13 → 6 gemessene offene Warnungen); PR #12530 verschärfte die eingefrorene Baseline von 11 → 6, um sie anzugleichen; die
verbleibenden 6 wurden anschließend mit einer Begründung für jede einzelne Warnung verworfen, sodass 0 offen blieben.
Verwerfungen liegen im Ermessen des Operators (Strikte Regel #14) — verwerfen Sie niemals eine CodeQL-Warnung,
ohne die technische Begründung im Verwerfungskommentar festzuhalten: won't fix für
eine Anforderung eines vorgelagerten Protokolls, used in tests für eine Test-Fixture, false positive
für einen Sanitizer, den CodeQL nicht erkennen kann (Präzedenzfall: docs/security/ERROR_SANITIZATION.md).
Richtlinie für Testwiederholungen (WS5.4, v3.8.49)
Abschnitt betitelt „Richtlinie für Testwiederholungen (WS5.4, v3.8.49)“Wiederholungen werden pro Runner konfiguriert, niemals pauschal global — eine pauschale Wiederholung macht aus echten Regressionen unsichtbare Flakes:
| Runner | Richtlinie | Begründung |
|---|---|---|
| Playwright (e2e) | retries: 1 nur in CI, mit trace: on-first-retry |
Browser-/Netzwerk-Timing ist tatsächlich nicht deterministisch; eine Wiederholung mit einem Trace macht aus einem Flake ein diagnostizierbares Artefakt |
| Vitest | KEINE globale Wiederholung. Ein nachweislich instabiler Test erhält eine explizite Wiederholung pro Test (im Diff sichtbar und im PR geprüft) | So bleibt die Quarantäneliste im Repository und ist niemals undurchsichtig |
| node:test (Unit) | NIEMALS Wiederholungen | Ein instabiler Unit-Test ist ein Fehler im Test — beheben, nicht erneut ausführen |
Ziel-SLOs, sobald die Flake-Telemetrie verfügbar ist (WS5.2/5.3): <1 % Flake-Rate pro Test (Schwellenwert für „sofort beheben“), ≥95 % Erfolgsrate pro Pipeline. Branchenübliche Referenzwerte — anhand unserer eigenen Messungen neu kalibrieren.
Drift der Ratchets auf Release-Ebene (WS5.5, v3.8.49)
Abschnitt betitelt „Drift der Ratchets auf Release-Ebene (WS5.5, v3.8.49)“Wenn sich ein Ratchet (Dateigröße, Komplexität, eslint-Warnungen) am REINEN Release- Tip verschlechtert — d. h., die KOMBINATION der Merges hat die Verschlechterung verursacht und kein einzelner PR reproduziert sie in seinem eigenen Branch — obliegt die Behebung einmalig dem Release Captain auf dem Release-Branch: Extraktion/Refactoring bevorzugen; die Baseline nur mit dem dokumentierten Begründungseintrag neu setzen. Kombinationsbedingte Drift niemals auf einen Contributor-PR abwälzen und niemals pro PR neu baselinen (das verbirgt echte Regressionen). Zuerst differenzieren: Den roten Status in einem Probe-Worktree gegen den reinen Tip reproduzieren, bevor angenommen wird, dass der eigene PR ihn verursacht hat.
Ratchet-Absenkungen übernehmen — die Abwärtsrichtung (#8584)
Abschnitt betitelt „Ratchet-Absenkungen übernehmen — die Abwärtsrichtung (#8584)“Das Ratchet ist nur zur Hälfte automatisiert, und zwar zur falschen Hälfte. Das Anheben eines Limits ist eine
manuelle JSON-Bearbeitung, die zehn Sekunden dauert und der schnellste Weg ist, einen roten PR wieder freizugeben.
Das Absenken erfordert, dass jemand --update ausführt und das Ergebnis committet — und bis
der Job bank-ratchet-shrinks eingeführt wurde, führte kein Workflow diesen Vorgang aus. Die gemessene Folge
(2026-07-25): 18 eingefrorene Dateien lagen bereits bei oder unter dem Limit von 800 Zeilen für neue Dateien, im schlimmsten
Fall beim 132-Fachen (src/shared/validation/schemas.ts, 19 Zeilen bei einem Limit von 2.523); die
Komplexitätsobergrenze stieg über etwa 37 Rebaseline-Hinweise hinweg von 1794 → 2169, bei genau einer
Absenkung (−1); und „im nächsten Zyklus über --update verschärfen“ wurde 31-mal geschrieben und
einmal umgesetzt. Ein Limit, das länger bestehen bleibt als der Code, durch den es begründet wurde, verwandelt
jede abgeschlossene Zerlegung stillschweigend in zusätzlichen Wachstumsspielraum für die Person, die die Datei als Nächstes bearbeitet.
nightly-release-green.yml → Job bank-ratchet-shrinks schließt diesen Regelkreis:
| Läuft bei | schedule (3×/Tag) + workflow_dispatch — bewusst nicht bei push |
| Misst | den höchsten release/vX.Y.Z, mit derselben Auflösung und demselben Injection Guard wie release-green |
| Schreibt | check:file-size --update und check:complexity-ratchets --update (beide konstruktionsbedingt ausschließlich absenkend) |
| Verifiziert | npm run check:ratchet-bank (scripts/quality/verify-ratchet-bank.mjs) |
| Liefert aus | einen stets aktuellen PR gegen den Release-Branch — per Force-Update aktualisiert, niemals als Spam |
Die Übernahme erfolgt gebündelt statt bei jedem Push, da es keine Latenzanforderung gibt (eine innerhalb von
8 Stunden übernommene Absenkung ist ausreichend), während eine Ausführung bei jedem Merge den PR-Branch während
Merge-Kampagnen wiederholt neu erstellen und jedes Mal einen vollständigen ESLint-Durchlauf verursachen würde. Die Erkennung erfolgt weiterhin bei
push (release-green); nur die Übernahme wird gebündelt.
Der Sicherheitsprüfer
Abschnitt betitelt „Der Sicherheitsprüfer“Der Job schreibt unbeaufsichtigt in die Baselines, daher sorgt verify-ratchet-bank.mjs dafür,
dass dies vertretbar ist. Er vergleicht den Baum nach --update mit HEAD und bricht den Job ab,
bevor ein Commit existiert — ohne einen PR zu öffnen —, sofern nicht jede Änderung einer der folgenden Kategorien entspricht:
- ein numerischer
frozen- /testFrozen-Eintrag wurde abgesenkt oder entfernt complexity-baseline.json→countwurde abgesenktquality-baseline.json→metrics.cognitiveComplexity.valuewurde abgesenkt
Alles andere schlägt fehl: das Anheben einer Zahl, das Hinzufügen eines Eintrags, das Ändern von cap/testCap oder
das Löschen/Umschreiben eines _rebaseline_*-Hinweises (diese Hinweise bilden den Audit-Trail dafür, warum die jeweilige
Obergrenze existiert, und werden innerhalb desselben frozen-Objekts wie die Dateieinträge gespeichert).
Ein Bot, der ein Limit anheben könnte, wäre eindeutig schlechter als der Status quo. Regressions-
Guard: tests/unit/verify-ratchet-bank.test.ts.
Der Job pusht niemals nach release/* — ein Mensch mergt den PR, sodass eine fehlerhafte Messung
nicht ungeprüft übernommen werden kann.
Richtlinie für Positivlisten
Abschnitt betitelt „Richtlinie für Positivlisten“Jeder Prüfschritt, der bei bereits vorhandenen Verstößen nicht fehlschlagen darf, verwendet eine unveränderliche Positivliste
(z. B. KNOWN_STALE_DOC_REFS, KNOWN_MISSING, KNOWN_RAW_SQL). Es gilt folgende Richtlinie:
Beheben Sie die eigentliche Ursache; verwenden Sie die Positivliste nur, wenn der Verstoß bereits vorhanden ist und nicht im selben PR behoben werden kann.
Beim Hinzufügen eines Eintrags zu einer Positivliste:
- Fügen Sie einen Kommentar mit der Begründung ein.
- Verweisen Sie auf das zugehörige Tracking-Issue (z. B.
// #3498 — Funktion aus Phase 2, noch nicht implementiert). - Entfernen Sie den Eintrag in demselben PR, der den Verstoß behebt — ein veralteter Eintrag, der keinen aktiven Verstoß mehr unterdrückt, ist selbst ein Fehler (die stale-enforcement-Prüfung aus 6A.3 wird den Prüfschritt bei einem verwaisten Positivlisteneintrag fehlschlagen lassen, sobald sie implementiert ist).
Fügen Sie keine Positivlisteneinträge hinzu, nur damit Tests schneller erfolgreich sind. Ein erfolgreicher Prüfschritt bei einer wachsenden Positivliste vermittelt ein falsches Gefühl von Qualität.
Wenn ein Prüfschritt bei Ihrem PR fehlschlägt
Abschnitt betitelt „Wenn ein Prüfschritt bei Ihrem PR fehlschlägt“- Lesen Sie die Ausgabe des Prüfschritts sorgfältig — sie gibt genau an, welche Datei oder welches Symbol gegen die Regel verstoßen hat.
- Beheben Sie den Verstoß — die meisten Prüfschritte sind deterministische Dateisystemprüfungen, die erfolgreich sind, sobald der Code korrekt ist.
- Wenn der Verstoß bereits vorhanden ist (d. h., Sie haben ihn nicht verursacht, aber der Prüfschritt deckt ihn nun ab): Fügen Sie einen Positivlisteneintrag mit einem Begründungskommentar und einem Tracking-Issue hinzu.
- Wenn es sich um einen Ratchet-Prüfschritt handelt (Testabdeckung, ESLint-Warnungen, Duplizierung, Komplexität):
Ihre Änderung hat die Metrik verschlechtert. Beheben Sie das zugrunde liegende Problem oder führen Sie (in seltenen Fällen)
npm run quality:ratchet -- --updateaus, wenn die Änderung beabsichtigt und die Verschlechterung der Metrik akzeptabel ist — dokumentieren Sie die Gründe jedoch in der PR-Beschreibung. - Hinweisgebende Prüfschritte (
continue-on-error: true) dienen nur der Information — sie blockieren das Zusammenführen nicht, erscheinen aber in der CI-Zusammenfassung. Beheben Sie sie trotzdem.
Hinzufügen eines neuen Prüfschritts
Abschnitt betitelt „Hinzufügen eines neuen Prüfschritts“- Erstellen Sie
scripts/check/check-<name>.mjs(oder.ts). Richtlinienprüfschritte beenden sich mit 0/1. Ratchet-Prüfschritte schreiben übercollect-metrics.mjseine Metrik nachquality-metrics.json. - Fügen Sie
"check:<name>": "node scripts/check/check-<name>.mjs"zupackage.jsonhinzu. - Binden Sie ihn in
.github/workflows/ci.ymlunter dem passenden Job ein (Richtlinie →lintoderdocs-sync-strict; Ratchet →quality-gate). - Falls er eine Positivliste verwendet, wenden Sie
reportStaleEntries()ausscripts/check/lib/allowlist.mjsan, damit veraltete Einträge automatisch erkannt werden. - Schreiben Sie einen Test in
tests/unit/build/, der die Erkennungslogik des Prüfschritts abdeckt. - Aktualisieren Sie dieses Dokument (fügen Sie der Tabelle des entsprechenden Jobs eine Zeile hinzu).
Agentenwerkzeuge: LSP-in-the-loop (optional)
Abschnitt betitelt „Agentenwerkzeuge: LSP-in-the-loop (optional)“Zusätzlich zu den CI-Prüfschritten enthält OmniRoute ein optionales agent-lsp-Grundgerüst
(eine .mcp.json auf Projektebene, Phase 7, Aufgabe 15). Erstellen Sie .mcp.json,
um Coding-Agenten einen TypeScript-Sprachserver bereitzustellen, sodass sie Symbole /
Diagnosen vor dem Schreiben von Code auflösen — eine „Kompilieren vor dem Behaupten“-Ergänzung zu
typecheck:core, die Fehler durch „erfundene Symbole“ an der Quelle reduziert. Es wird absichtlich
nicht automatisch geladen (Sie wählen und überprüfen die MCP↔LSP-Brücke); ein fehlerhafter Eintrag protokolliert lediglich einen
Verbindungsfehler und unterbricht niemals Sitzungen.
Rationalisierungs-Backlog (ROI-Überprüfung — Phase 9 Welle 3)
Abschnitt betitelt „Rationalisierungs-Backlog (ROI-Überprüfung — Phase 9 Welle 3)“Dieses Inventar wurde am 2026-06-17 mit ci.yml abgeglichen (in der vorherigen Version fehlten
audit:deps, check:tracked-artifacts, check:lockfile, check:licenses,
check:dead-code, check:cognitive-complexity, check:type-coverage,
check:codeql-ratchet, check:pr-evidence). Eine ROI-Überprüfung des abgeglichenen Bestands
ergab die folgenden Rationalisierungskandidaten. Die Zusammenführungen sind mechanische CI-
Änderungen; die Umstellungen/Streichungen sind Richtlinienentscheidungen, die dem Betreiber vorbehalten sind. Keine der nachstehenden
Änderungen wurde bisher angewendet.
Oben ebenfalls nicht dokumentiert (nur hinweisend, geringe Aussagekraft): der Job docs-lint
(markdownlint + Vale, gesamter Job mit continue-on-error) und die eigenständigen Scanner-Workflows
semgrep.yml / codeql.yml / scorecard.yml. semgrepFindings: 0 ist in
quality-baseline.json enthalten, aber in ci.yml nicht mit einem blockierenden Ratchet verknüpft — die Metrik ist
derzeit verwaist.
Zusammenführen / Deduplizieren (mechanisch, geringeres Risiko)
Abschnitt betitelt „Zusammenführen / Deduplizieren (mechanisch, geringeres Risiko)“Jeder Kandidat wurde am 2026-06-17 anhand des aktuellen Gate-Status validiert (Vertrauen ist gut, Kontrolle ist besser); mehrere „offensichtliche“ Zusammenführungen erwiesen sich als versteckte Altlasten und sind keine direkt einsetzbaren Ersetzungen.
check:docs-syncwird zweimal ausgeführt — eigenständig im Joblintund erneut innerhalb voncheck:docs-all(docs-sync-strict) sowie im Husky-Pre-Commit-Hook. ✅ ERLEDIGT — eigenständiger Aufruf inlintentfernt.- CVE-Scanning — ❌ KEINE saubere Zusammenführung.
audit:depsschlägt bei jeder CVE mit hohem/kritischem Schweregrad zwingend fehl;check:vuln-ratchet(osv) schlägt nur bei einer Regression gegenüber der Baseline fehl (derzeit 1 MODERATE). Unterschiedliche Semantik — durch das Entfernen vonaudit:depsginge das absolute Gate für hohe/kritische Schweregrade verloren. Beide beibehalten. - Zyklenerkennung — ❌ KEINE saubere Zusammenführung.
check:circular-deps(dpdm) meldet 91 Zyklen (deshalb ist die Prüfung nur hinweisend); sie kann nicht auf blockierend hochgestuft werden, ohne diese zuvor zu beheben, und ihr Umfang ist größer als der der erfolgreichen, kuratierten Prüfungcheck:cycles.check:cyclesals blockierend beibehalten; die Behebung der 91 dpdm-Zyklen ist ein eigener Backlog-Eintrag. - Komplexität — ✅ ERLEDIGT (
check:complexity-ratchets/eslint.complexity-ratchets.config.mjs): ein ESLint-Durchlauf, Zählung nach ruleId, sodass die Baselines für zyklomatische Komplexität + maximale Zeilenzahl und kognitive Komplexität unabhängig bleiben; die einzelnen Prüfungencheck:complexity/check:cognitive-complexitybleiben für lokale Ausführungen mit--updateerhalten. /api-Anti-Halluzination — ✅ ERLEDIGT (check:api-docs-refs+scripts/check/lib/apiRoutes.mjs): ein einziges FS-Inventar vonsrc/app/api; openapi-routes + docs-symbols melden weiterhin unabhängig; die einzelnen Prüfungen bleiben für lokale Ausführungen erhalten.check:node-runtimewird in 11 Jobs ausgeführt — ⚠️ geringer ROI. Jeder Job verwendet einen separaten Runner und die Prüfung dauert <1 s; Gesamtersparnis etwa 10 s, bei gleichzeitigem Verlust einer kostengünstigen Schutzprüfung pro Job. Den Änderungsaufwand nicht wert.typecheck:noimplicit:coreim CI-Linting — ✅ aus dem Joblintentfernt (war mitcontinue-on-errornur hinweisend); die blockierende Typoberfläche besteht austypecheck:core+check:type-coverage. Lokales Skript beibehalten.
Umstellen / Entscheiden (Betreiberrichtlinie)
Abschnitt betitelt „Umstellen / Entscheiden (Betreiberrichtlinie)“check:openapi-security-tiers(hinweisend) — ❌ NICHT ohne Weiteres umstellbar. Die Prüfung wird mit 0 beendet, warnt jedoch, dass bei mehrerentraffic-inspector-Routen unterLOCAL_ONLY_API_PREFIXESdie Annotationx-loopback-only: truefehlt. Für eine Erzwingung müssen diese Annotationen zuerst zuopenapi.yamlhinzugefügt werden.typecheck:noimplicit:core(hinweisend) — weitgehend durch das blockierende Ratchetcheck:type-coverageabgedeckt. Auf ein Ratchet umstellen oder den redundanten zweitentsc-Durchlauf entfernen.test:vitest:ui(jetzt blockierend) — bereits bestehende Fehler werden invitest.config.tsexplizit mit// #8618-Nachverfolgungskommentaren ausgeschlossen; neue Fehler lassen den Job fehlschlagen.check:secrets(gitleaks, blockierendes Ratchet, bei 3 dokumentierten Falschmeldungen eingefroren) — die 3 auf die Positivliste setzen, um 0 zu erreichen, oder auf hinweisend herabstufen. Überschneidet sich mit dem nativen GitHub-Secret-Scanning +check:public-creds.check:pr-evidence(blockierend, durchsucht den Fließtext des PR-Bodys mit grep) — hohes Falsch-positiv-Risiko; eine Entfernung schwächt die Durchsetzung von Hard Rule #18, daher handelt es sich um eine echte Richtlinienentscheidung.semgrep(eigenständig, hinweisend) — überschneidet sich bei den OWASP-Familien mit CodeQL; die Baseline mit einem Ratchet verknüpfen oder entfernen.
Zugehörige Dokumentation
Abschnitt betitelt „Zugehörige Dokumentation“- Lieferkette (Provenienz, SBOM, Trivy, Scorecard):
docs/security/SUPPLY_CHAIN.md
check-key-completeness — Prüfschranke für die Übereinstimmung der Schlüsselmengen
Abschnitt betitelt „check-key-completeness — Prüfschranke für die Übereinstimmung der Schlüsselmengen“scripts/i18n/check-key-completeness.mjs (npm run i18n:check-keys, Job i18n-ui-coverage).
Vergleicht die Menge der Blattschlüssel jeder Datei src/i18n/messages/<locale>.json mit en.json
und schlägt bei jedem fehlenden oder zusätzlichen Blatt fehl, unabhängig davon, wann der Schlüssel
hinzugefügt wurde. __MISSING__:-Platzhalter gelten als vorhanden (ihr Inhalt ist Sache der
Verhältnis-Prüfschranke). Dies ist die absolute Ergänzung zu den beiden diff-basierten bzw.
prozentualen Prüfschranken: check-ui-keys-coverage erzwingt eine Untergrenze von 80 % pro Locale
(43 fehlende Schlüssel von etwa 13.000 ergeben immer noch 99,7 %), und check-new-key-coverage
bewertet nur die Schlüssel, die ein PR zu en.json hinzufügt. Ein Locale-Batch wird aus dem
en.json des Tages generiert, an dem sein Branch erstellt wird, und über mehrere Tage übersetzt,
während die Basis weiterhin neue Schlüssel hinzufügt; der Batch-PR selbst fügt keinen Schlüssel
hinzu, sodass beide verwandten Prüfschranken stumm blieben, als Batch 1 (#13044) mit 43 fehlenden
Schlüsseln in neun Locales und Batch 2 (#13660) mit 10 fehlenden Schlüsseln in acht Locales
(2026-09-15) integriert wurden. Beheben Sie einen roten Fehler mit
node scripts/i18n/sync-ui-keys.mjs --locale=<codes> --translate-markers; ein extra-Blatt
bedeutet, dass es aus der Quelle entfernt wurde — löschen Sie es aus der Locale. --warn meldet
Probleme, ohne fehlzuschlagen. --catalog=cli führt denselben Vergleich für bin/cli/locales aus
(npm run i18n:check-keys:cli); beide Schritte befinden sich im Job i18n-ui-coverage.
check-new-key-coverage — i18n-Prüfschranke für neue Schlüssel
Abschnitt betitelt „check-new-key-coverage — i18n-Prüfschranke für neue Schlüssel“Verwandte Prüfschranke von check-ui-value-drift. Letztere erkennt einen englischen Wert, der
umgeschrieben wurde, während seine Übersetzungen unverändert blieben; diese erkennt einen
englischen Schlüssel, der hinzugefügt wurde, ohne dass einige Locales ihn erhalten haben.
check-ui-keys-coverage kann diese Fehlerklasse nicht erkennen: Es erzwingt eine prozentuale
Untergrenze pro Locale, und elf fehlende Schlüssel von etwa 13.000 lassen die Abdeckung bei
99,9 %. Ein Prozentsatz pro Sprache kann nicht ausdrücken: „Diese Funktion wurde unübersetzt
ausgeliefert“ — eine vollständige Funktion kann in einer neuen Locale ohne jeglichen Text
hinzukommen, ohne den Wert jemals zu verändern.
Der zugrunde liegende Vorfall: Phase 3 des Orchestration Canvas übersetzte ihre elf Schlüssel in
die 42 Locales, die zu diesem Zeitpunkt existierten. Stunden später erhöhte der EU-Sprachen-Batch
(#13044) die Anzahl der Locales im Repository auf 51, und die neun Neuzugänge (el, et, ga,
hr, lt, lv, mt, sl, sr) erhielten sie nie. deepMergeFallback setzt für einen
fehlenden Schlüssel Englisch ein, sodass der Fehler zu einer unübersetzten statt einer leeren
Benutzeroberfläche führte — ein reales Problem, das konstruktionsbedingt unbemerkt blieb.
Wie die verwandte Prüfschranke ist auch diese diff-bewusst: Sie vergleicht den englischen Stand an der Merge-Basis mit dem Arbeitsbaum, sodass bereits vorhandene Lücken eingefroren bleiben und für die Aktivierung der Prüfschranke keine Migration erforderlich war.
Ein __MISSING__:<english>-Marker erfüllt die Anforderung nicht (seit 2026-09-17). Zuvor war
er der dokumentierte Aufschub — zur Laufzeit wird auf korrektes Englisch zurückgegriffen —, bis
acht Feature-PRs am 2026-09-16 61 Schlüssel hinzufügten und den Marker in alle 65 Locales
eintrugen, anstatt sie zu übersetzen: Diese Prüfschranke akzeptierte jeden einzelnen davon, nichts
blockierte die PRs, und die blockierende Prüfschranke für das Verhältnis echter Übersetzungen
schlug anschließend an der Release-Spitze für alle fehl (pt-BR 3,2 % > 2,5 % + 0,5). Ein Marker
wird nun wie eine fehlende Übersetzung bewertet. Beheben Sie einen roten Fehler mit
node scripts/i18n/sync-ui-keys.mjs --locale=<codes> --translate-markers --batch-size=40 oder
alle Locales parallel mit npm run i18n:translate-new-keys (scripts/i18n/translate-new-keys.sh,
sicher bei getrenntem Terminal, verweigert den Start ohne die Umgebungsvariablen
OMNIROUTE_TRANSLATION_*). Ein Schlüssel, der Englisch bleiben muss (der fest vorgegebene Name
eines Produkts, einer Engine oder eines Flags), gehört in
scripts/i18n/untranslatable-keys.json, niemals hinter einen Marker. vi verbietet Marker
vollständig (tests/unit/i18n-vi-completeness.test.ts).
check-vitest-exclusions — Prüfschranke für zurückgestellte Tests
Abschnitt betitelt „check-vitest-exclusions — Prüfschranke für zurückgestellte Tests“Eine Datei in der exclude-Liste von vitest.config.ts ist ein Test, der nicht ausgeführt wird,
und wirkt für jeden, der den Verzeichnisbaum liest, wie vorhandene Abdeckung. Zweiundsechzig
Dateien sammelten sich hinter dem Kommentar
// #8618 — bereits vorhandener Fehler; diese Ausnahme nach der Behebung entfernen an. Issue
#8618 wurde am 2026-08-11 geschlossen, während die von ihm nachverfolgte Liste von 45 auf 62
Einträge anwuchs, wobei jeder neue Eintrag einen Kommentar erbte, der auf ein abgeschlossenes
Issue verwies. Als die Liste schließlich Datei für Datei geprüft wurde (#13204), bestanden
51 der 62 Tests mit dem aktuellen Stand des Verzeichnisbaums ohne jegliche Änderung am
Quellcode.
Die Prüfschranke verlangt, dass jeder Ausschluss, der auf eine tatsächlich vorhandene Datei
verweist, (a) ein Tracking-Issue benennt und (b) mit seinem gemessenen Status in
config/quality/vitest-exclusions.json aufgeführt ist. Dadurch wird das Hinzufügen eines
Ausschlusses zu einem überprüfbaren Diff in einer dedizierten Datei statt zu einer weiteren Zeile
in einem Array mit 60 Einträgen. Die ausgeschlossenen Tests werden bewusst nicht erneut
ausgeführt — das dauert etwa 10 Minuten und gehört in einen regelmäßigen Job; das Inventar hält
fest, wann jeder Test zuletzt gemessen wurde.
HagiCode
HagiCode ist ein agentischer Coding-Arbeitsplatz mit strukturierten Workflows, Multi-Agent-Ausführung und Hero-Dungeon-Ansichten.
Mit einem intelligenteren, schnelleren und unterhaltsameren agentischen Workflow wird aus Ideen nutzbare Software.

- SmartStrukturierte Workflows machen aus Absichten einen umsetzbaren Weg von der Idee bis zur Auslieferung.
- EfficientMulti-Agent-Workflows führen Recherche, Umsetzung und Prüfung parallel aus.
- FunHero Dungeon macht lange Coding-Sitzungen anschaulich und gemeinschaftlich.