Neue Komponente BatchRunSummaryBanner aggregiert die Ergebnisliste nach
Laufende und zeigt je Kategorie Icon + Anzahl + Text an. Banner verschwindet
beim Start des nächsten Laufs. READY_FOR_AI, PROPOSAL_READY und PROCESSING
werden nicht gezählt (nicht im DocumentCompletionStatus-Enum enthalten);
Reset-Pending-Zeilen werden explizit ausgeschlossen.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Neue zentrale Klasse ProcessingStatusPresentation als einzige autoritative
Quelle fuer Icons, CSS-Farben, Tooltip-Texte und Summary-Kategorielabels
aller DocumentCompletionStatus-Werte. GuiBatchRunResultRow delegiert
statusIcon() und statusColor() an diese Klasse und stellt neue Methode
statusTooltip() bereit. In GuiBatchRunTab erhalten Status-Icons Tooltips
per CellFactory; die duplizierte private statusColor()-Methode entfaellt.
Fuer FAILED_PERMANENT wird im Detailbereich ein erweiterter Erklaerungstext
gemaess Spezifikation #51 angezeigt. Unit-Tests fuer ProcessingStatusPresentation
(alle Status, Eindeutigkeit, korrekte Mapping-Werte) und statusTooltip() in
GuiBatchRunResultRowTest ergaenzt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ${revision}-Property im Parent-POM eingeführt; alle Kind-POM-<parent>-Blöcke
verwenden ${revision} statt hartkodierter Version
- flatten-maven-plugin 1.6.0 in <build><plugins> des Parent-POM aktiviert
(resolveCiFriendliesOnly), sodass installierte POMs keine unaufgelösten
${revision}-Referenzen enthalten
- MANIFEST.MF des Shade-JARs enthält Implementation-Version und Implementation-Title
- app.version im Packaging-Modul auf ${revision} umgestellt (war 2.5.0)
- ApplicationVersionProvider: neue Utility-Klasse im Bootstrap-Modul liest
Implementation-Version aus MANIFEST.MF, Fallback "dev" bei ungepacktem Betrieb
- ApplicationVersionProviderTest: prüft Fallback-Verhalten im Testlauf
- .gitignore: .flattened-pom.xml-Dateien ausgeschlossen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bei mehrfachem Provider-Wechsel oder Modelle-Neu-Laden konnten parallele
HTTP-Threads ihre Ergebnisse in dieselbe Meldungsliste schreiben. Mit
einem AtomicLong-Generationszaehler wird vor jedem Lauf eine Generation
festgehalten; bei der UI-Auslieferung auf dem JavaFX Application Thread
wird verworfen, was nicht mehr zur aktuellen Generation gehoert. Damit
ueberschreiben veraltete Worker den UI-Zustand nicht mehr.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Statt fuer jede openConfigurationFile-Anfrage einen neuen Thread zu
starten, werden Anfragen jetzt ueber einen Single-Thread-ExecutorService
mit Daemon-ThreadFactory eingereiht. Mehrfaches Klicken auf Oeffnen
erzeugt keine konkurrierenden Worker-Threads mehr; Anfragen werden
seriell hintereinander abgearbeitet.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Die Felder currentDocument, currentRenderer, currentSourceFile,
currentPage und totalPages werden vom Worker-Thread geschrieben und
vom JavaFX Application Thread gelesen. Das volatile-Keyword garantiert
nun die Sichtbarkeit zwischen den Threads gemaess Java Memory Model.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Neues funktionales Interface FilePickerDialog eingefuehrt, das Titel,
Anfangspfad und ExtensionFilter-Liste entgegennimmt. showNativeFileChooser
wendet die Filter auf den FileChooser an. pickFile reicht die Filter
durch. Test-Stubs verwenden die aktualisierte Drei-Parameter-Signatur.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pendingMessages.clear() wurde aus runTechnicalTestsAction() in den
Coordinator verlagert (erste Anweisung in triggerTechnicalTests()).
Damit liegen clear() und Worker-Start auf demselben Thread (FX),
und das Race-Fenster zwischen clear() und den per Platform.runLater
zurueckgefuehrten add()-Aufrufen entfaellt.
Die fachliche Produktionssemantik (Replace beim Trigger) bleibt
identisch. JavaDoc und Kommentare wurden auf Replace-Semantik
korrigiert. Der Smoke-Test trigger_twice_accumulatesTestEntries
wurde zu trigger_twice_replacesTestEntries umbenannt und prueft
nun die Replace-Erwartung des isolierten Coordinators.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
setMaxHeight(200) entfernt und VBox.setVgrow(messagesListView, ALWAYS)
gesetzt. Die ListView füllt nun den verbleibenden Platz innerhalb der
Meldungs-Card; der Button darunter bleibt davon unberührt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
VBox.setVgrow(card, ALWAYS) auf dem Meldungs-Card macht die Sektion
dehnbar innerhalb von sectionsBox. Damit das VGrow überhaupt wirken kann,
wurde scrollPane.setFitToHeight(true) ergänzt – ohne diese Voraussetzung
bleibt tabContent auf seine natürliche Höhe beschränkt und das VGrow
läuft ins Leere.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Die leeren Label-Spacer in Spalte 0 der Fehler- und Info-Zeilen des
fieldGrid waren managed=true (JavaFX-Default). JavaFX reservierte dadurch
pro Zeile ~20px Hoehe, selbst wenn das eigentliche Fehler-Label in
Spalte 1 unmanaged/unsichtbar war. Fuenf betroffene Zeilen (baseUrl-Fehler,
Timeout-Fehler, Modell-Fehler, API-Key-Fehler, API-Key-Herkunft) erzeugten
zusammen ~96-120px ungenutzten Leerraum unterhalb der Felder.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- VBox-Spacing in Provider-Block von 2 auf 4 Pixels erhöht (wie im Pfade-Bereich)
- Padding in der Provider-Box von 6px auf 8px erhöht (wie im createCardContainer)
- Abstände zwischen Basis-URL, Modell und API-Key sind nun einheitlich mit dem Pfade-Bereich
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Die beiden SKIPPED-Statuswerte teilten sich bisher Icon und Farbe.
Jeder Status erhaelt jetzt ein eigenes Unicode-Icon und passende Farbe:
SUCCESS gruen, FAILED_RETRYABLE orange, FAILED_PERMANENT rot,
SKIPPED_ALREADY_PROCESSED blau (Naechster-Track), SKIPPED_FINAL_FAILURE
grau (Durchgestrichener Kreis).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Basis-URL und Timeout stehen jetzt nebeneinander (4-Spalten-Layout,
Timeout schmal rechts), Modell und API-Key belegen jeweils volle Breite
- Meldungsbereich: minHeight/prefHeight von 140px auf 60px reduziert
- Sektionsabstände (sectionsBox spacing) von 12 auf 4px reduziert
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Problem 1: Falsche Meldung bei reinen SKIPPED-Läufen (0 failed, >0 skipped)
- Die Nachricht enthielt immer "fehlgeschlagen" auch wenn failedCount=0
- Neue Logik formuliert Meldung basierend auf tatsächlichen Zählern
Problem 2: Falsche rote Farbe für SKIPPED-only-Läufe
- Farblogik basierte auf Keywords im Text statt auf failedCount
- Neue Logik färbt rot nur wenn failedCount > 0
- Farbe neutral (kein Hintergrund) für SKIPPED-only-Läufe
Neue buildSummaryMessage()-Methode mit drei Fällen:
- Alle erfolgreich (0 failed, 0 skipped)
- Nur übersprungen (0 failed, >0 skipped)
- Mit Fehlern (failed > 0)
Neue Farblogik in appendSummary() direkt auf failedCount basieren.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Padding unterhalb der Selektions-Button-Leiste ergaenzt
- Hinweisbereich wird nur eingeblendet wenn eine Meldung vorliegt
- Farbliche Unterscheidung: Erfolg gruen, Fehler rot, neutral Standard
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Der Reset-Button wird jetzt explizit deaktiviert, wenn kein KI-Vorschlag
vorhanden ist (finalFileName ist Optional.empty()). Die Bedingung in
refreshUiState() wurde geklaert und dokumentiert.
Nicht-erfolgreiche Zeilen (FAILED, FAILED_RETRYABLE, SKIPPED_FINAL_FAILURE)
können im Detailbereich des Verarbeitungslauf-Tabs nun einen manuellen
Zieldateinamen erhalten. Beim Bestätigen wird die Quelldatei mit dem
benutzerdefinierten Namen ins Zielverzeichnis kopiert und der Stammsatz
atomar auf SUCCESS gehoben.
Neuer Inbound-Port ManualFileCopyUseCase mit sealed Result-Hierarchie,
Default-Implementierung mit Best-Effort-Rollback bei Persistenzfehler
sowie GUI-Brücke GuiManualFileCopyPort. Die GUI entscheidet anhand des
Status zwischen Umbenennen (SUCCESS, SKIPPED_ALREADY_PROCESSED) und
Kopieren (FAILED_*, SKIPPED_FINAL_FAILURE).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Die Buttons 'Vorherige' und 'Naechste' in der PDF-Vorschau hatten keinen
Abstand nach unten zur Trennlinie/zum Panel-Rand. Padding unten am navBar-
Container (HBox) hinzugefügt, konsistent mit dem Padding oben.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Jeder Fehlertyp erhält jetzt eine präzise deutsche Meldung:
- Kein lesbarer Text (NO_USABLE_TEXT) → OCR-Hinweis
- Titel zu lang → Titeltext + tatsächliche Länge + Limit
- Defekte/nicht extrahierbare PDF → Beschädigungshinweis
- Verbindungsfehler/Timeout → Verbindungs- und Konfigurationshinweis
- Unbekannter Fehler → neutraler Fallback ohne Log-Verweis
Der Verweis auf "Details im Anwendungslog" wurde vollständig entfernt.
Das "Fehler:"-Präfix in buildDetailText() entfällt; bei vorhandener
Fehlermeldung wird NO_REASONING_TEXT unterdrückt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Teile DocumentCompletionStatus.SKIPPED in SKIPPED_ALREADY_PROCESSED und
SKIPPED_FINAL_FAILURE auf, um den Skip-Grund unterscheidbar zu machen
- Führe neuen Typ HistoricalDocumentContext ein (lastTargetFileName,
lastSuccessInstant, lastFailureInstant, wasEverSuccessful)
- Führe ResolveHistoricalDocumentContextUseCase und
DefaultResolveHistoricalDocumentContextUseCase ein
- Ersetze GuiHistoricalFileNamePort durch GuiHistoricalDocumentContextPort
- Lade historischen Kontext für übersprungene Zeilen im Coordinator-Worker-Thread
- Zeige im Detailbereich je nach Skip-Grund:
SKIPPED_ALREADY_PROCESSED: "Bereits erfolgreich verarbeitet am [Datum]. Zieldatei: [Name]."
SKIPPED_FINAL_FAILURE: "Endgültig fehlgeschlagen am [Datum]. Erneute Verarbeitung nur nach Reset möglich."
- Passe alle betroffenen Tests an
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Neue Komponenten:
- ResolveHistoricalFileNameUseCase (port/in) und DefaultResolveHistoricalFileNameUseCase (usecase)
- GuiHistoricalFileNamePort (GUI-interner Port, folgt dem Muster von GuiManualFileRenamePort)
GuiBatchRunCoordinator ruft in toRow() für SKIPPED-Zeilen ohne finalName den
historicalFileNamePort auf und trägt den Rückgabewert als neuen Dateinamen ein.
Bootstrap verdrahtet resolveHistoricalFileNameForGui als GuiHistoricalFileNamePort
und übergibt ihn über GuiStartupContext an den GUI-Adapter.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Issue #40: Entferne Platzhaltertext aus Dateiname-Eingabefeld
- Der promptText "Basisname ohne .pdf" wird nicht mehr angezeigt,
wenn keine Zeile selektiert ist
- Das Feld bleibt leer und ausgegraut im deaktivierten Zustand
Issue #39: Addiere fehlende rechte Padding zu Detailbereich
- Der Detailbereich hatte nur links Padding (SECONDARY_SPACING),
aber nicht rechts
- Jetzt ist das Padding symmetrisch auf beiden Seiten
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Das überflüssige Label rechts neben dem Dateinamen-Eingabefeld in der
FileNameEditorPane wird entfernt. Die Dateiendung ist implizit bekannt.
- Entferne Feldinitialisierung extensionLabel
- Entferne Label aus HBox inputRow
- Entferne entsprechende Initialisierungen
- Aktualisiere JavaDoc-Kommentar
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Nach erfolgreicher Umbenennung loeste resultItems.set() in
upsertResultRowByFingerprint() den selectedItemProperty-Listener aus,
der handleSelectionChange() mit noch aktivem Dirty-State aufrief.
Drei Korrekturen:
1. fileNameEditor.clearDirtyState() in handleRenameResult() vor dem
Zeilen-Upsert: setzt lastSavedName = aktueller Textfeldinhalt, damit
isDirty() false ist bevor die Tabellenzeile ersetzt wird.
2. selectionSyncInProgress-Schutz um resultItems.set() in
upsertResultRowByFingerprint(): unterbindet mehrfache JavaFX-interne
Change-Events (oldRow > null > newRow) waehrend des Upserts.
3. Neue Methode FileNameEditorPane.clearDirtyState() eingeführt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Schließt Issue #21: Alle vier Icon-Größen (16/32/64/128 px) werden beim
Start am primären Stage gesetzt; JavaFX wählt automatisch die passende
Größe je nach Kontext (Titelleiste, Taskleiste, Alt+Tab).
Schließt Issue #20: Beim Klick auf den X-Button wird das Fenster in den
Windows System-Tray minimiert (stage.hide()) statt die Anwendung zu
beenden. Platform.setImplicitExit(false) hält die JavaFX-Runtime aktiv.
Das Tray-Icon zeigt ein Kontextmenü mit "Öffnen" und "Beenden";
Doppelklick öffnet das Fenster ebenfalls. Beim Beenden über das Tray-Menü
wird das Icon sauber entfernt.
Die gesamte AWT-Tray-Logik ist in SystemTrayManager gekapselt. Der
Headless-Betrieb bleibt unberührt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Nutzt java.util.prefs.Preferences mit dem Schluessel "lastConfigPath"
um den Pfad der zuletzt geladenen Konfigurationsdatei zu speichern.
Beim naechsten Start wird diese Datei automatisch geladen, sofern sie
noch existiert. Falls nicht oder falls nie eine Datei geladen wurde,
startet die GUI normal ohne Fehlermeldung.
Geaenderte Klassen:
- GuiConfigurationEditorWorkspace: Speichern des Pfads nach erfolgreichem Laden,
neue Methode autoLoadLastConfiguration() fuer automatisches Laden beim Start
- PdfUmbenennerGuiApplication: Aufruf von autoLoadLastConfiguration() nach
Initialisierung des Fensters
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Fuegt stage.setMaximized(true) in PdfUmbenennerGuiApplication.start() hinzu,
so dass das Fenster beim Start automatisch maximiert wird.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Ersetzt die PDFView-basierte Vorschau durch direktes Rendering einzelner Seiten
mit PDFBox (Loader.loadPDF + PDFRenderer.renderImageWithDPI bei 120 DPI).
BufferedImage wird über SwingFXUtils.toFXImage in eine JavaFX-Image konvertiert
und in einer ImageView angezeigt. fit-to-view entsteht nativ durch Binding von
fitWidth/fitHeight an den StackPane-Bereich bei preserveRatio=true. Keine
Scrollbalken, keine Zoom-Einschraenkungen, Seitenanfang immer sichtbar.
Lazy Rendering mit In-Memory-Cache fuer bereits gerenderte Seiten; asynchrones
Oeffnen und Rendering auf pdf-preview-worker-Thread; "latest preview request
wins"-Prinzip bleibt erhalten. pdfviewfx-Abhaengigkeit aus adapter-in-gui pom
entfernt, pdfbox stattdessen explizit aufgenommen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ersetzt fetchAspectRatioAsync/fitToView durch updateZoom() mit A4-Dimensionen
(595x842 Punkte) als Fallback. Scrollbalken werden per CSS und ScrollPane-Policy
ausgeblendet. Zoom-Listener auf pdfView statt viewStack.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GuiBatchRunTab: Buttons "Erneut verarbeiten" / "Status zurücksetzen" und
Meldungsbereich in die linke SplitPane-Spalte unterhalb der Tabelle
verschoben. Detailbereich (rechte Spalte) erstreckt sich dadurch vollständig
von oben bis unten – mehr Platz für die PDF-Vorschau.
PdfPreviewPane: Gesamten suppressScrollReset / ChangeListener-Code entfernt.
Seite wird jetzt immer fit-to-view ohne Scrollbalken angezeigt: Seitenverhältnis
wird asynchron per renderPage(0.05f) ermittelt, Zoom über setZoomFactor() gesetzt
und bei Größenänderungen der Anzeigefläche automatisch neu berechnet.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Der bisherige ImageView-imageProperty-Listener mit Platform.runLater()
wurde von PDFViewFX nach dem Rendering noch einmal ueberschrieben, weil
die interne Scroll-Korrektur ebenfalls asynchron laeuft und spaeter
ausgefuehrt wird.
Neuer Ansatz: Nach jedem pdfView.load() und pdfView.setPage()-Aufruf
wird ein einmaliger ChangeListener auf die vvalueProperty des internen
ScrollPane registriert (scheduleScrollToTop). Sobald PDFViewFX seine
interne Scroll-Position durchschreibt und der Wert von 0 abweicht,
korrigiert der Listener ihn sofort auf 0 und entfernt sich danach selbst.
Damit greift der Eingriff immer nach dem internen PDFViewFX-Scroll,
unabhaengig von der Renderzeit.
Zusaetzlich wird ein aktiver Listener bei schnellen Seitenwechseln
(cancelScrollToTopListener) und bei clear() sauber aufgeraeumt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pdfviewfx wird von 3.1.1 auf 3.3.2 aktualisiert. Version 3.3.1 behebt
'Do not interrupt rendering', wodurch ClosedByInterruptException bei
schnellem Seitenwechsel (#27 Folge-Bug) und das Ausbleiben weiterer
Renderings ab Seite 3+ (#29 Folge-Bug) nicht mehr auftreten.
Das 100-ms-PauseTransition-Workaround fuer den Seitenanfang wird ersetzt
durch einen Listener auf die imageProperty des internen ImageView der
PDFView-Skin. Der Listener scrollt erst dann zum Seitenanfang, wenn
das Rendering tatsaechlich abgeschlossen ist und pendingScrollToTop
gesetzt wurde (bei loadSource und Seitenwechsel-Buttons). Dadurch wird
der Seitenanfang zuverlaessig angezeigt, unabhaengig von der Renderzeit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bug #27: Den zu aggressiven ScrollEvent::consume-Filter durch einen
gezielten Filter auf dem internen ScrollPane der PDFView-Skin ersetzt.
Der Filter konsumiert nur dann, wenn die Seite keinen ueberlaufenden
Inhalt hat oder der Scroll-Inhalt an der oberen bzw. unteren Grenze
angekommen ist. Dadurch bleibt Inhalts-Scrolling innerhalb einer Seite
weiterhin moeglich; nur der Seitenwechsel per Mausrad wird verhindert.
Bug #29: Platform.runLater() durch eine PauseTransition (100 ms) ersetzt,
die nach dem vollstaendigen Rendering-Durchlauf der PDFView-Skin den
internen ScrollPane explizit auf vValue=0 zuruecksetzt. So wird der
Seitenanfang zuverlaessig angezeigt, ohne dass die Skin die Position
nachtraeglich ueberschreibt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bug #27: ScrollEvent-Filter auf PDFView verhindert Seitenwechsel durch Mausrad.
Seitenwechsel sind ausschliesslich ueber die Navigations-Buttons moeglich.
Die Seitenzahl wird nur noch bei Button-Klick aktualisiert.
Bug #29: Nach dem Laden einer PDF und bei Seitenwechsel ueber Buttons wird
die Seite jetzt explizit von oben angezeigt. Der setPage()-Aufruf erfolgt
via Platform.runLater() nach dem Layout-Pass, sodass stets der Seitenanfang
sichtbar ist.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Neu im Tab "Verarbeitungslauf":
- Integrierte PDF-Vorschau der Quelldatei mit Lazy Rendering (Seite 1 sofort,
weitere Seiten on-demand), Cache pro Selektion, "latest preview request wins"
- Editierbarer KI-Dateinamenvorschlag mit Live-Validierung, Dirty-State-Dialog
bei Zeilen-/Tabwechsel, Schließen und Laufstart, atomare FS+DB-Transaktion
inkl. Rollback und Fingerprint-basierter Konfliktauflösung
Architektur:
- Neuer Application-Use-Case ManualFileRenameUseCase und Outbound-Port
TargetFileRenamePort mit Filesystem-Adapter
- Neuer GuiManualFileRenamePort, verdrahtet im Bootstrap
- GuiBatchRunResultRow um correctedFileName erweitert
- GuiBatchRunTab auf SplitPane-Layout (60/40) umgebaut, Detail-Panel mit
KI-Begründung, FileNameEditorPane und PdfPreviewPane
- Spike-Code (PdfViewerSpike) entfernt, produktive Implementierung ersetzt
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Neue Klasse AiFailureMessageTranslator übersetzt technische englische
Fehlertexte (z.B. HTTP-Statuscodes, Verbindungsfehler) in lesbare
deutsche Benutzerhinweise. GuiBatchRunTab nutzt den Translator vor der
Anzeige; das Datenmodell (aiFailureMessage) bleibt unverändert.
Unit-Tests decken alle definierten Mapping-Fälle ab.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DocumentCompletionEvent um optionales Feld failureMessage erweitert
- DocumentProcessingCoordinator leitet Fehlermeldung bei Fehler-Status durch
- GuiBatchRunResultRow um aiFailureMessage (Optional<String>) ergänzt
- GuiBatchRunCoordinator.toRow() befüllt aiFailureMessage aus dem Event
- GuiBatchRunTab.buildDetailText() zeigt bei fehlendem Reasoning und
vorhandenem Fehlergrund: "⚠ Fehler: <Meldung>" vor dem Hinweistext
- Alle Tests angepasst und neue Unit-Tests für aiFailureMessage ergänzt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Verarbeitungsfehler (PreCheckFailed, AiFunctionalFailure) und
Retry-Entscheidungen (FAILED_RETRYABLE, FAILED_FINAL) werden nun auf
WARN-Level geloggt. EmptyList- und IncompleteConfiguration-Ergebnisse
des Modellabrufs sowie fehlende Quelldateien im Mini-Lauf ebenfalls.
Tests angepasst: Assertions prüfen jetzt das korrekte WARN-Level.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Synthetisierte Fehlzeilen (fehlende Quelldatei) werden nur im lokalen
failedCount gezählt, nicht in RunSummary. Der abschließende Log-Eintrag
verwendete bisher summary.failedCount() und zeigte daher fehlgeschlagen=0
obwohl die GUI-Anzeige korrekt war.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
appendSummary verwendete bisher summary.failedCount() aus dem RunSummary-Objekt
des echten Laufs, das von synthesizeMissingSourceFileRows() nachträglich hochgezählte
failedCount nicht kannte. Nun werden die lokalen Zähler (successCount, failedCount,
skippedCount) verwendet, die über onDocumentCompleted und die Synthese konsistent
gepflegt werden. Test ergänzt um Assertion auf '1 fehlgeschlagen' in der Zusammenfassung.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>