Files
tessera-ctl/.planning/quick/260921-i8x-fehlerverdaechtige-lint-klassen-steuerze/260921-i8x-SUMMARY.md
T
schalli cfba3c9532
Tessera CI/CD / Lint & Type Check (push) Successful in 54s
Tessera CI/CD / Tests (push) Successful in 1m35s
Tessera CI/CD / Desktop-Pakete bauen (push) Successful in 19s
Tessera CI/CD / Build & Publish Images (push) Successful in 3m10s
docs(quick-260921-i8x): fuenf Fehlerklassen geprueft, kein echter Fehler darunter
Zusammenfassung und STATE.md zum Quick-Vorgang 260921-i8x.

Zwoelf Stellen einzeln beurteilt: sieben gleichwertig oder Absicht,
zwei Haertungen, drei idiomatisch korrekt. Kein echter Defekt.

Die eine Stelle mit echtem Wert ist safe-next.ts, der Schutz gegen
Weiterleitung auf fremde Seiten. Der Kommentar behauptete Escapes,
die rohen Bytes zeigten eingebettete Steuerzeichen. Jetzt echte
Escapes; Gleichwertigkeit ueber alle 65536 Codepunkte nachgerechnet,
54 abgelehnte Zeichen, null Abweichung, vom Orchestrator unabhaengig
gegen ein eigenes Referenzmuster gegengeprueft.

Bewusst nicht angefasst: die NUL-Maskierung in ldap.service.ts nach
RFC 4515 - genau dieses Zeichen zu treffen ist ihr Zweck.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
2026-09-21 13:36:37 +02:00

17 KiB

phase, plan, subsystem, tags, requires, provides, affects, actuals, tech-stack, key-files, key-decisions, requirements-completed, coverage, duration, completed, status
phase plan subsystem tags requires provides affects actuals tech-stack key-files key-decisions requirements-completed coverage duration completed status
quick-260921-i8x 01 security
biome
lint
regex
ldap
cookie
jest
vitest
nextjs
safe-next.ts: FORBIDDEN_CHARS_RE beweisbar unveraendert, jetzt als Unicode-Escapes statt Rohbytes
Vier isNaN -> Number.isNaN Haertungen in tender-radar/dkv-fleet-Komponenten
Drei exec-Schleifen (dkv-parser.service.ts, dkv-parser.validate.ts, icon-discovery.service.ts) ohne Unterdrueckungskommentar umgeschrieben
escapeLdapFilterValue dokumentiert (unveraendert) als RFC-4515-Absicht
NEXT_LOCALE-Cookie mit SameSite=Lax
dkv-fleet-module
tender-radar-module
ldap-sync
i18n
tokens tasks commits
3691 3 3
added patterns
for (let m = re.exec(t); m !== null; m = re.exec(t)) statt while ((m = re.exec(t)) !== null) — vermeidet noAssignInExpressions ohne Unterdrueckungskommentar
biome-ignore unmittelbar ueber der beanstandeten Zeile, ohne Leerzeile — sonst bleibt der Befund UND es kommt suppressions/unused hinzu
created modified
apps/api/src/dkv/dkv-parser.service.spec.ts
apps/web/src/components/locale-switcher.test.tsx
apps/web/src/lib/safe-next.ts
apps/web/src/lib/safe-next.test.ts
apps/api/src/dkv/dkv-parser.service.ts
apps/api/src/dkv/dkv-parser.validate.ts
apps/api/src/favorites/icon-discovery.service.ts
apps/api/src/ldap/ldap.service.ts
apps/web/src/components/locale-switcher.tsx
apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.tsx
apps/web/src/app/(portal)/modules/tender-radar/components/ResultsList.tsx
apps/web/src/app/(portal)/modules/dkv-fleet/components/InvoiceHistoryTable.tsx
apps/web/src/app/(portal)/modules/cert-manager/actions.ts
Sieben der zwoelf Befunde waren keine Fehler (vier isNaN, ein forEach-Rueckgabewert, drei exec-Schleifen) — als gleichwertig/Absicht dokumentiert statt stillschweigend zu Fehlern erklaert
escapeLdapFilterValue in ldap.service.ts bleibt zeichengleich — die NUL-Maskierung ist RFC-4515-Pflicht, kein Steuerzeichen-Bug
Zwei-Zeichen-Praefixtest und Schema-Liste in safe-next.ts unangetastet — nur die Regex-Zeile und zwei Kommentare geaendert
D-01
D-02
D-03
D-04
D-05
D-06
id description requirement verification human_judgment
D1 safe-next.ts: Steuerzeichen als Escapes statt Rohbytes, Zeichenmenge beweisbar unveraendert (54 Codepunkte ueber alle 65536 aus U+0000..U+FFFF) D-01
kind ref status
unit apps/web/src/lib/safe-next.test.ts#Test A: die abgewiesene Zeichenmenge ist und bleibt genau diese 54 Codepunkte pass
kind ref status
unit apps/web/src/lib/safe-next.test.ts#Test B: die Datei enthaelt kein rohes Steuerzeichen pass
false
id description verification human_judgment
D2 Vier isNaN -> Number.isNaN Haertungen (TenderDetail x2, ResultsList, InvoiceHistoryTable)
kind ref status
unit pnpm --filter @tessera/web test (67 -> 68 Dateien, 480 -> 481 Tests bleiben gruen) pass
kind ref status
other biome lint JSON category-Zaehlung: lint/suspicious/noGlobalIsNan == 0 pass
false
id description verification human_judgment
D3 cert-manager/actions.ts: forEach-Rueckgabewert verworfen (useIterableCallbackReturn)
kind ref status
other biome lint JSON category-Zaehlung: lint/suspicious/useIterableCallbackReturn == 0 pass
kind ref status
integration pnpm --filter @tessera/web test — form.append-Reihenfolge unveraendert, keine Regression pass
false
id description requirement verification human_judgment
D4 Drei exec-Schleifen (dkv-parser.service.ts, dkv-parser.validate.ts, icon-discovery.service.ts) auf for-Kopf-Form umgeschrieben, verhaltensgleich D-03
kind ref status
unit apps/api/src/dkv/dkv-parser.service.spec.ts#liefert zwei Fahrzeugbloecke sowie Rechnungsnummer und -datum aus dem Beispieltext pass
kind ref status
other node --experimental-strip-types apps/api/src/dkv/dkv-parser.validate.ts gegen invoice.pdf: 27 Fahrzeugbloecke/66 Transaktionen unveraendert pass
kind ref status
unit apps/api/src/favorites/icon-discovery.service.spec.ts (19 Tests, alle gruen) pass
false
id description requirement verification human_judgment
D5 escapeLdapFilterValue dokumentiert als RFC-4515-Absicht, Funktion zeichengleich D-03
kind ref status
other git diff apps/api/src/ldap/ldap.service.ts zeigt ausschliesslich eine hinzugefuegte Kommentarzeile pass
false
id description requirement verification human_judgment
D6 NEXT_LOCALE-Cookie mit SameSite=Lax gehaertet D-03
kind ref status
unit apps/web/src/components/locale-switcher.test.tsx#schreibt beim Klick genau ein Cookie mit NEXT_LOCALE, path=/, max-age=31536000 und SameSite=Lax pass
false
id description requirement verification human_judgment
D7 Biome-Warnungen 446 -> 434, keine neue Fundstelle, keine neue Abhaengigkeit D-06
kind ref status
other npx biome lint --reporter=json . -> total 434, sev {warning:433, info:1}, suppressions/unused 0 pass
kind ref status
other git diff -- package.json '*/package.json' pnpm-lock.yaml (leer) pass
false
35min 2026-09-21 complete

Quick 260921-i8x: Fehlerverdaechtige Lint-Klassen (Steuerzeichen & Co.) Summary

Zwoelf Befunde aus fuenf Regelklassen einzeln beurteilt: drei echte Haertungen umgesetzt (safe-next.ts-Escapes, Number.isNaN, SameSite=Lax), sieben als gleichwertig/Absicht dokumentiert (vier isNaN, ein forEach, drei exec-Schleifen), zwei als bewusste Nicht-Fixes belassen (LDAP-NUL-Maskierung, Praefixtest) — Biome-Warnungen 446 -> 434, kein Verhalten aendert sich ausser an den drei nachgewiesenen Haertungsstellen.

Performance

  • Duration: ca. 35 min
  • Tasks: 3/3 abgeschlossen
  • Files modified: 13 (11 geaendert, 2 neu)

Urteilstabelle (aus <verdicts> des Plans, mit tatsaechlich Umgesetztem)

# Datei Regel Urteil Umgesetzt
1 apps/web/src/lib/safe-next.ts (2 Befunde) noControlCharactersInRegex Haertung Regex-Zeile auf Unicode-Escapes umgestellt, Kommentar korrigiert (die frühere Behauptung, Escapes seien "am Edge" noetig, war falsch), biome-ignore unmittelbar ueber der Zeile gesetzt. Zeichenmenge ueber alle 65536 Codepunkte als identisch nachgewiesen (54 Codepunkte, Bitmap-SHA-256 unveraendert).
2 apps/api/src/ldap/ldap.service.ts:1662 noControlCharactersInRegex Absicht Keine Aenderung an der Funktion — nur biome-ignore mit Begruendung (RFC 4515, LDAP-Filter-Injection-Risiko) ergaenzt. escapeLdapFilterValue ist zeichengleich zur Ausgangsfassung.
3 apps/web/src/app/(portal)/modules/cert-manager/actions.ts:154 useIterableCallbackReturn gleichwertig Pfeilfunktion mit Kurzform-Rumpf auf Block-Rumpf umgestellt; forEach verwarf den Rueckgabewert ohnehin. Reine Lesbarkeitsaenderung, kein Verhaltensunterschied.
4-7 TenderDetail.tsx (2x), InvoiceHistoryTable.tsx, ResultsList.tsx noGlobalIsNan gleichwertig isNaN(d.getTime()) auf Number.isNaN(d.getTime()) umgestellt. getTime() liefert immer number, die Umwandlung fand nie statt — der Tausch ist Haertung gegen eine zukuenftige Aenderung, kein Fehler heute.
8-10 dkv-parser.service.ts:104, dkv-parser.validate.ts:139, icon-discovery.service.ts:182 noAssignInExpressions Absicht while ((m = re.exec(t)) !== null) auf for (let m = re.exec(t); m !== null; m = re.exec(t)) umgeschrieben — verhaltensgleich, kein Unterdrueckungskommentar mehr noetig. Keine der drei Variablen wird nach der Schleife gelesen.
11 apps/web/src/components/locale-switcher.tsx:15 noDocumentCookie Haertung SameSite=Lax ergaenzt (path=/ und max-age waren bereits korrekt — kein Persistenzdefekt). biome-ignore dokumentiert, warum document.cookie bleibt: die Cookie-Store-API fehlt in WebKit/Tauri auf Linux und macOS.

Sieben der zwoelf Befunde waren keine Fehler — vier isNaN-Stellen, eine forEach-Stelle und drei exec-Schleifen sind als gleichwertig bzw. Absicht ausgewiesen, nicht nachtraeglich zu Bugs erklaert. Zwei weitere (LDAP-NUL-Maskierung, Praefixtest in safe-next.ts) sind bewusste Nicht-Fixes: an ihnen wurde nichts geaendert.

Vorher-/Nachher-Zahlen (aus <verification>)

Pruefung Erwartet Gemessen
pnpm lint 5/5 5 successful, 5 total
Biome JSON-Zaehlung: total / sev 434 / {warning:433, info:1} 434 / {'info': 1, 'warning': 433}
noControlCharactersInRegex 0 0
useIterableCallbackReturn 0 0
noGlobalIsNan 0 0
noAssignInExpressions 4 (nur Testdateien) 4
noDocumentCookie 17 (nur Testdateien) 17
suppressions/unused 0 0
pnpm type-check 4/4 4 successful, 4 total
pnpm --filter @tessera/web test >= 68 Dateien, >= 480 Tests 68 Dateien, 481 Tests, alle passed
pnpm --filter @tessera/api test 72 Dateien, >= 1137 Tests 72 Dateien, 1137 Tests, alle passed
Byte-Scan safe-next.ts CTRL_BYTES 0 [] CTRL_BYTES 0 []
git status --porcelain -- apps packages genau die 13 Dateien aus files_modified bestaetigt (11 geaendert + 2 neu, keine weitere)
git diff -- package.json '*/package.json' pnpm-lock.yaml leer leer

Baseline bei Planungsbeginn (selbst nachgemessen, identisch zur Plan-Messung): 446 Diagnosen gesamt (445 warning + 1 info), noControlCharactersInRegex 3, useIterableCallbackReturn 1, noGlobalIsNan 4, noAssignInExpressions 7, noDocumentCookie 18, suppressions/unused 0.

Task Commits

Jeder Task wurde atomar committet:

  1. Task 1: safe-next.ts — Steuerzeichen als Escapes, Zeichenmenge beweisbar unveraendert - f85c91b (fix), inkl. Plan-Datei
  2. Task 2: isNaN und forEach — vier plus ein gleichwertiger Tausch - 076ca4b (fix)
  3. Task 3: exec-Schleifen, LDAP-NUL-Maskierung und das Sprachumschalter-Cookie - b92dd5d (fix)

Files Created/Modified

  • apps/web/src/lib/safe-next.ts - FORBIDDEN_CHARS_RE auf Unicode-Escapes, Kommentar korrigiert, biome-ignore gesetzt
  • apps/web/src/lib/safe-next.test.ts - Test A (54-Codepunkte-Zusicherung), Test B (Byte-Scan), Test C (Praefixtest) ergaenzt
  • apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.tsx - zwei isNaN -> Number.isNaN
  • apps/web/src/app/(portal)/modules/tender-radar/components/ResultsList.tsx - isNaN -> Number.isNaN
  • apps/web/src/app/(portal)/modules/dkv-fleet/components/InvoiceHistoryTable.tsx - isNaN -> Number.isNaN
  • apps/web/src/app/(portal)/modules/cert-manager/actions.ts - forEach-Callback auf Block-Rumpf
  • apps/api/src/dkv/dkv-parser.service.ts - exec-Schleife auf for-Kopf-Form
  • apps/api/src/dkv/dkv-parser.service.spec.ts - neu: Rueckfall-Tor fuer parseDkvText (zwei Fahrzeugbloecke, Rechnungsnummer/-datum)
  • apps/api/src/dkv/dkv-parser.validate.ts - exec-Schleife auf for-Kopf-Form (Stand-alone-Skript)
  • apps/api/src/favorites/icon-discovery.service.ts - exec-Schleife auf for-Kopf-Form
  • apps/api/src/ldap/ldap.service.ts - biome-ignore-Kommentar ueber der RFC-4515-NUL-Maskierung, Funktion unveraendert
  • apps/web/src/components/locale-switcher.tsx - SameSite=Lax ergaenzt, biome-ignore gesetzt
  • apps/web/src/components/locale-switcher.test.tsx - neu: haelt die vollstaendige geschriebene Cookie-Zeichenkette fest

Decisions Made

  • Die Erwartungsliste der 54 abgewiesenen Codepunkte in Test A wurde hart hinterlegt statt aus der Regel abgeleitet (D-01) — eine aus derselben Regel erzeugte Erwartung wuerde jede Aenderung der Regel mitmachen und bewiese damit nichts.
  • Alle drei biome-ignore-Kommentare in diesem Vorgang mussten als einzeilige Kommentare unmittelbar ueber der beanstandeten Zeile stehen — ein mehrzeiliger Kommentarblock wird von Biome nur in seiner letzten Zeile als Kommentar erkannt, nicht als Unterdrueckungsdirektive, und erzeugt zusaetzlich suppressions/unused. Das wurde bei safe-next.ts zunaechst falsch gemacht (dreizeiliger Kommentar) und beim ersten Testlauf korrigiert (siehe Deviations).
  • escapeLdapFilterValue bleibt zeichengleich (D-03) — nur ein Kommentar wurde ergaenzt, keine Zeile der Funktion geaendert.

Deviations from Plan

Auto-fixed Issues

1. [Rule 3 - Blocking] biome-ignore-Kommentar bei safe-next.ts musste einzeilig sein, nicht dreizeilig

  • Found during: Task 1
  • Issue: Der erste Entwurf des biome-ignore-Kommentars war ueber drei Zeilen umgebrochen. Biome erkennt nur die letzte dieser drei Zeilen als unmittelbar vor der Regex stehend, und diese Zeile beginnt nicht mit biome-ignore — die Unterdrueckung griff nicht, der urspruengliche Befund blieb bestehen UND suppressions/unused kam hinzu (npx biome lint meldete danach 2 statt 0 Befunde fuer die Datei).
  • Fix: Kommentar auf eine einzige Zeile mit der vollen Begruendung zusammengefasst, direkt ueber der Regex-Zeile ohne Leerzeile.
  • Files modified: apps/web/src/lib/safe-next.ts
  • Verification: npx biome lint apps/web/src/lib/safe-next.ts meldet danach 0 Warnungen.
  • Committed in: f85c91b (Teil des Task-1-Commits, kein separater Commit noetig — der Fehler wurde vor dem Commit gefunden)

2. [Rule 3 - Blocking] import.meta.url in Test B lieferte keine file:-URL in der Vitest/jsdom-Umgebung

  • Found during: Task 1
  • Issue: Der erste Entwurf von Test B nutzte fileURLToPath(new URL('./safe-next.ts', import.meta.url)); das schlug mit TypeError: The URL must be of scheme file fehl, bevor der eigentliche Byte-Scan ueberhaupt lief.
  • Fix: Umgestellt auf join(import.meta.dirname, 'safe-next.ts') (Node 24, verfuegbar).
  • Files modified: apps/web/src/lib/safe-next.test.ts
  • Verification: Test B laeuft danach korrekt rot (3 Bytes) vor dem Umbau und gruen (0 Bytes) danach.
  • Committed in: f85c91b

3. [Rule 3 - Blocking] Erste Commit-Nachricht (Task 1) enthielt rohe NUL-Bytes durch das Write-Werkzeug

  • Found during: Commit von Task 1
  • Issue: Genauso wie im Plan fuer safe-next.ts selbst gewarnt, wandelte das Write-Werkzeug die Unicode-Escape-Schreibweise fuer den Bereich U+0000 bis U+001F plus U+007F in der Commit-Nachricht (als Freitext, nicht als Code) still in die tatsaechlichen Steuerbytes um. git commit verweigerte den Commit mit "a NUL byte in commit log message not allowed".
  • Fix: Commit-Nachricht ohne \uXXXX-Schreibweise umformuliert (Bereichsangabe in Worten statt als Escape-Literal), vor dem Commit per Python auf verbleibende Steuerbytes geprueft.
  • Files modified: keine (nur die Commit-Nachricht betroffen, kein Code)
  • Verification: Python-Bytescan der Commit-Nachricht-Datei ergab bad bytes [], danach committete git commit -F fehlerfrei.
  • Committed in: f85c91b

Total deviations: 3 auto-fixed (alle Rule 3 - Blocking, alle Werkzeugfallen ohne Codeauswirkung) Impact on plan: Keine Verhaltensaenderung, keine Ausweitung des Umfangs. Alle drei Abweichungen wurden vor dem jeweiligen Commit gefunden und behoben — kein fehlerhafter Zwischenstand wurde committet.

Issues Encountered

Keine ueber die drei oben dokumentierten Werkzeugfallen hinaus. Alle <verify>-Bloecke aus dem Plan wurden real ausgefuehrt (keiner musste umformuliert werden), alle Zielzahlen wurden exakt erreicht.

User Setup Required

None - keine externe Konfiguration erforderlich.

Next Phase Readiness

Alle zwoelf Befunde sind abgeschlossen und dokumentiert. noArrayIndexKey und noNonNullAssertion (zusammen 19+11 der verbliebenen 434 Warnungen) sind explizit nicht angefasst — sie gehoeren laut Auftrag in den naechsten Vorgang. noUselessSwitchCase bleibt der dokumentierte Nicht-Fix aus 260921-bi2. Keine Blocker.


Quick-Vorgang: 260921-i8x Completed: 2026-09-21

Self-Check: PASSED

Alle 13 in files_modified genannten Dateien existieren auf der Platte. Alle drei Task-Commit-Hashes (f85c91b, 076ca4b, b92dd5d) sind im lokalen Git-Verlauf gefunden. commits: 3 in actuals per git rev-list --count 287799a..HEAD gemessen (kein narrativer Wert). Byte-Scan dieser SUMMARY-Datei selbst ergab 0 rohe Steuerbytes, nachdem ein durch das Write-Werkzeug verursachter Treffer (dieselbe \uXXXX-Falle wie in Task 1) gefunden und korrigiert wurde.