


Eine große Desktop-Medien-App ändern, ohne die UI einzufrieren oder den Rückgängig-Verlauf zu brechen
Für eine große Desktop-App mit Dateien und Medien: Die KI hält schwere Arbeit vom UI-Thread fern, deckt Abbrüche und Grenzfälle ab, hält den Rückgängig-Verlauf exakt und meldet nur die Tests, die wirklich liefen.
Diese KI-Regeln verwenden
## Den ganzen Aufrufweg verfolgen und jedem Zustand einen einzigen Besitzer geben
- Verstehe die zuständige Funktion und die bestehenden Abstraktionen, bevor du Änderungen vornimmst, und verfolge den vollständigen Aufrufpfad durch Benutzeroberfläche, Automatisierung, Rückgängig-Funktion, Persistenz und Hintergrundarbeit.
- Bestimme bei nicht trivialen Änderungen vor dem Schreiben von Code die maßgebliche Datenquelle, den Zustandsverantwortlichen, die Isolationsdomäne, die Invarianten sowie das Verhalten bei Fehlern und Abbrüchen.
- Entwirf die Architektur vor den Implementierungsdetails und bevorzuge eine in sich stimmige Änderung gegenüber verstreuten Patches in unzusammenhängenden Schichten.
- Halte für jeden veränderlichen Zustand genau einen maßgeblichen Eigentümer; abgeleiteter Zustand wird berechnet oder von einem Cache mit einem expliziten Invalidierungsvertrag gepflegt.
- Nutze vorhandene Domänenoperationen wieder; füge keine zweite Implementierung hinzu, nur weil der Aufrufer eine Vorschau, eine Ansicht, ein Controller, ein Automatisierungswerkzeug oder ein Test ist.
- Platziere Code bei der Funktion, der er gehört, halte gemeinsam genutzte Hilfsfunktionen für Infrastruktur bereit, die von mehreren unabhängigen Funktionen verwendet wird, und benenne Typen und Dateien so, dass die Zuständigkeit klar ist.
## Kommentare kurz halten und toten Code entfernen
- Halte Kommentare minimal: Schreibe nur dann einen, wenn der Grund, die Invariante, die Sicherheitsbedingung oder der Workaround nicht offensichtlich ist, und beschränke ihn auf eine kurze Zeile.
- Erzähle den Code nicht nach, wiederhole keine Namen, beschreibe nicht den aktuellen Patch, hinterlasse keine Hinweise auf Entferntes und behalte keinen auskommentierten Code.
- Bevorzuge präzise Namen, kleine Typen und ausgelagerte Operationen gegenüber erklärenden Kommentaren.
- Eine Berechnung oder Geschäftsregel hat genau eine maßgebliche Quelle; kopiere sie niemals in eine andere Datei oder Oberfläche.
- Entferne vor Abschluss toten Code, ungenutzten Zustand, veraltete Kompatibilitätspfade und temporäre Diagnosen.
- Füge keinen Kompatibilitätscode für Plattformen, Versionen oder Konfigurationen hinzu, die das Projekt nicht unterstützt.
## Schwere Arbeit vom UI-Thread fernhalten und den Zustand nach jedem await neu prüfen
- Behandle den UI-Thread als knappe Ressource: Er darf UI- und leichten Koordinationszustand halten, aber keine Dateizugriffe, Dekodierung, Modellinferenz, Bildverarbeitung, Indizierung, Export, blockierende Aufrufe oder große Transformationen ausführen.
- Isolation ist keine Performance: Arbeit als asynchron zu markieren oder in eine Task zu verpacken, verschiebt sie nicht vom aktuellen Thread. Verfolge den tatsächlichen Executor.
- Mache Thread-Wechsel explizit; erstelle einen Snapshot der minimal nötigen unveränderlichen Eingabe, bevor du einen Thread verlässt, gib einen Wert zurück und wende ihn erst an, nachdem bestätigt ist, dass er noch aktuell ist.
- Gehe nach jedem Suspensionspunkt davon aus, dass sich gemeinsam genutzter Zustand geändert hat: Überprüfe Identität, Generation, Auswahl und Vorbedingungen erneut, bevor du ein Ergebnis committest.
- Bevorzuge strukturierte Nebenläufigkeit; eine unstrukturierte Task braucht einen klaren Eigentümer, bei relevanter Abbrechbarkeit ein gespeichertes Handle und ein definiertes Teardown.
- Abbruch ist kooperativ: Lange Schleifen prüfen ihn an sinnvollen Grenzen und committen niemals partielle oder veraltete Ergebnisse.
- Begrenze parallele Arbeit anhand der tatsächlich knappen Ressource, dedupliziere identische, bereits laufende Anfragen, erwirb und gib Gates in zueinander passenden Scopes frei, und setze jede Continuation oder jeden Callback genau einmal fort.
- Blockiere den UI-Thread niemals mit synchronem Warten, Semaphoren, Locks oder Polling auf asynchrone Arbeit.
## Dateiarbeit außerhalb des UI-Threads ausführen und Dateien atomar ersetzen
- Jede Dateisystemoperation läuft außerhalb des UI-Threads: Lesen, Schreiben, Existenz- und Metadatenprüfungen, Auflistung, Kopieren, Verschieben, Ersetzen, Löschen und Verzeichniserstellung.
- Gehe davon aus, dass jedes Volume langsam, wechselbar, extern verändert oder netzwerkgebunden sein kann; eine geringe Größe oder ein zuvor erfolgreicher Zugriff macht synchronen Zugriff nicht sicher.
- Erstelle vor der Dateiarbeit einen Snapshot der eigenen Modelldaten und verändere keinen beobachtbaren Zustand aus dem Executor der Dateiarbeit heraus.
- Bereite die vollständige Ausgabe außerhalb des Live-Ziels vor, stelle den Ersatz am Zielort bereit und installiere ihn dann atomar; leite Live-Schreibvorgänge über einen einzigen Koordinator, statt direkt zu schreiben.
- Serialisiere Operationen, die auf dieselbe Datei oder dasselbe Ziel zielen, damit Speichern, Import, Erzeugung, Thumbnail-Erstellung, Löschen, Export und Schließen niemals in einen Wettlauf geraten.
- Verwende eindeutige temporäre Pfade und räume sie bei Erfolg, Fehler und Abbruch auf; lösche oder ersetze ein Ziel niemals, bevor der vollständige Ersatz fertig ist.
- Mache vom Nutzer angeforderte Dateifehler sichtbar; verstecke sie nicht hinter ignorierten Fehlern, leeren Ergebnissen oder erfolgsförmigen Antworten.
## Vor Aussagen über mehr Tempo messen und häufige Pfade schlank halten
- Identifiziere performancekritische Pfade wie Rendering, Wiedergabe, Eingabeverarbeitung, Ansichts-Updates, Import, Indizierung, Speichern, Wiederherstellen und Export, und behandle sie als besonders leistungskritisch.
- Führe innerhalb von Pfaden, die pro Element, pro Frame oder bei wiederholten Interaktionen durchlaufen werden, keine Dateizugriffe, Logging, Serialisierung, Modell- oder Decoder-Initialisierung oder sonstige blockierende Einrichtung aus.
- Miss, bevor du eine Verbesserung behauptest: Profiliere oder benchmarke dieselbe Arbeitslast vor und nach der Änderung.
- Behebe algorithmische Komplexität und unnötige Arbeit vor dem Feintuning auf niedriger Ebene; achte auf verschachtelte Scans, wiederholtes Sortieren, Copy-in-Loop-Mutationen, Zwischenallokationen und wiederholte Thread-Wechsel.
- Bündle und fasse Massenänderungen zusammen und leere ausstehenden Zustand vor Snapshots, Rückgängig-Aktionen, Export, Schließen und Lesevorgängen, die aktuelle Daten liefern müssen.
- Lade und befülle Daten verzögert (lazy), und cache aufwendige, wiederverwendbare Arbeit nur mit einem expliziten Schlüssel, einer Kapazität, einer Invalidierungsregel und einer Richtlinie für veraltete Ergebnisse.
- Nutze aufwendige Objekte wieder, soweit ihr Lebenszyklus es erlaubt, und invalidiere sie bei relevanten Konfigurationsänderungen; verhindere, dass hochfrequenter Zustand wie Fortschritt und Messwerte ganze Ansichten invalidiert; begrenze den gehaltenen Speicher.
## Vor der Umsetzung Grenzfälle und Fehlerpfade auflisten
- Der Erfolgspfad allein reicht nicht aus: Zähle vor der Implementierung die relevanten Grenz-, Lebenszyklus-, Nebenläufigkeits- und Fehlerfälle auf und entscheide, welche Schicht für jeden zuständig ist.
- Validiere je nach Anwendbarkeit leere, nil-, Null-, negative, maximale, überlaufende, nicht-endliche, fehlerhafte, doppelte, fehlende, veraltete und nicht unterstützte Eingaben.
- Validiere vor Arithmetik, Indizierung oder numerischer Konvertierung; verlasse dich niemals darauf, dass ein späterer Catch eine arithmetische Falle abfängt, und definiere exaktes Runden und Clamping, statt stillschweigend zu clampen.
- Decke No-Op- und wiederholte Operationen ab: Sie müssen korrekt berichten und dürfen keine Mutationen, Verlaufseinträge, doppelte Arbeit oder irreführenden Erfolg erzeugen.
- Berücksichtige Abbruch vor dem Start, während jeder Phase und nach Abschluss der Arbeit, aber vor dem Commit, sowie veraltete Abschlüsse nach Änderungen an Auswahl, Ziel oder Konfiguration.
- Berücksichtige Teardown-Pfade: Schließen, Beenden, Ruhezustand, Aufwachen, Deaktivierung, Gerätewechsel und Speichern-unter während laufender Arbeit.
- Bewahre Invarianten auf jedem Fehlerpfad: Teilerfolg ist entweder sicher fortsetzbar und wird auch so gemeldet, oder er wird zurückgerollt.
## Eine Nutzeraktion mit einem einzigen Rückgängig-Schritt zurücknehmbar machen
- Route Nutzeraktionen und automatisierte Aktionen über dieselben Domänen-Mutationsoperationen und denselben gemeinsamen Verlauf.
- Eine in sich stimmige Nutzerabsicht erzeugt genau eine rückgängig machbare Aktion; zeige interne Teilschritte nicht als separate Verlaufseinträge, es sei denn, jeder ist für sich genommen bedeutsam.
- Validiere Argumente und Vorbedingungen, bevor du eine Verlaufsgruppe öffnest; fehlgeschlagene, abgebrochene, verweigerte und unveränderte Operationen dürfen keine leeren Einträge erzeugen.
- Verschachtelte Arbeit verschmilzt mit der äußeren Aktion, ohne Gruppen zu schließen, die der Plattform oder einem anderen Subsystem gehören.
- Rückgängig stellt den exakten Zustand wieder her, ohne kumulative Rundungsfehler, Drift im abgeleiteten Zustand, verwaiste Beziehungen oder veraltete Auswahl.
- Wenn eine Änderung den Verlauf betrifft, teste die Verschachtelung zwischen Nutzerbearbeitungen, automatisierten Bearbeitungen, plattformseitiger Ereignisgruppierung und gleichzeitigen Anfragen.
## Automatisierungswerkzeuge danach entwerfen, was Nutzer erreichen wollen
- Entwirf Werkzeuge ausgehend von der Nutzerabsicht, nicht von internen APIs, Speicheroperationen oder Servicegrenzen; definiere Ergebnis, Erfolgskriterien, Warnungen, Fehlerfall, Abbruch, Idempotenz und Rückgängig-Semantik, bevor du das Schema festlegst.
- Ein Werkzeug führt eine in sich stimmige Aktion aus; ein Aufruf schließt normalerweise genau einen atomaren, verständlichen, rückgängig machbaren Arbeitsablauf ab. Baue kein breites Werkzeug mit unzusammenhängenden Modi, und zwinge Aufrufer nicht, für Arbeit, die das System sicher selbst erledigen kann, Low-Level-Werkzeuge aneinanderzureihen.
- Drücke Parameter in nutzerorientierten Domänenbegriffen aus und verberge Speicherlayout und Implementierungsdetails; verwende für Automatisierung stabile Entitäts-Identifikatoren und behandle Positionsindizes und Beschriftungen nur als Kontext, nicht als dauerhafte Identität.
- Behandle jedes Argument als nicht vertrauenswürdig: Verlange exakte Typen, endliche Zahlen, explizite Grenzen und gültige Identifikatoren; löse die vollständige Anfrage auf und validiere sie, bevor du Änderungen vornimmst, und wende Änderungen an mehreren Entitäten atomar an.
- Nutze dieselben Domänenoperationen wie die Benutzeroberfläche wieder und dupliziere keine Logik für Platzierung, Verknüpfung oder Validierung.
- Gib strukturierte Belege zurück, die beschreiben, was sich geändert hat, mit stabilen Identifikatoren, explizitem No-Op-Zustand, Warnungen und umsetzbaren Fehlermeldungen; gib niemals eine erfolgsförmige Antwort zurück, wenn das Ergebnis angepasst oder nicht erreicht wurde, und clampe, retargete oder falle niemals stillschweigend zurück, es sei denn, der Vertrag verspricht und meldet dies.
- Lang laufende Werkzeuge stellen einen dauerhaften Job oder ein Endergebnis bereit, das der Aufrufer einsehen kann; halte maschinenlesbare Verträge stabil und getrennt von lokalisierten Texten; Beschreibungen erklären, wann, warum und wie ein Werkzeug mit anderen zusammenwirkt.
## UI-Zustand auf dem UI-Thread halten und natives Plattformverhalten bewahren
- Halte beobachtbaren UI-Zustand auf dem UI-Thread und lass Hintergrundergebnisse als unveränderliche Werte über die Grenze wandern.
- Begrenze Beobachtung auf die kleinste Ansicht, die einen Wert benötigt; hochfrequenter Fortschritts-, Hover- und Wiedergabezustand darf keine unabhängigen Ansichtsbäume invalidieren.
- Starte keine dauerhaften Seiteneffekte aus einem Render-Body heraus; verwende lebenszyklusbewusste Tasks oder Controller mit explizitem Abbruch und Teardown, und halte Render-Bodys schnell und frei von Seiteneffekten.
- Bewahre das native Plattformverhalten für Fokus, Tastatur, Escape, Menüs, Fensterwiederherstellung, Rückgängig, Drag-Zustand und Schließbestätigung.
- Delegate- und Completion-Handler-Verträge schließen bei jedem Erfolgs-, Fehler-, Abbruch- und Fehlendes-Ziel-Pfad genau einmal ab.
- Gehe nicht davon aus, dass ein Framework- oder Completion-Callback auf dem UI-Thread ankommt, sofern die API dies nicht garantiert.
## Medien ohne Blockieren verarbeiten und Zeit- und Frame-Werte exakt halten
- Verwende asynchrones Laden von Eigenschaften für externe Assets und rufe keine veralteten synchronen Zugriffsmethoden auf, die den aufrufenden Thread blockieren können.
- Halte Werte so lange wie möglich in ihrer exakten Domäne, etwa als präzise Zeit-, Frame- oder Einheiten-Ganzzahlen, und konvertiere erst an expliziten UI- oder externen Formatgrenzen in Gleitkommazahlen.
- Definiere und bewahre Quellsemantik wie Timing, Skalierung, Transformationen, Farbe, Alpha, Kanallayout und Metadaten, sofern die Funktion sie nicht ausdrücklich ändert.
- Nutze Reader, Render-Kontexte und Pipelines wieder, soweit ihr Lebenszyklus es erlaubt, und baue sie während fortlaufender Interaktion nicht neu auf, es sei denn, eine Invalidierung erfordert dies.
- Begrenze gleichzeitige Decoder, Reader, Exporte, Inferenz und Extraktion, und leite Abbruch durch jede Dekodier-, Render- und Export-Schleife weiter, indem du zwischen den Chunks prüfst, wenn ein zugrunde liegender Schritt nicht abgebrochen werden kann.
- Teste mit fehlenden Spuren, ungewöhnlichen Containern, null oder unbestimmter Dauer, gedrehten oder Alpha-Eingaben, nicht standardmäßigen Raten und Abbruch.
## Design-Tokens statt fest eingetragener Stilwerte verwenden
- Style alles über das gemeinsame Design-Token-System; codiere Abstände, Größen, Schriftstärken, Radien, Randbreiten, Deckkraft, Farben, Schatten oder Animationsdauern niemals fest.
- Falls ein benötigtes Token nicht existiert, füge es zuerst dem Token-System hinzu, statt einen Wert fest zu codieren.
- Ressourcen-Lookup muss in der paketierten Anwendung, bei lokalen Läufen und in Tests funktionieren; verwende die gemeinsame Ressourcen-Lookup-Abstraktion statt funktionsspezifischer Prüfungen, und behandle jedes Bundle-Layout als eigenständige, zu verifizierende Konfiguration.
- Verwende Debug-only-Flags nicht, um einen grundlegend anderen Ressourcenpfad oder ein anderes Verhalten auszuwählen, es sei denn, der Unterschied ist beabsichtigt und getestet.
- Aktualisiere beim Hinzufügen einer gebündelten Ressource das Paketmanifest, die Build-Skripte und die Tests, verifiziere das endgültige paketierte Layout, und halte optionalen Feature-Flag-Code sowohl mit als auch ohne das Flag baubar.
## Jedem Vorgang ein sichtbares Ende und nützliche Logs geben
- Jede vom Nutzer oder von einer Automatisierung initiierte Operation erreicht einen beobachtbaren Zustand: Erfolg, Fehler, Ablehnung oder Abbruch.
- Ignoriere einen Fehler an einer Interaktionsgrenze nicht, wenn ein Scheitern das Ergebnis verändert; wandle ihn in UI-Zustand, einen Werkzeugfehler, einen Job-Fehler oder ein umsetzbares Protokoll um.
- Fire-and-forget-Arbeit ist nur erlaubt, wenn sie ausdrücklich als Best-Effort gekennzeichnet ist; sie darf keine erforderliche Persistenz übernehmen, und ihre Fehler müssen sicher ignorierbar oder protokolliert sein.
- Protokolliere Fehler mit der Operation, stabilen Identifikatoren und der Lebenszyklusphase; schreibe niemals Geheimnisse, Zugangsdaten oder rohe Nutzereingaben in Protokolle.
- Bewahre genügend Diagnoseinformationen, um Abbruch, Validierungsfehler, nicht verfügbare Ressource, Framework-Fehler und interne Invarianzverletzung voneinander zu unterscheiden.
- Verwende Assertions nur für Programmierer-Invarianten, nicht für behebbare Nutzereingaben, externe Dateien, Lebenszyklus-Wettläufe oder Automatisierungsanfragen.
## Kleine, deterministische Tests schreiben, die parallel laufen können
- Unit-Tests sind knapp und verhaltensfokussiert: Ein Test etabliert eine Invariante oder Regression mit genau dem Setup, das sie verständlich macht, unter Verwendung aussagekräftiger Namen und ohne schritterzählende Kommentare.
- Verwende parametrisierte Tests für Grenzwertmatrizen und gemeinsame Fixture-Builder, statt Setup über mehrere Suiten hinweg zu duplizieren.
- Teste über die kleinste stabile Schnittstelle, die das Verhalten belegt, und vermeide Kopplung an private Details oder beiläufige Aufrufzähler.
- Jeder Bugfix erhält, wenn praktikabel, einen Regressionstest, der für den ursprünglichen Defekt fehlschlägt, und deckt negative Pfade ab: Validierung, No-Op, Teilfehler, Abbruch, veralteter Abschluss und Aufräumen.
- Nebenläufigkeitstests koordinieren deterministisch mit Gates, Continuations oder injizierten Hooks und verlassen sich nicht auf Sleeps, Timing-Zufall oder Ausführungsreihenfolge.
- Tests laufen parallel: Teile keinen veränderlichen globalen Zustand, keine festen temporären Namen, Ports oder Verzeichnisse; verwende eindeutige temporäre Verzeichnisse und räume sie auf, und halte echte Zugangsdaten, externe Dienste und echte Nutzerdateien aus Unit-Tests heraus.
## Zuerst die Korrektheit prüfen und genau melden, welche Tests liefen
- Prüfe zuerst auf Korrektheit, dann auf Stil: Verfolge geändertes Verhalten durch Aufrufer, gemeinsam genutzten Zustand, Hintergrundarbeit, Persistenz, Rückgängig, UI und Automatisierungsoberflächen.
- Priorisiere Befunde, die Datenverlust, Korruption, Abstürze, Hänger, Wettlaufsituationen, Sicherheitslücken, falsche Ergebnisse, defektes Rückgängig oder irreführenden Erfolg verursachen, danach Performance, Wartbarkeit und Feinschliff.
- Achte auf Blockieren des UI-Threads, Nebenläufigkeitsfehler wie Zustand, der nach einer Suspension ohne erneute Prüfung committet wird, herrenlose Tasks, fehlenden Abbruch, unbegrenzten Fan-out, unausgeglichene Gates und doppelt fortgesetzte Callbacks, sowie duplizierte Domänenlogik, unsichere Caches und unvalidierte Grenzarithmetik; begrenze den Review auf die Änderung und das, was sie direkt betrifft.
- Verifiziere Behauptungen: Führe den für die Änderung passenden Build und die passenden Tests aus, prüfe bei Nebenläufigkeitsänderungen Abbruch- und Lebenszyklus-Pfade, und miss Performance-Änderungen unter einer repräsentativen Arbeitslast.
- Berichte genau, was ausgeführt wurde und was nicht; behaupte keine vollständige Build-, Test- oder Laufzeitverifikation, wenn nur ein Teil abgeschlossen wurde.
- Halte Commits fokussiert mit einem engen, präzisen Kategorie-Präfix und ohne unzusammenhängende Aufräumarbeiten, und beschreibe eine Änderung anhand ihrer Zusammenfassung, ihres Ansatzes, wichtiger Designentscheidungen und Testnachweise statt anhand der Abfolge der vorgenommenen Bearbeitungen.
