Files
tickte-system/docs/superpowers/plans/2026-10-05-weisses-design-p10-aufraeumen.md
T

51 KiB
Raw Blame History

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, <Navigate replace> 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-<svg> 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 <Dialog as="form"> 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" <A> <B> [--rauschen <A2>] [--out <Ordner>] → 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 (<w>x<h>/<id>.png, z. B. 1440x900/tickets.png und 390x844/tickets.png).
    • node "$W/token-check.mjs" <worktree> [--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:

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:

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:

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: <Testzahl>, JS <x> B, CSS <y> 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 <w>x<h>/<id>.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:

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 <n> .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.
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:

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 '<!doctype html><meta charset="utf-8"><title>Probe</title><div class="page-head"><h1>Test</h1><button class="btn btn-primary">A</button><button class="btn btn-primary">B</button></div>' > "$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

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:

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
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 <noreply@anthropic.com>"

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
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 <noreply@anthropic.com>"

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

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:

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.

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 <die geprüften Dateien aus der Liste oben>
git commit -m "Aufraeumen: Token-Aliase der Altnamen durch die neuen Tokens ersetzt und geloescht" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"

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

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:

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 <tr>) 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 <section> 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 <tr> 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 <a>, sonst die Regel in den Block des Nutzers

In jedem <Dialog as="form">, 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 '<tr' Expected: keine Treffer. Ein Treffer in einem Kommentar wird umformuliert, jeder Code-Treffer nach der Tabelle umgestellt, eine Gruppe je Commit (Meldung „Aufraeumen: Restnutzer von 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:

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.

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 <weitere geprüfte Dateien>
git commit -m "Aufraeumen: KOMPAT-Block, .page-Verschachtelungsregel und Altklassen entfernt" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"

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:

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:

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 "<Dateiname>" 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“.

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 <die geprüften Dateien>
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 <noreply@anthropic.com>"

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:

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 "<svg" src --glob '*.jsx'                                                   # 9
rg -n -e "Kpi" -e "kpi" src                                                       # 10
rg -n -e "<title>" -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:

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.

git add docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md <die geprüften Dateien aus Step 1 bis 4>
git commit -m "Aufraeumen: Inline-Styles nur noch fuer Laufzeitwerte, Regelpruefung und Invarianten dokumentiert" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"

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:

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.

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 <noreply@anthropic.com>"
  • 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=<N> mit einer echten Nummer landet auf /tickets/<N>. 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.