# WOMS „Weißes Design“ P10: Aufräumen – Umsetzungsplan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Nach P10 gibt es keine Übergangsschicht mehr. `react-icons` und `@tabler/icons-react` sind deinstalliert, die KOMPAT-Regeln, die alten Token-Aliase und alle toten Klassen sind gelöscht, `previewEnv.dotColor` ist entfernt. Sichtbar ändert sich nichts, das Bundle wird kleiner. Die Umleitung `/tickets?woid=N` auf `/tickets/N` bleibt. **Architecture:** - Es wird nur gelöscht, umbenannt oder auf vorhandene Bausteine umgestellt. Die Bilder von `design-p9` sind die Referenz, ein Pixelvergleich (`vergleich.mjs`, gestartet über `run-browser.sh`) beweist nach jedem Löschschritt, dass nichts kippt. - Reihenfolge nach Risiko: Pakete, `dotColor`, Token-Aliase (reine Umbenennung), KOMPAT, tote Klassen, Inline-Styles und Regelprüfung, Gate und Tag. - Der Wächtertest `tests/unit/hygiene.test.mjs` hält die Ziele fest (drei Tests, je einer in Task 2, 4 und 5). - Die Ergebnisdatei `docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md` sammelt die Belege. **Tech Stack:** wie P1. Node 24 (`readdirSync` mit `recursive`), npm 11, ripgrep 13 ohne PCRE2 (keine PCRE2-Option, keine Lookarounds). **Spec:** `docs/superpowers/specs/2026-10-04-weisses-design-design.md`, Abschnitte „Gestaltungsregeln“, „Design-Tokens“ (Alias-Tabelle), „Übergangsschicht KOMPAT“, „Ticket als eigene Seite / Route und Links“, „Was gleich bleibt“, „Abnahme“ und Zeile P10. Dateidetails im Anhang `…-umbaukarte.md`, Abschnitt 5 (P10), 2.2, 2.3, 4 (D) und 7. Globale Regeln, Befehlsregeln (`env.sh`, `check.sh`, `run-browser.sh`) und Schnittstellen: `2026-10-05-weisses-design-00-uebersicht.md`. ## Global Constraints Jeder Run-Block beginnt mit `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&`. Danach gelten `$WT` (Worktree `/home/webklar/apps/ticket.webklar.com/dev-design`, Arbeitsverzeichnis), `$W` (Werkzeug) und `$TMPDIR` (Scratchpad). Tests und Build laufen nur über `"$W/check.sh"`, Browser-Skripte nur über `"$W/shots.sh"` oder `"$W/run-browser.sh"`. Suche nur mit `rg` oder `git grep`, nie mit dem Shell-`grep` auf Dateien. Es gelten die Regeln der Übersicht. Für P10 kommt hinzu: - Voraussetzung sind die Tags `design-p0` bis `design-p9`, alle Diff-Prüfungen vergleichen gegen `design-p9`. Erlaubt ist nur Löschen, Umbenennen und Umstellen auf vorhandene Bausteine, keine neuen Funktionen, Klassen, Texte oder Tokens. Ausnahmen: Wächtertest, Ergebnisdatei, das Werkzeug außerhalb des Repos und, nur falls sie fehlt, die Deklaration `font-variant-numeric: tabular-nums` an `.num`, `.stat .v` und `.fin-amount` (Task 7 Step 4). Neue Ansichten braucht P10 nicht, das Gate läuft über alle bestehenden. - Nicht angefasst werden zusätzlich: die `?woid=`-Umleitung (`woidRedirectTarget` in `lib/ticketListUrl.js`, `` in `TicketsPage.jsx`), der Token-Block der Spec und die Klassen-Hooks aus „Was gleich bleibt“ (`data-testid`, `data-label`, `data-storage-done`, `data-hidden-hits`). - Klassensuche token-genau mit `(^|[^A-Za-z0-9_-])NAME([^A-Za-z0-9_-]|$)`. `rg -w` reicht nicht, weil `-` als Wortgrenze gilt und `card` sonst `fin-card` trifft. - `git add` mit ausdrücklichen Pfaden. Wo ein Schritt viele Dateien ändert, läuft vorher `git diff --name-only`, und `git add` bekommt genau diese geprüfte Liste. - **Entscheidung:** Pixelinvariante. Das Aussehen der Bilder von `design-p9` gilt, jede Abweichung ist ein Fehler und wird behoben. Ausgenommen sind nur Ansichten mit Rauschen (relative Zeiten wie „vor 5 Minuten“), das ein zweiter Lauf von `design-p9` selbst zeigt. - **Entscheidung:** Stoppregel für Icons. Liefert `rg "react-icons|@tabler" src` einen Treffer, stammt er aus einem früheren Paket oder aus Commits, die der Rebase von `origin/test` mitbrachte. P10 behebt ihn nach der Ersetzungsregel der Spec (Icon-Knopf wird Textknopf oder Textlink, Zeichen „ד „←“ „→“) in einem eigenen Commit vor Task 2 und nennt ihn in der Ergebnisdatei. - **Entscheidung:** Die Tokens des Spec-Blocks bleiben, auch ein ungenutztes. Nur die Aliase der Spec-Tabelle fallen, `--sp-1…6` bleiben. `Button` behält die Prop `size` in der Signatur (Spec „Knöpfe“), Aufrufe mit `size="sm"` verschwinden, weil sie nichts bewirken. - **Entscheidung:** Farbliterale in JSX sind nur in `src/components/Logo.jsx` (Markenzeichen, `#111` und `#fff` wie `public/favicon.svg`) und `src/components/serverpuls/chartColors.js` erlaubt. Inline-`` bleibt nur in `Logo.jsx` und `Sparkline.jsx`. Der Check `icon-svg` nimmt `svg.sp-spark` (P9) und `.woms-chat .chat-composer *` (P0) in `checks.mjs` aus, dazu das Gate alles unter `.woms-chat` (`ignore`, P6). P10 fügt keine Ausnahme hinzu. - **Entscheidung:** Beim Umstellen gelten die Regeln „Bausteine benutzen“ der Übersicht und die CSS-Reihenfolge: In jedem `` trägt jeder Knopf außer dem Absenden-Knopf `type="button"`, ein `Card` ohne Titel und Aktionen rendert kein `h2`, und Bereichs-CSS (`chat.css`, `serverpuls.css`, `pages/AdminPage.css`) lädt vor `global.css`. Überstimmt eine globale Regel es nach dem Löschen nicht mehr, braucht der Bereichs-Selektor eine höhere Spezifität, nie `!important`. - **Entscheidung:** Die Ergebnisdatei hat sieben Abschnitte: 1 Token-Aliase, 2 KOMPAT-Inventur, 3 Tote Klassen, 4 Inline-Styles, 5 Regelprüfung und Invarianten, 6 Bundle, 7 Offene Punkte. Task 4 legt sie mit allen Überschriften an, jeder Task nimmt seinen Abschnitt in seinen Commit auf. ## Review Focus Aus der Übersicht gehört P10 kein Punkt allein. Alle fünf laufen aber als Ansichten im Gate `p10` mit (`ticket-altdaten*`, `*-lang*`, `fehler-*`, `tasten-*`, `ticket-viel`, `tickets-suche`) und müssen unverändert bleiben. P10 verantwortet sechs eigene Prüfungen: 1. **Nichts Sichtbares ändert sich.** Pixelvergleich `design-p9` gegen P10 über alle Ansichten in allen Viewports (Standard 1440×900 und 390×844, bei `dlg-*` auch 1440×700 und 390×700), keine abweichende Ansicht außerhalb des Rauschens (Task 4, 5, 6 und 8). 2. **Keine noch gebrauchte Regel geht verloren.** Jede KOMPAT-Klasse hat eine Inventurzeile mit Nutzerzahl, jeder Restnutzer wird vor dem Löschen umgestellt (Task 5). Kein `var(--…)` zeigt ins Leere, `undefinedUsed` ist leer (Task 4). 3. **Die Icon-Pakete fehlen nirgends.** `rg` meldet 0 Treffer, der Build ist grün, kein `console-error` in irgendeiner Ansicht (ein fehlender Import wäre zur Laufzeit ein `pageerror`), das Lock passt zu `package.json` (Task 2). 4. **Die `?woid=`-Umleitung bleibt.** Ansicht `alt-link` im Gate, Test `woidRedirectTarget` aus P2 grün, `TicketsPage.jsx` und `ticketListUrl.js` unverändert (Task 8). 5. **Die Spec-Invarianten halten:** alle `data-testid`, die Zahl der `window.confirm`, Hooks und Lib-Logik nur wie in den Paketplänen geändert (Task 7 Step 5, Task 8 Review). 6. **Die übergreifenden Gestaltungsregeln gelten:** höchstens ein `.btn-primary` je `.page-head` (Spec-Regel 4, Check `max-primary` im Gate, Task 1 Step 6 und Task 8) und `tabular-nums` an Zahlen und Beträgen (Spec-Regel 6, `rg` in Task 7 Step 4). --- ### Task 1: Ausgangslage, Referenzbilder, Werkzeug **Files** (alle unter `$W/`, kein Commit im Repo): - Create: `vergleich.mjs`, `token-check.mjs` - Modify: `css-klassen.mjs` (Flag `--ohne-ausnahmen`), `checks.mjs` (Check `max-primary`), `gates.mjs` (Gate `p10`) **Interfaces:** - Consumes: Tag `design-p9`, `build.sh`, `shots.sh`, `run-browser.sh`, `check.sh`, `css-klassen.mjs`, `farben.mjs`, `GATES.p9` (P0 bis P9). - Produces: - `"$W/run-browser.sh" "$W/vergleich.mjs" [--rauschen ] [--out ]` → JSON `{ geprueft, anders: [{ view, viewport, diffPixels, bbox }], rauschen: [view], fehlt: [view] }`. Exit 1, wenn `anders` oder `fehlt` nicht leer ist. A, B und A2 sind Ausgabeordner von `shots.sh` (`x/.png`, z. B. `1440x900/tickets.png` und `390x844/tickets.png`). - `node "$W/token-check.mjs" [--fix]` → JSON `{ legacy: [{ name, ersatz, file, line, art }], undefinedUsed: [{ name, file, line }], mitFallback: [{ name, file, line }], definedUnused: [name] }`. Exit 1, wenn `legacy` oder `undefinedUsed` nicht leer ist. - `css-klassen.mjs --ohne-ausnahmen`: ignoriert die Ausnahmeliste und gibt zusätzlich `nurAusnahme: [name]` aus, die Klassen, die nur durch die Liste als benutzt gelten. - Check `max-primary` in `checks.mjs`: Verstoß `{ check: 'max-primary', selector: '.page-head', detail }` für jedes sichtbare `.page-head` mit mehr als einem sichtbaren `.btn-primary`. - `GATES.p10` nach dem Schema der Übersicht (Step 6). - [ ] **Step 1: Paketstart und Stand prüfen** Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git fetch origin && git merge-base --is-ancestor design-p9 HEAD && git rebase origin/test && "$W/check.sh" git log --oneline origin/test..feature/terminplaner-tp2 -- src package.json package-lock.json tests git tag --list 'design-p*'; git log --oneline design-p9..origin/test; git status --short ``` Expected: - Erste Zeile: `design-p9` ist Vorfahre (sonst Exit 1: stoppen und melden, der Rebase schrieb die Pakete um), der Rebase läuft ohne Konflikt, `check.sh` endet mit Exit 0, `# fail 0`, `# pass` ist `N9` (notieren). - Zweite Zeile (Abgleich mit `feature/terminplaner-tp2`, P10 berührt fast alle Dateien unter `src`): leer. Gibt sie etwas aus, stoppt der Agent und fragt den Eigentümer. Er empfiehlt dabei, TP2 zuerst nach `test` zu bringen. - Tags `design-p0` bis `design-p9`, `git log` und `git status` leer. Kommen fremde Commits mit, werden ihre Dateien in den folgenden Tasks wie alle anderen geprüft. - [ ] **Step 2: Voraussetzungen im Werkzeug** Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "GATES\.p9|p1:" "$W/gates.mjs"; rg -n "ignore" "$W/gates.mjs"; rg -n "sp-spark" "$W/checks.mjs" ls "$W/check.sh" "$W/run-browser.sh" "$W/css-klassen.mjs" "$W/farben.mjs" "$W/build.sh" "$W/shots.sh" ``` Expected: Gates `p1` und `p9`, im `ignore` nur `.woms-chat` (P6, `.ticket-projects` strich P5), Ausnahme `svg.sp-spark` und alle sechs Dateien sind da. Fehlt etwas, wird gestoppt und gemeldet. - [ ] **Step 3: Ausgangswerte des Bundles festhalten** Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git log design-p0 --format=%B | rg "Ausgangswerte" && "$W/check.sh" --nur-build && { find dist -type f \( -name '*.js' -o -name '*.css' -o -name '*.ttf' \) -printf '%s %p\n'; for f in dist/assets/*.js dist/assets/*.css; do echo "$f gzip=$(gzip -9 -c "$f" | wc -c)"; done; wc -l src/styles/*.css src/pages/*.css; } | tee "$W/p10-baseline-p9.txt" ``` Expected: die P0-Zeile `Ausgangswerte: , JS B, CSS B` (Gegenprobe der Umbaukarte: JS 680.818 B, CSS 64.433 B, Lato 96.184 B, 2.079 CSS-Zeilen), Build grün, keine `.ttf` in `dist`, alle Zahlen in `$W/p10-baseline-p9.txt`. - [ ] **Step 4: Referenzbilder und Rauschmaß** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p9-ref && "$W/shots.sh" p9-ref "$W/shots/p9-ref" --gate p9 && "$W/shots.sh" p9-ref "$W/shots/p9-ref2" --gate p9 && ls "$W/shots/p9-ref/1440x900" | wc -l` Expected: beide Läufe Exit 0, je Ansicht ein Bild je Viewport (`1440x900` und `390x844`, bei `dlg-*` zusätzlich `1440x700` und `390x700`). Die Zahl der Ansichten ist die Sollzahl aller späteren Läufe (notieren). - [ ] **Step 5: `vergleich.mjs` schreiben und prüfen** Umsetzung: - Das Skript startet Chromium selbst (Ladeweise wie `shots.mjs`) und läuft deshalb nur über `run-browser.sh`. - Die PNGs werden in Playwright-Chromium (`about:blank`) per `createImageBitmap` und Canvas dekodiert und pixelweise verglichen. Eine andere Bildgröße ist `anders` und nennt beide Größen. `bbox` ist der kleinste Rahmen um alle abweichenden Pixel. - `--out` bekommt je abweichender Ansicht ein Bild unter `x/.png`, abweichende Pixel rot. - Eine Ansicht mit Abweichung zwischen A und A2 zählt als `rauschen`, außer die Abweichung zwischen A und B reicht über deren `bbox` hinaus. Dann ist sie `anders`. Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && cp -r "$W/shots/p9-ref" "$TMPDIR/probe" && cp "$TMPDIR/probe/1440x900/tickets.png" "$TMPDIR/probe/1440x900/kunden.png" "$W/run-browser.sh" "$W/vergleich.mjs" "$W/shots/p9-ref" "$TMPDIR/probe"; echo "exit $?" "$W/run-browser.sh" "$W/vergleich.mjs" "$W/shots/p9-ref" "$W/shots/p9-ref2"; echo "exit $?" ``` Expected: Der erste Aufruf nennt genau `kunden` bei 1440×900 als `anders`, Exit 1. Der zweite endet mit Exit 0 oder nennt wenige Rausch-Ansichten. Jede wird einmal angesehen und in `$W/p10-rauschen.txt` notiert. - [ ] **Step 6: `token-check.mjs`, Flag, Check `max-primary` und Gate** Umsetzung von `token-check.mjs`: - Es liest `src/**/*.{css,jsx,js}` und schreibt nur dort. Definiert ist ein Name durch `--name:` in CSS oder den Schlüssel `'--name'` in JSX-Objekten, benutzt durch `var(--name`. - `legacy` enthält jede Nutzung und jede Definition eines Alias-Namens der Tabelle in Task 4 (`art` ist `nutzung` oder `definition`, `ersatz` der neue Name oder der Wert `4px` bzw. `none`). - `undefinedUsed` sind benutzte, nirgends definierte Namen ohne Rückfallwert, mit Rückfallwert landen sie in `mitFallback`. - `--fix` schreibt nur die `nutzung`-Einträge um (`var(--alt)` und `var(--alt, …)`), `--sidebar-w-collapsed` nie. Dazu kommen: - das Flag in `css-klassen.mjs`, - der Check `max-primary` in `checks.mjs` (Spec, Gestaltungsregel 4: höchstens ein `.btn-primary` je Seitenkopf), mit `detail` ` .btn-primary`, - `GATES.p10` in `gates.mjs`. P10 hat keine eigenen Ansichten, `icon-svg` gilt deshalb für alle (`'*'` ist der Präfix-Platzhalter für alle Ansichten, wie in P2), mit dem `ignore` aus `p9` unverändert. `step-failed`, `external-request` und `console-error` sind wie in jedem Gate aktiv. ```js const iconSvg = GATES.p9.scoped['icon-svg'] GATES.p10 = { ...GATES.p9, checks: [...GATES.p9.checks, 'max-primary'], scoped: { ...GATES.p9.scoped, 'icon-svg': { ...iconSvg, views: ['*'] } }, } ``` Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && mkdir -p "$TMPDIR/tc/src" && printf 'a{color:var(--nope);border:1px solid var(--border)}' > "$TMPDIR/tc/src/x.css" node "$W/token-check.mjs" "$TMPDIR/tc"; echo "exit $?" node "$W/token-check.mjs" . | node -e "const j=JSON.parse(require('fs').readFileSync(0));console.log(j.legacy.length, j.undefinedUsed.length)" node "$W/css-klassen.mjs" . --ohne-ausnahmen | node -e "const j=JSON.parse(require('fs').readFileSync(0));console.log(j.dead.length, j.nurAusnahme.length)" mkdir -p "$TMPDIR/probe-primary" && printf 'Probe

Test

' > "$TMPDIR/probe-primary/index.html" "$W/shots.sh" probe "$TMPDIR/probe-primary-out" --static "$TMPDIR/probe-primary" --only tickets --gate p10; echo "exit $?" rg -o "max-primary" "$TMPDIR/probe-primary-out/report.json" | wc -l ``` Expected: - Der erste Aufruf endet mit Exit 1, `undefinedUsed` nennt `--nope`, `legacy` nennt `--border` mit `ersatz` `--line`. - Der zweite zeigt eine Zahl über 0 für `legacy` (die Alias-Definitionen stehen noch) und 0 für `undefinedUsed`. - Der dritte nennt zwei Zahlen, sie werden notiert. - Die Probe mit zwei Primärknöpfen in einem `.page-head` endet mit Exit 1, die letzte Zeile nennt eine Zahl über 0 (der Check `max-primary` schlägt an). - [ ] **Step 7: Gate `p10` gegen `design-p9`** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/shots.sh" p9-ref "$W/shots/p9-ref-p10" --gate p10; echo "exit $?"` Expected: Exit 0 (die Bilder dieses Laufs werden nicht gebraucht). Ein Treffer `icon-svg` folgt der Stoppregel für Icons. Ein Treffer `max-primary` ist ein Fehler eines früheren Pakets: Der Agent stoppt und meldet ihn dem Eigentümer, weil der überzählige Knopf das Aussehen ändern würde. ### Task 2: Icon-Pakete entfernen **Files:** - Create: `tests/unit/hygiene.test.mjs` - Modify: `package.json` (Zeilen 6 und 11), `package-lock.json` **Interfaces:** - Consumes: nichts. Voraussetzung ist `rg "react-icons|@tabler" src` = 0. - Produces: ein Lock ohne `@tabler/icons-react`, `@tabler/icons` und `react-icons`, dazu `hygiene.test.mjs` mit den Helfern `files`, `read`, `offenders(re, only)`, auf denen Task 4 und 5 aufbauen. - [ ] **Step 1: Failing Test schreiben** ```js import test from 'node:test' import assert from 'node:assert/strict' import { readFileSync, readdirSync } from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..') const files = readdirSync(path.join(root, 'src'), { recursive: true }) .filter((f) => /\.(jsx?|css)$/.test(f)) .map((f) => path.join('src', f)) const read = (rel) => readFileSync(path.join(root, rel), 'utf8') const offenders = (re, only = /./) => files.filter((f) => only.test(f) && re.test(read(f))) test('Icon-Pakete sind weder Abhängigkeit noch Import', () => { const pkg = JSON.parse(read('package.json')) for (const n of ['react-icons', '@tabler/icons-react']) assert.equal(pkg.dependencies[n], undefined, n) assert.deepEqual(offenders(/react-icons|@tabler/), []) }) ``` Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/hygiene.test.mjs` Expected: FAIL (`package.json` führt beide Pakete). - [ ] **Step 2: Beweisen, dass nichts mehr importiert** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "react-icons|@tabler" src` Expected: keine Ausgabe. Bei einem Treffer gilt die Stoppregel der Global Constraints. - [ ] **Step 3: Deinstallieren** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && systemd-run --scope -q -p MemoryMax=1500M -p MemorySwapMax=0 npm uninstall react-icons @tabler/icons-react --no-audit --no-fund` Expected: Exit 0. - [ ] **Step 4: Lock und Index prüfen** Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git status --short; git diff package.json | rg "^[-+] "; rg -c "tabler|react-icons" package.json package-lock.json; git diff --numstat package-lock.json npm ls react-icons @tabler/icons-react 2>&1 | rg "empty"; npm ci --dry-run --no-audit --no-fund; echo "exit $?" ``` Expected: - `git status` zeigt genau `M package-lock.json`, `M package.json` und `?? tests/unit/hygiene.test.mjs`, keine `D`-Zeile (`node_modules` ist nicht getrackt). - Der Diff von `package.json` hat genau zwei `-`-Zeilen, `rg -c` gibt nichts aus. - `numstat` zeigt 0 hinzugefügte Zeilen. Stehen dort wenige, sind es höchstens geänderte Flags (`"peer"`, `"dev"`), und jede `+`-Zeile wird angesehen. - `npm ls` meldet `(empty)`, `npm ci --dry-run` endet mit Exit 0. - [ ] **Step 5: Tests und Build** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh"` Expected: Exit 0, `# fail 0`, `# pass` = `N9 + 1`, Build grün. - [ ] **Step 6: Commit** ```bash git add package.json package-lock.json tests/unit/hygiene.test.mjs git commit -m "Aufraeumen: react-icons und @tabler/icons-react deinstalliert (src ohne Icon-Importe), Waechtertest" -m "Co-Authored-By: Claude Opus 5.5 " ``` ### Task 3: `dotColor` und Icon-Kommentare **Files:** - Modify: `src/lib/previewEnv.js` (Zeile 1 und Zeilen 15–18 laut Ausgangsstand), `tests/unit/previewEnv.test.mjs` (Zeile 5 und der Test `dotColor`, Zeilen 21–29) - Modify: `src/lib/navLinks.js` (Zeile 1), `tests/unit/navLinks.test.mjs` (Zeile 5) **Interfaces:** - Consumes: `isValidEnvName`, `buildEnvPayload`, `isDevPreview`, `envValueTooLong`, `MAX_ENV_VARS` aus `previewEnv.js`, unverändert. - Produces: `previewEnv.js` ohne `dotColor` und `DOT_COLORS`. - [ ] **Step 1: Beweisen, dass `dotColor` unbenutzt ist** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "dotColor|DOT_COLORS" src tests` Expected: Treffer nur in `src/lib/previewEnv.js` und `tests/unit/previewEnv.test.mjs` (P5 hat `PreviewBlock` und `ServicesPage` umgestellt). Weitere Treffer sind ein Fehler eines früheren Pakets. - [ ] **Step 2: Test zuerst anpassen** Der Test `dotColor` und der Name im `loadModule`-Destrukturieren entfallen. Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/previewEnv.test.mjs` Expected: PASS mit 4 Tests (`isValidEnvName`, `buildEnvPayload`, `isDevPreview`, `envValueTooLong`). - [ ] **Step 3: Funktion löschen** `DOT_COLORS` und `dotColor` fallen, der Kopfkommentar heißt „(Variablen, Dev-Erkennung)“. Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/previewEnv.test.mjs; rg -n "dotColor|DOT_COLORS|#10b981|#f59e0b|#a0aec0" src tests` Expected: PASS, keine Treffer. - [ ] **Step 4: Icon-Kommentare** - `src/lib/navLinks.js` Zeile 1 wird `// Eintraege der Sidebar als reine Daten (unter Node testbar); Navbar.jsx rendert sie als Textliste.` Der zweite Kommentarsatz zu Unterpunkten und `count` bleibt. - `tests/unit/navLinks.test.mjs` Zeile 5 wird `// Sidebar: Eintraege als reine Daten (Navbar.jsx rendert sie als Textliste)`. Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n -i "(^|[^a-z])icons?([^a-z]|$)" src tests --glob '!*.css' --glob '!hygiene.test.mjs'` Expected: keine Treffer, höchstens Kommentare zum fremden Chat-Baustein in `src/components/chat` und `src/lib/loadChatComposer.js`. Jeder andere Treffer wird umformuliert. „favicon“ und der Wächtertest zählen nicht. - [ ] **Step 5: Test** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" --nur-tests` Expected: Exit 0, `# fail 0`, `# pass` = `N9` (hygiene +1, `dotColor` −1). - [ ] **Step 6: Commit** ```bash git add src/lib/previewEnv.js tests/unit/previewEnv.test.mjs src/lib/navLinks.js tests/unit/navLinks.test.mjs git commit -m "Aufraeumen: previewEnv.dotColor samt Test entfernt, Icon-Kommentare in navLinks angepasst" -m "Co-Authored-By: Claude Opus 5.5 " ``` ### Task 4: Token-Aliase abbauen **Files:** - Modify: `src/styles/global.css` (Alias-Block in `:root`), alle Dateien unter `src/` mit alten Namen (Liste aus Step 3) - Create: `docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md` (Überschriften 1 bis 7, Abschnitt 1 gefüllt) - Test: `tests/unit/hygiene.test.mjs` (zweiter Test) **Interfaces:** - Consumes: `$W/token-check.mjs` (Task 1) und die Alias-Tabelle der Spec: | Alter Name | Neu | |---|---| | `--surface-1`, `--surface-3`, `--surface`, `--dark-bg`, `--dark-card-bg` | `--bg` | | `--surface-2`, `--surface-hover` | `--bg-hover` | | `--border`, `--gray-700`, `--admin-line` | `--line` | | `--border-strong`, `--admin-line-strong` | `--line-strong` | | `--border-accent` | `--accent-ring` | | `--text-muted`, `--text-faint`, `--gray-800` | `--text-2` | | `--dark-text`, `--gray-900` | `--text` | | `--accent-2`, `--green-secondary` | `--accent-hover` | | `--green-primary` | `--accent` | | `--info`, `--warn`, `--ok` | `--blue-fg`, `--orange-fg`, `--green-fg` | | `--r-sm`, `--r-md`, `--r-lg`, `--r-pill` | `--radius`, `--radius-lg`, `--radius-lg`, Wert `4px` | | `--shadow-1`, `--shadow-2`, `--shadow-3` | `none`, `--shadow-btn`, `--shadow-pop` | | `--sidebar-w-collapsed` | entfällt, kein Nutzer erlaubt | - Produces: `:root` ohne Aliase, `token-check` meldet `legacy` und `undefinedUsed` leer. - [ ] **Step 1: Failing Test ergänzen** ```js const LEGACY = ['surface-1', 'surface-2', 'surface-3', 'surface-hover', 'surface', 'dark-bg', 'dark-card-bg', 'border', 'border-strong', 'border-accent', 'gray-700', 'gray-800', 'gray-900', 'admin-line', 'admin-line-strong', 'text-muted', 'text-faint', 'dark-text', 'accent-2', 'green-secondary', 'green-primary', 'info', 'warn', 'ok', 'r-sm', 'r-md', 'r-lg', 'r-pill', 'shadow-1', 'shadow-2', 'shadow-3', 'sidebar-w-collapsed'] test('keine alten Token-Namen mehr (Aliase sind gelöscht)', () => { const re = new RegExp(`(^|[^A-Za-z0-9-])--(${LEGACY.join('|')})([^A-Za-z0-9-]|$)`) assert.deepEqual(offenders(re), []) }) ``` Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/hygiene.test.mjs` Expected: FAIL im neuen Test. - [ ] **Step 2: Bestandsaufnahme** Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node "$W/token-check.mjs" . > "$TMPDIR/token-vorher.json"; node -e "const j=JSON.parse(require('fs').readFileSync(process.argv[1]));const c={};for(const e of j.legacy)c[e.name+' '+e.art]=(c[e.name+' '+e.art]||0)+1;console.log(c)" "$TMPDIR/token-vorher.json" ``` Expected: Zahl der Nutzungen und Definitionen je Alias. Sie kommt in Abschnitt 1 der Ergebnisdatei (Spalten: alter Name, Nutzungen vorher, ersetzt durch). - [ ] **Step 3: Nutzungen umbenennen** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node "$W/token-check.mjs" . --fix; git diff --name-only` Expected: Es ändern sich nur `.css`, `.jsx` und `.js` unter `src/`. Das ist eine reine Umbenennung, der Wert jedes Tokens bleibt gleich. - [ ] **Step 4: Alias-Block löschen** In `global.css` fallen der Alias-Block hinter dem Token-Block samt Kommentar und jede übrige Definition eines Alias-Namens, auch außerhalb von `:root`. Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/hygiene.test.mjs && node "$W/token-check.mjs" . | node -e "const j=JSON.parse(require('fs').readFileSync(0));console.log(j.legacy.length, j.undefinedUsed.length, j.mitFallback.length)"` Expected: PASS und `0 0` plus eine Zahl für `mitFallback`. Jeder Eintrag dort wird angesehen: Der Rückfallwert fällt, wenn das Token existiert, sonst steht der Eintrag in Abschnitt 7. - [ ] **Step 5: Bauen, Gate, Pixelvergleich** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p10 && "$W/shots.sh" p10 "$W/shots/p10-t4" --gate p10 && "$W/run-browser.sh" "$W/vergleich.mjs" "$W/shots/p9-ref" "$W/shots/p10-t4" --rauschen "$W/shots/p9-ref2" --out "$W/shots/p10-t4-diff"` Expected: Gate Exit 0, Vergleich Exit 0. Weicht eine Ansicht ab, hat `--fix` einen Namen falsch ersetzt oder eine Definition lag in einer Datei, die das Skript nicht liest. Das wird behoben. - [ ] **Step 6: Ergebnisdatei und Commit** Die Ergebnisdatei wird mit den Überschriften 1 bis 7 angelegt, Abschnitt 1 bekommt die Tabelle aus Step 2. ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git diff --name-only git add docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md tests/unit/hygiene.test.mjs git commit -m "Aufraeumen: Token-Aliase der Altnamen durch die neuen Tokens ersetzt und geloescht" -m "Co-Authored-By: Claude Opus 5.5 " ``` ### Task 5: KOMPAT-Block entfernen **Files:** - Modify: `src/styles/global.css` (Block `/* ===== KOMPAT (bis P10) ===== */` und der Gliederungskommentar am Dateianfang), Dateien mit Restnutzern (Liste aus Step 3) - Modify: Ergebnisdatei Abschnitt 2 - Test: `tests/unit/hygiene.test.mjs` (dritter Test) **Interfaces:** - Consumes: die Bausteine aus P1 (`.btn`, `.btn-primary`, `.btn-quiet`, `.link`, `.link-danger`, `.badge`, `.field`, `.input`, `.select`, `.textarea`, `.msg`, `.muted`, `.dialog`, `.overlay`, `.seg button.on`) und `Dialog`, `Card`, `Badge`, `StatusPill`. - Produces: `global.css` ohne KOMPAT. Kein Selektor der Spec-Tabelle „Übergangsschicht KOMPAT“ ist übrig, `.page` bleibt als Wurzelklasse der Seiten. - [ ] **Step 1: Failing Test ergänzen** ```js test('keine Übergangsschicht und kein !important im CSS', () => { assert.deepEqual(offenders(/KOMPAT|!important/, /\.css$/), []) }) ``` Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/hygiene.test.mjs` Expected: FAIL im neuen Test. - [ ] **Step 2: Grenzen und Inventur** Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && read A B < <(awk '/KOMPAT \(bis P10\)/{a=NR; next} a && /^\/\* (=====|---)/{print a+1, NR-1; f=1; exit} END{if(a&&!f)print a+1, NR}' src/styles/global.css); echo "KOMPAT $A-$B" sed -n "${A},${B}p" src/styles/global.css | rg -o "\.[a-z][a-z0-9_-]*" | sort -u | sed 's/^\.//' | while read c; do echo "$(rg -l "(^|[^A-Za-z0-9_-])${c}([^A-Za-z0-9_-]|$)" src --glob '!*.css' | wc -l) $c"; done | sort -n | tee "$TMPDIR/kompat-inventur.txt" ``` Expected: - Der Block endet an der nächsten Kopfzeile `/* =====` oder `/* ---`, sonst am Dateiende. - Die Inventur hat 0 Nutzer für jede Klasse der Tabelle in Step 3. Bekannte Ausnahmen: `overlay` (nur `src/components/ui/Dialog.jsx`), `row` (nur an ``) und Klassen, die auch ein neuer Baustein trägt (`btn`, `badge`, `field`, `link`). Deren Regel wandert nach Step 4 in Block 3. - Die Liste kommt als Tabelle (Klasse, Nutzer, Entscheidung) in Abschnitt 2 der Ergebnisdatei. - [ ] **Step 3: Restnutzer finden und umstellen** | KOMPAT-Zeile der Spec | Gesuchte Namen | Ersatz | |---|---|---| | `.ui-card*` | `ui-card` | `Card` (ohne Titel und Aktionen rendert es kein `h2`) oder `
` mit `h2.section` | | `.ui-btn*` | `ui-btn`, `-primary`, `-ghost`, `-danger`, `-sm`, Muster `ui-btn-${…}` | `btn`, `btn btn-primary`, `link-danger`, Zeilenaktion `link` | | `.form-group`, `.form-label`, `.form-control` | dieselben drei | `field`, Label im `.field`, `input`, `select`, `textarea` | | `.badge-*`, `.status-*`, `.priority-*` | `badge-` und `status-` mit `muted`, `info`, `ok`, `warn`, `danger`, `open`, `working`, `awaiting`, `assigned`, `closed`; `priority-critical`; Muster `badge-${…}`, `status-${…}` | `Badge`, `StatusPill` | | `.overlay` (Altform), `.overlay-content`, `.overlay-close` | `overlay-content`, `overlay-close`, `overlay` außerhalb von `Dialog.jsx`, `fin-dialog` (760 px, laut P7 tot) | `Dialog` | | `.seg button.active` | kein festes Muster: jedes `seg` in JSX ansehen | Knopf mit `on` und `aria-pressed` | | `.bg-red`, `.text-white`, `.text-grey`, `.text-red` | dieselben vier | `msg err` bzw. `muted` | | `.side-count`, `.side-logo` | dieselben zwei | schon entfernt: `.side-logo` in P4, `.side-count` in P6. Ein Treffer ist ein Rest und wird entfernt | | `.btn-dark`, `.btn-teal` | dazu `btn-green` | `btn btn-primary` | | `.card*`, `.row`, `.col*`, `.dropdown*` | `card`, `card-header`, `card-body`, `col`, `col-6`, `dropdown*`, `row` außerhalb von `` | entfallen | | `.spinner` | `spinner` | Text „Wird geladen …“ | | `.page .page`, `.page .main-content` | `main-content` | entfällt (Step 5) | | Links in Bestandsklassen | `fin-link`, `credit-cols`, `area-rows`. Die Klasse `legal-files` bleibt (P8), nur die Regel `.legal-files a` fällt. | Klasse `link` am ``, sonst die Regel in den Block des Nutzers | In jedem ``, das dabei entsteht oder angefasst wird, trägt jeder Knopf außer dem Absenden-Knopf `type="button"`. Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n '(^|[^A-Za-z0-9_-])(ui-(card|btn)|form-(group|label|control)|(badge|status)-(muted|info|ok|warn|danger|open|working|awaiting|assigned|closed)|priority-critical|overlay-(content|close)|fin-dialog|bg-red|text-(white|grey|red)|side-(count|logo)|btn-(dark|teal|green)|spinner|dropdown[a-z-]*|card|card-header|card-body|col|col-6|main-content|fin-link|credit-cols|area-rows)([^A-Za-z0-9_-]|$)' src --glob '!*.css'; rg -n '(badge|status|ui-btn)-\$\{' src; rg -n 'className="[^"]*(^|[^A-Za-z0-9_-])row([^A-Za-z0-9_-]|")' src | rg -v ' auf umgestellt“). - [ ] **Step 4: Regeln, die ein Baustein noch braucht** Entscheidung: Das Aussehen der Bilder von `design-p9` gilt. Eine KOMPAT-Regel, deren Selektor auch einen neuen Baustein trifft, wird nicht gelöscht. Ihre Deklarationen gehören dann an den Baustein in Block 3, nur die alten Selektoren fallen. Bekannter Fall ist `.overlay`, die Hülle von `Dialog`: - Ist die KOMPAT-Zeile für die Altform ein eigener Selektor (`overlay-content`, `:has(…)`), fällt sie weg. - Hat sie die Basisregel `.overlay` selbst verändert (`overflow-y: auto`, Abstand 24/16 px), gelten die Werte, die die Bilder von `design-p9` für `Dialog` zeigen, und bleiben in der Basisregel. Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "^\.(overlay|dialog)\b" src/styles/global.css` Expected: eine Basisregel `.overlay` mit der Mobilregel bei 860 px, ohne Verweis auf `overlay-content`. - [ ] **Step 5: Block löschen, Verschachtelung statisch beweisen** Der Block samt Marker fällt, der Gliederungskommentar nennt danach vier Blöcke statt fünf. Entscheidung: `.page` bleibt als Wurzelklasse jeder Seite. Gelöscht werden nur die Verschachtelungsregel `.page .page, .page .main-content` und die alte `.main-content`-Regel. Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/hygiene.test.mjs rg -n "KOMPAT|main-content" src rg -n 'className=\{?["`]([^"`]* )?page([ "`}]|$)' src --glob '*.jsx' | rg -v '^src/pages/' rg -n '<[A-Za-z]+Page\b' src --glob '!App.jsx' ``` Expected: PASS und drei leere Ausgaben. Es gibt also kein `KOMPAT` und kein `main-content` mehr, die Klasse `page` steht nur in `src/pages/*.jsx` (der Treffer-Filter erfasst nur Klassenstellen, keine Props wie `page` in `Pager`), und nur `App.jsx` rendert `*Page`-Komponenten. Eine Seite in einer Seite ist damit ausgeschlossen. Ein Treffer, der nur ein Wort im Kommentar ist, wird umformuliert. - [ ] **Step 6: Bauen, Gate, Pixelvergleich** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p10 && "$W/shots.sh" p10 "$W/shots/p10-t5" --gate p10 && "$W/run-browser.sh" "$W/vergleich.mjs" "$W/shots/p9-ref" "$W/shots/p10-t5" --rauschen "$W/shots/p9-ref2" --out "$W/shots/p10-t5-diff"` Expected: Gate Exit 0, Vergleich Exit 0. Auch alle Alt-Dialoge (`dlg-*`), die `.seg`-Ansichten (`finanzen`, `serverpuls`) und Links bleiben unverändert. Weicht eine Ansicht ab, wird das Diff-Bild angesehen. Es gibt zwei Ursachen: - Die gelöschte Regel gehört an die Stelle ihres Bausteins (Step 4). - Bereichs-CSS (`chat.css`, `serverpuls.css`, `pages/AdminPage.css`) lädt vor `global.css` und wurde bisher von KOMPAT überstimmt. Der Bereichs-Selektor bekommt dann eine höhere Spezifität, nie `!important`. - [ ] **Step 7: Commit** Abschnitt 2 der Ergebnisdatei ist gefüllt. ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git diff --name-only git add docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md tests/unit/hygiene.test.mjs src/styles/global.css git commit -m "Aufraeumen: KOMPAT-Block, .page-Verschachtelungsregel und Altklassen entfernt" -m "Co-Authored-By: Claude Opus 5.5 " ``` ### Task 6: Tote Klassen und Keyframes **Files:** - Modify: `src/styles/*.css`, `src/pages/*.css`, JSX-Dateien mit Klassen ohne Regel, Ergebnisdatei Abschnitt 3, `$W/css-klassen.mjs` (Ausnahmeliste) - Delete: CSS-Dateien ohne verbleibende Regel samt Importzeilen **Interfaces:** - Consumes: `css-klassen.mjs` mit `--ohne-ausnahmen` (Task 1). - Produces: `dead` und `undefinedUsed` sind leer, die Ausnahmeliste enthält nur Namen mit belegter Konstruktionsstelle. - [ ] **Step 1: Liste erzeugen** Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node "$W/css-klassen.mjs" . --ohne-ausnahmen > "$TMPDIR/klassen-p10.json"; node -e "const j=JSON.parse(require('fs').readFileSync(process.argv[1]));for(const k of ['dead','undefinedUsed','nurAusnahme'])console.log(k, j[k].length+':', j[k].join(' '))" "$TMPDIR/klassen-p10.json" ``` Expected: drei Zeilen mit Namen. `dead` enthält zunächst auch die Namen aus `nurAusnahme`. - [ ] **Step 2: Gegenprobe und Löschen** Für jeden Namen aus `dead`, der nicht in `nurAusnahme` steht: Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "(^|[^A-Za-z0-9_-])NAME([^A-Za-z0-9_-]|$)" src --glob '!*.css'` Expected: keine Treffer. Dann fällt jede Regel mit diesem Namen in der definierenden Datei, in einer Selektorliste nur der Name. Für jeden Namen aus `nurAusnahme` bekommt Abschnitt 3 der Ergebnisdatei eine Zeile mit der Stelle, die ihn baut: ein Template-Präfix wie `fin-fixed-${`, eine Zeichenkette in `lib/*.js` oder der Fremd-Composer bei `chat-*`. Ohne Beleg gilt die Klasse als tot und fällt. - [ ] **Step 3: Klassen ohne Regel, `size`, Keyframes** Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n 'size="sm"' src; rg -n '(^|[^A-Za-z0-9_-])(btn-sm|p-4|status-filter|supporters-editor|timeline)([^A-Za-z0-9_-]|$)' src --glob '!*.css' rg -o "@keyframes [A-Za-z0-9_-]+" src --glob '*.css' | sed 's/.*@keyframes //' | sort -u | while read k; do rg -q "animation[^;]*(^|[^A-Za-z0-9_-])${k}([^A-Za-z0-9_-]|;)" src --glob '*.css' || echo "TOT $k"; done ``` Expected: alle drei Ausgaben leer. Treffer der ersten beiden Befehle werden aus dem JSX entfernt (die Klassen haben keine Regel, `size` bewirkt nichts). Ein toter Keyframe fällt samt Regel. Zu erwarten ist `spin`, wenn `.spin` (Notiz aus P8) und `.spinner` keinen Aufrufer mehr haben. - [ ] **Step 4: Leere Dateien, Ausnahmeliste, Schriftordner** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && wc -l src/styles/*.css src/pages/*.css; rg -n "admin-areas" src index.html; ls src/assets 2>&1 | head -1; rg -n -i "assets/fonts|lato" src index.html` Expected: - Eine CSS-Datei ohne Regel wird mit `git rm` gelöscht, ihre `import`-Zeilen verschwinden (`rg -l "" src`). `admin-areas.css` hat P6 schon gelöscht, ein Treffer von `rg -n "admin-areas" src index.html` ist ein Rest und wird entfernt. - `src/assets` existiert nicht, das letzte `rg` hat keine Treffer. - Die Ausnahmeliste in `$W/css-klassen.mjs` enthält nur noch die Namen mit Beleg aus Step 2. `badge-*`, `status-*`, `ticket-tab-active`, `ui-btn-*` und `side-dot-*` fallen. - [ ] **Step 5: Prüfen** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node "$W/css-klassen.mjs" . | node -e "const j=JSON.parse(require('fs').readFileSync(0));console.log(j.dead.length, j.undefinedUsed.length)" && "$W/check.sh" && "$W/build.sh" "$WT" p10 && "$W/shots.sh" p10 "$W/shots/p10-t6" --gate p10 && "$W/run-browser.sh" "$W/vergleich.mjs" "$W/shots/p9-ref" "$W/shots/p10-t6" --rauschen "$W/shots/p9-ref2" --out "$W/shots/p10-t6-diff"` Expected: `0 0`, `check.sh` Exit 0 mit `# fail 0` und `# pass` = `N9 + 2`, Gate Exit 0, Vergleich Exit 0. - [ ] **Step 6: Commit** Abschnitt 3 der Ergebnisdatei hat die Tabelle: Klasse, definierende Datei, Beleg oder „gelöscht“. ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git status --short git add docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md git commit -m "Aufraeumen: tote Klassen, Keyframes und leere CSS-Dateien geloescht, Klassen ohne Regel aus dem JSX entfernt" -m "Co-Authored-By: Claude Opus 5.5 " ``` ### Task 7: Inline-Styles, Regelprüfung, Invarianten **Files:** - Modify: JSX-Dateien mit Inline-Styles ohne Laufzeitwert (Ersatz sind vorhandene Klassen, neue kommen nicht dazu), Ergebnisdatei Abschnitte 4, 5 und 7 **Interfaces:** - Consumes: `$W/farben.mjs` (P1) und der Abschnitt „Bewusst offen“ in `docs/superpowers/plans/2026-10-05-weisses-design-p1-tote-klassen.md`. - Produces: eine begründete Liste aller `style=`-Stellen und die Regelprüfung der Spec als belegte Liste. - [ ] **Step 1: Inline-Styles nur noch für Laufzeitwerte** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -nU "style=\{\{(\s*[A-Za-z]+:\s*('[^']*'|\"[^\"]*\"|-?[0-9]+(\.[0-9]+)?)\s*,?)+\s*\}\}" src --glob '*.jsx'` Expected: keine Treffer. Das Muster findet jedes Objekt, dessen Werte alle feste Zahlen oder Zeichenketten sind. Jeder Treffer wird durch eine vorhandene Klasse ersetzt. - [ ] **Step 2: Rest begründen** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "style=\{" src --glob '*.jsx'` Expected: wenige Zeilen. Abschnitt 4 der Ergebnisdatei bekommt je Zeile Datei:Zeile, Ausdruck und Begründung. Erlaubt sind ein aus Daten oder Messung berechneter Wert (Breite in Prozent, Höhe, Spaltenzahl) und das Durchreichen der `style`-Prop in `Badge.jsx`. Feste Abstände, Farben, Schrift, Flex und Größen sind nicht erlaubt, solche Stellen werden umgestellt, und Step 1 beginnt von vorn. - [ ] **Step 3: Farben** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n '#[0-9a-fA-F]{3,8}\b|rgba?\(|hsla?\(' src --glob '*.jsx' --glob '*.js'; node "$W/farben.mjs" .` Expected: - Der `rg` nennt nur `src/components/Logo.jsx` und `src/components/serverpuls/chartColors.js`. - `farben.mjs` listet kein Literal unter 3:1 auf Weiß, keine dunkle Schrift auf `--accent` und kein Weiß-Alpha. - Jede Zeile des Abschnitts „Bewusst offen“ in `p1-tote-klassen.md` ist erledigt. Hat sie das Zielpaket P10, wird sie hier behoben und in Abschnitt 5 genannt. - [ ] **Step 4: Regelprüfung der Spec** Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "!important" src # 1 rg -n -e "gradient\(" -e "backdrop-filter" -e "filter: *blur" src --glob '*.css' # 2 rg -n "text-transform" src --glob '*.css' # 3 rg -n "font-weight: *(800|900)" src # 4 rg -n -e "Lato" -e "@font-face" src index.html # 5 rg -n "font-family" src --glob '*.css' # 6 rg -n -e "color-scheme" -e "data-theme" -e "data-accent" src index.html # 7 rg -no -e "@media[^{]*" -e "@container[^{]*" src --glob '*.css' # 8 rg -n "" -e 'rel="icon"' index.html # 11 for s in '\.num' '\.stat \.v' '\.fin-amount'; do printf '%s: ' "$s"; rg -l -U "$s([^A-Za-z0-9_{}-][^{}]*)?\{[^}]*tabular-nums" src --glob '*.css' | tr '\n' ' '; echo; done # 12 ``` Expected: - 1, 4, 5 und 10: leer. - 2: höchstens eine Zeile, der Chevron von `.select`. 3: eine Zeile, die Wochentage `.wd` im Planboard. - 6: nur `var(--font)` und der Monospace-Stapel (`ui-monospace`). 7: nur `color-scheme: light`. - 8: nur `max-width: 1100px` und `860px`, bei `@container` 560, 640 und 860 px, dazu `prefers-reduced-motion`. Zugelassen ist außerdem der eine Block `max-width: 640px` in `src/styles/chat.css`: Er setzt im Eingabefeld des fremden Portal-Composers wieder `font-size: 16px` (gegen das iOS-Zoomen, P6) und ist die WOMS-eigene Überschreibung des Composers. - 9: nur `Logo.jsx` und `Sparkline.jsx`. 11: `Webklar WOMS 2.0` und die Zeile für `/favicon.svg`. - 12 (Spec-Regel 6, Zahlen und Beträge): drei Zeilen, jede nennt mindestens `src/styles/global.css`. Fehlt bei einem Selektor die Datei, trägt seine Regel kein `font-variant-numeric: tabular-nums`. P10 ergänzt dann genau diese Deklaration an der bestehenden Regel. Das ist die einzige erlaubte Abweichung von der Pixelinvariante. Die Ansichten, die dadurch im Vergleich von Task 8 abweichen, stehen mit Begründung in Abschnitt 5. - Spec-Regel 4 (höchstens ein schwarzer Knopf je Seitenkopf) prüft kein `rg`, sondern der Check `max-primary` im Gate `p10` (Task 1 Step 6, Lauf in Task 8 Step 2). Seitenbreakpoints außerhalb von 860 und 1100 px werden auf diese Werte gezogen (Spec, Regel 7), ausgenommen der 640-px-Block in `chat.css`. Jede andere Abweichung steht mit Begründung in Abschnitt 7. Befehl, Ausgabe und Urteil jeder Zeile stehen in Abschnitt 5. - [ ] **Step 5: Invarianten gegen `design-p0`** Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git grep -ho 'data-testid=[^ >]*' design-p0 -- src | sort -u > "$TMPDIR/ti-p0.txt" rg -oN --no-filename 'data-testid=[^ >]*' src | sort -u > "$TMPDIR/ti-jetzt.txt" diff "$TMPDIR/ti-p0.txt" "$TMPDIR/ti-jetzt.txt" | rg '^<' echo "confirm: $(git grep -h 'window\.confirm' design-p0 -- src | wc -l) -> $(rg --no-filename 'window\.confirm' src | wc -l)" git diff --name-status design-p0..HEAD -- src/hooks src/lib ``` Expected: - Das `diff` zeigt keine `<`-Zeile, es ging keine `data-testid` verloren. Neue (`>`) sind erlaubt und werden genannt. - Die Zahl der `window.confirm` ist gleich. - In `src/hooks` steht nur `M useWorkorders.js` plus die neuen `useWorkorder.js`, `useTicketCounts.js`, `useTicketMinutes.js`. In `src/lib` stehen nur `D sidebar.js`, neue Dateien (darunter `rowClick.js` aus P2) und `M` für `ticketStatus.js`, `navLinks.js`, `previewEnv.js`, `serverpulsFormat.js`, `creditFormat.js`, `offerFormat.js`, `storageFormat.js`, `projectList.js`, `leads.js`. Jede andere `M`- oder `D`-Zeile ist ein Befund. Die Ausgaben stehen in Abschnitt 5. - [ ] **Step 6: Commit** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" --nur-tests && git status --short` Expected: Exit 0, `# fail 0`, `# pass` = `N9 + 2`, nur die erwarteten Änderungen. ```bash git add docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md git commit -m "Aufraeumen: Inline-Styles nur noch fuer Laufzeitwerte, Regelpruefung und Invarianten dokumentiert" -m "Co-Authored-By: Claude Opus 5.5 " ``` ### Task 8: Gate P10, Bundle, Review, Tag - [ ] **Step 1: Rebase** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git fetch origin && git merge-base --is-ancestor design-p9 HEAD && git rebase origin/test && "$W/check.sh"` Expected: `design-p9` ist Vorfahre, der Rebase läuft ohne Konflikt, Exit 0 mit `# fail 0` und `# pass` = `N9 + 2`. Gate, Bilder und Review beziehen sich damit auf den Stand, der getaggt wird. - [ ] **Step 2: Vollständiger Lauf und Pixelvergleich** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p10 && "$W/shots.sh" p10 "$W/shots/p10" --gate p10 && "$W/run-browser.sh" "$W/vergleich.mjs" "$W/shots/p9-ref" "$W/shots/p10" --rauschen "$W/shots/p9-ref2" --out "$W/shots/p10-diff"` Expected: - Das Gate `p10` endet mit Exit 0. Über alle Ansichten, auch die der Review-Focus-Punkte 1 bis 5 der Übersicht, gibt es keine Verstöße gegen `external-request`, `console-error`, `dark-surface`, `low-contrast`, `overflow-x`, `icon-svg` (außer unter `.woms-chat`), `max-primary` und `step-failed`. - Der Vergleich endet mit Exit 0, `fehlt` ist leer, die Zahl der Ansichten gleicht der Sollzahl aus Task 1 Step 4. Rausch-Ansichten stehen in `$W/p10-rauschen.txt`. - Die Ansicht `alt-link` hat keinen Verstoß. Ihr Schritt prüft, dass `/tickets?woid=100131&status=done` auf `/tickets/100131` endet. - [ ] **Step 3: Bundle-Größe** Run: ```bash source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" --nur-build && { find dist -type f \( -name '*.js' -o -name '*.css' -o -name '*.ttf' \) -printf '%s %p\n'; for f in dist/assets/*.js dist/assets/*.css; do echo "$f gzip=$(gzip -9 -c "$f" | wc -c)"; done; wc -l src/styles/*.css src/pages/*.css; } | tee "$W/p10-baseline-p10.txt" ``` Expected: - Abschnitt 6 der Ergebnisdatei bekommt eine Tabelle mit den Zeilen JS in Byte, JS gzip, CSS in Byte, CSS gzip, Schrift in Byte, CSS-Zeilen und Testzahl und den Spalten P0, `design-p9`, P10. Die P0-Werte stammen aus der Commit-Zeile `Ausgangswerte` (Gegenprobe: Umbaukarte), die P9-Werte aus `$W/p10-baseline-p9.txt`. - CSS und CSS-Zeilen sind kleiner als bei `design-p9`, JS ist nicht größer. Gegenüber P0 fehlen 96.184 B Schrift. Werte, die gegenüber P0 wachsen, stehen in Abschnitt 7. - [ ] **Step 4: Ergebnisdatei abschließen** Abschnitt 7 (Offene Punkte) ist gefüllt, auch wenn er nur „keine“ sagt. Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git status --short` Expected: nur `M docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md`. ```bash git add docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md git commit -m "Aufraeumen: Ergebnisdatei mit Bundle-Vergleich und offenen Punkten" -m "Co-Authored-By: Claude Opus 5.5 " ``` - [ ] **Step 5: Code-Review (sonnet)** Geprüft wird der Diff `design-p9..HEAD` gegen die Spec-Abschnitte „Übergangsschicht KOMPAT“, „Gestaltungsregeln“ und „Was gleich bleibt“, dazu liest der Prüfer die Ergebnisdatei. Schwerpunkte: - Der Diff enthält nur Löschungen, Umbenennungen und Umstellungen auf vorhandene Bausteine, keine neuen Texte, Klassen oder Tokens außer dem Wächtertest. - Zehn Stichproben aus Abschnitt 2 (KOMPAT) und 3 (tote Klassen): Die Klasse hat per `rg` keinen Nutzer, ihre Regel ist weg. - `package.json` und Lock haben genau `@tabler/icons-react`, `@tabler/icons` und `react-icons` verloren. - `git diff design-p9 -- src/pages/TicketsPage.jsx src/lib/ticketListUrl.js` ist leer oder enthält nur Kommentare, `woidRedirectTarget` ist erhalten. - Jede Begründung in Abschnitt 4 stimmt, die Invarianten aus Abschnitt 5 sind erfüllt. Wichtige Befunde werden behoben, danach laufen Step 1 bis 3 erneut. Kleinigkeiten kommen in Abschnitt 7. - [ ] **Step 6: Tag und Übergabe** Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" && git tag design-p10 && git log --oneline origin/test..design-p10 && git rev-parse design-p10` Expected: Exit 0, Tag gesetzt. Brachte der Rebase in Step 1 neue Commits mit, liefen Gate und Vergleich bereits auf dem rebaseten Stand. Der Eigentümer bekommt: - den Bericht des Pixelvergleichs („0 abweichende Ansichten von “) und die Screenshots aus `$W/shots/p10/1440x900` und `$W/shots/p10/390x844` (Auswahl: `login`, `tickets`, `ticket`, `kunde-overview`, `projekte`, `finanzen`, `dlg-rechnung-kunde`, `serverpuls`, ein Alt-Dialog) - die Bundle-Tabelle aus Abschnitt 6 der Ergebnisdatei - den Hinweis, dass sichtbar nichts Neues erscheint, der Link `/tickets?woid=N` aus Portal-Mails weiter funktioniert und die offenen Punkte in Abschnitt 7 stehen - den Hinweis, dass damit alle Pakete ausgeliefert sind und Worktree `dev-design` samt Branch `feature/design-weiss` danach entfernt werden können, wenn er das will - die Push-Zeile `git -C /home/webklar/apps/ticket.webklar.com/dev-design push origin 'design-p10^{commit}:refs/heads/test'` - die Rücknahme `git revert --no-commit design-p9..design-p10` (Commit und Push auf `test` durch den Eigentümer, gilt nur solange P10 das jüngste Paket ist) - [ ] **Step 7: Nach dem Push (erst, wenn der Eigentümer gepusht hat)** - Im Log von `webklar-ticket-build` steht „Deployment completed successfully“. Dort läuft `npm install` mit dem neuen Lock durch. - `curl -s https://ticket.webklar.com/ | grep -o 'assets/index-[^"]*\.js'` entspricht `dist/index.html` des Tags. - `curl -s -o /dev/null -w '%{http_code}' 'https://ticket.webklar.com/tickets?woid=1'` liefert 200 (Seiten-Fallback). - Ein lesender Sichttest im Chrome des Eigentümers, ohne Schreibaktion: Ein alter Link `/tickets?woid=` mit einer echten Nummer landet auf `/tickets/`. Ticketliste, ein Ticket, das Menü mit dem Serverpuls-Punkt und ein Dialog (öffnen, mit Esc schließen) sehen aus wie vor dem Push, und die Konsole zeigt keinen Fehler.