1
0

Umsetzung von M1

This commit is contained in:
2026-04-20 10:11:19 +02:00
parent cd6e5221aa
commit b5044f62a9
59 changed files with 5891 additions and 884 deletions
+86 -56
View File
@@ -1,18 +1,28 @@
---
model: sonnet
---
# AP05 Befundmodell mit Spec-/Diagnose-Trennung
> **Meilenstein:** M1
> **Vorgänger:** AP03, AP04 ✅
> **Nachfolger:** AP06, AP07, AP09
> **Grundlage:** `docs/specs/technik-und-architektur.md` v5, §§ „Ergebnis- und Befundmodell", „Befundarten", „Gültigkeitsentscheidung und Exit-Codes"
> **Entscheidungsprotokoll:** `docs/arbeitspakete/m1/E00-entscheidungsprotokoll.md`
## Ziel
Im Paket `domain` ein **stabiles Befundmodell** einführen, das von Anfang an zwischen **Spec-Urteil** (verbindliches Prüfurteil gemäß Spezifikation) und **diagnostischer Weiteranalyse** (zusätzliche, das Spec-Urteil nicht verändernde Hinweise) unterscheidet. Dieses Modell ist das **Herzstück** für alle nachfolgenden Meilensteine.
Der bestehende Typ `de.gecheckt.asv.validation.model.ValidationResult` wird nicht einfach gelöscht, sondern **ersetzt** durch ein sauber geschnittenes Domain-Modell. Der alte Typ wird im Rahmen von AP09 eingefroren.
Der bestehende Typ `de.gecheckt.asv.validation.model.ValidationResult` wird nicht geändert — er wird in AP09 eingefroren.
## Voraussetzungen
- AP03 (Paketstruktur)
- AP03 (Paketstruktur vorhanden)
- AP04 (Logging-Adapter)
## Scope IN
Folgende Typen im Paket `de.gecheckt.asv.domain.finding` (oder ähnliches Unterpaket von `domain`):
Folgende Typen im Paket `de.gecheckt.asv.domain.finding`:
### `Severity` (Enum)
- `ERROR`
@@ -21,88 +31,108 @@ Folgende Typen im Paket `de.gecheckt.asv.domain.finding` (oder ähnliches Unterp
### `FindingKind` (Enum)
- `SPEC` — Befund ist Teil des Spec-Urteils, beeinflusst `Verdict`
- `DIAGNOSTIC` — zusätzliche Weiteranalyse, beeinflusst `Verdict` **nicht**
- `DIAGNOSTIC` — zusätzliche Weiteranalyse, beeinflusst `Verdict` **niemals**
### `FindingLayer` (Enum)
- `ARTIFACT` — äußeres Artefakt / Dateiebene
- `TECHNICAL_STRUCTURE` — Service-Segmente, KKS, Transport
- `DOMAIN_MODEL` — kanonisches Fachmodell (ASVREC/ASVFEH)
### `Finding` (Record)
### `Finding` (Record oder unveränderliche Klasse)
Alle Pflichtfelder laut `technik-und-architektur.md` §„Befundarten":
```java
public record Finding(
FindingKind kind, // SPEC oder DIAGNOSTIC
Severity severity, // ERROR/WARNING/HINT
FindingLayer layer, // ARTIFACT/TECHNICAL_STRUCTURE/DOMAIN_MODEL
String ruleId, // interne Regel-ID, optional null
String officialErrorCode, // offizieller Fehlercode, optional null
String segmentType, // z.B. "UNB", optional
Integer segmentIndex, // optional
String fieldId, // z.B. "UNB_0020", optional
String rawValue, // Rohwert, optional
Integer position, // Byte-/Zeichenposition, optional
String messageReference, // UNH 0062 bei Nachrichtenbezug, optional
String germanMessage // deutscher Befundtext
String ruleId, // interne Regel-ID, nullable
String officialErrorCode, // offizieller Spec-Fehlercode, nullable
String segmentType, // z.B. "UNB", nullable
Integer segmentIndex, // nullable
String fieldId, // z.B. "UNB_0020", nullable
String rawValue, // Rohwert, nullable
Integer position, // Byte-/Zeichenposition, nullable
String messageReference, // UNH 0062 bei Nachrichtenbezug, nullable
String germanMessage // deutscher Befundtext, nicht nullable
) {}
```
Records mit vielen optionalen Feldern sind unschön — als Alternative ist eine reguläre Klasse mit Builder erlaubt, solange sie unveränderlich (`final`) ist und die gleichen Felder trägt. **Wichtig ist: unveränderlich und mit allen Metadaten aus `technik-und-architektur.md` Abschnitt „Befundarten".**
Records mit vielen optionalen Feldern sind unschön — als Alternative ist eine reguläre unveränderliche Klasse mit Builder erlaubt, solange alle Felder vorhanden sind.
### `Verdict` (Enum)
- `VALID` — keine Spec-ERROR-Befunde
- `INVALID` — mindestens ein Spec-ERROR-Befund
- `OPERATIONAL_ERROR` — Bedienfehler (Exit-Code 2)
- `VALID` — keine SPEC-ERROR-Befunde
- `INVALID` — mindestens ein SPEC-ERROR-Befund
- `OPERATIONAL_ERROR` — Bedienfehler (Exit-Code 2), wird in AP08 genutzt
### `ValidationReport` (Klasse)
- unveränderlich
- enthält:
- `List<Finding> findings` (alle Befunde, SPEC und DIAGNOSTIC gemischt, Reihenfolge erhalten)
- Methode `Verdict computeVerdict()` — berücksichtigt **nur** `kind == SPEC` und `severity == ERROR`
- Methode `List<Finding> specFindings()` — filtert auf `kind == SPEC`
- Methode `List<Finding> diagnosticFindings()` — filtert auf `kind == DIAGNOSTIC`
- Methode `boolean hasSpecErrors()`
- Metadaten: `String fileName`, `Instant timestamp`
- **invariant:** eine `DIAGNOSTIC`-Severity `ERROR` darf das Verdict **niemals** auf `INVALID` setzen. Dies ist per Unit-Test abzusichern.
### `ValidationReport` (unveränderliche Klasse)
### Unit-Tests
- `ValidationReport` ohne Befunde → `Verdict.VALID`
- `ValidationReport` mit einem SPEC-ERROR → `Verdict.INVALID`
- `ValidationReport` mit einem DIAGNOSTIC-ERROR → `Verdict.VALID` (dieser Test ist kritisch!)
- `ValidationReport` mit SPEC-WARNING → `Verdict.VALID` (nur ERROR zählt)
- `specFindings()` / `diagnosticFindings()` filtern korrekt
- Unveränderlichkeit: `findings`-Liste ist nicht modifizierbar
```java
public final class ValidationReport {
// Metadaten
String fileName;
Instant timestamp;
// Befunde
List<Finding> findings; // unveränderlich
// Kern-Methoden
Verdict computeVerdict(); // NUR SPEC+ERROR zählt
boolean hasSpecErrors();
List<Finding> specFindings();
List<Finding> diagnosticFindings();
// Factory für Bedienfehler (AP08)
static ValidationReport operationalError(String fileName, String ruleId, String message);
}
```
**Invariante:** `computeVerdict()` berücksichtigt **ausschließlich** Findings mit `kind == SPEC` und `severity == ERROR`. Ein `DIAGNOSTIC`-ERROR darf das Verdict **niemals** auf `INVALID` setzen. Dies ist per Unit-Test abzusichern.
### Unit-Tests (Mindestanforderung)
1. Leerer Report → `Verdict.VALID`
2. Ein SPEC-ERROR → `Verdict.INVALID`
3. **Ein DIAGNOSTIC-ERROR → `Verdict.VALID`** (dieser Test ist kritisch und muss explizit vorhanden sein)
4. SPEC-WARNING → `Verdict.VALID` (nur ERROR zählt)
5. `specFindings()` / `diagnosticFindings()` filtern korrekt
6. `findings`-Liste ist nicht von außen modifizierbar
7. `operationalError(...)``Verdict.OPERATIONAL_ERROR`
## Scope OUT
- Integration des neuen Modells in den bestehenden Lauf (kommt in AP06)
- Löschen oder Umbenennen der alten `validation.model.ValidationResult`-Klasse (das ist Teil von AP09)
- Berichtserzeugung (Text-Rendering), Bericht-Format, Konsolenausgabe (kommt in AP07)
- Architekturtest (kommt in AP10)
- Integration des neuen Modells in den bestehenden Lauf (AP06)
- Löschen oder Umbenennen der alten `ValidationResult`-Klasse (AP09)
- Berichtserzeugung, Textrendering, Konsolenausgabe (AP07)
- Architekturtest (AP10)
## Schritte
1. Branch `m1/ap05-befundmodell`
2. Paket `de.gecheckt.asv.domain.finding` anlegen
3. Enums und Klassen implementieren
4. Unit-Tests schreiben, mindestens die sechs oben genannten
5. `mvn clean verify` grün bekommen
6. Commit `M1-AP05: Befundmodell mit Spec-/Diagnose-Trennung`
7. Abschlussbericht schreiben
1. Paket `de.gecheckt.asv.domain.finding` anlegen
2. Enums `Severity`, `FindingKind`, `FindingLayer` implementieren
3. `Finding` implementieren
4. `Verdict` implementieren
5. `ValidationReport` implementieren
6. Unit-Tests schreiben — mindestens die sieben oben genannten
7. `mvn clean verify` grün bekommen
8. Abschlussbericht schreiben
## Abnahmekriterien
- Paket `domain.finding` enthält alle oben genannten Typen
- **Der Test „DIAGNOSTIC-ERROR ergibt VALID" ist grün** und wird im Bericht explizit genannt
- `ValidationReport.findings` ist unveränderlich (Test vorhanden)
- alle Metadaten-Felder aus `technik-und-architektur.md` Abschnitt „Befundarten" sind im `Finding`-Typ vorhanden
- `mvn clean verify` ist grün
- keine Änderung an `validation.model.ValidationResult` (Altmodell)
- Abschlussbericht liegt vor
- [ ] Paket `domain.finding` enthält alle genannten Typen
- [ ] **Test „DIAGNOSTIC-ERROR ergibt VALID" ist grün** und im Bericht explizit genannt
- [ ] `ValidationReport.findings` ist unveränderlich (Test vorhanden)
- [ ] Alle Metadatenfelder aus `technik-und-architektur.md` §„Befundarten" sind im `Finding`-Typ vorhanden
- [ ] `operationalError(...)` Factory-Methode existiert
- [ ] Keine Änderung an `ValidationResult` (Altmodell)
- [ ] `mvn clean verify` grün
- [ ] Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP05-bericht.md`
## Rest-Risiken und offene Punkte
- Wir haben jetzt zwei parallele Ergebnis-Typen: den alten `ValidationResult` und den neuen `ValidationReport`. Das ist **Absicht** bis AP09, wo die alte Logik sauber eingefroren wird.
- Das Befundmodell ist bewusst **keine** Hierarchie (Datei → Schicht → Nachricht → Befund), sondern eine flache Liste mit Metadaten. Die hierarchische Berichtserzeugung passiert später auf Basis dieser Metadaten in M9. Für M1 genügt die flache Struktur.
- Zwei parallele Ergebnistypen (`ValidationResult` alt, `ValidationReport` neu) sind bis AP09 Absicht.
- Das Befundmodell ist bewusst eine **flache Liste** mit Metadaten, keine Hierarchie. Die hierarchische Berichtserzeugung kommt in M9.
## Bericht
`docs/arbeitspakete/m1/berichte/AP05-bericht.md` nach `templates/ap-bericht.md`.
`docs/arbeitspakete/m1/berichte/AP05-bericht.md` nach `docs/arbeitspakete/m1/templates/ap-bericht.md`.
+128 -55
View File
@@ -1,13 +1,22 @@
---
model: sonnet
---
# AP06 Bootstrap und CLI-Adapter
> **Meilenstein:** M1
> **Vorgänger:** AP05 ✅ erforderlich
> **Nachfolger:** AP07, AP09
> **Grundlage:** `docs/specs/technik-und-architektur.md` v5, §§ „CLI-Zuschnitt", „Laufzeit- und Betriebsmodell", „Gültigkeitsentscheidung und Exit-Codes", „Zeichensätze"
> **Entscheidungsprotokoll:** `docs/arbeitspakete/m1/E00-entscheidungsprotokoll.md` (E-05 fat JAR)
## Ziel
Die bestehende `AsvValidatorApplication` wird in zwei klar getrennte Verantwortlichkeiten zerlegt:
1. **Bootstrap** (`de.gecheckt.asv.bootstrap.Main`) — verdrahtet die Komponenten manuell per Constructor Injection und ist der einzige `public static void main`.
2. **CLI-Adapter** (`de.gecheckt.asv.adapter.in.cli.CliRunner` oder ähnlich) — nimmt CLI-Argumente entgegen, ruft die Application-Schicht auf, übersetzt das Ergebnis in einen Exit-Code.
1. **Bootstrap** (`de.gecheckt.asv.bootstrap.Main`) — verdrahtet alle Komponenten manuell per Constructor Injection, ist der einzige `public static void main`
2. **CLI-Adapter** (`de.gecheckt.asv.adapter.in.cli.CliRunner`) — nimmt CLI-Argumente entgegen, ruft Application-Schicht auf, übersetzt Ergebnis in Exit-Code
Zusätzlich werden die **Exit-Codes spec-konform** auf `0/1/2` umgestellt.
Zusätzlich werden Exit-Codes spec-konform auf `0/1/2` umgestellt, ISO-8859-15 als Eingabe-Encoding eingeführt, und das Uber-JAR via `maven-shade-plugin` gebaut.
## Voraussetzungen
@@ -15,82 +24,146 @@ Zusätzlich werden die **Exit-Codes spec-konform** auf `0/1/2` umgestellt.
## Scope IN
### Bootstrap
- Klasse `de.gecheckt.asv.bootstrap.Main` mit `public static void main(String[] args)`
- verdrahtet manuell:
- Logging-Konfigurator
- CLI-Runner
- (Application-Service — Platzhalter, wird in AP09 feingeschnitten)
- ruft `CliRunner.run(args)` auf, gibt den zurückgegebenen Exit-Code an `System.exit` weiter
### Bootstrap (`de.gecheckt.asv.bootstrap.Main`)
- `public static void main(String[] args)`
- Verdrahtet manuell per Constructor Injection:
- `LoggingConfigurator`
- `CliRunner`
- Application-Service (in M1 noch Dummy-Pfad — Datei lesen, leeren `ValidationReport` zurückgeben)
- Ruft `CliRunner.run(args)` auf und gibt den Exit-Code an `System.exit` weiter
- Log4j2-Typen dürfen **nur** hier und in `adapter.out.logging` sichtbar sein
### CLI-Adapter (`de.gecheckt.asv.adapter.in.cli.CliRunner`)
### CLI-Adapter
- Klasse `CliRunner` im Paket `adapter.in.cli`
- Methode `int run(String[] args)`
- akzeptiert **genau ein Positionsargument**: den Pfad zur Eingabedatei
- bei 0 oder ≥2 Argumenten → Exit-Code `2`, Minimalbericht-Vorbereitung (vollständige Minimalbericht-Logik kommt in AP08)
- bei nicht existierender, nicht lesbarer oder nicht regulärer Eingabedatei → Exit-Code `2`
- bei erfolgreichem Lauf ohne Spec-Fehler → Exit-Code `0`
- bei erfolgreichem Lauf mit Spec-Fehlern → Exit-Code `1`
- Akzeptiert **genau ein Positionsargument**: Pfad zur Eingabedatei
- Bei 0 oder ≥ 2 Argumenten → Exit-Code `2`, kurze deutsche Fehlermeldung auf STDERR (vollständiger Minimalbericht kommt in AP08)
- Bei nicht existierender, nicht lesbarer oder nicht regulärer Eingabedatei → Exit-Code `2`
- Bei erfolgreichem Lauf ohne Spec-Fehler → Exit-Code `0`
- Bei erfolgreichem Lauf mit Spec-Fehlern → Exit-Code `1`
### Exit-Code-Konstanten
- Konstanten **nur noch in einer Klasse** (z.B. `ExitCode` im Paket `adapter.in.cli`)
- Werte:
- `0` = gültig, keine Fehler-Befunde
- `1` = ungültig, mindestens ein Spec-Fehler
- `2` = Bedienfehler
- Die alten Konstanten (`EXIT_CODE_INVALID_ARGUMENTS=1`, `EXIT_CODE_FILE_ERROR=2`, `EXIT_CODE_VALIDATION_ERRORS=3`) werden **gelöscht**
Konstanten **nur noch in einer Klasse** (z.B. `ExitCode` im Paket `adapter.in.cli`):
```java
public final class ExitCode {
public static final int VALID = 0;
public static final int INVALID = 1;
public static final int OPERATIONAL_ERROR = 2;
private ExitCode() {}
}
```
Die alten Konstanten (`EXIT_CODE_INVALID_ARGUMENTS=1`, `EXIT_CODE_FILE_ERROR=2`, `EXIT_CODE_VALIDATION_ERRORS=3`) werden **gelöscht**.
### Verdrahtung mit Befundmodell (AP05)
- `CliRunner` gibt am Ende einen `ValidationReport` aus AP05 weiter oder erzeugt selbst einen Minimal-`ValidationReport` mit einem `Finding` des Kinds `SPEC`, Severity `ERROR`, Layer `ARTIFACT` im Bedienfehlerfall
- das eigentliche Einlesen und Verarbeiten der Datei kann für M1 noch ein **Dummy-Pfad** sein: die Datei wird gelesen, die Bytes gezählt, ein leerer `ValidationReport` mit `fileName` und `timestamp` zurückgegeben. Echte Validierung gehört nicht in M1.
- `CliRunner` nutzt `ValidationReport.computeVerdict()` zur Exit-Code-Ableitung
- Im Bedienfehlerfall: `ValidationReport.operationalError(...)` → Exit-Code `2`
- Der eigentliche M1-Dummy-Pfad: Datei wird gelesen (ISO-8859-15), Bytes gezählt, leerer `ValidationReport` mit `fileName` und `timestamp` zurückgegeben. **Keine echte Validierung in M1.**
### Zeichensatz-Korrektur
- beim Einlesen der Eingabedatei wird **ISO 8859-15** verwendet, nicht UTF-8. Das ist eine harte Spec-Vorgabe aus `fachliche-anforderungen.md` §5.1 und muss ab jetzt dauerhaft so bleiben.
```java
Files.readString(path, StandardCharsets.ISO_8859_1); // nicht ideal — besser Charset.forName("ISO-8859-15")
```
Achtung: Java kennt `StandardCharsets.ISO_8859_1`, aber **nicht** `ISO_8859_15`. Daher `Charset.forName("ISO-8859-15")` verwenden.
Beim Einlesen der Eingabedatei wird **ISO-8859-15** verwendet:
```java
// Korrekt:
Charset iso = Charset.forName("ISO-8859-15");
// NICHT: StandardCharsets.UTF_8
// NICHT: Charset.defaultCharset()
```
JDK-21-Verfügbarkeit per Test belegen: Eine Datei mit Byte `0xA4` ergibt beim Einlesen das Euro-Zeichen `€`, weil `0xA4` in ISO-8859-15 auf Euro-Zeichen liegt.
### Uber-JAR via `maven-shade-plugin`
`maven-jar-plugin`-Platzhalter aus AP02 ersetzen durch `maven-shade-plugin`:
```xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version><!-- aktuell stabil --></version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<transformers>
<transformer implementation=
"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>de.gecheckt.asv.bootstrap.Main</mainClass>
</transformer>
<!-- Log4j2 PluginCache zusammenführen -->
<transformer implementation=
"org.apache.maven.plugins.shade.resource.Log4j2PluginsCacheFileTransformer"/>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
```
`java -jar target/asv-format-validator-*.jar <datei>` muss ohne `-cp` funktionieren.
### `.gitignore` — `logs/` ergänzen
`logs/` zum `.gitignore` hinzufügen (gemäß E-04 aus Entscheidungsprotokoll). Der statische Dateipfad aus AP04 wird nach AP07 durch dynamische Logdatei ersetzt.
## Scope OUT
- Berichtdatei und Log-Datei im Eingabeverzeichnis (AP07)
- vollständiger Minimalbericht bei Exit-Code `2` (AP08)
- Vollständiger Minimalbericht bei Exit-Code `2` (AP08)
- Entkopplung der Altlogik (AP09)
- Architekturtest (AP10)
## Schritte
1. Branch `m1/ap06-bootstrap-cli`
2. `de.gecheckt.asv.bootstrap.Main` anlegen mit `public static void main`
3. `CliRunner` in `adapter.in.cli` anlegen
4. `ExitCode`-Konstantenklasse anlegen
5. `AsvValidatorApplication` schrittweise entkernen: Code wandert nach `CliRunner` und `Main`
6. Einlese-Encoding auf `Charset.forName("ISO-8859-15")` umstellen
7. `maven-jar-plugin` in `pom.xml` auf `de.gecheckt.asv.bootstrap.Main` setzen (Platzhalter aus AP02 konkretisieren)
8. Alle Tests, die auf `AsvValidatorApplication` direkt zeigen, auf `CliRunner` umziehen
9. `mvn clean package` laufen lassen, das erzeugte JAR manuell mit `java -jar target/asv-format-validator-*.jar <test-datei>` prüfen
1. `de.gecheckt.asv.bootstrap.Main` anlegen
2. `CliRunner` in `adapter.in.cli` anlegen
3. `ExitCode`-Konstantenklasse anlegen
4. `AsvValidatorApplication` schrittweise entkernen: Code wandert nach `CliRunner` und `Main`
5. Einlese-Encoding auf `Charset.forName("ISO-8859-15")` umstellen
6. `maven-shade-plugin` in `pom.xml` einbinden, `maven-jar-plugin`-Platzhalter entfernen
7. `logs/` in `.gitignore` ergänzen
8. Alle Tests die auf `AsvValidatorApplication` direkt zeigen auf `CliRunner` umziehen
9. `mvn clean package` erzeugtes JAR mit `java -jar target/asv-format-validator-*.jar <testdatei>` manuell prüfen
10. `mvn clean verify` grün bekommen
11. Commit `M1-AP06: Bootstrap, CLI-Adapter, Exit-Codes 0/1/2, ISO 8859-15`
12. Abschlussbericht schreiben
11. Abschlussbericht schreiben
## Abnahmekriterien
- `de.gecheckt.asv.bootstrap.Main` existiert und ist `Main-Class` des JAR
- `CliRunner` ist der einzige Ort mit CLI-Argument-Parsing
- Exit-Codes `0`, `1`, `2` sind definiert und spec-konform eingesetzt
- **Test:** Aufruf ohne Argument → Exit-Code `2`
- **Test:** Aufruf mit nicht existierender Datei → Exit-Code `2`
- **Test:** Aufruf mit leerer, lesbarer Datei → Exit-Code `0` (Dummy-Pfad, leerer `ValidationReport`)
- Einlese-Encoding ist ISO 8859-15 (per Test belegt: eine Datei mit Byte `0xA4` ergibt beim Einlesen ``, weil `0xA4` in ISO 8859-15 auf Euro-Zeichen liegt)
- ausführbares JAR unter `target/` ist manuell startbar
- `mvn clean verify` ist grün
- Abschlussbericht liegt vor
- [ ] `de.gecheckt.asv.bootstrap.Main` existiert und ist `Main-Class` des Uber-JAR
- [ ] `CliRunner` ist der einzige Ort mit CLI-Argument-Parsing
- [ ] Exit-Codes `0`, `1`, `2` sind definiert und spec-konform eingesetzt, kein Exit-Code `3` mehr erreichbar
- [ ] Test: Aufruf ohne Argument → Exit-Code `2`
- [ ] Test: Aufruf mit nicht existierender Datei → Exit-Code `2`
- [ ] Test: Aufruf mit leerer, lesbarer Datei → Exit-Code `0`
- [ ] Einlese-Encoding ist ISO-8859-15 (per Test belegt: Byte `0xA4``€`)
- [ ] `java -jar target/asv-format-validator-*.jar <datei>` startet ohne `-cp`
- [ ] `logs/` in `.gitignore`
- [ ] Keine Log4j2-Typen außerhalb von `bootstrap` und `adapter.out.logging`
- [ ] `mvn clean verify` grün
- [ ] Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP06-bericht.md`
## Rest-Risiken und offene Punkte
- Der Dummy-Pfad (Datei wird gelesen, leerer Report zurückgegeben) ist bewusst dünn. Die Einbindung der alten Parser-Logik passiert in AP09.
- Es ist verlockend, schon hier in AP06 die bestehende Parser-/Validator-Kette mit dem neuen Modell zu verknüpfen. **Nicht tun.** AP06 soll nur die äußere Hülle geradeziehen.
- Der Dummy-Pfad (Datei lesen, leerer Report) ist bewusst dünn. Echte Parser-/Validator-Einbindung kommt in M3+.
- Nicht versuchen, in AP06 schon die alte Parser-/Validator-Kette mit dem neuen Modell zu verknüpfen — das ist AP09-Scope.
- `maven-shade-plugin` mit Log4j2 benötigt den `Log4j2PluginsCacheFileTransformer`, sonst werden Log4j2-Plugins nicht korrekt geladen.
## Bericht
`docs/arbeitspakete/m1/berichte/AP06-bericht.md` nach `templates/ap-bericht.md`.
`docs/arbeitspakete/m1/berichte/AP06-bericht.md` nach `docs/arbeitspakete/m1/templates/ap-bericht.md`.
+82 -46
View File
@@ -1,12 +1,21 @@
---
model: sonnet
---
# AP07 Ausgabeartefakte: Berichtdatei und Log-Datei mit Suffix-Logik
> **Meilenstein:** M1
> **Vorgänger:** AP04, AP05, AP06 ✅ erforderlich
> **Nachfolger:** AP08, AP10
> **Grundlage:** `docs/specs/technik-und-architektur.md` v5, §§ „Ausgabeartefakte", „Zeichensätze", „Logging und Berichtserzeugung"
> **Entscheidungsprotokoll:** `docs/arbeitspakete/m1/E00-entscheidungsprotokoll.md` (E-04 logs/-Verzeichnis)
## Ziel
Pro Lauf werden **zwei Ausgabedateien** im **Verzeichnis der Eingabedatei** erzeugt:
- eine **Berichtdatei** `<basename>.txt`
- eine **Log-Datei** `<basename>.log`
Beide in **UTF-8**. Zusätzlich wird der Bericht weiterhin in die **Konsole** geschrieben. Wenn bereits gleichnamige Dateien existieren, werden neue mit laufendem Suffix `_v1`, `_v2`, … erzeugt, **pro Eingabedatei-Basisname**.
Beide in **UTF-8**. Der Bericht wird zusätzlich in die **Konsole** geschrieben. Bei bereits vorhandenen Dateien gleichen Namens werden neue mit laufendem Suffix `_v1`, `_v2`, … erzeugt.
## Voraussetzungen
@@ -14,69 +23,96 @@ Beide in **UTF-8**. Zusätzlich wird der Bericht weiterhin in die **Konsole** ge
## Scope IN
### Berichtdatei
- Klasse `ReportFileWriter` oder ähnlich im Paket `adapter.out.reporting`
- Eingabe: `ValidationReport` (aus AP05) und Eingabedatei-Pfad
- Ausgabe: eine UTF-8-Textdatei im **selben Verzeichnis** wie die Eingabedatei
- Dateiname: `<basename-der-eingabedatei>.txt`, bei Konflikt `<basename>_v1.txt`, `<basename>_v2.txt`, …
- Inhalt für M1: **einfach gehalten**. Pro `Finding` eine Zeile mit den wichtigsten Metadaten (Severity, Kind, Layer, Feld-ID, deutsche Nachricht). Kopfzeile mit Dateiname, Zeitstempel, Verdict. Die fein strukturierte hierarchische Darstellung kommt erst in M9.
### `SuffixResolver` im Paket `adapter.out.filesystem`
### Log-Datei
- Wiederverwendung des `LoggingConfigurator` aus AP04
- Methode `configureLogFile(Path logFile)` wird im Bootstrap **vor** dem CLI-Runner aufgerufen
- Log-Datei liegt im **selben Verzeichnis** wie die Eingabedatei
- Dateiname: `<basename>.log`, Suffix-Logik analog zur Berichtdatei
- Log4j2 wird programmatisch umkonfiguriert: der File-Appender schreibt nach dem neuen Pfad. Die statische `log4j2.xml` aus AP04 ist nur der Fallback für „kein Eingabeargument".
```java
public class SuffixResolver {
/**
* Ermittelt den ersten freien Dateipfad für den gegebenen Basisnamen
* und die gegebene Extension im Zielverzeichnis.
* Probiert: <baseName>.<ext>, dann <baseName>_v1.<ext>, <baseName>_v2.<ext>, ...
*/
public Path resolveNextFreePath(Path directory, String baseName, String extension) { ... }
}
```
### Suffix-Logik
- eigene kleine Utility-Klasse `SuffixResolver` im Paket `adapter.out.filesystem`
- Methode `Path resolveNextFreePath(Path baseDirectory, String baseName, String extension)`:
- probiert `<baseName>.<ext>`, dann `<baseName>_v1.<ext>`, `<baseName>_v2.<ext>`, …
- gibt den ersten freien Pfad zurück
- wird sowohl für die Berichtdatei als auch für die Log-Datei verwendet
- **Hinweis:** Die Zählung ist pro Basisname unabhängig. Wenn für `test.auf.txt` schon `test.auf_v1.txt` existiert, aber für `test.auf.log` noch keine `_v1`, kann das vorkommen — die Suffixe müssen **nicht synchron** sein.
- Suffix-Zählung ist **pro Extension unabhängig**`.txt` und `.log` haben getrennte Zähler
- Unit-Tests mindestens für: keine Datei vorhanden, `.txt` vorhanden, `.txt` + `_v1` vorhanden
### `ReportFileWriter` im Paket `adapter.out.reporting`
- Eingabe: `ValidationReport` (AP05) + Eingabedatei-Pfad
- Ausgabe: UTF-8-Textdatei im Verzeichnis der Eingabedatei
- Dateiname via `SuffixResolver`
- **Berichtinhalt für M1** (absichtlich minimal, wird in M9 ausgebaut):
- Kopfzeile: Zeitstempel, Eingabedatei, Verdict
- Pro `Finding`: eine Zeile mit Severity, Kind, Layer, Feld-ID, deutscher Meldung
- Fußzeile: Hinweis auf bewusst nicht geprüfte Bereiche
Alle Texte auf **Deutsch**, Encoding **UTF-8** explizit — kein Plattform-Default.
### `LoggingConfigurator.configureLogFile(Path)` in `adapter.out.logging`
- Methode wird im Bootstrap **vor** dem ersten fachlichen Log-Aufruf aufgerufen
- Konfiguriert Log4j2-File-Appender programmatisch auf den gewünschten Pfad
- Dateiname via `SuffixResolver` (analog zur Berichtdatei, eigene Zählung)
- Log4j2-Typen (`LoggerContext`, `Appender` etc.) bleiben **ausschließlich** in `adapter.out.logging` und `bootstrap`
- Statischer `logs/`-Pfad aus `log4j2.xml` (AP04) wird entfernt oder auf Fallback-Default gesetzt, der nur greift wenn `configureLogFile` nicht aufgerufen wurde (z.B. für Testläufe)
- **Fallback:** Falls programmatische Log4j2-Umkonfiguration sich als instabil erweist, ist eine System-Property-basierte Konfiguration (`-Dasv.log.file=...`) ein zulässiger Ausweg — Entscheidung im Bericht dokumentieren
### Integration in `bootstrap.Main`
Reihenfolge vor dem Validierungslauf:
1. Eingabedatei-Pfad bestimmen
2. Basisnamen und Zielverzeichnis ableiten
3. `SuffixResolver` für `.log` aufrufen
4. `LoggingConfigurator.configureLogFile(logPath)` aufrufen → ab jetzt gehen Logs in die Datei
5. Validierungslauf starten
6. `ReportFileWriter` schreiben
7. Konsolenausgabe (identisch zum Berichtinhalt)
### Konsolenausgabe
- bleibt erhalten, schreibt denselben Bericht-Text wie die Berichtdatei
- Konsolenausgabe erfolgt **nach** der Berichtdatei-Erstellung, damit ein IO-Fehler beim Schreiben der Berichtdatei nicht die Konsolenausgabe verhindert
- Schreibt denselben Text wie die Berichtdatei
- Erfolgt **nach** der Berichtdatei-Erstellung, damit ein IO-Fehler beim Schreiben die Konsolenausgabe nicht verhindert
## Scope OUT
- hierarchische Berichtsgliederung (M9)
- Einfärbung / ANSI-Codes in der Konsole
- Hierarchische Berichtsgliederung (M9)
- ANSI-Farben / Einfärbung in der Konsole
- Log-Rotation
- Minimalbericht bei Exit-Code 2 (AP08)
- Minimalbericht bei Exit-Code `2` (AP08)
## Schritte
1. Branch `m1/ap07-ausgabeartefakte`
2. `SuffixResolver` implementieren inkl. Unit-Tests für: keine Datei vorhanden, `.txt` vorhanden, `.txt` + `_v1` vorhanden, mehrere Lücken
3. `ReportFileWriter` implementieren mit einfachem Zeilenformat für M1
4. `LoggingConfigurator.configureLogFile(Path)` implementieren (programmatische Log4j2-Reconfiguration)
5. Bootstrap erweitern: vor CLI-Lauf → Log-Datei-Pfad bestimmen → `LoggingConfigurator` aufrufen
6. CLI-Runner erweitert: nach Lauf → Berichtdatei schreiben → Konsolenausgabe erzeugen
7. End-to-End-Test mit Dummy-Eingabedatei: beide Ausgabedateien entstehen, Suffix-Logik funktioniert
8. `mvn clean verify` grün
9. Commit `M1-AP07: Berichtdatei und Log-Datei im Eingabeverzeichnis mit Suffix-Logik`
10. Abschlussbericht schreiben
1. `SuffixResolver` implementieren inkl. Unit-Tests
2. `ReportFileWriter` implementieren mit einfachem Zeilenformat für M1
3. `LoggingConfigurator.configureLogFile(Path)` implementieren
4. Bootstrap erweitern: Log-Datei-Pfad bestimmen → `LoggingConfigurator` aufrufen
5. `CliRunner` erweitern: nach Lauf → Berichtdatei schreiben → Konsolenausgabe
6. End-to-End-Test: beide Ausgabedateien entstehen, Suffix-Logik funktioniert, UTF-8
7. `mvn clean verify` grün bekommen
8. Abschlussbericht schreiben
## Abnahmekriterien
- nach einem Lauf mit Eingabedatei `foo/bar.auf` existieren `foo/bar.auf.txt` und `foo/bar.auf.log`
- zweiter Lauf mit derselben Eingabedatei erzeugt `foo/bar.auf_v1.txt` und `foo/bar.auf_v1.log`
- dritter Lauf → `_v2` usw.
- beide Ausgabedateien sind UTF-8
- Konsolenausgabe ist identisch zum Inhalt der Berichtdatei
- `SuffixResolver` hat mindestens vier Unit-Tests
- `mvn clean verify` ist grün
- Abschlussbericht liegt vor
- [ ] Nach Lauf mit `foo/bar.auf` entstehen `foo/bar.auf.txt` und `foo/bar.auf.log`
- [ ] Zweiter Lauf mit derselben Datei → `foo/bar.auf_v1.txt` und `foo/bar.auf_v1.log`
- [ ] Dritter Lauf → `_v2` usw.
- [ ] Beide Ausgabedateien sind UTF-8
- [ ] Konsolenausgabe ist identisch zum Inhalt der Berichtdatei
- [ ] `SuffixResolver` hat mindestens drei Unit-Tests
- [ ] Log4j2-Typen sind außerhalb von `adapter.out.logging` und `bootstrap` nicht sichtbar
- [ ] Statischer `logs/`-Pfad aus `log4j2.xml` entfernt oder auf Fallback-Default gesetzt
- [ ] `mvn clean verify` grün
- [ ] Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP07-bericht.md`
## Rest-Risiken und offene Punkte
- **Race Conditions** bei gleichzeitigen Läufen auf derselben Eingabedatei: laut `technik-und-architektur.md` bewusst nicht behandelt (kein Mehrbenutzerbetrieb in V1).
- Die programmatische Log4j2-Reconfiguration ist technisch nicht ganz ohne. Falls sie sich als zu instabil erweist, ist eine **sys-property-basierte** Konfiguration der Log-Datei (`-Dasv.log.file=...`) ein zulässiger Fallback. Entscheidung im Bericht dokumentieren.
- Race Conditions bei gleichzeitigen Läufen auf derselben Eingabedatei: laut `technik-und-architektur.md` bewusst nicht behandelt (kein Mehrbenutzerbetrieb in V1).
- Das Bericht-Dateiformat ist in M1 absichtlich primitiv. In M9 wird es durch die finale hierarchische Struktur ersetzt.
- Fallback bei instabiler programmatischer Log4j2-Umkonfiguration im Bericht dokumentieren.
## Bericht
`docs/arbeitspakete/m1/berichte/AP07-bericht.md` nach `templates/ap-bericht.md`.
`docs/arbeitspakete/m1/berichte/AP07-bericht.md` nach `docs/arbeitspakete/m1/templates/ap-bericht.md`.
+50 -44
View File
@@ -1,8 +1,16 @@
---
model: sonnet
---
# AP08 Minimalbericht bei Bedienfehlern (Exit-Code 2)
> **Meilenstein:** M1
> **Vorgänger:** AP06, AP07 ✅ erforderlich
> **Nachfolger:** AP10, AP11
> **Grundlage:** `docs/specs/technik-und-architektur.md` v5, §§ „Gültigkeitsentscheidung und Exit-Codes", „Laufzeit- und Betriebsmodell"
## Ziel
Auch bei **Bedien- oder Zugriffsfehlern** (Exit-Code `2`) soll ein **Minimalbericht** entstehen, der den Fehler nachvollziehbar beschreibt. Das verlangt `technik-und-architektur.md` ausdrücklich: „Auch bei Exit-Code 2 soll, soweit technisch möglich, ein Minimalbericht erzeugt werden, der den Bedien- oder Zugriffsfehler nachvollziehbar beschreibt."
Auch bei **Bedien- oder Zugriffsfehlern** (Exit-Code `2`) entsteht ein **Minimalbericht**, der den Fehler nachvollziehbar beschreibt. `technik-und-architektur.md` verlangt das ausdrücklich: „Auch bei Exit-Code 2 soll, soweit technisch möglich, ein Minimalbericht erzeugt werden."
## Voraussetzungen
@@ -10,71 +18,69 @@ Auch bei **Bedien- oder Zugriffsfehlern** (Exit-Code `2`) soll ein **Minimalberi
## Scope IN
### Bedienfehler-Fälle
Alle diese Fälle müssen in Exit-Code `2` mit Minimalbericht resultieren:
### Bedienfehler-Fälle (alle müssen Exit-Code `2` + Minimalbericht ergeben)
1. **Kein Argument übergeben** → Minimalbericht auf Konsole (Eingabeverzeichnis unbekannt, also keine Dateiausgabe möglich)
2. **Mehr als ein Argument**Minimalbericht auf Konsole
3. **Eingabedatei existiert nicht**Minimalbericht auf Konsole und falls möglich in das übergeordnete Verzeichnis (dort wo die Datei hätte liegen sollen), sonst nur Konsole
4. **Eingabepfad ist kein regulärer Dateityp** (z.B. Verzeichnis) → Minimalbericht auf Konsole, keine Dateiausgabe
5. **Eingabedatei ist nicht lesbar** (Permissions) → Minimalbericht auf Konsole, Dateiausgabe wird versucht wenn Zielverzeichnis schreibbar ist, sonst nur Konsole
1. **Kein Argument** → nur Konsolenausgabe (Eingabeverzeichnis unbekannt)
2. **Mehr als ein Argument**nur Konsolenausgabe
3. **Eingabedatei existiert nicht**Konsolenausgabe + Berichtdatei im übergeordneten Verzeichnis, sofern dieses schreibbar ist
4. **Eingabepfad ist kein regulärer Dateityp** (z.B. Verzeichnis) → nur Konsolenausgabe
5. **Eingabedatei ist nicht lesbar** (Berechtigungen) → Konsolenausgabe + Berichtdatei sofern Zielverzeichnis schreibbar
### Minimalbericht-Inhalt
Der Minimalbericht ist ein **`ValidationReport`** (aus AP05) mit:
- `fileName` = übergebener Pfad (oder Platzhalter `<kein Argument>` bzw. `<mehrere Argumente>`)
Ein `ValidationReport` (AP05) via `ValidationReport.operationalError(...)` mit:
- `fileName` = übergebener Pfad (oder `<kein Argument>` / `<mehrere Argumente>`)
- `timestamp` = jetzt
- genau ein `Finding`:
- `kind = SPEC`
- Genau ein `Finding`:
- `kind = SPEC` → Verdict wird `OPERATIONAL_ERROR`
- `severity = ERROR`
- `layer = ARTIFACT`
- `ruleId = "OPERATIONAL-<fallkennung>"` (z.B. `OPERATIONAL-MISSING-ARG`, `OPERATIONAL-FILE-NOT-FOUND`, `OPERATIONAL-NOT-READABLE`, `OPERATIONAL-NOT-REGULAR`, `OPERATIONAL-TOO-MANY-ARGS`)
- `germanMessage` = kurzer, verständlicher deutscher Text
- **wichtig:** das Verdict dieses Reports ist **nicht** `INVALID`, sondern `OPERATIONAL_ERROR`. Die `Verdict`-Ableitungslogik muss in AP05 bereits den Fall „nur OPERATIONAL-Findings" erkennen können — falls das in AP05 noch nicht vorgesehen wurde, muss `ValidationReport` hier minimal erweitert werden.
- Alternative, sauberere Modellierung: ein zusätzlicher Konstruktor oder Factory-Methode `ValidationReport.operationalError(String fileName, String ruleId, String message)`, der den Verdict-Status explizit auf `OPERATIONAL_ERROR` setzt.
- `ruleId` = z.B. `OPERATIONAL-MISSING-ARG`, `OPERATIONAL-FILE-NOT-FOUND`, `OPERATIONAL-NOT-READABLE`, `OPERATIONAL-NOT-REGULAR`, `OPERATIONAL-TOO-MANY-ARGS`
- `germanMessage` = kurzer verständlicher deutscher Text
### Dateiausgabe bei Exit-Code 2
- wenn das Zielverzeichnis ermittelbar und schreibbar ist: Berichtdatei wird gemäß AP07-Logik erzeugt
- wenn nicht: **nur Konsolenausgabe**, keine Fehlermeldung („Bericht konnte nicht geschrieben werden"), weil das den Benutzer doppelt verunsichert
- eine kurze Hinweiszeile auf der Konsole ist okay: „Bericht konnte nicht in das Verzeichnis geschrieben werden, siehe Konsolenausgabe oben."
### Wichtige Regeln
### Logging
- der Minimalbericht wird zusätzlich **geloggt** (`logger.error(...)`) — damit in der Log-Datei (sofern erzeugt) dokumentiert ist, was schiefging
- bei Fall 1 und 2 (keine Dateipfadinformation) ist die Log-Datei nicht sinnvoll zu platzieren → Fallback auf `log4j2.xml`-Default aus AP04
- **Kein Stack-Trace für den Nutzer** — technische Details gehören ins Log, nicht in den Bericht
- Wenn Zielverzeichnis nicht schreibbar: **nur Konsolenausgabe**, kein Fehler-auf-Fehler
- Eine kurze Hinweiszeile auf Konsole ist okay: „Bericht konnte nicht in das Verzeichnis geschrieben werden."
- Der Bedienfehler wird zusätzlich geloggt (`logger.error(...)`)
### Tests
- Unit-Test für alle fünf Fälle: Exit-Code `2` + korrekter `ruleId`-Wert
- Negativ-Test: kein Stack-Trace in der Ausgabe
- Test: Fall 3 (Datei nicht vorhanden) → Berichtdatei im übergeordneten Verzeichnis, wenn schreibbar
## Scope OUT
- Unterscheidung zwischen verschiedenen IO-Exceptions im Detail (`FileSystemException`, `AccessDeniedException`, …) — ein einheitlicher Fall „nicht lesbar" reicht
- Unterscheidung feingranularer IO-Exceptions (`AccessDeniedException`, `FileSystemException` etc.) — ein einheitlicher Fall „nicht lesbar" reicht
- Internationalisierung
- Exit-Codes jenseits von `0/1/2`
- Behandlung von `OutOfMemoryError`, `StackOverflowError` etc.
## Schritte
1. Branch `m1/ap08-minimalbericht`
2. Factory-Methode `ValidationReport.operationalError(...)` in AP05-Modell ergänzen (falls noch nicht vorhanden)
3. `CliRunner` um die fünf Bedienfehler-Fälle erweitern; pro Fall wird der passende Minimalbericht erzeugt
4. `ReportFileWriter`: im OPERATIONAL-Fall weichere IO-Fehlerbehandlung (keine `RuntimeException`, stattdessen Konsolenhinweis)
5. Unit-Tests für alle fünf Fälle
6. End-to-End-Test: `java -jar ... /pfad/zu/nichtvorhandener/datei.auf` erzeugt auf Konsole einen Minimalbericht und Exit-Code `2`
7. `mvn clean verify` grün
8. Commit `M1-AP08: Minimalbericht bei Exit-Code 2`
9. Abschlussbericht schreiben
1. `ValidationReport.operationalError(...)` prüfen — falls noch nicht vollständig in AP05 implementiert, hier ergänzen
2. `CliRunner` um alle fünf Bedienfehler-Fälle erweitern
3. `ReportFileWriter`: im `OPERATIONAL_ERROR`-Fall weichere IO-Fehlerbehandlung (kein `RuntimeException`, stattdessen Konsolenhinweis)
4. Unit-Tests für alle fünf Fälle
5. `mvn clean verify` grün bekommen
6. Abschlussbericht schreiben
## Abnahmekriterien
- alle fünf Bedienfehler-Fälle erzeugen einen Minimalbericht (per Unit-Test belegt)
- Exit-Code in allen fünf Fällen ist `2`
- Im Fall „Eingabedatei existiert nicht" wird der Minimalbericht in das übergeordnete Verzeichnis geschrieben, sofern dieses schreibbar ist
- Im Fall „kein Argument" wird der Minimalbericht **nur** auf Konsole ausgegeben (keine Dateiausgabe)
- `Verdict.OPERATIONAL_ERROR` ist in mindestens einem Test verifiziert
- `mvn clean verify` ist grün
- Abschlussbericht liegt vor
- [ ] Alle fünf Bedienfehler-Fälle erzeugen Exit-Code `2` (per Unit-Test belegt)
- [ ] Fall „kein Argument" → **nur** Konsolenausgabe, keine Dateiausgabe
- [ ] Fall „Datei nicht vorhanden" → Berichtdatei im übergeordneten Verzeichnis, sofern schreibbar
- [ ] `Verdict.OPERATIONAL_ERROR` ist in mindestens einem Test verifiziert
- [ ] Kein Stack-Trace in STDERR (Negativ-Test vorhanden)
- [ ] `mvn clean verify` grün
- [ ] Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP08-bericht.md`
## Rest-Risiken und offene Punkte
- Im Fall „Eingabedatei existiert nicht, Zielverzeichnis aber schon" ist der Bericht-Basisname der **angegebene** Dateiname (obwohl die Datei nicht existiert). Das ist okay — der Benutzer findet den Bericht dort, wo er die Datei erwartet hätte.
- Die Unterscheidung zwischen `OPERATIONAL_ERROR` und `INVALID` im Verdict ist wichtig für spätere Reporting-Logik. Falls sich herausstellt, dass `OPERATIONAL_ERROR` als separater Verdict-Wert zu Komplikationen führt, kann alternativ ein Boolean-Flag `isOperational` auf dem Report verwendet werden. Entscheidung im Bericht dokumentieren.
- Im Fall „Datei nicht vorhanden, Zielverzeichnis aber existiert" ist der Basisname der **angegebene** Dateiname — der Nutzer findet den Bericht dort, wo er die Datei erwartet hätte.
- Falls `Verdict.OPERATIONAL_ERROR` als separater Wert zu Komplikationen führt: Boolean-Flag `isOperational` auf dem Report ist zulässiger Ausweg — Entscheidung im Bericht dokumentieren.
## Bericht
`docs/arbeitspakete/m1/berichte/AP08-bericht.md` nach `templates/ap-bericht.md`.
`docs/arbeitspakete/m1/berichte/AP08-bericht.md` nach `docs/arbeitspakete/m1/templates/ap-bericht.md`.
@@ -1,86 +1,121 @@
# AP09 Altlogik aus M1 entkoppeln (Parser/Validator einfrieren)
---
model: sonnet
---
# AP09 Altlogik einfrieren (Preview-Code deaktivieren)
> **Meilenstein:** M1
> **Vorgänger:** AP03, AP05, AP06 ✅ erforderlich
> **Nachfolger:** AP10, AP11
> **Grundlage:** AP00-ist-analyse.md §§ 7, 8
> **Entscheidungsprotokoll:** `docs/arbeitspakete/m1/E00-entscheidungsprotokoll.md` (E-01 Option b, E-03 leere Testklasse)
## Ziel
Die **bereits vorhandene Parser- und Validator-Logik** aus der früheren Implementierung (vor dieser M1-Planung) wird **nicht gelöscht**, aber sauber **entkoppelt** vom aktiven M1-Lauf. Sie wird als „Vorbau für M3 und folgende" explizit markiert und ist während M1 **nicht** Bestandteil der aktiven Verarbeitungskette.
Die bestehende Preview-Parser- und Validator-Logik (`DefaultStructureValidator`, `DefaultFieldValidator`, `DefaultInputFileValidator`) wird **nicht gelöscht und nicht verschoben**, sondern im Bootstrap **nicht mehr verdrahtet**. Ein M1-Lauf erzeugt keine fachlichen ASVREC-/ASVFEH-Befunde mehr. Die Klassen bleiben physisch an ihrem Ort als M3-Vorbau.
Hintergrund: Der ursprüngliche Stand im Repository enthält bereits `DefaultInputFileParser`, `DefaultSegmentLineTokenizer`, `DefaultStructureValidator`, `DefaultFieldValidator`, `DefaultInputFileValidator` und `validation.model.ValidationResult`. Das ist wertvoll und darf nicht verloren gehen — gehört aber fachlich in M3 (Parser), M5 (Feldregeln) und M6 (Beziehungen), nicht in M1.
## Hintergrund und Entscheidung
Laut AP00-Ist-Analyse läuft `DefaultStructureValidator` (19 ASVREC/ASVFEH-Regeln) aktiv im produktiven Lauf mit — was dem M1-Ziel „noch keine ASV-Fachvalidierung" widerspricht.
**Entscheidung E-01: Option (b)** — Klassen bleiben in ihren Paketen, werden aber im Bootstrap nicht mehr verdrahtet. Für M3 kann die Verdrahtung direkt wieder aktiviert werden.
Kein Paketumzug, keine Umbenennung, kein `@Deprecated`.
## Voraussetzungen
- AP03 (Migration), AP05 (neues Befundmodell), AP06 (neuer Bootstrap/CLI)
- AP03 (Paketstruktur)
- AP05 (neues Befundmodell)
- AP06 (neuer Bootstrap/CLI)
## Scope IN
### Einfrieren statt Löschen
- Die bestehenden Klassen bleiben **vollständig erhalten**, inklusive Tests
- Sie werden in ein klar erkennbares Unterpaket verschoben, z.B.:
```
de.gecheckt.asv.legacy.parser
de.gecheckt.asv.legacy.validation
de.gecheckt.asv.legacy.model
```
oder alternativ:
```
de.gecheckt.asv.application.preview
```
Die Entscheidung zwischen `legacy` und `preview` wird im Bericht dokumentiert und begründet. Empfehlung: **`preview`**, weil „legacy" suggeriert, dass etwas alt und zu entsorgen ist — tatsächlich wird der Code in M3/M5/M6 weiterverwendet.
- Jedes Paket bekommt ein `package-info.java` mit deutlichem Hinweis:
```
Diese Klassen stammen aus einer früheren Implementierung und sind
für die Meilensteine M3 bis M6 vorgesehen. Sie sind in M1 nicht Teil
der aktiven Validierungskette. Änderungen an diesen Klassen während
M1 sind zu vermeiden.
```
### 1. Bootstrap-Verdrahtung anpassen
### Entkopplung vom Lauf
- `CliRunner` und `Bootstrap` dürfen die Preview-Klassen **nicht** aufrufen
- der aktive M1-Lauf verwendet ausschließlich den Dummy-Pfad aus AP06 (Datei einlesen, leeren `ValidationReport` erzeugen)
- die alten Tests der Preview-Klassen laufen **weiterhin grün mit**, damit der Code nicht verrottet
- `validation.model.ValidationResult` (alt) bleibt im Preview-Paket und wird **nicht** mit dem neuen `ValidationReport` aus AP05 verwechselt
In `bootstrap.Main`: `DefaultInputFileValidator` erhält statt `DefaultStructureValidator` und `DefaultFieldValidator` jeweils eine **Null-Implementation** — eine leere Implementierung der jeweiligen Interfaces, die keine Befunde produziert.
### Saubere Kennzeichnung
- In `README.md` des Repos (falls vorhanden, sonst anlegen) ein kurzer Abschnitt „Preview-Code" mit Verweis auf `docs/arbeitspakete/m1/AP09-altlogik-einfrieren.md`
- Kein `@Deprecated`! Deprecated würde bedeuten „wird entfernt" — das Gegenteil ist der Fall.
Die Null-Implementierungen können als benannte Klassen in `bootstrap` oder `application` angelegt werden:
```java
/** M1-Platzhalter. Ab M3 durch DefaultStructureValidator ersetzen. */
public final class NoOpStructureValidator implements StructureValidator {
@Override
public List<Finding> validate(ValidationContext ctx) {
return List.of(); // bewusst leer in M1
}
}
```
Analog für `NoOpFieldValidator`.
### 2. Einfriermarker als JavaDoc-Kommentar
`DefaultStructureValidator` und `DefaultFieldValidator` erhalten folgenden JavaDoc-Kommentar — keine andere Änderung:
```java
/**
* M3-Vorbau. In M1 bewusst nicht im produktiven Lauf verdrahtet.
* Wird ab M3 wieder aktiviert und gegen die finalen Regelklassifikationen
* (V1-V/T/N/K) aus fachliche-anforderungen.md bewertet.
*
* @see docs/arbeitspakete/m1/E00-entscheidungsprotokoll.md E-01
*/
```
### 3. Abnahmetest
Ein Integrationstest prüft, dass ein Lauf mit einer beliebigen Testdatei **keine** fachlichen Findings mit Bezug auf ASVREC-/ASVFEH-Segmentregeln erzeugt.
### 4. Aufräumen
- `DefaultStructureValidatorTestAdditional` (leere Testklasse ohne `@Test`-Methoden) löschen (gemäß E-03)
- Sicherstellen dass `logs/` in `.gitignore` steht (falls AP06 das noch nicht erledigt hat)
- Aktive Tests von `DefaultStructureValidator` und `DefaultFieldValidator` bleiben **erhalten und grün** — sie testen den M3-Vorbau
### 5. Grep-Nachweis im Bericht
```bash
grep -rn "DefaultStructureValidator\|DefaultFieldValidator" \
src/main/java/de/gecheckt/asv/adapter \
src/main/java/de/gecheckt/asv/bootstrap
```
Muss **leer** sein — der aktive Code darf diese Klassen nicht mehr referenzieren.
## Scope OUT
- Weiterentwicklung der Preview-Klassen
- Änderung der Preview-Tests (außer notwendige Import-Anpassungen durch den Package-Umzug)
- Integration der Preview-Klassen in die neue `domain.finding`-Struktur (das ist explizit M3+)
- Löschung von Preview-Klassen, auch wenn sie wie Duplikate wirken
- Paketumzug der Preview-Klassen (explizit **nicht** — Entscheidung E-01 Option b)
- Inhaltliche Änderung an `DefaultStructureValidator` oder `DefaultFieldValidator`
- Fachliche Neubewertung der 19 Preview-Regeln (das ist M3)
- Löschen von Preview-Klassen
## Schritte
1. Branch `m1/ap09-preview-einfrieren`
2. Zielpaket wählen (`preview` empfohlen) und im Bericht begründen
3. Alle Parser-Klassen verschieben
4. Alle Validator-Klassen verschieben
5. `validation.model.ValidationResult` und `validation.model.*` mit verschieben
6. Tests entsprechend verschieben; Imports anpassen
7. `CliRunner`/`Bootstrap` auf Preview-Imports prüfen — **darf keine haben**, sonst entkoppeln
8. `package-info.java` mit Warnhinweis in jedem Preview-Unterpaket anlegen
9. README-Abschnitt „Preview-Code" ergänzen
10. `mvn clean verify` grün bekommen (alle Tests der Preview-Klassen laufen weiter mit)
11. Commit `M1-AP09: Alt-Parser und Alt-Validator nach preview-Paket, vom M1-Lauf entkoppelt`
12. Abschlussbericht schreiben
1. `NoOpStructureValidator` und `NoOpFieldValidator` anlegen
2. `bootstrap.Main` umverdrahten: Preview-Validatoren durch NoOp-Implementierungen ersetzen
3. JavaDoc-Einfriermarker in `DefaultStructureValidator` und `DefaultFieldValidator` ergänzen
4. `DefaultStructureValidatorTestAdditional` löschen
5. Grep-Nachweis ausführen und im Bericht dokumentieren
6. Integrationstest: Lauf erzeugt keine ASVREC-/ASVFEH-Segmentbefunde
7. `mvn clean verify` grün — alle bisherigen Tests der Preview-Klassen müssen weiterhin grün sein
8. Abschlussbericht schreiben
## Abnahmekriterien
- alle ursprünglich vorhandenen Parser- und Validator-Klassen liegen im Preview-Paket
- alle zugehörigen Tests laufen weiterhin grün
- `grep -rn "de.gecheckt.asv.preview" src/main/java/de/gecheckt/asv/adapter src/main/java/de/gecheckt/asv/bootstrap src/main/java/de/gecheckt/asv/application` ist **leer** (keine Referenzen aus dem aktiven Code)
- `package-info.java` mit Warnhinweis in jedem Preview-Unterpaket
- README enthält Abschnitt „Preview-Code"
- keine Klasse wurde gelöscht (`git log --diff-filter=D` für diesen Commit zeigt nur Verschiebungen)
- `mvn clean verify` ist grün
- Abschlussbericht liegt vor
- [ ] `NoOpStructureValidator` und `NoOpFieldValidator` existieren
- [ ] `bootstrap.Main` verdrahtet keine Preview-Validatoren mehr
- [ ] Grep auf `DefaultStructureValidator`/`DefaultFieldValidator` in `adapter` und `bootstrap` ist leer (Nachweis im Bericht)
- [ ] Einfriermarker-JavaDoc in beiden Preview-Klassen vorhanden
- [ ] `DefaultStructureValidatorTestAdditional` ist gelöscht
- [ ] Bestehende Tests der Preview-Klassen laufen weiterhin grün
- [ ] Integrationstest: Lauf mit Testdatei erzeugt keine ASVREC-/ASVFEH-Segmentbefunde
- [ ] `mvn clean verify` grün
- [ ] Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP09-bericht.md`
## Rest-Risiken und offene Punkte
- Bei Wiederaufnahme in M3 wird zu klären sein, wie der Preview-Code an das neue Befundmodell angebunden wird. Das ist explizit M3-Aufgabe, nicht M1.
- Falls die Preview-Tests beim Package-Umzug brechen (wegen relativer Ressourcenpfade o.ä.), müssen sie einmalig angepasst werden. Das ist kein Scope-Verstoß, sondern Teil des Umzugs.
- Bei Wiederaufnahme in M3: jede der 19 Preview-Regeln ist neu gegen V1-V/T/N/K-Klassifikation zu bewerten. Explizit M3-Aufgabe.
- Falls Preview-Tests beim Einfrieren brechen (z.B. wegen Interface-Änderungen durch AP05): einmalige Anpassung der Testimports ist kein Scope-Verstoß, sondern Teil der Konsolidierung.
## Bericht
`docs/arbeitspakete/m1/berichte/AP09-bericht.md` nach `templates/ap-bericht.md`.
`docs/arbeitspakete/m1/berichte/AP09-bericht.md` nach `docs/arbeitspakete/m1/templates/ap-bericht.md`.
+85 -41
View File
@@ -1,26 +1,42 @@
---
model: sonnet
---
# AP10 Architekturtest
> **Meilenstein:** M1
> **Vorgänger:** AP04, AP09 ✅ erforderlich (alle AP05AP09 sollten abgeschlossen sein)
> **Nachfolger:** AP11
> **Grundlage:** `docs/specs/technik-und-architektur.md` v5, §§ „Architekturprinzipien", „Test- und Qualitätsanforderungen"
> **Entscheidungsprotokoll:** `docs/arbeitspakete/m1/E00-entscheidungsprotokoll.md` (E-02 Test-Log, E-03 leere Testklasse)
## Ziel
Ein **automatisierter Architekturtest** stellt sicher, dass die in M1 etablierten Strukturregeln auch in Zukunft eingehalten werden. Insbesondere darf:
1. die **Log4j2-Bindung** nur in `adapter.out.logging` und `bootstrap` sichtbar sein
2. das `domain`-Paket **nichts** aus Adaptern oder Infrastruktur importieren
3. das `application`-Paket **nichts** aus konkreten Adaptern importieren, sondern nur aus `domain` und eigenen Ports
4. **Preview-Code** nicht aus dem aktiven Code (Bootstrap, CLI-Adapter, Application) referenziert werden
Automatisierte Architekturtests sichern die in M1 etablierten Strukturregeln dauerhaft ab. Zusätzlich wird das Build-Rauschen durch ERROR-Log-Zeilen in Negativ-Tests beseitigt.
## Voraussetzungen
- AP04 (Logging-Adapter), AP09 (Preview eingefroren)
- AP04 (Logging-Adapter etabliert)
- AP09 (Preview-Code eingefroren)
- Idealerweise alle AP05AP09 abgeschlossen
## Scope IN
### Technische Umsetzung
- **ArchUnit** (`com.tngtech.archunit:archunit-junit5`) als Test-Dependency aufnehmen
- neue Test-Klasse `ArchitectureTest` im Paket `de.gecheckt.asv` im Testbereich
- vier Tests:
### 1. ArchUnit als Test-Dependency
### Test 1: Log4j2-Sichtbarkeit
```xml
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
<version><!-- aktuell stabile Version --></version>
<scope>test</scope>
</dependency>
```
### 2. Architekturtest-Klasse
Neue Testklasse `de.gecheckt.asv.ArchitectureTest` im Testbereich. Mindestens vier Regeln:
**Regel A — Log4j2-Sichtbarkeit:**
```java
@ArchTest
static final ArchRule log4j2_nur_in_logging_adapter_und_bootstrap =
@@ -33,7 +49,7 @@ static final ArchRule log4j2_nur_in_logging_adapter_und_bootstrap =
.because("Log4j2 darf nur im Logging-Adapter und im Bootstrap sichtbar sein.");
```
### Test 2: Domain ist frei
**Regel B — Domain-Reinheit:**
```java
@ArchTest
static final ArchRule domain_hat_keine_adapter_abhaengigkeit =
@@ -42,11 +58,10 @@ static final ArchRule domain_hat_keine_adapter_abhaengigkeit =
.should().dependOnClassesThat()
.resideInAnyPackage(
"de.gecheckt.asv.adapter..",
"de.gecheckt.asv.bootstrap..",
"de.gecheckt.asv.preview..");
"de.gecheckt.asv.bootstrap..");
```
### Test 3: Application ist frei von konkreten Adaptern
**Regel C — Application-Reinheit:**
```java
@ArchTest
static final ArchRule application_kennt_keine_adapter_implementierungen =
@@ -58,53 +73,82 @@ static final ArchRule application_kennt_keine_adapter_implementierungen =
"de.gecheckt.asv.bootstrap..");
```
### Test 4: Preview wird nicht referenziert
**Regel D — Preview-Isolation:**
```java
@ArchTest
static final ArchRule preview_wird_nicht_aus_aktivem_code_referenziert =
noClasses()
.that().resideInAnyPackage(
"de.gecheckt.asv.adapter..",
"de.gecheckt.asv.application..",
"de.gecheckt.asv.bootstrap..",
"de.gecheckt.asv.domain..")
"de.gecheckt.asv.bootstrap..")
.should().dependOnClassesThat()
.resideInAPackage("de.gecheckt.asv.preview..")
.because("Preview-Code ist aus M1-Sicht eingefroren und wird erst ab M3 aktiv verwendet.");
.haveSimpleNameContaining("DefaultStructureValidator")
.orShould().dependOnClassesThat()
.haveSimpleNameContaining("DefaultFieldValidator")
.because("Preview-Validatoren sind in M1 eingefroren und werden erst ab M3 aktiv verwendet.");
```
### Zusätzlich: Paketstruktur-Check
- Prüfen, dass die Soll-Pakete aus `technik-und-architektur.md` tatsächlich existieren (als ArchUnit-Regel oder einfacher Dateisystem-Test)
**Wichtig:** Wenn beim ersten Lauf Regeln rot sind, **müssen die Verstöße behoben werden** — die Regeln werden nicht abgeschwächt.
### 3. Test-Log-Konfiguration (E-02)
`src/test/resources/log4j2-test.xml` anlegen:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_ERR">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="WARN">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
```
Log4j2 bevorzugt `log4j2-test.xml` im Test-Classpath gegenüber `log4j2.xml`. Das unterdrückt die erwartete ERROR-Zeile aus dem CLI-Negativ-Test.
### 4. Aufräumen
- Prüfen ob `DefaultStructureValidatorTestAdditional` bereits in AP09 gelöscht wurde — falls nicht, hier löschen
- Sicherstellen dass keine weiteren leeren Testklassen im Projekt existieren
## Scope OUT
- komplexere Regeln wie „keine zyklischen Abhängigkeiten zwischen Paketen" — wäre schön, ist aber für M1 zu weitgehend
- Regeln zu Klassenbenennung
- Regeln zu `public`-Sichtbarkeit
- Tests für Preview-internen Aufbau
- Komplexe Regeln wie zyklische Abhängigkeiten für M1 zu weitgehend
- Regeln zu Klassenbenennung oder `public`-Sichtbarkeit
- Coverage- und Mutation-Schwellwerte (kommen erst in M9)
- Neue Produktionsklassen
## Schritte
1. Branch `m1/ap10-architekturtest`
2. ArchUnit in `pom.xml` als Test-Dependency aufnehmen
3. `ArchitectureTest`-Klasse im Testbereich anlegen
4. Die vier Regeln implementieren
5. `mvn clean verify` laufen lassen — die Tests müssen **grün** sein. Falls rot: **das heißt, eine frühere M1-Phase hat die Regel verletzt**. Die Verletzung muss gefunden und behoben werden (kein Entschärfen der Regel!).
6. Commit `M1-AP10: Architekturtest für Log4j2-Sichtbarkeit, Paketabhängigkeiten, Preview-Isolation`
1. ArchUnit in `pom.xml` als Test-Dependency aufnehmen
2. `ArchitectureTest`-Klasse mit den vier Regeln implementieren
3. `log4j2-test.xml` unter `src/test/resources/` anlegen
4. `mvn clean verify` ausführen — alle vier ArchUnit-Regeln müssen grün sein
5. Falls Regeln rot: Verstöße identifizieren, beheben, erneut testen
6. Im Bericht dokumentieren ob beim ersten Lauf Regeln rot waren und wie behoben
7. Abschlussbericht schreiben
## Abnahmekriterien
- ArchUnit ist als Test-Dependency eingebunden
- vier Architektur-Regeln sind implementiert und grün
- `mvn clean verify` ist grün
- Abschlussbericht liegt vor und dokumentiert, ob beim ersten Lauf Regeln rot waren und wenn ja, wie sie behoben wurden
- [ ] ArchUnit als Test-Dependency in `pom.xml`
- [ ] Vier Architekturregeln AD implementiert und grün
- [ ] `log4j2-test.xml` unter `src/test/resources/` vorhanden
- [ ] Keine leeren Testklassen im Projekt
- [ ] `mvn clean verify` grün, kein unerwartetes Log-Rauschen
- [ ] Bericht dokumentiert ob erste Ausführung Regeln rot hatte und wie behoben
- [ ] Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP10-bericht.md`
## Rest-Risiken und offene Punkte
- ArchUnit hat beim ersten Einsatz manchmal Überraschungen mit transitiven Abhängigkeiten (Regel greift auch auf Framework-Klassen, die nicht gemeint waren). In dem Fall: Regel präzisieren, **nicht** ausschalten.
- Die Regel „Log4j2-Sichtbarkeit" schließt auch den Bootstrap mit ein. Wenn der Bootstrap später (M8) Krypto-Typen referenziert, müssen analoge Regeln ergänzt werden — aber das ist M8-Thema.
- ArchUnit hat beim ersten Einsatz manchmal Überraschungen mit transitiven Abhängigkeiten (Regel greift auch auf Framework-Klassen). In dem Fall: Regel präzisieren, **nicht** ausschalten.
- Regel D (Preview-Isolation) ist auf Klassennamen-Basis formuliert, weil kein separates Paket existiert (Option b). Falls das zu fragil ist, kann alternativ auf Package-Ebene mit einem `preview`-Paket geprüft werden — aber nur wenn AP09 entsprechend umgebaut wurde.
## Bericht
`docs/arbeitspakete/m1/berichte/AP10-bericht.md` nach `templates/ap-bericht.md`.
`docs/arbeitspakete/m1/berichte/AP10-bericht.md` nach `docs/arbeitspakete/m1/templates/ap-bericht.md`.
+74 -59
View File
@@ -1,92 +1,107 @@
---
model: sonnet
---
# AP11 M1-Abnahme
> **Meilenstein:** M1
> **Vorgänger:** AP01AP10 alle ✅ erforderlich
> **Nachfolger:** M2
> **Grundlage:** `docs/specs/meilensteine.md` v3, M1-Abnahmekriterien
## Ziel
Der letzte Schritt in M1: Alles wird gegen die Meilenstein-Abnahmekriterien aus `docs/specs/meilensteine.md` v3 **geprüft**, ein **End-to-End-Lauf** mit einer Minimal-Eingabedatei wird durchgeführt, und alle AP-Berichte werden in einem **konsolidierten M1-Abschlussbericht** zusammengeführt.
M1 wird formal abgenommen. Alle Abnahmekriterien aus `meilensteine.md` sind erfüllt und nachweisbar. Das Projekt ist bereit für M2.
## Voraussetzungen
- AP01 bis AP10 abgeschlossen und grün
- alle AP-Berichte liegen in `docs/arbeitspakete/m1/berichte/` vor
- AP01AP10 abgeschlossen und grün
- Alle AP-Berichte liegen in `docs/arbeitspakete/m1/berichte/` vor
## Scope IN
### End-to-End-Lauf
1. **Minimaldatei erstellen**: eine einfache Dummy-Textdatei im ISO-8859-15-Encoding, z.B. `test-artefakte/m1/minimal.txt` mit ein paar Zeilen Inhalt. Keine echten ASV-Daten, kein gültiges EDIFACT — dies ist nur ein Lauftest, kein Fachtest.
2. **JAR bauen**: `mvn clean package`
3. **Lauf 1**: `java -jar target/asv-format-validator-0.0.1-SNAPSHOT.jar test-artefakte/m1/minimal.txt`
- **Erwartung:** Exit-Code `0` (Dummy-Pfad, leerer Report), Berichtdatei `minimal.txt.txt` und Log-Datei `minimal.txt.log` entstehen, Konsolenausgabe vorhanden
4. **Lauf 2**: identischer Aufruf
- **Erwartung:** `minimal.txt_v1.txt` und `minimal.txt_v1.log` entstehen
5. **Lauf 3**: `java -jar ... nicht-vorhanden.txt`
- **Erwartung:** Exit-Code `2`, Minimalbericht auf Konsole, gegebenenfalls Berichtdatei im übergeordneten Verzeichnis wenn schreibbar
6. **Lauf 4**: `java -jar ...` (ohne Argument)
- **Erwartung:** Exit-Code `2`, Minimalbericht **nur** auf Konsole
7. **Lauf 5**: `java -jar ... datei1.txt datei2.txt`
- **Erwartung:** Exit-Code `2`, Minimalbericht auf Konsole
### 1. Test-Artefakt anlegen
Alle fünf Läufe werden im M1-Abschlussbericht dokumentiert (Befehl, Exit-Code, relevante Ausgabe).
`test-artefakte/m1/minimal.txt` anlegen — eine einfache ISO-8859-15-kompatible Textdatei mit 35 Zeilen Dummy-Inhalt. Keine echten ASV-Daten, kein gültiges EDIFACT — reiner Lauftest.
### Meilenstein-Abnahmeprüfung
Jeder Abnahmepunkt aus `docs/specs/meilensteine.md` v3 Abschnitt „Abnahme von M1" wird mit einem konkreten Nachweis verknüpft:
### 2. End-to-End-Läufe durchführen
| M1-Abnahmekriterium | Nachweis | Status |
`mvn clean package` ausführen, dann alle fünf Läufe:
| Lauf | Befehl | Erwarteter Exit-Code | Erwartetes Verhalten |
|---|---|---|---|
| 1 | `java -jar target/asv-format-validator-*.jar test-artefakte/m1/minimal.txt` | `0` | `.txt` und `.log` entstehen im Verzeichnis |
| 2 | identischer Aufruf wie Lauf 1 | `0` | `_v1.txt` und `_v1.log` entstehen |
| 3 | `java -jar ... nicht-vorhanden.txt` | `2` | Minimalbericht auf Konsole |
| 4 | `java -jar ...` (ohne Argument) | `2` | Minimalbericht nur auf Konsole |
| 5 | `java -jar ... datei1.txt datei2.txt` | `2` | Minimalbericht nur auf Konsole |
Alle fünf Läufe werden im M1-Abschlussbericht dokumentiert (Befehl, tatsächlicher Exit-Code, relevante Ausgabe).
### 3. Meilenstein-Abnahmeprüfung
Jeden Punkt aus `docs/specs/meilensteine.md` v3 §„Abnahme von M1" mit konkretem Nachweis verknüpfen:
| Kriterium | Nachweis | Status |
|---|---|---|
| Anwendung ist als JAR unter Windows mit Java 21 startbar | Lauf 1, JAR-Pfad | ✅ |
| falsches oder fehlendes Argument → Exit-Code `2` mit Minimalbericht | Lauf 3, 4, 5 | |
| Bericht- und Log-Datei werden im Eingabeverzeichnis mit korrekter Suffix-Logik erzeugt | Lauf 1 + Lauf 2 | |
| Log4j2-Bindung ist außerhalb von Bootstrap und Logging-Adapter nicht sichtbar | Architekturtest AP10, Test 1 | ✅ |
| Befundmodell unterscheidet Spec-Urteil und diagnostische Weiteranalyse | Unit-Test AP05 | |
| Build und Tests sind grün | `mvn clean verify` | |
| Anwendung als JAR unter Windows mit Java 21 startbar | Lauf 1 | |
| Fehlendes/falsches Argument → Exit-Code `2` mit Minimalbericht | Lauf 3, 4, 5 | |
| Bericht- und Log-Datei im Eingabeverzeichnis mit korrekter Suffix-Logik | Lauf 1 + 2 | |
| Log4j2-Bindung außerhalb Bootstrap/Logging-Adapter nicht sichtbar | Architekturtest AP10 Regel A | |
| Befundmodell trennt Spec-Urteil und diagnostische Weiteranalyse | Unit-Test AP05 | |
| Build und Tests grün | `mvn clean verify` | |
### M1-Abschlussbericht
- Datei: `docs/arbeitspakete/m1/berichte/M1-abschlussbericht.md`
- Inhalt:
- **Zusammenfassung**: Was ist M1 geworden, in zwei Absätzen
- **AP-Übersicht**: Tabelle mit allen 11 APs, Status, Commit-Hashes, Abschlussdatum
- **Meilenstein-Abnahmetabelle** (siehe oben)
- **End-to-End-Protokoll**: die fünf Läufe mit Befehl, Exit-Code, Zusammenfassung der Ausgabe
- **Quality-Metriken** (Coverage, Testanzahl — **keine harten Gates in M1**, nur Informationswert)
- **Rest-Risiken und übertragene Punkte** aus allen AP-Berichten konsolidiert
- **Empfehlungen für M2**: Was sollte M2 beachten? Was ist aus M1-Sicht offen geblieben?
- **Commit-Graph-Snapshot**: `git log --oneline --graph main` für den M1-Zeitraum
- Freigabe-Vermerk am Ende: „M1 ist abnahmebereit" oder „M1 ist mit folgenden Einschränkungen abnahmebereit: ..."
### 4. Konsolidierter M1-Abschlussbericht
### Tagging
- Git-Tag `m1-done` auf dem letzten AP11-Commit setzen
- Tag-Message: „Meilenstein 1 abgeschlossen, siehe docs/arbeitspakete/m1/berichte/M1-abschlussbericht.md"
Datei: `docs/arbeitspakete/m1/berichte/M1-abschlussbericht.md`
Pflichtabschnitte:
- **Zusammenfassung** — Was ist M1 geworden (max. zwei Absätze)
- **AP-Übersicht** — Tabelle mit allen 11 APs, Status, letzter Commit
- **Meilenstein-Abnahmetabelle** (siehe oben, vollständig ausgefüllt)
- **End-to-End-Protokoll** — alle fünf Läufe mit Befehl, Exit-Code, Ausgabe-Zusammenfassung
- **Quality-Metriken** — Testanzahl, Coverage-Wert (informativ, keine Gate-Prüfung in M1)
- **Rest-Risiken** — konsolidiert aus allen AP-Berichten
- **Empfehlungen für M2** — was M2 beachten sollte
- **Freigabe-Vermerk** — „M1 ist abnahmebereit" oder „M1 ist mit folgenden Einschränkungen abnahmebereit: ..."
### 5. Git-Tag setzen
```bash
git tag -a m1-done -m "Meilenstein 1 abgeschlossen, siehe docs/arbeitspakete/m1/berichte/M1-abschlussbericht.md"
```
## Scope OUT
- Vorgriffe auf M2-Themen (Dateinamensschemata, globale Rahmenregeln, ISO-8859-15 über Dateinamen hinaus — außer dem Einlese-Encoding aus AP06, das bleibt)
- Vorgriffe auf M2-Themen
- Release-Builds, Signierung, Publizierung
- Externe Reviews (die kommen vom Rezensenten der Arbeitspakete, nicht aus diesem AP)
- Inhaltliche Berichtsvertiefung über M1-Minimum hinaus
## Schritte
1. Branch `m1/ap11-abnahme`
2. Test-Artefakt `test-artefakte/m1/minimal.txt` anlegen (ISO-8859-15, 35 Zeilen Dummy-Inhalt)
3. `mvn clean package` ausführen
4. Die fünf Läufe durchführen und protokollieren
1. `test-artefakte/m1/minimal.txt` anlegen
2. `mvn clean package`
3. Alle fünf Läufe durchführen und protokollieren
4. `mvn clean verify` ein letztes Mal
5. Konsolidierten M1-Abschlussbericht schreiben
6. `mvn clean verify` ein letztes Mal laufen lassen
7. Commit `M1-AP11: M1-Abnahme, End-to-End-Protokoll, konsolidierter Abschlussbericht`
8. Git-Tag `m1-done` setzen: `git tag -a m1-done -m "Meilenstein 1 abgeschlossen"`
6. Git-Tag `m1-done` setzen
## Abnahmekriterien
- `test-artefakte/m1/minimal.txt` existiert
- alle fünf Läufe sind protokolliert
- M1-Abschlussbericht existiert und enthält alle oben genannten Abschnitte
- Meilenstein-Abnahmetabelle ist vollständig und jede Zeile hat einen konkreten Nachweis
- `mvn clean verify` ist grün
- Git-Tag `m1-done` ist gesetzt
- der Freigabe-Vermerk am Ende des Abschlussberichts ist explizit
- [ ] `test-artefakte/m1/minimal.txt` existiert
- [ ] Alle fünf Läufe sind protokolliert
- [ ] `M1-abschlussbericht.md` existiert mit allen Pflichtabschnitten
- [ ] Meilenstein-Abnahmetabelle vollständig, jede Zeile mit konkretem Nachweis
- [ ] Kein Exit-Code `3` mehr erreichbar
- [ ] `mvn clean verify` grün
- [ ] Git-Tag `m1-done` gesetzt
- [ ] Freigabe-Vermerk ist explizit
- [ ] Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP11-bericht.md`
## Rest-Risiken und offene Punkte
- Dieser AP ist ein reines Zusammenfassungs-AP. Wenn hier Abnahmekriterien nicht erfüllt sind, zeigt das, dass ein früheres AP unvollständig war. In dem Fall: **zurück zum betroffenen AP**, nachbessern, dann AP11 wiederholen. Keine Abkürzungen.
- Wenn hier Abnahmekriterien nicht erfüllt sind, zeigt das, dass ein früheres AP unvollständig war. In dem Fall: **zurück zum betroffenen AP**, nachbessern, dann AP11 wiederholen. Keine Abkürzungen.
## Bericht
`docs/arbeitspakete/m1/berichte/AP11-bericht.md` nach `templates/ap-bericht.md` **zusätzlich** zum konsolidierten `M1-abschlussbericht.md`.
`docs/arbeitspakete/m1/berichte/AP11-bericht.md` nach `docs/arbeitspakete/m1/templates/ap-bericht.md`.
**Zusätzlich** konsolidierter `docs/arbeitspakete/m1/berichte/M1-abschlussbericht.md`.
@@ -0,0 +1,57 @@
# M1-Orchestrierung: AP05 bis AP11
Dieser Prompt wird mit `claude --model opusplan` gestartet.
---
Lies vor dem Start vollständig und in dieser Reihenfolge:
1. `CLAUDE.md`
2. `docs/specs/technik-und-architektur.md` (Überblick — nicht jede Zeile)
3. `docs/specs/meilensteine.md` (nur M1-Abschnitt)
4. `docs/arbeitspakete/m1/E00-entscheidungsprotokoll.md`
5. `docs/arbeitspakete/m1/README.md`
6. Alle AP05- bis AP11-Dateien in `docs/arbeitspakete/m1/`
---
Du bist der Lead-Orchestrator für Meilenstein M1. Deine Aufgabe ist es,
die Arbeitspakete AP05 bis AP11 sequenziell zu orchestrieren.
Jede AP-Datei enthält `model: sonnet` im Frontmatter — nutze dieses Modell
für die Subagenten die die Implementierung übernehmen.
## Vorgehen
Für jedes Arbeitspaket in der unten angegebenen Reihenfolge:
1. Lies das AP-Dokument vollständig
2. Starte einen Subagenten (Task-Tool) mit dem Auftrag, genau dieses AP
umzusetzen — Subagent-Modell: sonnet
3. Der Subagent folgt den Schritten im AP-Dokument und endet mit
`mvn clean verify` und dem Abschlussbericht
4. Du prüfst nach Abschluss des Subagenten:
- Ist `mvn clean verify` grün?
- Liegt der Abschlussbericht unter `docs/arbeitspakete/m1/berichte/`?
- Sind alle Abnahmekriterien des APs erfüllt?
5. Nur wenn alle drei Punkte erfüllt: weiter zum nächsten AP
6. Wenn ein AP fehlschlägt: analysiere die Ursache, starte einen
Korrektur-Subagenten, prüfe erneut
## Reihenfolge
AP05 → AP06 → AP09 → AP07 → AP08 → AP10 → AP11
## Harte Regeln (aus CLAUDE.md — gelten für dich und alle Subagenten)
- Kein `git commit`, kein `git add`, kein `git push`
- Kein Schreiben außerhalb des jeweiligen AP-Scopes
- Abschlussbericht pro AP ist Pflicht
- `mvn clean verify` muss nach jedem AP grün sein
## Abschluss
Nach AP11: melde „M1-Orchestrierung abgeschlossen" mit einer Zusammenfassung
welche APs in wie vielen Versuchen abgeschlossen wurden.
Fange jetzt an.
@@ -0,0 +1,328 @@
# AP00 — Ist-Analyse Meilenstein M1
> **Bezug:** M1 aus `docs/specs/meilensteine.md` v3, technischer Soll-Rahmen aus `docs/specs/technik-und-architektur.md` v5
> **Bearbeiter:** Claude Code (claude-opus-4-7), Ist-Analyse auf Auftrag, keine Code-Änderungen
> **Datum:** 2026-04-20
> **Grundlage:** HEAD auf `main` nach den Commits AP01AP04 (letzter: `cd6e522 docs: Review-Korrekturen aus Peer-Review anwenden`)
> **Status:** Analyse abgeschlossen, reine Dokumentation
---
## 1. Zusammenfassung
Der aktuelle M1-Stand ist zu rund einem Drittel umgesetzt. Die **Build-Infrastruktur** (AP02), die **hexagonale Paketstruktur** (AP03) und die **SLF4J-Logging-Fassade** (AP04) sind fertig, `mvn clean verify` ist grün (147 Tests, 0 Fehler). Offen bleiben die fachlich tragenden Teile von M1: das **Befundmodell mit Spec-/Diagnose-Trennung** (AP05), das korrekte **Exit-Code-Modell `0/1/2`** (aktuell 4 Codes `0/1/2/3` mit vertauschter Semantik), der **CLI-/Bootstrap-Zuschnitt** (AP06), die **Ausgabeartefakte** (`_v1/_v2`-Suffixlogik, `.txt`/`.log`, AP07), der **Minimalbericht** bei Bedienfehlern (AP08), das **Einfrieren der Altlogik** (AP09) sowie der **Architekturtest** (AP10). Das Eingabeencoding ist aktuell hartkodiert `UTF-8` statt `ISO-8859-15`, das Hauptartefakt-JAR referenziert eine noch nicht existierende `bootstrap.Main`-Klasse, und der Preview-`DefaultStructureValidator` (19 ASVREC/ASVFEH-Regeln) läuft im produktiven Lauf mit und erzeugt fachliche Befunde, die in M1 noch nicht vorgesehen sind.
---
## 2. Projektstruktur
### 2.1 Verzeichnisbaum (Wurzel)
```
asv-format-validator/
├── .editorconfig, .gitattributes, .gitignore
├── CLAUDE.md, README.md, Spec.docx
├── pom.xml
├── Apply-ReviewPatches.ps1
├── docs/
│ ├── arbeitspakete/m1/{APxx.md, berichte/, templates/}
│ └── specs/{fachliche-anforderungen.md, technik-und-architektur.md, meilensteine.md}
├── logs/ # wurde vom Log4j2-File-Appender im Vorlauf angelegt
├── src/
│ ├── main/java/...
│ ├── main/resources/log4j2.xml
│ ├── test/java/...
│ └── test/resources/*.asv # Parser-Testartefakte
└── target/ # Maven Build-Output
```
### 2.2 Maven-Module
Ein einziges Modul: `de.gecheckt:asv-format-validator:0.0.1-SNAPSHOT`. Keine Submodule, keine Multi-Module-Struktur — wie vom Soll (M1) gefordert (evolutionär, kein Modulschnitt).
### 2.3 Java-Pakete (Ist-Stand)
```
de.gecheckt.asv
├── domain (package-info.java)
│ └── model
│ ├── Field (record)
│ ├── Segment (record)
│ ├── Message (record)
│ └── InputFile (record)
├── application (package-info.java)
│ ├── InputFileValidator (Interface)
│ ├── DefaultInputFileValidator (Orchestrator)
│ ├── model
│ │ ├── ValidationSeverity (enum INFO/WARNING/ERROR)
│ │ ├── ValidationError (record, 9 Felder)
│ │ └── ValidationResult (final class)
│ ├── field
│ │ ├── FieldValidator (Interface)
│ │ └── DefaultFieldValidator (Preview-Fachlogik)
│ └── structure
│ ├── StructureValidator (Interface)
│ └── DefaultStructureValidator (Preview, 19 ASVREC/ASVFEH-Regeln)
├── adapter
│ ├── in
│ │ └── cli (package-info.java)
│ │ └── AsvValidatorApplication (main, run, parseFile, printUsage)
│ └── out
│ ├── filesystem (package-info.java leer, AP07-Vorbehalt)
│ ├── parsing (package-info.java)
│ │ ├── InputFileParser (Interface)
│ │ ├── DefaultInputFileParser (ein Message pro Datei)
│ │ ├── SegmentLineTokenizer (Interface)
│ │ ├── DefaultSegmentLineTokenizer (hartes '+')
│ │ └── InputFileParseException
│ ├── reporting (package-info.java)
│ │ └── ValidationResultPrinter (Konsole)
│ └── logging (package-info.java)
│ └── LoggingConfigurator (Stub, AP07-Vorbehalt)
└── bootstrap (package-info.java leer, AP06-Vorbehalt)
```
Noch **nicht** angelegt: `adapter.out.crypto` (planmäßig erst in M8).
### 2.4 Konfigurationsdateien
| Datei | Zweck | Status |
|---|---|---|
| `pom.xml` | Maven-Build, Dependencies, Plugins | AP02-gehärtet (SLF4J, JaCoCo, PIT-Profil, Mockito-Agent, `maven-jar-plugin` mit Platzhalter-Main-Class) |
| `src/main/resources/log4j2.xml` | Log4j2-Konfiguration (Console→STDERR, File→`logs/asv-format-validator.log`) | AP04-gesetzt |
| `.editorconfig` | Encoding UTF-8, LF, 4 Spaces | AP02 |
| `.gitattributes` | LF-Policy | AP02 |
| `.classpath`, `.project`, `.settings/` | Eclipse-Projektfiles | Repo-Altbestand, unverändert |
### 2.5 Testklassen
21 Testklassen, 147 Tests gesamt (bestätigt durch `mvn clean verify`):
- `domain/model/*` — 4 Testklassen, 38 Tests (Record-Konstruktoren, Null-Guards)
- `adapter/out/parsing/*` — 2 Testklassen, 11 Tests
- `adapter/out/reporting/*` — 1 Testklasse, 3 Tests
- `adapter/in/cli/*` — 2 Testklassen, 6 Tests (`AsvValidatorApplicationTest`, `…AdditionalTest`)
- `application/*` — 1 Testklasse, 5 Tests (Orchestrator)
- `application/field/*` — 1 Testklasse, 9 Tests
- `application/model/*` — 2 Testklassen, 5 Tests
- `application/structure/*` — 8 Testklassen, 70 Tests (Preview-Regelabdeckung)
Eine Testklasse fällt auf: `DefaultStructureValidatorTestAdditional` enthält keine `@Test`-Methoden (seit AP01 dokumentiert, Aufräumen ist AP10 zugeordnet).
---
## 3. M1-Abnahmekriterien — Status je Punkt
Bewertung je Kriterium gegen den tatsächlichen Code (nicht gegen die bisherigen Berichte).
### 3.1 „Anwendung ist als JAR unter Windows mit Java 21 startbar"
**🔶 TEILWEISE.**
Der `pom.xml` konfiguriert zwar `maven-jar-plugin` mit `<mainClass>de.gecheckt.asv.bootstrap.Main</mainClass>` ([pom.xml:126](pom.xml#L126)), doch diese Klasse existiert noch nicht (Paket `bootstrap` enthält ausschließlich `package-info.java`). Ein `mvn clean package` würde ein JAR mit ungültigem Manifest-Eintrag erzeugen; `java -jar asv-format-validator.jar <datei>` schlägt mit `Error: Could not find or load main class de.gecheckt.asv.bootstrap.Main` fehl. Der aktuelle tatsächliche Einstiegspunkt ist [`de.gecheckt.asv.adapter.in.cli.AsvValidatorApplication#main`](src/main/java/de/gecheckt/asv/adapter/in/cli/AsvValidatorApplication.java:81) — der wird aber vom Manifest nicht referenziert. AP06 muss die `bootstrap.Main`-Klasse anlegen.
### 3.2 „Eingabedatei wird technisch entgegengenommen; falsches oder fehlendes Argument führt zu Exit-Code `2` mit Minimalbericht"
**❌ FEHLT** (semantisch falsch und ohne Minimalbericht).
Kritische Abweichungen ([AsvValidatorApplication.java:36-39](src/main/java/de/gecheckt/asv/adapter/in/cli/AsvValidatorApplication.java:36)):
```java
private static final int EXIT_CODE_SUCCESS = 0;
private static final int EXIT_CODE_INVALID_ARGUMENTS = 1; // Soll: 2
private static final int EXIT_CODE_FILE_ERROR = 2; // Soll: 2 (gleicher Wert, aber semantisch mit invalid args zu vereinen)
private static final int EXIT_CODE_VALIDATION_ERRORS = 3; // Soll: 1
```
Konsequenzen gegen den Soll-Rahmen:
- Fehlendes Argument → Exit `1` (sollte `2`) — `AsvValidatorApplication.java:97`
- Validierungsfehler → Exit `3` (sollte `1`) — `AsvValidatorApplication.java:113`
- Es existiert **vier** Exit-Codes statt der in Spec und `technik-und-architektur.md` vorgeschriebenen **drei** (`0/1/2`).
- Ein **Minimalbericht** bei Bedienfehlern wird nicht erzeugt. Bei fehlenden Argumenten ruft `printUsage()` nur `System.out.println(…)` auf; bei nicht lesbarer Datei wird `System.err.println("Fehler beim …")` geschrieben. Beide Wege erzeugen weder Berichtdatei noch strukturierten Text.
### 3.3 „Bericht- und Log-Datei werden im Eingabeverzeichnis mit korrekter Suffix-Logik erzeugt (`_v1`, `_v2`, …)"
**❌ FEHLT** vollständig.
- Keine Berichtdatei-Erzeugung im Code. `ValidationResultPrinter#printToConsole` schreibt ausschließlich auf `System.out` ([ValidationResultPrinter.java:22](src/main/java/de/gecheckt/asv/adapter/out/reporting/ValidationResultPrinter.java:22)).
- Die Log-Datei wird statisch nach `logs/asv-format-validator.log` relativ zum Arbeitsverzeichnis geschrieben ([log4j2.xml:7](src/main/resources/log4j2.xml:7)), nicht in das Verzeichnis der Eingabedatei.
- Keine Suffix-Logik `_v1/_v2/…` vorhanden (Grep `_v1` im Hauptcode: keine Treffer).
- `adapter.out.filesystem` ist leer. `LoggingConfigurator#configureLogFile(Path)` ist ein Stub (`// TODO: dynamische Log-Datei-Umleitung in AP07`).
### 3.4 „Log4j2-Bindung ist außerhalb von Bootstrap und Logging-Adapter nicht sichtbar"
**✅ ERFÜLLT.**
Grep über `src/`: `org.apache.logging.log4j` erscheint in **keinem einzigen** Produktions- oder Testcode-Import (`Grep org.apache.logging.log4j` → keine Treffer). Die Log4j2-Abhängigkeit wird ausschließlich per Runtime-Binding (`log4j-slf4j2-impl`, Scope `runtime`) gebunden. `LoggingConfigurator` liegt korrekt im erlaubten Paket, importiert aktuell aber noch keine Log4j2-Typen (Stub-Zustand). Das in AP10 vorgesehene Architekturgate kann diese Regel formal sichern.
### 3.5 „Befundmodell trennt Spec-Urteil und Diagnose strukturell"
**❌ FEHLT** vollständig.
Der bestehende `ValidationError`-Record ([ValidationError.java:20](src/main/java/de/gecheckt/asv/application/model/ValidationError.java:20)) hat neun Felder (`errorCode`, `description`, `severity`, `segmentName`, `segmentPosition`, `fieldName`, `fieldPosition`, `actualValue`, `expectedRule`). Keines davon trägt die Unterscheidung zwischen verbindlichem **Spec-Urteil** und zusätzlicher **diagnostischer Weiteranalyse** — beides wandert undifferenziert in eine gemeinsame `List<ValidationError>` in `ValidationResult`. Zentrale Soll-Metadaten (Artefaktschicht, Prüfstufe, Prüfbereich, Rohwert, Position, Nachrichtenbezug, optionaler offizieller Fehlercode) fehlen ebenfalls. Das ist AP05-Scope.
### 3.6 „Build und Tests sind grün"
**✅ ERFÜLLT.**
`mvn clean verify``BUILD SUCCESS`, `Tests run: 147, Failures: 0, Errors: 0, Skipped: 0` (lokal reproduziert am 2026-04-20). JaCoCo-Report wird erzeugt, keine Schwellwerte (kommt erst M9). Warnungen: nur die bekannte HotSpot-Sharing-Warnung aus AP02 (kosmetisch). Bei den CLI-Tests wird eine erwartete `ERROR`-Zeile „Fehler beim Lesen der Datei: File does not exist: /non/existent/file.txt" ausgegeben — Test-Nebeneffekt, nicht fehlerhaft.
### 3.7 Ergebnis-Tabelle
| Abnahmekriterium | Status |
|---|---|
| JAR unter Windows mit Java 21 startbar | 🔶 |
| Eingabedatei/Exit-Code 2/Minimalbericht | ❌ |
| Bericht/Log im Eingabeverzeichnis mit Suffix-Logik | ❌ |
| Log4j2-Bindung gekapselt | ✅ |
| Befundmodell Spec-/Diagnose-Trennung | ❌ |
| Build und Tests grün | ✅ |
Zwei von sechs erfüllt, einer teilweise, drei fehlend.
---
## 4. Soll-Ist-Vergleich Paketstruktur
| Soll-Paket | Ist-Stand | Bewertung |
|---|---|---|
| `domain` | Unterpaket `domain.model` mit 4 Records (`Field`, `Segment`, `Message`, `InputFile`); `package-info.java` auf `domain`-Ebene vorhanden | **vorhanden, aber flach** — noch kein Befundmodell, noch keine fachliche Schichtung |
| `application` | Orchestrator `DefaultInputFileValidator` + `application.model.*` + `application.field.*` + `application.structure.*` | **vorhanden, mischt Orchestrierung und Preview-Fachregeln** — AP09 muss entscheiden, wie die Preview-Teile markiert/abgetrennt werden |
| `adapter.in.cli` | `AsvValidatorApplication` (main + run + parseFile + printUsage) | **vorhanden, aber überladen** — enthält Bootstrap-Wiring, Dateisystemzugriff, CLI-Parsing und Fehlerbehandlung in einer Klasse |
| `adapter.out.filesystem` | leer (nur `package-info.java`) | **angelegt, unbefüllt** — AP07-Vorbehalt |
| `adapter.out.parsing` | 5 Klassen (Parser/Tokenizer + Exception) | **vorhanden** — Preview-Parser mit hartem `+` als Separator |
| `adapter.out.crypto` | nicht angelegt | **fehlt planmäßig** — ist M8-Scope, in M1 nicht gefordert |
| `adapter.out.reporting` | `ValidationResultPrinter` | **vorhanden** — nur Konsolenformat, kein Dateioutput |
| `adapter.out.logging` | `LoggingConfigurator` (Stub) | **angelegt, unbefüllt** — dynamische Log-Datei-Umleitung ist AP07 |
| `bootstrap` | leer (nur `package-info.java`) | **angelegt, unbefüllt**`Main` ist AP06-Scope |
Fazit: Die Paketstruktur ist aus AP03 heraus formal vollständig. Die Inhalte sind asymmetrisch — das Parser-, Validator- und Modellpaket ist „voll" (z.T. mit Preview-Code), das Bootstrap- und das Filesystem-Paket sind leer.
---
## 5. Architekturprinzipien — Befunde
### 5.1 Keine Log4j2-Typen außerhalb `adapter.out.logging`/`bootstrap`
**✅ eingehalten.** Grep `org.apache.logging.log4j` über `src/` liefert keine Treffer. Nach AP04 ist die einzig erlaubte Anlaufstelle `LoggingConfigurator` (der aktuell selbst keine Log4j2-Typen importiert, da er nur Stub ist).
### 5.2 Keine Infrastrukturabhängigkeiten in `domain` oder `application`
**⚠️ größtenteils eingehalten, mit einem Rest-Risiko.**
- `domain.*` importiert nur `java.util.*` und `java.util.Optional`**sauber**.
- `application.*` importiert keine CLI-, Filesystem-, Logging- oder Parser-Typen. Grep bestätigt: kein `java.nio.file`, kein `System.out/err`, kein `org.slf4j` in `application/`.
- **Rest-Risiko:** Die Klassen `application.structure.DefaultStructureValidator` (19 Regeln, u.a. zu `UNH`/`UNT`, `ASVREC`/`ASVFEH`, Rechnungskennzeichen, FHL) und `application.field.DefaultFieldValidator` enthalten bereits fachliche ASV-Regelkenntnis. Formal gehören solche Regeln ins Domänen- bzw. Regelpaket, nicht in die „Application"-Orchestrierungsschicht. Da AP09 vorsieht, diese Altlogik explizit als Vorbau einzufrieren und erst in M3+ wieder aufzunehmen, ist das derzeit akzeptierte Schulden — aber es verletzt den Soll-Zuschnitt leise (Fachregeln in `application/*` statt in einer eigenständigen Regelschicht).
### 5.3 Manuelle Constructor Injection, kein DI-Framework
**✅ eingehalten.** `AsvValidatorApplication` besitzt einen Default-Konstruktor, der alle Komponenten manuell per `new` verdrahtet ([AsvValidatorApplication.java:50-60](src/main/java/de/gecheckt/asv/adapter/in/cli/AsvValidatorApplication.java:50)), und einen Test-Konstruktor mit Constructor Injection ([AsvValidatorApplication.java:70](src/main/java/de/gecheckt/asv/adapter/in/cli/AsvValidatorApplication.java:70)). `DefaultInputFileValidator` nimmt `StructureValidator` und `FieldValidator` per Constructor entgegen ([DefaultInputFileValidator.java:33](src/main/java/de/gecheckt/asv/application/DefaultInputFileValidator.java:33)). Kein Spring, kein Quarkus, kein CDI, kein Guice in den Dependencies.
Anmerkung: Die Wiring-Logik liegt derzeit im CLI-Adapter selbst; der Soll-Zuschnitt will sie in `bootstrap` sehen (AP06).
### 5.4 Befundmodell unterscheidet Spec-Urteil und Diagnose
**❌ nicht eingehalten.** Siehe 3.5. Das aktuelle `ValidationResult` kennt nur `ERROR`/`WARNING`/`INFO`, keine Dimension „spec-verbindlich vs. diagnostisch".
### 5.5 Exit-Codes `0/1/2` korrekt verdrahtet
**❌ nicht eingehalten.** Siehe 3.2. Ist-Stand ist `0/1/2/3` mit teilweise invertierter Semantik. Konkrete Stellen: `AsvValidatorApplication.java:36-39` (Konstanten), `:97` (falscher Code bei fehlendem Argument), `:113` (falscher Code bei Validierungsfehler).
### 5.6 Weitere prinzipielle Befunde
- **Eingabe-Encoding ISO-8859-15 (`technik-und-architektur.md` §„Zeichensätze"):** Das Ist liest mit `StandardCharsets.UTF_8` ([AsvValidatorApplication.java:152](src/main/java/de/gecheckt/asv/adapter/in/cli/AsvValidatorApplication.java:152)). `java.nio.charset.StandardCharsets` bietet kein ISO-8859-15, man muss `Charset.forName("ISO-8859-15")` nutzen. Aktuelle Fehlkodierung verfälscht alle Umlaute (ä=0xE4 statt UTF-8-Doppelbyte) und jeden Euro-Sonderfall (`€`).
- **Schreiben statt Speichern der Bericht-/Log-Datei:** Die Bericht- und Log-Dateien müssten laut Soll in UTF-8 in das Verzeichnis der Eingabedatei geschrieben werden. Keine dieser Anforderungen ist umgesetzt.
- **EDIFACT-Konformität des Tokenizers:** `DefaultSegmentLineTokenizer` trennt starr an `+` ([Zeile 13](src/main/java/de/gecheckt/asv/adapter/out/parsing/DefaultSegmentLineTokenizer.java:13)). Das UNA-Segment und die Gruppenelementtrennung `:` werden nicht ausgewertet. Nicht M1-Scope (gehört zu M3), aber Rest-Risiko bei Tests und als Vorbau.
- **Parser-Vereinfachung:** `DefaultInputFileParser` erzeugt pro Datei genau eine `Message` ([Zeile 54](src/main/java/de/gecheckt/asv/adapter/out/parsing/DefaultInputFileParser.java:54)), unabhängig von UNH/UNT-Gruppen. Preview-Verhalten.
---
## 6. Qualitätsstatus (Build/Test)
> Hinweis zu den widersprüchlichen Vorgaben des Auftrags: Die Einleitung spricht von „machst kein mvn", Abschnitt 5 fordert jedoch explizit `mvn clean verify`, der abschließende Teil präzisiert auf „kein `mvn package`". Der Autor dieses Berichts interpretiert den spezifischen Auftrag in Abschnitt 5 als maßgeblich; `mvn clean verify` wurde einmalig ausgeführt. Kein `mvn package`, kein `git`, kein Schreiben außerhalb dieses Berichts.
- **`mvn clean verify`:** ✅ `BUILD SUCCESS` (lokal, 2026-04-20).
- **Tests:** 147 gesamt, 0 Failures, 0 Errors, 0 Skipped. Alle Testklassen der hexagonalen Struktur laufen durch.
- **Compile-/Javac-Warnungen:** keine über die aus AP02 bekannten hinaus.
- **JVM-Warnungen zur Laufzeit:**
- `Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended` — kosmetisch, stammt vom JaCoCo-Agent, bekannt seit AP02.
- Eine erwartete `ERROR`-Log-Zeile aus dem CLI-Test (nicht-existente Datei) ist sichtbar, wird aber nicht als Testfehler gewertet. Sie wäre zum M1-Ende über ein Logback-Test-Filter oder eine angepasste Test-Log-Konfiguration in AP10 unterdrückbar — kein Blocker.
- **Mutation Testing:** In AP02 einmalig ausgeführt (249 Mutationen, 83 % getötet), Schwellwerte kommen erst M9.
- **Coverage:** JaCoCo-Report unter `target/site/jacoco/`; keine Schwellwerte aktiv.
---
## 7. Preview-Code / Altlogik
### 7.1 Identifikation
Als **Preview-Code** der Sondierungsphase (README, Abschnitt „Preview-Code"; AP01 Klassifikation) gelten:
| Klasse | Paket | M1-Bewertung | Verdrahtung im Lauf |
|---|---|---|---|
| `DefaultInputFileParser` | `adapter.out.parsing` | Behalten, für M3 überarbeiten (Trennzeichen, Multi-Message) | aktiv in `AsvValidatorApplication` |
| `DefaultSegmentLineTokenizer` | `adapter.out.parsing` | Behalten, für M3 überarbeiten (UNA) | aktiv |
| `InputFileParser`/`SegmentLineTokenizer`/`InputFileParseException` | `adapter.out.parsing` | Behalten als stabile Ports | aktiv |
| `DefaultFieldValidator` | `application.field` | **einzufrieren (AP09)** — keine M1-Weiterentwicklung | aktiv über `DefaultInputFileValidator` |
| `DefaultStructureValidator` (19 ASVREC/ASVFEH-Regeln) | `application.structure` | **einzufrieren (AP09)** — 19 fachliche Regeln, M3+-Vorbau | aktiv über `DefaultInputFileValidator` |
| `ValidationError`, `ValidationResult`, `ValidationSeverity` | `application.model` | umzubauen/abzulösen durch Befundmodell mit Spec-/Diagnose-Trennung (AP05) | aktiv als einzige Befundträger |
| `ValidationResultPrinter` | `adapter.out.reporting` | Behalten als Konsolen-Formatierer | aktiv |
### 7.2 Aktiv oder eingefroren?
Alle Preview-Klassen sind **aktiv** in den Lauf verdrahtet: Der Default-Konstruktor von `AsvValidatorApplication` baut parser + validator + printer komplett mit der Preview-Logik zusammen ([AsvValidatorApplication.java:52-59](src/main/java/de/gecheckt/asv/adapter/in/cli/AsvValidatorApplication.java:52)). Der produktive Lauf führt deshalb heute schon fachliche ASVREC-/ASVFEH-Prüfungen aus — nominell M3+-Scope, real vorhandenes Verhalten. Ein formales „Einfrieren" (Kommentar-Marker, Paketumzug oder gezielte Deaktivierung) ist bis zum AP09 noch nicht erfolgt.
### 7.3 Risiken des Preview-Codes für M1
1. **Fachliche Befunde in M1:** Solange `DefaultStructureValidator` aktiv bleibt, liefert ein M1-Lauf bereits ASVREC-/ASVFEH-Befunde. Das widerspricht der M1-Vorgabe „noch keine ASV-Fachvalidierung" (`meilensteine.md` §M1 Ziel, und AP-README „Keine Fachvalidierung in M1").
2. **Exit-Code-Verwechslung:** Weil Fachbefunde schon produziert werden, schlagen sie über `hasErrors()` auf den (falschen) Exit-Code `3` durch. Ein M1-Lauf einer beliebigen Textdatei liefert deshalb heute realistisch `3`, nicht das geplante `0` (gültig mangels Regeln) oder das korrekte `1` (ungültig).
3. **Hartkodiertes `+` als Trennzeichen:** Jede Datei ohne ASV-typische EDIFACT-Struktur wird stumm „erfolgreich" geparst. Für M1-Akzeptanz mit einer Minimaldatei akzeptabel; für alles Reale gefährlich.
4. **UTF-8-Lesen:** Alle Preview-Tests laufen auf UTF-8-kodierten `*.asv`-Testressourcen. Beim Umstellen auf ISO-8859-15 werden vorhandene Testdaten zum Risiko — Umstellung muss zusammen mit Testressourcen-Anpassung erfolgen.
5. **`DefaultStructureValidatorTestAdditional` leer:** Eine Testklasse ohne `@Test`-Methoden bleibt seit AP01 bestehen und ist ein Restposten für AP10.
6. **Preview-Regeln als „V1-N"-Kandidaten:** Einige der 19 Regeln (z.B. strikte Reihenfolgeerzwingung der ASVREC-Segmente, FHL-Pflicht für ASVFEH) greifen zu rigide, wenn sie gegen die finalen Soll-Regelklassifikationen (`V1-V/T/N/K`) gestellt werden. Beim Wiederaufnehmen ab M3 ist jede Preview-Regel neu zu bewerten — das ist kein M1-Problem, aber ein M3-Erbe.
---
## 8. Offene Punkte und Risiken
### 8.1 Architekturrisiken
- **R-ARCH-01 — Exit-Code-Semantik falsch und erweitert.** Der Ist-Code hat vier Codes mit vertauschter Bedeutung. Muss in AP06 korrigiert werden, damit AP11 abnehmbar ist. Bis dahin ist ein M1-Lauf nicht spec-konform.
- **R-ARCH-02 — Eingabe-Encoding hartkodiert UTF-8.** Widerspricht direkt dem Soll-Rahmen. `StandardCharsets` kennt kein ISO-8859-15; `Charset.forName("ISO-8859-15")` muss genutzt werden, JDK-Verfügbarkeit ist zu verifizieren. Umstellung ist in AP06 oder spätestens in AP07 zu verankern.
- **R-ARCH-03 — Keine Spec-/Diagnose-Trennung im Befundmodell.** Das aktuelle `ValidationError`/`ValidationResult` reicht für die Fortführung ab M2 nicht aus. Es muss in AP05 komplett neu geschnitten (oder stark erweitert) werden, inklusive aller Metadatenfelder aus `technik-und-architektur.md` § „Befundarten". Weil der Preview-`DefaultStructureValidator` dieses Modell produktiv befüllt, wird der Umbau nicht kostenlos — AP09 muss die Altlogik zuvor entkoppeln.
- **R-ARCH-04 — Ausgabeartefakte fehlen komplett.** Weder Berichtdatei noch Logdatei werden im Eingabeverzeichnis erzeugt; die Suffix-Logik existiert nicht. Das ist der größte Einzel-Arbeitsblock in M1 (AP07).
- **R-ARCH-05 — Preview-Code läuft produktiv mit und erzeugt Fachbefunde.** Siehe 7.3. AP09 muss klären: entkoppeln, per Default deaktivieren oder nur inert im Classpath behalten.
### 8.2 Implementierungslücken (aus M1 noch offen)
- **L-AP05** — Befundmodell mit Spec-/Diagnose-Trennung.
- **L-AP06** — `bootstrap.Main`-Klasse, sauberes CLI-Wiring, Exit-Codes `0/1/2`, ISO-8859-15.
- **L-AP07** — `adapter.out.filesystem` mit Dateioutput; `LoggingConfigurator` mit dynamischer Log-Datei-Umleitung; Suffix-Logik `_v1/_v2/…`.
- **L-AP08** — Minimalbericht bei Bedienfehlern (Exit-Code `2`).
- **L-AP09** — Altlogik einfrieren (oder deaktivieren), damit M1-Läufe keine unerwarteten Fachbefunde mehr erzeugen.
- **L-AP10** — Architekturtest (Paketabhängigkeiten, Log4j2-Sichtbarkeit, idealerweise auch Exit-Code-Semantik und Preview-Deaktivierung).
- **L-AP11** — End-to-End-Abnahme mit Minimaldatei; Berichtskonsolidierung.
### 8.3 Unklarheiten / Entscheidungsbedarf
- **E-01: Wie wird der Preview-`DefaultStructureValidator` in AP09 konkret eingefroren?** Drei Optionen: (a) in ein Sub-Paket `application.preview.structure` verschieben und den Orchestrator gegen eine Null-Implementation austauschen; (b) in Ort belassen, den Orchestrator im Bootstrap aber nicht mehr damit verdrahten; (c) weiterlaufen lassen, aber dessen Befunde im neuen Befundmodell als „Diagnose" klassifizieren. Jede Option hat andere Auswirkungen auf AP05 und AP10.
- **E-02: Wie wird der Test-Log-Rauschen (`ERROR`-Zeile im Negativ-Test) eliminiert?** Eigene Test-Log-Konfiguration oder bewusst stehen lassen? AP10 sollte hier eine Entscheidung zusichern.
- **E-03: Was passiert mit `DefaultStructureValidatorTestAdditional`?** Stummes Artefakt seit AP01 — in AP10 entfernen oder mit Tests füllen?
- **E-04: Soll der aktuelle Inhalt `logs/asv-format-validator.log` (Arbeitsverzeichnis) nach AP07 noch eine Rolle spielen?** Wenn die Logdatei künftig neben die Eingabedatei geschrieben wird, wird der aus AP04 konfigurierte statische Pfad überflüssig. Der `logs/`-Ordner im Repo-Root ist Resultat früherer Läufe und gehört vermutlich `.gitignore`'d.
- **E-05: JAR-Aufbau als „fat jar" oder als JAR mit Classpath?** `maven-jar-plugin` alleine erzeugt kein Uber-JAR — `java -jar asv-format-validator.jar` würde ohne `maven-shade-plugin` oder `Class-Path`-Manifest ohne Log4j2/SLF4J starten. AP06 muss dies entscheiden (die AP-Texte nennen nur `maven-jar-plugin`).
---
## 9. Empfehlung: nächste sinnvolle Arbeitspakete für M1
Reihenfolge auf Basis der Abhängigkeiten in `docs/arbeitspakete/m1/README.md` und der oben sichtbaren Risiken:
1. **AP05 — Befundmodell mit Spec-/Diagnose-Trennung.** Höchste Hebelwirkung: freigeschaltet sind danach AP06 (Exit-Codes bauen auf dem neuen Urteil auf), AP07 (Bericht rendert das neue Modell) und AP09 (Preview-Befunde lassen sich als Diagnose klassifizieren). Unmittelbar angreifbar, keine vorangehenden APs mehr offen.
2. **AP06 — Bootstrap und CLI.** Exit-Codes `0/1/2` korrigieren, `bootstrap.Main` anlegen, Wiring aus `AsvValidatorApplication` herauslösen, ISO-8859-15 einziehen. Nur mit AP05-Modell sinnvoll, weil `hasErrors()` des neuen Befundmodells den Urteils-Exit-Code speist.
3. **AP09 — Altlogik einfrieren.** Direkt nach AP06 sinnvoll, weil ab dann der Bootstrap sauber entscheiden kann, ob und wie die Preview-Validatoren verdrahtet werden. Ohne AP09 bringt AP05 keinen realen Effekt — `DefaultStructureValidator` produziert weiter Fachbefunde.
4. **AP07 — Ausgabeartefakte.** Nach AP06 sinnvoll, weil dann eine stabile Ausgangs-CLI vorliegt, in die die Dateilogik eingezogen werden kann. `LoggingConfigurator` wird hier Leben bekommen.
5. **AP08 — Minimalbericht.** Reine Veredelung der Bedienfehler-Pfade auf Basis von AP07.
6. **AP10 — Architekturtest.** Sobald AP04AP09 stehen, kann ein ArchUnit-Scan die Log4j2-Sichtbarkeit, die Paketabhängigkeiten, die Exit-Codes (als Konstanten) und die Preview-Deaktivierung formell prüfen.
7. **AP11 — M1-Abnahme.** Abschlusslauf mit Minimaldatei, Konsolidierung aller Berichte.
Wichtig: Jedes dieser APs bleibt ein **eigener Claude-Lauf**. Diese Ist-Analyse hier bündelt nur die Ausgangslage; sie darf in späteren APs zitiert, aber nicht als implizite Entscheidung missverstanden werden — insbesondere die Optionen zu E-01 bis E-05 sind weiterhin offen.
@@ -0,0 +1,101 @@
# Abschlussbericht Arbeitspaket AP05 Befundmodell mit Spec-/Diagnose-Trennung
> **Bezug:** `docs/arbeitspakete/m1/AP05-befundmodell.md`
> **Bearbeiter:** Claude Code (claude-sonnet-4-6), Subagent-Lauf
> **Datum:** 2026-04-20
> **Commit(s):** ausstehend (Mensch committet nach Sichtung)
> **Status:** ✅ abgeschlossen
## 1. Zusammenfassung
Das Paket `de.gecheckt.asv.domain.finding` wurde vollständig neu angelegt und enthält alle im AP05 geforderten Typen: die Enums `Severity`, `FindingKind`, `FindingLayer`, `Verdict`, den unveränderlichen Record `Finding` mit Builder sowie die unveränderliche Klasse `ValidationReport`. Die zentrale Invariante — dass DIAGNOSTIC-ERROR das Verdict niemals auf INVALID setzt — ist durch einen explizit markierten Unit-Test (`diagnosticErrorLiefertVALID`) abgesichert. `mvn clean verify` ist grün (164 Tests, 0 Fehler).
## 2. Umgesetzte Änderungen
Folgende Dateien wurden **neu angelegt** (keine bestehende Datei wurde verändert):
**Produktionscode (`src/main/java/de/gecheckt/asv/domain/finding/`):**
- `Severity.java` — Enum: ERROR, WARNING, HINT; JavaDoc erklärt Einfluss auf Verdict
- `FindingKind.java` — Enum: SPEC, DIAGNOSTIC; JavaDoc beschreibt Verdict-Invariante
- `FindingLayer.java` — Enum: ARTIFACT, TECHNICAL_STRUCTURE, DOMAIN_MODEL; JavaDoc erklärt Schichttrennung
- `Verdict.java` — Enum: VALID, INVALID, OPERATIONAL_ERROR; Exit-Code-Zuordnung in JavaDoc
- `Finding.java` — Record mit allen 12 Feldern gemäß AP05; Null-Prüfung im Kompaktkonstruktor für Pflichtfelder; zusätzlicher innerer `Builder` für komfortablere Erzeugung; Hilfsmethode `isSpecError()`
- `ValidationReport.java` — unveränderliche Klasse; `findings` intern per `List.copyOf()` gesichert; Methoden `computeVerdict()`, `hasSpecErrors()`, `specFindings()`, `diagnosticFindings()`, `getFindings()`, `getFileName()`, `getTimestamp()`; Factory `operationalError(fileName, ruleId, message)`; privater Konstruktor für Bedienfehler-Flag
**Tests (`src/test/java/de/gecheckt/asv/domain/finding/`):**
- `ValidationReportTest.java` — 11 Tests (die 7 Pflicht-Tests aus AP05 plus 4 ergänzende Absicherungen)
- `FindingTest.java` — 6 Tests für Record, Builder und Null-Absicherung
**Keine bestehende Datei wurde verändert.** Insbesondere wurde `ValidationResult` (Altmodell) nicht angefasst.
## 3. Scope-Treue
| Scope-Punkt aus dem Arbeitspaket | Erfüllt? | Bemerkung |
|---|---|---|
| Paket `domain.finding` anlegen | ✅ | `de.gecheckt.asv.domain.finding` vollständig vorhanden |
| Enum `Severity` (ERROR/WARNING/HINT) | ✅ | Alle drei Werte implementiert |
| Enum `FindingKind` (SPEC/DIAGNOSTIC) | ✅ | Beide Werte mit präzisem JavaDoc |
| Enum `FindingLayer` (ARTIFACT/TECHNICAL_STRUCTURE/DOMAIN_MODEL) | ✅ | Alle drei Werte implementiert |
| `Finding` Record mit allen 12 Feldern | ✅ | Alle Felder vorhanden; `germanMessage` nicht nullable; übrige 11 nullable |
| `Verdict` Enum (VALID/INVALID/OPERATIONAL_ERROR) | ✅ | Alle drei Werte mit Exit-Code-Kommentar |
| `ValidationReport` unveränderliche Klasse | ✅ | `final`, findings per `List.copyOf()` gesichert |
| `computeVerdict()` nur SPEC+ERROR | ✅ | Invariante im Code und per Test abgesichert |
| `hasSpecErrors()` | ✅ | Implementiert |
| `specFindings()` / `diagnosticFindings()` | ✅ | Implementiert, per Test verifiziert |
| `operationalError(fileName, ruleId, message)` | ✅ | Factory-Methode vorhanden |
| Keine Änderung an `ValidationResult` | ✅ | Altmodell nicht angefasst |
| Integration in laufende Validierung (Scope OUT) | ✅ nicht gemacht | AP06 |
| Löschen/Umbenennen `ValidationResult` (Scope OUT) | ✅ nicht gemacht | AP09 |
| Berichtserzeugung/Textrendering (Scope OUT) | ✅ nicht gemacht | AP07 |
| Architekturtest (Scope OUT) | ✅ nicht gemacht | AP10 |
**Wurde der Scope eingehalten?** Ja, vollständig.
**Wurden Dinge außerhalb des Scopes gemacht?** Nein. Der `Builder` für `Finding` war im AP05 explizit als Alternative zum reinen Record erwähnt und fällt daher in den Scope.
## 4. Abnahmekriterien
| Abnahmekriterium aus dem Arbeitspaket | Erfüllt? | Nachweis |
|---|---|---|
| Paket `domain.finding` enthält alle genannten Typen | ✅ | 5 Dateien: `Severity`, `FindingKind`, `FindingLayer`, `Verdict`, `Finding`, `ValidationReport` |
| **Test „DIAGNOSTIC-ERROR ergibt VALID" ist grün** | ✅ | `ValidationReportTest#diagnosticErrorLiefertVALID()` — GRÜN; `@DisplayName("KRITISCH: Ein DIAGNOSTIC-ERROR-Befund liefert Verdict VALID (niemals INVALID)")` |
| `ValidationReport.findings` ist unveränderlich (Test vorhanden) | ✅ | `ValidationReportTest#findingsListeNichtModifizierbar()` testet: (1) Mutation der Eingabeliste nach Übergabe hat keinen Effekt; (2) `getFindings().add(...)` wirft `UnsupportedOperationException` |
| Alle Metadatenfelder aus technik-und-architektur.md §„Befundarten" im `Finding`-Typ | ✅ | Alle 12 Felder vorhanden: Artefaktschicht (`layer`), Prüfstufe/Art (`kind`), Segmenttyp, Segmentindex, Feld-ID, Rohwert, Position, Nachrichtenreferenz, offizieller Fehlercode, interne Regel-ID, Schweregrad, deutscher Befundtext |
| `operationalError(...)` Factory-Methode existiert | ✅ | Statische Methode in `ValidationReport`; Testnachweis: `ValidationReportTest#operationalErrorFactoryLiefertOPERATIONAL_ERROR()` |
| Keine Änderung an `ValidationResult` (Altmodell) | ✅ | Dateipfad `application/model/ValidationResult.java` wurde nicht geöffnet oder verändert |
| `mvn clean verify` grün | ✅ | 164 Tests, 0 Failures, 0 Errors, 0 Skipped |
| Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP05-bericht.md` | ✅ | Diese Datei |
## 5. Build- und Teststatus
- `mvn clean verify`: ✅ grün
- Anzahl Tests gesamt: **164** (davon **17 neu** in `domain.finding`: 11 in `ValidationReportTest`, 6 in `FindingTest`)
- Vorherige Testanzahl (vor AP05): 147
- Coverage: JaCoCo läuft; das neue Paket `domain.finding` hat vollständige Abdeckung aller kritischen Pfade durch die 17 neuen Tests
- Warnungen beim Build: keine testbezogenen Warnungen; eine Java-Compiler-Warnung bezüglich Annotationsverarbeitung (`-proc:none` empfohlen) — diese war bereits vor AP05 vorhanden und ist kein AP05-Artefakt
## 6. Rest-Risiken und offene Punkte
- **Zwei parallele Ergebnistypen:** `ValidationResult` (Altmodell im Paket `application.model`) und `ValidationReport` (neues Befundmodell in `domain.finding`) koexistieren bewusst bis AP09. Dies ist im AP05 explizit als Absicht dokumentiert und kein Risiko dieses Arbeitspakets.
- **`operationalError`-Befund nutzt `FindingLayer.ARTIFACT`:** Der Bedienfehler-Befund wurde auf Schicht `ARTIFACT` abgelegt, da Bedienfehler typischerweise die Artefaktebene betreffen (nicht lesbare Datei, fehlender Pfad). Falls AP08 eine andere Schicht bevorzugt, ist das in der Factory anpassbar ohne API-Bruch.
- **`Finding.isSpecError()`** ist eine Hilfsmethode für interne Verwendung. Ob sie öffentlich bleiben soll oder auf `package-private` reduziert wird, kann in AP10 (Architekturtest) beurteilt werden.
- **Keine `package-info.java`** für das neue Paket `domain.finding` angelegt — dies war nicht im AP05-Scope, kann aber in einem Folge-AP ergänzt werden.
## 7. Empfehlungen für Folge-Arbeitspakete
- **AP06 (Bootstrap/CLI):** Der `ValidationReport` ist bereit zur Integration. Die Factory `operationalError(...)` deckt den Exit-Code-2-Pfad ab. `computeVerdict()` liefert direkt den Verdict für die Exit-Code-Entscheidung.
- **AP07 (Ausgabeartefakte):** Das `Finding`-Record ist flat und enthält alle Traceability-Informationen, die für einen hierarchischen Bericht benötigt werden. `specFindings()` und `diagnosticFindings()` erleichtern die Gliederung.
- **AP09 (Altlogik einfrieren):** `ValidationResult` und `ValidationReport` koexistieren sauber. AP09 kann `ValidationResult` einfrieren oder entfernen, ohne `ValidationReport` anzufassen.
- **AP10 (Architekturtest):** Das Paket `domain.finding` hat keine Infrastrukturabhängigkeiten (nur `java.time.Instant`, `java.util.*`). Der ArchUnit-Test sollte diese Eigenschaft formal absichern.
## 8. Reviewer-Checkliste
- [x] Alle im Arbeitspaket genannten Scope-IN-Punkte sind nachweislich umgesetzt
- [x] Keine Scope-OUT-Punkte wurden angefasst
- [x] Abnahmekriterien sind mit konkreten Nachweisen belegt (Tests, Dateipfade)
- [x] `mvn clean verify` ist grün (164 Tests, 0 Failures)
- [ ] Der Commit für dieses AP hat eine sprechende Message (`M1-AP05: ...`) — ausstehend, Mensch committet
- [x] Keine Regeln der Grunddokumente (Spec, Fachliche, Technik) wurden verletzt
- [x] Rest-Risiken sind ehrlich dokumentiert
@@ -0,0 +1,112 @@
# Abschlussbericht Arbeitspaket AP06 Bootstrap und CLI-Adapter
> **Bezug:** `docs/arbeitspakete/m1/AP06-bootstrap-cli.md`
> **Bearbeiter:** Claude Code (claude-sonnet-4-6), Subagent-Lauf
> **Datum:** 2026-04-20
> **Commit(s):** ausstehend (Mensch committet nach Sichtung)
> **Status:** ✅ abgeschlossen
## 1. Zusammenfassung
Die bisherige `AsvValidatorApplication` wurde in zwei klar getrennte Verantwortlichkeiten zerlegt: `de.gecheckt.asv.bootstrap.Main` übernimmt die manuelle Constructor Injection und den einzigen `main`-Einstiegspunkt, `de.gecheckt.asv.adapter.in.cli.CliRunner` übernimmt die CLI-Argument-Verarbeitung und die Exit-Code-Übersetzung. Exit-Codes wurden auf die normativen Werte 0/1/2 umgestellt, ISO-8859-15 als Eingabe-Encoding eingeführt, und das Uber-JAR wird nun über `maven-shade-plugin` erzeugt. `mvn clean verify` ist grün (168 Tests, 0 Fehler).
## 2. Umgesetzte Änderungen
**Neu angelegt:**
- `src/main/java/de/gecheckt/asv/adapter/in/cli/ExitCode.java` — Normative Exit-Code-Konstanten (VALID=0, INVALID=1, OPERATIONAL_ERROR=2). Alte Konstanten aus `AsvValidatorApplication` entfernt.
- `src/main/java/de/gecheckt/asv/adapter/in/cli/CliRunner.java` — CLI-Adapter; einziger Ort mit Argument-Parsing; nutzt `ValidationReport.computeVerdict()` zur Exit-Code-Ableitung; enthält keine Log4j2-Typen (nur SLF4J).
- `src/main/java/de/gecheckt/asv/application/FileValidationService.java` — Anwendungsschnittstelle für die Dateivalidierung, mit `ValidationReport validate(Path)`.
- `src/main/java/de/gecheckt/asv/application/DummyFileValidationService.java` — M1-Platzhalter; liest Datei mit `Charset.forName("ISO-8859-15")`, zählt Bytes, gibt leeren `ValidationReport` zurück. Konstante `INPUT_CHARSET` paketöffentlich für Testbarkeit.
- `src/main/java/de/gecheckt/asv/bootstrap/Main.java` — Einziger `public static void main`; verdrahtet `LoggingConfigurator`, `DummyFileValidationService`, `CliRunner` per Constructor Injection; delegiert Exit-Code an `System.exit`. Log4j2-Typen nur über `LoggingConfigurator` (in `adapter.out.logging`) sichtbar.
- `src/test/java/de/gecheckt/asv/adapter/in/cli/CliRunnerTest.java` — 5 Tests: kein Argument → 2, zwei Argumente → 2, nicht existierende Datei → 2, leere lesbare Datei → 0, operationalError-Report → 2.
- `src/test/java/de/gecheckt/asv/application/DummyFileValidationServiceTest.java` — 4 Tests: leere Datei → VALID, Datei mit Inhalt → VALID, Byte 0xA4 → Euro-Zeichen €, INPUT_CHARSET-Name korrekt.
**Geändert:**
- `src/main/java/de/gecheckt/asv/adapter/in/cli/AsvValidatorApplication.java` — Auf leere Hülle reduziert; `main` delegiert an `Main.main`. Mit `@Deprecated(forRemoval=true)` markiert. Wird in AP09 endgültig entfernt.
- `src/test/java/de/gecheckt/asv/adapter/in/cli/AsvValidatorApplicationTest.java` — Auf leere Klasse reduziert; Tests nach `CliRunnerTest` migriert.
- `src/test/java/de/gecheckt/asv/adapter/in/cli/AsvValidatorApplicationAdditionalTest.java` — Auf leere Klasse reduziert; Tests nach `CliRunnerTest` migriert.
- `pom.xml``maven-jar-plugin`-Platzhalter durch `maven-shade-plugin` 3.5.2 ersetzt; `log4j-transform-maven-shade-plugin-extensions` 0.1.0 als Plugin-Dependency ergänzt; `Log4j2PluginCacheFileTransformer` konfiguriert; META-INF-Signatur-Filter ergänzt.
- `.gitignore``logs/` und `dependency-reduced-pom.xml` (erzeugt durch shade-Plugin) hinzugefügt.
## 3. Scope-Treue
| Scope-Punkt aus dem Arbeitspaket | Erfüllt? | Bemerkung |
|---|---|---|
| `Main` mit `public static void main` und Constructor Injection | ✅ | `bootstrap.Main` verdrahtet alle Komponenten |
| Log4j2-Typen nur in `bootstrap` und `adapter.out.logging` | ✅ | `Main` hat keine direkten Log4j2-Importe; nur `LoggingConfigurator` (in `adapter.out.logging`) |
| `CliRunner.run(String[])` mit Argument-Prüfung | ✅ | Genau ein Positionsargument; 0 oder ≥2 → Exit 2 |
| Datei-Vorabprüfung (existent, regulär, lesbar) | ✅ | Alle drei Prüfungen implementiert |
| Exit-Code 0/1/2 spec-konform | ✅ | Kein Exit-Code 3 mehr erreichbar |
| `ExitCode`-Klasse mit VALID/INVALID/OPERATIONAL_ERROR | ✅ | Alte Konstanten gelöscht |
| Verdrahtung mit `ValidationReport.computeVerdict()` | ✅ | `CliRunner` nutzt den Report aus AP05 direkt |
| `operationalError(...)` für Bedienfehler → Exit 2 | ✅ | Im `CliRunner` nicht direkt verwendet; Verdict-Switch deckt den Fall ab |
| M1-Dummy-Pfad: ISO-8859-15 einlesen, leerer Report | ✅ | `DummyFileValidationService` implementiert genau das |
| `Charset.forName("ISO-8859-15")`, nicht UTF_8 | ✅ | Hardkodiert in `DummyFileValidationService.INPUT_CHARSET` |
| Uber-JAR via `maven-shade-plugin` | ✅ | `Log4j2PluginCacheFileTransformer` + Signatur-Filter konfiguriert |
| `java -jar ... <datei>` ohne `-cp` | ✅ | Manuell verifiziert, Exit-Code 0 |
| `logs/` in `.gitignore` | ✅ | Eingetragen |
| `AsvValidatorApplication` entkern | ✅ | Auf Delegations-Hülle reduziert |
| Tests von `AsvValidatorApplication` nach `CliRunner` migrieren | ✅ | `CliRunnerTest` deckt alle relevanten Szenarien ab |
| Berichtdatei/Log-Datei im Eingabeverzeichnis (Scope OUT) | ✅ nicht gemacht | AP07 |
| Vollständiger Minimalbericht bei Exit 2 (Scope OUT) | ✅ nicht gemacht | AP08 |
| Altlogik-Entkopplung (Scope OUT) | ✅ nicht gemacht | AP09 |
| Architekturtest (Scope OUT) | ✅ nicht gemacht | AP10 |
**Wurde der Scope eingehalten?** Ja, vollständig.
**Wurden Dinge außerhalb des Scopes gemacht?** `dependency-reduced-pom.xml` in `.gitignore` eingetragen — dieses Artefakt wird automatisch vom shade-Plugin erzeugt und hatte keinen `.gitignore`-Eintrag. Dies ist eine direkte Konsequenz der Shade-Plugin-Einbindung und fällt in den Scope.
## 4. Abnahmekriterien
| Abnahmekriterium aus dem Arbeitspaket | Erfüllt? | Nachweis |
|---|---|---|
| `de.gecheckt.asv.bootstrap.Main` existiert und ist Main-Class des Uber-JAR | ✅ | `Main.java` angelegt; `mainClass` in shade-Plugin-Konfiguration gesetzt; JAR-Test erfolgreich |
| `CliRunner` ist einziger Ort mit CLI-Argument-Parsing | ✅ | `AsvValidatorApplication` enthält kein Argument-Parsing mehr |
| Exit-Codes 0, 1, 2 definiert und spec-konform, kein Exit-Code 3 | ✅ | `ExitCode.java`; `CliRunner`-Switch über `Verdict`; kein `return 3` mehr im Produktionscode |
| Test: Aufruf ohne Argument → Exit-Code 2 | ✅ | `CliRunnerTest#keineArgumente_liefernExitCode2()` — GRÜN |
| Test: Aufruf mit nicht existierender Datei → Exit-Code 2 | ✅ | `CliRunnerTest#nichtExistierendeDatei_liefertExitCode2()` — GRÜN |
| Test: Aufruf mit leerer, lesbarer Datei → Exit-Code 0 | ✅ | `CliRunnerTest#leereLesbareDatei_liefertExitCode0()` — GRÜN |
| Einlese-Encoding ist ISO-8859-15 (Byte 0xA4 → €) | ✅ | `DummyFileValidationServiceTest#byte0xA4_wirdAlsEuroZeichenDekodiert()` — GRÜN |
| `java -jar target/asv-format-validator-*.jar <datei>` startet ohne `-cp` | ✅ | Manuell getestet: `/tmp/test-asv.txt` → Exit 0; kein Argument → Exit 2; nicht existierende Datei → Exit 2 |
| `logs/` in `.gitignore` | ✅ | `.gitignore` enthält `logs/` |
| Keine Log4j2-Typen außerhalb von `bootstrap` und `adapter.out.logging` | ✅ | `CliRunner`, `DummyFileValidationService`, `FileValidationService` importieren nur SLF4J/JDK; `Main` importiert keine Log4j2-Typen direkt |
| `mvn clean verify` grün | ✅ | 168 Tests, 0 Failures, 0 Errors, 0 Skipped |
| Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP06-bericht.md` | ✅ | Diese Datei |
## 5. Build- und Teststatus
- `mvn clean verify`: ✅ grün
- Anzahl Tests gesamt: **168** (davon **9 neu** in AP06: 5 in `CliRunnerTest`, 4 in `DummyFileValidationServiceTest`)
- Vorherige Testanzahl (vor AP06, nach AP05): 164
- Coverage: JaCoCo läuft; neue Klassen vollständig durch Tests abgedeckt
- Warnungen beim Build:
- Shade-Plugin: überlappende META-INF-Ressourcen (LICENSE, NOTICE, DEPENDENCIES) aus Log4j2-JARs — harmlos, bekanntes Verhalten bei Fat-JAR-Erzeugung mit mehreren Apache-Projekten
- `sun.reflect.Reflection.getCallerClass is not supported` beim JAR-Test — Log4j2-interne Warnung, kein Fehler
- Compiler-Warnung zu `@Deprecated`-Annotationsverarbeitung — war bereits vor AP06 vorhanden
## 6. Rest-Risiken und offene Punkte
- **`AsvValidatorApplication` als Delegations-Hülle:** Die Klasse existiert noch mit einer `@Deprecated`-`main`-Methode. AP09 entfernt sie endgültig. Bis dahin könnten Tools, die `main`-Methoden suchen, beide Einstiegspunkte anzeigen.
- **Dummy-Pfad ohne echte Validierung:** `DummyFileValidationService` liest die Datei nur, validiert sie nicht. Jede Eingabedatei ergibt Exit-Code 0, solange sie lesbar ist. Echte Validierung kommt ab M3.
- **Shade-Warnung `sun.reflect.Reflection.getCallerClass`:** Log4j2 2.20.0 erzeugt diese Warnung im Shade-JAR-Betrieb. Betrifft nur die Startzeit-Performance, kein Fehler. Kann durch Log4j2-Upgrade auf 2.23+ behoben werden (nicht AP06-Scope).
- **`LoggingConfigurator.configureLogFile(Path)` wird in `Main` nicht aufgerufen:** Der Aufruf wurde weggelassen, da `configureLogFile` in M1 ein No-Op ist und `null` als Argument technisch korrekt, aber semantisch fragwürdig wäre. AP07 füllt diese Methode aus und wird `Main` entsprechend aktualisieren.
- **`dependency-reduced-pom.xml`:** Das shade-Plugin erzeugt diese Datei im Projekt-Root. Sie wurde in `.gitignore` eingetragen, sodass sie nicht versehentlich committet wird.
## 7. Empfehlungen für Folge-Arbeitspakete
- **AP07 (Ausgabeartefakte):** `Main` erwartet, dass `LoggingConfigurator.configureLogFile(Path)` mit dem korrekten Pfad aufgerufen wird. Der Pfad muss aus dem Eingabedatei-Pfad abgeleitet werden — AP07 soll `Main` entsprechend erweitern.
- **AP08 (Minimalbericht):** Bei Exit-Code 2 wird derzeit nur eine kurze STDERR-Meldung ausgegeben. AP08 soll einen vollständigen Minimalbericht erzeugen. `CliRunner` bietet dafür eine klare Erweiterungsstelle im Bedienfehler-Pfad.
- **AP09 (Altlogik einfrieren):** `AsvValidatorApplication` (deprecated), `AsvValidatorApplicationTest` und `AsvValidatorApplicationAdditionalTest` (beide leer) können in AP09 vollständig gelöscht werden. Der Altpfad (Parser → Validator → Printer) ist noch vorhanden und wird in AP09 eingefroren/entkoppelt.
- **AP10 (Architekturtest):** `CliRunner`, `Main` und `DummyFileValidationService` haben keine unerwünschten Infrastrukturabhängigkeiten. ArchUnit sollte sicherstellen, dass keine Log4j2-Typen außerhalb von `bootstrap` und `adapter.out.logging` importiert werden.
## 8. Reviewer-Checkliste
- [x] Alle im Arbeitspaket genannten Scope-IN-Punkte sind nachweislich umgesetzt
- [x] Keine Scope-OUT-Punkte wurden angefasst
- [x] Abnahmekriterien sind mit konkreten Nachweisen belegt (Tests, Dateipfade, JAR-Test)
- [x] `mvn clean verify` ist grün (168 Tests, 0 Failures)
- [ ] Der Commit für dieses AP hat eine sprechende Message (`M1-AP06: ...`) — ausstehend, Mensch committet
- [x] Keine Regeln der Grunddokumente (Spec, Fachliche, Technik) wurden verletzt
- [x] Rest-Risiken sind ehrlich dokumentiert
@@ -0,0 +1,110 @@
# Abschlussbericht Arbeitspaket AP07 Ausgabeartefakte: Berichtdatei und Log-Datei mit Suffix-Logik
> **Bezug:** `docs/arbeitspakete/m1/AP07-ausgabeartefakte.md`
> **Bearbeiter:** Claude Code (claude-sonnet-4-6), Subagent-Lauf
> **Datum:** 2026-04-20
> **Commit(s):** ausstehend (Mensch committet nach Sichtung)
> **Status:** ✅ abgeschlossen
## 1. Zusammenfassung
Pro Lauf werden nun zwei Ausgabedateien im Verzeichnis der Eingabedatei erzeugt: eine UTF-8-Berichtdatei (`<dateiname>.txt`) und eine Log-Datei (`<dateiname>.log`). Bei Folgeläufen greift die Suffix-Logik (`_v1`, `_v2`, …) unabhängig pro Extension. Die Konsolenausgabe ist identisch zum Berichtinhalt. `mvn clean verify` ist grün (202 Tests, 0 Fehler).
## 2. Umgesetzte Änderungen
**Neu angelegt:**
- `src/main/java/de/gecheckt/asv/adapter/out/filesystem/SuffixResolver.java` — Ermittelt den ersten freien Dateipfad per Suffix-Logik. Probiert `<baseName>.<ext>`, dann `<baseName>_v1.<ext>`, `<baseName>_v2.<ext>` usw.; Zählung pro Extension unabhängig.
- `src/main/java/de/gecheckt/asv/adapter/out/reporting/ReportFileWriter.java` — Schreibt den Validierungsbericht als UTF-8-Textdatei; nutzt `SuffixResolver`; Basisname = vollständiger Dateiname der Eingabedatei inkl. Extension; enthält `ReportWriteResult`-Record für Rückgabe von Inhalt, Pfad und ggf. IOException.
- `src/test/java/de/gecheckt/asv/adapter/out/filesystem/SuffixResolverTest.java` — 10 Unit-Tests: keine Datei, `.txt` vorhanden, `.txt` + `_v1` vorhanden, Extensions unabhängig, drei aufeinanderfolgende Läufe, Null-Guards.
- `src/test/java/de/gecheckt/asv/adapter/out/reporting/ReportFileWriterTest.java` — 10 Unit-Tests: Datei erzeugt, UTF-8-Encoding (Sonderzeichen äöü߀), Kopfzeile (Zeitstempel, Datei, Urteil), Befundzeile (Severity/Kind/Layer/Feld-ID/Meldung), Fußzeile (M1-Platzhalter-Hinweis), Suffix-Logik (zweiter Lauf → `_v1`), UNGÜLTIG-Urteil, Null-Guards.
- `src/test/java/de/gecheckt/asv/adapter/in/cli/CliRunnerOutputArtifactsTest.java` — 5 End-to-End-Integrationstests: Lauf 1 (`foo.auf.txt`), Lauf 2 (`foo.auf_v1.txt`), Lauf 3 (`foo.auf_v2.txt`), Suffix-Unabhängigkeit, UTF-8-Kodierung, Konsolenausgabe ≡ Berichtdatei.
**Geändert:**
- `src/main/java/de/gecheckt/asv/adapter/out/logging/LoggingConfigurator.java` — Implementiert `configureLogFile(Path)` mit programmatischer Log4j2-Umkonfiguration; erstellt einen neuen `FileAppender` ("DynamicFile") und hängt ihn an alle vorhandenen LoggerConfigs. Kapselt Log4j2-Typen vollständig in `adapter.out.logging`.
- `src/main/resources/log4j2.xml` — Statischer `logs/asv-format-validator.log` in `logs/asv-format-validator-fallback.log` umbenannt; Kommentar „FALLBACK-Default" ergänzt. Greift nur wenn `configureLogFile` nicht aufgerufen wurde (z.B. Unit-Tests ohne Log-Datei).
- `src/main/java/de/gecheckt/asv/bootstrap/Main.java` — Erzeugt nun `SuffixResolver`, `ReportFileWriter` und übergibt alle vier Adapter an `CliRunner` per Constructor Injection.
- `src/main/java/de/gecheckt/asv/adapter/in/cli/CliRunner.java` — Neuer 4-Parameter-Konstruktor; bestimmt Log-Datei-Pfad via `SuffixResolver` und ruft `configureLogFile` vor dem ersten fachlichen Log-Aufruf auf; ruft nach Validierungslauf `ReportFileWriter.write()` auf; gibt Berichtinhalt identisch auf stdout aus; IO-Fehler beim Datei-Schreiben blockiert Konsolenausgabe nicht.
- `src/test/java/de/gecheckt/asv/adapter/in/cli/CliRunnerTest.java` — Auf neuen 4-Parameter-Konstruktor umgestellt; `LoggingConfigurator` als Mockito-No-Op-Mock, um TempDir-Locking durch geöffnete Log4j2-Appender auf Windows zu vermeiden; 2 neue Tests (Konsolenausgabe, Berichtdatei-Erzeugung).
## 3. Scope-Treue
| Scope-Punkt aus dem Arbeitspaket | Erfüllt? | Bemerkung |
|---|---|---|
| `SuffixResolver` in `adapter.out.filesystem` | ✅ | Vollständig implementiert |
| Suffix-Zählung pro Extension unabhängig | ✅ | `.txt` und `.log` haben getrennte Zähler |
| Unit-Tests: keine Datei, `.txt` vorhanden, `.txt`+`_v1` vorhanden | ✅ | Alle drei Testfälle + weitere |
| `ReportFileWriter` in `adapter.out.reporting` | ✅ | Vollständig implementiert |
| Basisname = vollständiger Dateiname inkl. Extension | ✅ | `foo.auf``foo.auf.txt` |
| UTF-8 explizit (nicht Plattform-Default) | ✅ | `StandardCharsets.UTF_8` in `ReportFileWriter` |
| Kopfzeile: Zeitstempel (ISO), Eingabedatei, Verdict | ✅ | Alle drei Felder |
| Pro Finding: Severity, Kind, Layer, Feld-ID, deutsche Meldung | ✅ | Format `[SEV] [KIND] [LAYER] Feld=... Meldung` |
| Fußzeile: Hinweis auf nicht geprüfte Bereiche | ✅ | M1-Platzhalter-Hinweis |
| `LoggingConfigurator.configureLogFile(Path)` | ✅ | Programmatische Umkonfiguration implementiert |
| Log4j2-Typen nur in `adapter.out.logging` und `bootstrap` | ✅ | Verifiziert per grep; CLI-Paket enthält keine Log4j2-Importe |
| Statischer `logs/`-Pfad entfernt/Fallback | ✅ | Auf `logs/asv-format-validator-fallback.log` umbenannt mit Kommentar |
| Integration in `bootstrap.Main` | ✅ | Reihenfolge korrekt: SuffixResolver → configureLogFile → Validierung → ReportFileWriter → Konsolenausgabe |
| Konsolenausgabe nach Berichtdatei | ✅ | IO-Fehler bei Datei blockiert Konsolenausgabe nicht |
| Hierarchische Berichtsgliederung (Scope OUT) | ✅ nicht gemacht | M9 |
| ANSI-Farben (Scope OUT) | ✅ nicht gemacht | — |
| Log-Rotation (Scope OUT) | ✅ nicht gemacht | — |
| Minimalbericht bei Exit 2 (Scope OUT) | ✅ nicht gemacht | AP08 |
**Wurde der Scope eingehalten?** Ja, vollständig.
**Wurden Dinge außerhalb des Scopes gemacht?** Nein.
## 4. Abnahmekriterien
| Abnahmekriterium aus dem Arbeitspaket | Erfüllt? | Nachweis |
|---|---|---|
| Nach Lauf mit `foo/bar.auf` entstehen `foo/bar.auf.txt` und `foo/bar.auf.log` | ✅ | E2E-Test (JAR): `test.auf``test.auf.txt` + `test.auf.log` bestätigt; `CliRunnerOutputArtifactsTest#lauf1_erzeugtBerichtdateiOhneSuffix()` |
| Zweiter Lauf → `_v1.txt` und `_v1.log` | ✅ | E2E-Test (JAR): `test.auf_v1.txt` + `test.auf_v1.log` bestätigt; `CliRunnerOutputArtifactsTest#lauf2_erzeugtBerichtdateiMitV1Suffix()` |
| Dritter Lauf → `_v2` | ✅ | E2E-Test (JAR): `test.auf_v2.txt` + `test.auf_v2.log` bestätigt; `CliRunnerOutputArtifactsTest#lauf3_erzeugtBerichtdateiMitV2Suffix()` |
| Beide Ausgaben UTF-8 | ✅ | `file test.auf.txt``Unicode text, UTF-8`; `ReportFileWriterTest#berichtdatei_istInUtf8()` mit `äöü߀`; `CliRunnerOutputArtifactsTest#berichtdatei_istInUtf8()` mit `GÜLTIG` |
| Konsolenausgabe identisch zum Berichtdatei-Inhalt | ✅ | `CliRunnerOutputArtifactsTest#konsolenausgabe_identischZumBerichtinhalt()` — direkter String-Vergleich |
| `SuffixResolver` hat ≥3 Unit-Tests | ✅ | 10 Tests in `SuffixResolverTest` |
| Log4j2-Typen nicht außerhalb `adapter.out.logging` und `bootstrap` | ✅ | Grep auf `import org.apache.logging.log4j` im `src/main/java/` ohne `adapter/out/logging` und `bootstrap` ergibt leer |
| Statischer `logs/`-Pfad aus `log4j2.xml` entfernt oder Fallback | ✅ | `log4j2.xml`: `logs/asv-format-validator-fallback.log`; Kommentar „FALLBACK-Default" |
| `mvn clean verify` grün | ✅ | 202 Tests, 0 Failures, 0 Errors |
| Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP07-bericht.md` | ✅ | Diese Datei |
## 5. Build- und Teststatus
- `mvn clean verify`: ✅ grün
- Anzahl Tests gesamt: **202** (davon **29 neu** in AP07: 10 `SuffixResolverTest`, 10 `ReportFileWriterTest`, 2 neue in `CliRunnerTest`, 5 in `CliRunnerOutputArtifactsTest`, 2 in `CliRunnerTest` erweitert)
- Vorherige Testanzahl (vor AP07, nach AP09): 173
- Coverage: JaCoCo läuft; neue Klassen durch Tests abgedeckt
- Warnungen beim Build: identisch zu AP06/AP09 (Shade-Plugin META-INF-Überlappungen, `sun.reflect.Reflection.getCallerClass`-Warnung zur Laufzeit) — keine neuen Warnungen
## 6. Rest-Risiken und offene Punkte
- **TempDir-Locking auf Windows durch Log4j2-FileAppender:** Wenn der echte `LoggingConfigurator` in Tests aufgerufen wird, hält Log4j2 den File-Appender für die Log-Datei im TempDir offen. JUnit 5 kann das TempDir dann nach dem Test nicht löschen. Lösung in `CliRunnerTest` und `CliRunnerOutputArtifactsTest`: `LoggingConfigurator` als Mockito-No-Op-Mock. Die echte Umkonfiguration ist durch den manuellen E2E-Test mit dem Uber-JAR verifiziert. AP10 (Architekturtest) könnte dieses Verhalten formell absichern.
- **Fallback-Entscheidung: Programmatische Log4j2-Umkonfiguration vs. System-Property:** Die programmatische Umkonfiguration über `LoggerContext`/`FileAppender.newBuilder()` ist stabil und funktioniert. Fallback (`-Dasv.log.file=...`) wurde nicht implementiert, da nicht nötig. Entscheidung: programmatisch, kein Fallback.
- **Fallback-Datei `logs/asv-format-validator-fallback.log`:** Der Fallback-Appender in `log4j2.xml` schreibt bei Unit-Tests (ohne Eingabedatei-Pfad) in `logs/asv-format-validator-fallback.log`. Dieses Verzeichnis wird automatisch durch Log4j2 angelegt. Die `.gitignore`-Einträge `logs/` decken diese Datei ab.
- **Race Conditions:** Gleichzeitige Läufe auf derselben Eingabedatei können zu Suffix-Konflikten führen. Laut `technik-und-architektur.md` bewusst nicht behandelt (kein Mehrbenutzerbetrieb in V1).
- **Berichtformat absichtlich minimal:** Das M1-Format (Kopfzeile, Befundzeilen, Fußzeile) wird in M9 durch eine finale hierarchische Gliederung ersetzt.
- **Konsolenausgabe-Encoding auf Windows:** Die Konsolenausgabe (`System.out.print`) zeigt auf Windows-Konsolen Mojibake für Umlaute (`GLTIG`), weil Windows-Konsolen oft CP1252/OEM437 nutzen. Die Datei selbst ist korrekt UTF-8. Dies ist ein bekanntes Konsolen-Encoding-Problem unter Windows und kein Fehler des Validators. Empfehlung für AP11: Hinweis in der Benutzer-Dokumentation.
## 7. Empfehlungen für Folge-Arbeitspakete
- **AP08 (Minimalbericht bei Exit 2):** `CliRunner` gibt bei Bedienfehler bisher nur STDERR-Meldungen aus. AP08 kann hier anknüpfen und einen Minimalbericht erzeugen. Der `ReportFileWriter` ist dafür bereit.
- **AP10 (Architekturtest):** ArchUnit sollte sicherstellen, dass keine Log4j2-Typen außerhalb `adapter.out.logging` und `bootstrap` importiert werden. `SuffixResolver` und `ReportFileWriter` haben keine Infrastrukturabhängigkeiten — AP10 sollte diese Kapselung formell erzwingen.
- **AP11 (M1-Abnahme):** End-to-End-Test kann nun auf die Ausgabedateien prüfen: `exit 0`, `foo.auf.txt` existiert, enthält `GÜLTIG`, ist UTF-8; Zweiter Lauf erzeugt `foo.auf_v1.txt`.
- **M9 (Berichtformat ausbauen):** `ReportFileWriter.buildReportContent()` ist der Erweiterungspunkt. Die `ReportWriteResult`-Signatur kann unverändert bleiben.
## 8. Reviewer-Checkliste
- [x] Alle im Arbeitspaket genannten Scope-IN-Punkte sind nachweislich umgesetzt
- [x] Keine Scope-OUT-Punkte wurden angefasst
- [x] Abnahmekriterien sind mit konkreten Nachweisen belegt (Tests, E2E-JAR-Läufe, Dateipfade)
- [x] `mvn clean verify` ist grün (202 Tests, 0 Failures)
- [ ] Der Commit für dieses AP hat eine sprechende Message (`M1-AP07: ...`) — ausstehend, Mensch committet
- [x] Keine Regeln der Grunddokumente (Spec, Fachliche, Technik) wurden verletzt
- [x] Rest-Risiken sind ehrlich dokumentiert
@@ -0,0 +1,115 @@
# Abschlussbericht Arbeitspaket AP08 Minimalbericht bei Bedienfehlern (Exit-Code 2)
> **Bezug:** `docs/arbeitspakete/m1/AP08-minimalbericht.md`
> **Bearbeiter:** Claude Code (claude-sonnet-4-6), Subagent-Lauf
> **Datum:** 2026-04-20
> **Commit(s):** ausstehend (Mensch committet nach Sichtung)
> **Status:** ✅ abgeschlossen
## 1. Zusammenfassung
Alle fünf Bedienfehler-Fälle erzeugen nun einen `ValidationReport` mit `Verdict.OPERATIONAL_ERROR` und geben den Minimalbericht auf STDERR aus. Wo das übergeordnete Verzeichnis bekannt und schreibbar ist (Fälle 3 und 5), wird die Berichtdatei zusätzlich als `.txt`-Datei geschrieben. `mvn clean verify` ist grün (218 Tests, 0 Failures, 1 Skipped auf Windows).
## 2. Umgesetzte Änderungen
**Geändert:**
- `src/main/java/de/gecheckt/asv/adapter/in/cli/CliRunner.java`
- Alle fünf Bedienfehler-Fälle erzeugen jetzt `ValidationReport.operationalError(...)` mit den definierten `ruleId`-Werten
- Zwei neue private Hilfsmethoden: `writeMinimalReportToConsoleOnly(report)` (STDERR-only) und `writeMinimalReportWithOptionalFile(report, directory, baseName)` (STDERR + optionale Datei)
- Fälle 1 (kein Arg), 2 (zu viele Args) und 4 (kein regulärer Dateityp) → nur Konsole
- Fälle 3 (Datei nicht gefunden) und 5 (Datei nicht lesbar) → Konsole + Berichtdatei im übergeordneten Verzeichnis, sofern schreibbar
- Alle Bedienfehler werden via `logger.error(...)` protokolliert
- Platzhalter-Konstanten: `<kein Argument>` und `<mehrere Argumente>` für den `fileName`-Parameter
- `src/main/java/de/gecheckt/asv/adapter/out/reporting/ReportFileWriter.java`
- Neue `public`-Methode `writeOperationalError(ValidationReport, Path, String)`: Schreibt Bedienfehler-Bericht direkt in ein angegebenes Verzeichnis; IO-Fehler lösen keine `RuntimeException` aus, sondern werden geloggt und als fehlgeschlagenes `ReportWriteResult` zurückgegeben
- Neue `public`-Methode `buildMinimalReportContent(ValidationReport)`: Erzeugt Berichtinhalt ohne `Path`-Parsing, damit Platzhalter mit Sonderzeichen (`<kein Argument>`) funktionieren
- `buildReportContent(ValidationReport, Path)` delegiert jetzt an die neue private `buildReportContentWithFileName(ValidationReport, String)` — kein Duplizierungsrisiko
- Befundzeilen zeigen jetzt auch `Regel=<ruleId>`, wenn eine `ruleId` gesetzt ist
**Neu angelegt:**
- `src/test/java/de/gecheckt/asv/adapter/in/cli/CliRunnerOperationalErrorTest.java`
- 16 Tests, 1 Skipped (Fall 5 auf Windows)
- Alle fünf Bedienfehler-Fälle getestet (Exit-Code 2)
- Korrekte `ruleId`-Werte für alle fünf Fälle verifiziert
- `Verdict.OPERATIONAL_ERROR` in dediziertem Test verifiziert
- Drei Negativ-Tests: kein Stack-Trace in STDERR
- Fall 3: Berichtdatei im übergeordneten Verzeichnis vorhanden und enthält `BEDIENFEHLER` + `OPERATIONAL-FILE-NOT-FOUND`
## 3. Scope-Treue
| Scope-Punkt aus dem Arbeitspaket | Erfüllt? | Bemerkung |
|---|---|---|
| Fall 1: Kein Argument → Exit 2 + nur Konsole | ✅ | `writeMinimalReportToConsoleOnly` |
| Fall 2: Mehr als ein Argument → Exit 2 + nur Konsole | ✅ | `writeMinimalReportToConsoleOnly` |
| Fall 3: Datei nicht gefunden → Exit 2 + Konsole + Datei | ✅ | `writeMinimalReportWithOptionalFile` |
| Fall 4: Kein regulärer Dateityp → Exit 2 + nur Konsole | ✅ | `writeMinimalReportToConsoleOnly` |
| Fall 5: Datei nicht lesbar → Exit 2 + Konsole + Datei | ✅ | Nur auf Unix; Windows-Test übersprungen |
| `ruleId`-Werte: OPERATIONAL-MISSING-ARG, OPERATIONAL-TOO-MANY-ARGS, OPERATIONAL-FILE-NOT-FOUND, OPERATIONAL-NOT-REGULAR, OPERATIONAL-NOT-READABLE | ✅ | Alle fünf implementiert und getestet |
| Kein Stack-Trace für den Nutzer | ✅ | Drei Negativ-Tests |
| `logger.error(...)` für Bedienfehler | ✅ | In jedem Fall vorhanden |
| `ReportFileWriter`: weiche IO-Fehlerbehandlung bei OPERATIONAL_ERROR | ✅ | `writeOperationalError` ohne RuntimeException |
| Konsole-Hinweis wenn Verzeichnis nicht schreibbar | ✅ | „Bericht konnte nicht in das Verzeichnis geschrieben werden." |
| Unit-Tests für alle fünf Fälle: Exit 2 + ruleId | ✅ | Alle fünf Fälle im neuen Test |
| Test Fall 3: Berichtdatei im übergeordneten Verzeichnis | ✅ | Test vorhanden und grün |
| `Verdict.OPERATIONAL_ERROR` in Test verifiziert | ✅ | `operationalErrorReport_verdictIstOPERATIONAL_ERROR` |
| `ValidationReport.operationalError(...)` vollständig (Layer ARTIFACT) | ✅ | War bereits in AP05 vollständig implementiert |
| Feingranulare IO-Exception-Unterscheidung (Scope OUT) | ✅ nicht gemacht | Einheitlich „nicht lesbar" |
| Internationalisierung (Scope OUT) | ✅ nicht gemacht | — |
| Exit-Codes jenseits 0/1/2 (Scope OUT) | ✅ nicht gemacht | — |
**Wurde der Scope eingehalten?** Ja, vollständig.
**Wurden Dinge außerhalb des Scopes gemacht?**
Die `buildReportContent`-Methode wurde intern auf `buildReportContentWithFileName` umgestellt und gibt jetzt auch `ruleId`-Werte aus. Das ist eine minimale Erweiterung des Berichtformats, aber direkt notwendig für den AP08-Abnahmetest (`fall3_dateiExistiertNicht_berichtdateiEnthaeltOpertionalError` prüft auf `OPERATIONAL-FILE-NOT-FOUND` im Berichtinhalt). Kein Code außerhalb des erlaubten Scope wurde berührt.
## 4. Abnahmekriterien
| Abnahmekriterium aus dem Arbeitspaket | Erfüllt? | Nachweis |
|---|---|---|
| Alle fünf Bedienfehler-Fälle erzeugen Exit-Code 2 (per Unit-Test) | ✅ | `CliRunnerOperationalErrorTest`: fall1…fall5, alle grün (fall5 Skipped auf Windows) |
| Fall „kein Argument" → nur Konsolenausgabe, keine Dateiausgabe | ✅ | `fall1_keinArgument_nurKonsole`: `countTxtFiles(tempDir) == 0` |
| Fall „Datei nicht vorhanden" → Berichtdatei im übergeordneten Verzeichnis | ✅ | `fall3_dateiExistiertNicht_berichtdateiImUebergeordnetenVerzeichnis` + `fall3_dateiExistiertNicht_berichtdateiEnthaeltOpertionalError` |
| `Verdict.OPERATIONAL_ERROR` in mindestens einem Test verifiziert | ✅ | `operationalErrorReport_verdictIstOPERATIONAL_ERROR` und `alleRuleIds_sindKorrektDefiniert` |
| Kein Stack-Trace in STDERR (Negativ-Test vorhanden) | ✅ | `keinArgument_keinStackTraceInStderr`, `dateiNichtGefunden_keinStackTraceInStderr`, `pfadIstVerzeichnis_keinStackTraceInStderr` |
| `mvn clean verify` grün | ✅ | 218 Tests, 0 Failures, 0 Errors, 1 Skipped |
| Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP08-bericht.md` | ✅ | Diese Datei |
## 5. Build- und Teststatus
- `mvn clean verify`: ✅ grün
- Anzahl Tests gesamt: **218** (davon **16 neu** in `CliRunnerOperationalErrorTest`)
- Vorherige Testanzahl (vor AP08, nach AP07/AP09): 202
- 1 Test Skipped: `fall5_dateiNichtLesbar_exitCode2` — Windows-bedingt; `setReadable(false)` hat auf Windows keine Wirkung für den eigenen Prozess. Der Test enthält `assumeTrue(...)` zum expliziten Überspringen.
- Coverage: JaCoCo läuft; neue Methoden in `CliRunner` und `ReportFileWriter` sind durch die neuen Tests abgedeckt
- Warnungen beim Build: identisch zu AP06/AP07 (Shade-Plugin META-INF-Überlappungen) — keine neuen Warnungen
## 6. Rest-Risiken und offene Punkte
- **Fall 5 (Datei nicht lesbar) nur auf Unix testbar:** Auf Windows kann `setReadable(false)` eine Datei nicht für den eigenen Prozess unlesbar machen. Der Test wird explizit übersprungen. Die Implementierung in `CliRunner` ist korrekt und folgt demselben Muster wie Fall 3 (der auf beiden Plattformen vollständig getestet wird). Das Verhalten bei echten Berechtigungsfehlern auf Windows (z.B. NTFS-ACL) ist vom aktuellen Test nicht abgedeckt.
- **`buildReportContent`-Refactoring:** Die Umstellung auf `buildReportContentWithFileName` ist intern und ändert das nach außen sichtbare Verhalten nicht. Bestehende Tests in `ReportFileWriterTest` wurden nicht gebrochen. Die neu hinzugefügte `ruleId`-Ausgabe (`Regel=...`) in der Befundzeile ist eine Erweiterung des M1-Formats — M9 wird das Format ohnehin final gestalten.
- **Platzhalter `<kein Argument>` und `<mehrere Argumente>`:** Diese Strings enthalten `<>`, die auf Windows als ungültige Pfadzeichen gelten. Durch den Wechsel auf `buildReportContentWithFileName` (kein `Path.of(...)`) ist das Problem gelöst. AP10 (Architekturtest) sollte sicherstellen, dass `ReportFileWriter` kein `Path.of(report.getFileName())` mehr aufruft.
- **Konsolen-Encoding-Problem (Windows, bekannt aus AP07):** Die STDERR-Ausgabe des Minimalberichts enthält Umlaute (`BEDIENFEHLER`, `Fehler`). Auf Windows-Konsolen mit CP1252/OEM437 können diese als Mojibake erscheinen. Die Berichtdatei ist korrekt UTF-8. Bekanntes Windows-Konsolen-Problem, nicht AP08-Scope.
## 7. Empfehlungen für Folge-Arbeitspakete
- **AP10 (Architekturtest):** ArchUnit sollte sicherstellen, dass `ReportFileWriter` kein `Path.of(report.getFileName())` aufruft (wurde in AP08 explizit vermieden). Die drei Negativ-Stack-Trace-Tests könnten als Basis für eine formale „kein Exception-Stacktrace in STDERR"-Regel dienen.
- **AP11 (M1-Abnahme):** End-to-End-Test kann die Bedienfehler-Szenarien prüfen: kein Arg → Exit 2, Berichtdatei nur wenn Verzeichnis bekannt, BEDIENFEHLER im Bericht.
- **M9 (Berichtformat ausbauen):** Die neue `buildReportContentWithFileName`-Methode ist der Erweiterungspunkt für das finale Berichtformat. Die `ruleId`-Ausgabe (`Regel=...`) ist ein Vorgriff und kann in M9 in das finale Format integriert werden.
## 8. Reviewer-Checkliste
- [x] Alle im Arbeitspaket genannten Scope-IN-Punkte sind nachweislich umgesetzt
- [x] Keine Scope-OUT-Punkte wurden angefasst
- [x] Abnahmekriterien sind mit konkreten Nachweisen belegt (Tests, Dateipfade)
- [x] `mvn clean verify` ist grün (218 Tests, 0 Failures)
- [ ] Der Commit für dieses AP hat eine sprechende Message (`M1-AP08: ...`) — ausstehend, Mensch committet
- [x] Keine Regeln der Grunddokumente (Spec, Fachliche, Technik) wurden verletzt
- [x] Rest-Risiken sind ehrlich dokumentiert
@@ -0,0 +1,134 @@
# Abschlussbericht Arbeitspaket AP09 Altlogik einfrieren (Preview-Code deaktivieren)
> **Bezug:** `docs/arbeitspakete/m1/AP09-altlogik-einfrieren.md`
> **Bearbeiter:** Claude Code (claude-sonnet-4-6), Subagent-Lauf
> **Datum:** 2026-04-20
> **Commit(s):** ausstehend (Mensch committet nach Sichtung)
> **Status:** ✅ abgeschlossen
## 1. Zusammenfassung
Die Preview-Validatoren `DefaultStructureValidator` und `DefaultFieldValidator` wurden formell eingefroren: Beide erhalten den normativen JavaDoc-Einfriermarker, und zwei M1-Platzhalter-Implementierungen (`NoOpStructureValidator`, `NoOpFieldValidator`) wurden im Paket `de.gecheckt.asv.bootstrap` angelegt. Ein Integrationstest belegt, dass kein aktiver Lauf über `DefaultInputFileValidator` mit NoOp-Verdrahtung ASVREC-/ASVFEH-Segmentbefunde erzeugt. Der Grep-Nachweis bestätigt: keine funktionale Verdrahtung der Preview-Klassen in `adapter` oder `bootstrap`. `mvn clean verify` ist grün (173 Tests, 0 Fehler).
## 2. Umgesetzte Änderungen
**Neu angelegt:**
- `src/main/java/de/gecheckt/asv/bootstrap/NoOpStructureValidator.java` — M1-Platzhalter; implementiert `StructureValidator`, gibt stets leeres `ValidationResult` zurück; JavaDoc auf Deutsch; null-Guard vorhanden.
- `src/main/java/de/gecheckt/asv/bootstrap/NoOpFieldValidator.java` — M1-Platzhalter; implementiert `FieldValidator`, gibt stets leeres `ValidationResult` zurück; JavaDoc auf Deutsch; null-Guard vorhanden.
- `src/test/java/de/gecheckt/asv/bootstrap/NoOpValidatorsIntegrationTest.java` — 5 Tests: ASVREC-Struktur → keine Befunde, ASVFEH-Struktur → keine Befunde, leere Eingabedatei → keine Befunde, null-Guard NoOpStructureValidator, null-Guard NoOpFieldValidator.
**Geändert (nur JavaDoc, keine Logik):**
- `src/main/java/de/gecheckt/asv/application/structure/DefaultStructureValidator.java` — Einfriermarker-JavaDoc ergänzt: „M3-Vorbau. In M1 bewusst nicht im produktiven Lauf verdrahtet. Wird ab M3 wieder aktiviert und gegen die finalen Regelklassifikationen (V1-V/T/N/K) aus fachliche-anforderungen.md bewertet. @see E-01".
- `src/main/java/de/gecheckt/asv/application/field/DefaultFieldValidator.java` — identischer Einfriermarker-JavaDoc ergänzt.
**Gelöscht:**
- `src/test/java/de/gecheckt/asv/adapter/in/cli/AsvValidatorApplicationTest.java` — seit AP06 leere Hülle (keine `@Test`-Methoden), gemäß AP06-Bericht für AP09 vorgesehen.
- `src/test/java/de/gecheckt/asv/adapter/in/cli/AsvValidatorApplicationAdditionalTest.java` — seit AP06 leere Hülle (keine `@Test`-Methoden), gemäß AP06-Bericht für AP09 vorgesehen.
**Nicht geändert:**
- `src/main/java/de/gecheckt/asv/bootstrap/Main.java``Main` verdrahtet bereits seit AP06 ausschließlich `DummyFileValidationService`; kein Preview-Validator war dort nach AP06 noch verdrahtet. Keine Änderung erforderlich.
## 3. Scope-Treue
| Scope-Punkt aus dem Arbeitspaket | Erfüllt? | Bemerkung |
|---|---|---|
| `NoOpStructureValidator` anlegen | ✅ | `bootstrap`-Paket, leeres `ValidationResult`, JavaDoc Deutsch |
| `NoOpFieldValidator` anlegen | ✅ | `bootstrap`-Paket, leeres `ValidationResult`, JavaDoc Deutsch |
| Bootstrap-Verdrahtung: Preview-Validatoren durch NoOps ersetzen | ✅ | `Main` nutzte nach AP06 schon keine Preview-Validatoren mehr; formale NoOps bereit für `DefaultInputFileValidator`-Pfad in M3 |
| Einfriermarker-JavaDoc in `DefaultStructureValidator` | ✅ | Nur JavaDoc ergänzt, keine Logikänderung |
| Einfriermarker-JavaDoc in `DefaultFieldValidator` | ✅ | Nur JavaDoc ergänzt, keine Logikänderung |
| `DefaultStructureValidatorTestAdditional` löschen | ⚠️ | Klasse enthält 3 aktive `@Test`-Methoden — sie ist NICHT leer (entgegen AP09-Aussage „leere Testklasse"); Löschen wäre ein Scope-Verstoß gegen „aktive Tests der Preview-Klassen bleiben grün". Bewusst nicht gelöscht. Siehe Abschnitt 6. |
| `logs/` in `.gitignore` | ✅ | Bereits durch AP06 eingetragen; keine Änderung erforderlich |
| Aktive Tests der Preview-Klassen bleiben grün | ✅ | 7 Testklassen, 70 Tests für `DefaultStructureValidator` und 9 Tests für `DefaultFieldValidator` weiterhin grün |
| Integrationstest: Lauf erzeugt keine ASVREC-/ASVFEH-Segmentbefunde | ✅ | `NoOpValidatorsIntegrationTest` mit 5 Tests |
| Grep-Nachweis leer (funktionale Verdrahtung) | ✅ | Nur JavaDoc-`@see`-Referenzen in NoOp-Klassen; keine Code-Verdrahtung. Nachweis in Abschnitt 4. |
| Paketumzug der Preview-Klassen (Scope OUT) | ✅ nicht gemacht | Klassen in ihren Originalpaketen belassen |
| Inhaltliche Änderung an `DefaultStructureValidator`/`DefaultFieldValidator` (Scope OUT) | ✅ nicht gemacht | Nur JavaDoc ergänzt |
| Fachliche Neubewertung der 19 Preview-Regeln (Scope OUT) | ✅ nicht gemacht | M3-Aufgabe |
| Löschen von Preview-Klassen (Scope OUT) | ✅ nicht gemacht | Beide Klassen physisch erhalten |
**Wurde der Scope eingehalten?** Ja, mit einer begründeten Abweichung bei `DefaultStructureValidatorTestAdditional` (siehe Abschnitt 6).
**Wurden Dinge außerhalb des Scopes gemacht?** Die leeren Hüllen `AsvValidatorApplicationTest` und `AsvValidatorApplicationAdditionalTest` wurden gelöscht. Dies ist im AP06-Bericht §7 explizit als Aufgabe für AP09 vorgesehen und fällt daher in den Scope.
## 4. Abnahmekriterien
| Abnahmekriterium aus dem Arbeitspaket | Erfüllt? | Nachweis |
|---|---|---|
| `NoOpStructureValidator` und `NoOpFieldValidator` existieren | ✅ | `bootstrap/NoOpStructureValidator.java`, `bootstrap/NoOpFieldValidator.java` |
| `bootstrap.Main` verdrahtet keine Preview-Validatoren mehr | ✅ | `Main.java` enthält keinen Import von `DefaultStructureValidator` oder `DefaultFieldValidator`; verdrahtet ausschließlich `DummyFileValidationService` |
| Grep auf `DefaultStructureValidator`/`DefaultFieldValidator` in `adapter` und `bootstrap` ist leer (Nachweis) | ✅ (mit Einschränkung) | Kommando und Ergebnis: siehe unten. Keine Code-Verdrahtung; nur JavaDoc-Referenzen in NoOp-Klassen. |
| Einfriermarker-JavaDoc in `DefaultStructureValidator` | ✅ | JavaDoc-Block Zeile 119 in `DefaultStructureValidator.java` |
| Einfriermarker-JavaDoc in `DefaultFieldValidator` | ✅ | JavaDoc-Block Zeile 119 in `DefaultFieldValidator.java` |
| `DefaultStructureValidatorTestAdditional` gelöscht | ⚠️ | Klasse enthält 3 aktive Tests — nicht gelöscht (Begründung in Abschnitt 6) |
| Bestehende Tests der Preview-Klassen laufen weiterhin grün | ✅ | 7 Testklassen für `DefaultStructureValidator` (70 Tests), 1 Testklasse für `DefaultFieldValidator` (9 Tests): alle grün |
| Integrationstest: Lauf mit Testdatei erzeugt keine ASVREC-/ASVFEH-Segmentbefunde | ✅ | `NoOpValidatorsIntegrationTest#asvrecStruktur_erzeugtKeineBefunde()` — GRÜN; `@DisplayName("KRITISCH: NoOp-Validatoren erzeugen keine Befunde für ASVREC-Struktur")` |
| `mvn clean verify` grün | ✅ | 173 Tests, 0 Failures, 0 Errors, 0 Skipped |
| Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP09-bericht.md` | ✅ | Diese Datei |
### Grep-Nachweis
Ausgeführtes Kommando:
```
grep -rn "DefaultStructureValidator\|DefaultFieldValidator" \
src/main/java/de/gecheckt/asv/adapter \
src/main/java/de/gecheckt/asv/bootstrap
```
Ergebnis (vollständig):
```
src/main/java/de/gecheckt/asv/bootstrap/NoOpFieldValidator.java:15: * <p>Ab M3 durch {@link de.gecheckt.asv.application.field.DefaultFieldValidator}
src/main/java/de/gecheckt/asv/bootstrap/NoOpFieldValidator.java:19: * @see de.gecheckt.asv.application.field.DefaultFieldValidator
src/main/java/de/gecheckt/asv/bootstrap/NoOpStructureValidator.java:15: * <p>Ab M3 durch {@link de.gecheckt.asv.application.structure.DefaultStructureValidator}
src/main/java/de/gecheckt/asv/bootstrap/NoOpStructureValidator.java:19: * @see de.gecheckt.asv.application.structure.DefaultStructureValidator
```
**Bewertung:** Alle vier Treffer sind ausschließlich JavaDoc-Kommentare (`{@link ...}` und `@see`) — keine Code-Verdrahtung, keine Instanziierung, kein `import`-Statement im Produktionspfad. Der aktive Code referenziert die Preview-Klassen nicht. Das Abnahmekriterium „aktiver Code darf diese Klassen nicht mehr referenzieren" ist erfüllt.
## 5. Build- und Teststatus
- `mvn clean verify`: ✅ grün
- Anzahl Tests gesamt: **173** (davon **5 neu** in `NoOpValidatorsIntegrationTest`)
- Vorherige Testanzahl (vor AP09, nach AP06): 168
- Preview-Tests weiterhin grün:
- `DefaultStructureValidatorTest`: 22 Tests ✅
- `DefaultStructureValidatorAsvfehFhlSegmentTest`: 8 Tests ✅
- `DefaultStructureValidatorAsvrecRechnungsbetragTest`: 7 Tests ✅
- `DefaultStructureValidatorAsvrecRechnungskennzeichenTest`: 12 Tests ✅
- `DefaultStructureValidatorAsvrecSegmentCardinalityTest`: 9 Tests ✅
- `DefaultStructureValidatorAsvrecSegmentOrderTest`: 5 Tests ✅
- `DefaultStructureValidatorAsvrecSegmentsTest`: 7 Tests ✅
- `DefaultStructureValidatorTestAdditional`: 3 Tests ✅ (bewusst nicht gelöscht, siehe Abschnitt 6)
- `DefaultFieldValidatorTest`: 9 Tests ✅
- **Summe Preview-Tests: 82 Tests, alle grün**
- Warnungen beim Build: dieselben wie nach AP06 (Shade-Plugin META-INF-Überlappungen, `sun.reflect.Reflection.getCallerClass`, Annotationsverarbeitung) — keine neuen Warnungen.
## 6. Rest-Risiken und offene Punkte
- **`DefaultStructureValidatorTestAdditional` enthält aktive Tests:** AP09 bezeichnet diese Klasse als „leere Testklasse ohne `@Test`-Methoden" (gemäß AP00-Ist-Analyse). Zum Zeitpunkt des AP09-Laufs enthält sie jedoch 3 aktive `@Test`-Methoden (`validate_shouldNotReportErrorWhenMessageTypeIsASVREC`, `validate_shouldNotReportErrorWhenMessageTypeIsASVFEH`, `validate_shouldReportErrorWhenMessageTypeIsInvalid`). Löschen würde gegen das AP09-Kriterium „aktive Tests der Preview-Klassen bleiben grün" verstoßen. Entscheidung: nicht gelöscht. Empfehlung an Reviewer: Falls die Klasse in einem früheren AP manuell befüllt wurde und die Tests inhaltlich korrekt sind (was sie sind — sie testen STRUCTURE_012-Logik), kann die Klasse als reguläre Testklasse verbleiben. Falls sie tatsächlich gelöscht werden soll, muss ein separater Auftrag mit explizitem OK für den Testverlust erteilt werden.
- **M3-Reaktivierung:** Bei der Wiederaufnahme in M3 ist jede der 19 Preview-Regeln in `DefaultStructureValidator` neu gegen V1-V/T/N/K-Klassifikation zu bewerten. Dies ist kein Risiko von AP09, aber ein kritisches M3-Erbe.
- **`DefaultInputFileValidator` wird in M1 nicht im aktiven Lauf verwendet:** `Main.java` verdrahtet `DummyFileValidationService` direkt; `DefaultInputFileValidator` ist zwar funktional vorhanden und vollständig getestet, aber nicht in den Aufrufpfad eingebunden. In M3 muss `Main.java` auf einen echten `FileValidationService` mit `DefaultInputFileValidator` und den reaktivierten Preview-Validatoren umgestellt werden.
- **`ValidationResult` und `ValidationSeverity` (Altmodell) koexistieren weiterhin:** Die Preview-Klassen und ihre Tests nutzen das Altmodell `application.model.*` (nicht `domain.finding.*`). Dieser Überstand ist bewusst — AP09 soll nur einfrieren, nicht umbauen. Die Ablösung des Altmodells ist M3-Scope.
## 7. Empfehlungen für Folge-Arbeitspakete
- **AP10 (Architekturtest):** Der Einfrierzustand ist formal durch den Grep-Nachweis und den Integrationstest belegt. Ein ArchUnit-Test könnte zusätzlich sicherstellen, dass `adapter` und `bootstrap` keine direkte Abhängigkeit auf `application.structure.DefaultStructureValidator` oder `application.field.DefaultFieldValidator` haben. Dies wäre ein starkes formales Gate gegen versehentliche Reaktivierung.
- **AP11 (M1-Abnahme):** Der M1-Lauf erzeugt keine Fachbefunde mehr. `DummyFileValidationService` liefert stets einen leeren `ValidationReport`. AP11 kann dies in einem End-to-End-Test mit einer Minimaldatei bestätigen (Exit-Code 0, kein Bericht mit Findings).
- **M3:** Beim Wiederaufnehmen die `NoOpStructureValidator`/`NoOpFieldValidator`-Klassen im `bootstrap`-Paket durch die echten Implementierungen ersetzen und `DefaultInputFileValidator` in `Main.java` verdrahten. `DefaultStructureValidatorTestAdditional` kann dann ggf. gelöscht oder in eine reguläre Testklasse umbenannt werden.
## 8. Reviewer-Checkliste
- [x] Alle im Arbeitspaket genannten Scope-IN-Punkte sind nachweislich umgesetzt (mit begründeter Abweichung bei `DefaultStructureValidatorTestAdditional`)
- [x] Keine Scope-OUT-Punkte wurden angefasst
- [x] Abnahmekriterien sind mit konkreten Nachweisen belegt (Grep-Nachweis, Testklassen, Dateipfade)
- [x] `mvn clean verify` ist grün (173 Tests, 0 Failures)
- [ ] Der Commit für dieses AP hat eine sprechende Message (`M1-AP09: ...`) — ausstehend, Mensch committet
- [x] Keine Regeln der Grunddokumente (Spec, Fachliche, Technik) wurden verletzt
- [x] Rest-Risiken sind ehrlich dokumentiert
@@ -0,0 +1,84 @@
# Abschlussbericht Arbeitspaket AP10 Architekturtest
> **Bezug:** `docs/arbeitspakete/m1/AP10-architekturtest.md`
> **Bearbeiter:** Claude Code (claude-sonnet-4-6), Subagent
> **Datum:** 2026-04-20
> **Commit(s):** noch offen (Mensch committet nach Sichtung)
> **Status:** ✅ abgeschlossen
## 1. Zusammenfassung
ArchUnit 1.3.0 wurde als Test-Dependency aufgenommen und die Architekturtest-Klasse `de.gecheckt.asv.ArchitectureTest` mit vier Regeln (AD) implementiert. Alle vier Regeln waren beim ersten Lauf **grün** — es wurden keine Verstöße gefunden. Zusätzlich wurde `src/test/resources/log4j2-test.xml` angelegt (E-02).
## 2. Umgesetzte Änderungen
- `pom.xml` — ArchUnit-Dependency `com.tngtech.archunit:archunit-junit5:1.3.0` (test scope) ergänzt
- `src/test/java/de/gecheckt/asv/ArchitectureTest.java` — neue Testklasse mit Regeln AD (`@AnalyzeClasses`, `@ArchTest`)
- `src/test/resources/log4j2-test.xml` — Test-Log-Konfiguration angelegt (Root level WARN, Console/SYSTEM_ERR); Log4j2 bevorzugt diese Datei im Test-Classpath gegenüber `log4j2.xml`
## 3. Scope-Treue
| Scope-Punkt aus dem Arbeitspaket | Erfüllt? | Bemerkung |
|---|---|---|
| ArchUnit als Test-Dependency | ✅ | `archunit-junit5:1.3.0`, test scope |
| Vier Regeln AD implementiert | ✅ | `ArchitectureTest.java` |
| `log4j2-test.xml` anlegen (E-02) | ✅ | Root level WARN, SYSTEM_ERR |
| Leere Testklassen prüfen und löschen | ✅ | Keine leeren Testklassen gefunden; `DefaultStructureValidatorTestAdditional` hat 4 aktive `@Test`-Methoden (bewusst behalten) |
| Keine neuen Produktionsklassen | ✅ | Kein einziger neuer `.java`-Produktionscode |
| Zyklische Abhängigkeits-Regeln (Scope OUT) | ✅ | Nicht umgesetzt |
| Coverage-/Mutation-Schwellen (Scope Out) | ✅ | Nicht umgesetzt |
**Wurde der Scope eingehalten?** Ja, vollständig.
**Wurden Dinge außerhalb des Scopes gemacht?** Nein.
## 4. Abnahmekriterien
| Abnahmekriterium aus dem Arbeitspaket | Erfüllt? | Nachweis |
|---|---|---|
| ArchUnit als Test-Dependency in `pom.xml` | ✅ | `archunit-junit5:1.3.0`, test scope, `pom.xml` |
| Vier Architekturregeln AD implementiert und grün | ✅ | `Tests run: 4, Failures: 0, Errors: 0` in `de.gecheckt.asv.ArchitectureTest` |
| `log4j2-test.xml` unter `src/test/resources/` | ✅ | `src/test/resources/log4j2-test.xml` |
| Keine leeren Testklassen | ✅ | Alle Testklassen haben mindestens einen `@Test` |
| `mvn clean verify` grün, kein unerwartetes Log-Rauschen | ✅ | `BUILD SUCCESS`, 222 Tests, 0 Failures |
| Bericht dokumentiert erste Ausführung (rot/grün) | ✅ | Siehe Abschnitt 5 unten |
| Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP10-bericht.md` | ✅ | Diese Datei |
## 5. Build- und Teststatus
- `mvn clean verify`: ✅ grün (`BUILD SUCCESS`)
- Anzahl Tests: 222 gesamt (davon 1 Skipped — Windows-bedingter `fall5_dateiNichtLesbar_exitCode2` aus AP08); 4 neu in `ArchitectureTest`
- ArchUnit-Tests beim ersten Lauf: **alle 4 Regeln sofort grün** — keine Verstöße
- Log-Rauschen: Im Maven-Konsolenoutput erscheinen ERROR/WARN-Zeilen aus `CliRunnerOperationalErrorTest` (z.B. `Bedienfehler: Kein Argument übergeben`). Diese stammen vom SLF4J/Log4j2-Logger innerhalb des zu testenden `CliRunner.run()`-Aufrufs. Sie sind fachlich korrekt und erwünscht. Die `log4j2-test.xml` (Root=WARN) unterdrückt INFO/DEBUG-Rauschen; ERROR-Zeilen aus Negativ-Tests bleiben sichtbar — das ist das dokumentierte Verhalten aus E-02. Der Build ist sauber.
- Warnungen beim Build: die üblichen maven-shade-plugin-Überlappungswarnungen (unveränderter Stand seit AP02)
### Erster Lauf der 4 Regeln
Alle vier ArchUnit-Regeln waren beim ersten Lauf sofort grün. Das bestätigt:
- **Regel A (Log4j2-Sichtbarkeit):** `CliRunner` verwendet nur SLF4J (`org.slf4j`), kein direktes Log4j2. `LoggingConfigurator` liegt korrekt in `adapter.out.logging`. `Main` in `bootstrap` verwendet keine Log4j2-Typen direkt.
- **Regel B (Domain-Reinheit):** Keine Domain-Klasse referenziert Adapter oder Bootstrap.
- **Regel C (Application-Reinheit):** Keine Application-Klasse referenziert Adapter oder Bootstrap. (Die Testklassen wurden von `@AnalyzeClasses(..., importOptions = ImportOption.DoNotIncludeTests.class)` ausgeschlossen, sodass `DefaultStructureValidatorTestAdditional` mit seinen Adapter-Importen keine Rolle spielt.)
- **Regel D (Preview-Isolation):** Die `@see`- und `@link`-JavaDoc-Referenzen auf `DefaultStructureValidator` und `DefaultFieldValidator` in `NoOpStructureValidator` und `NoOpFieldValidator` erzeugen **keine** Bytecode-Abhängigkeiten. ArchUnit analysiert Bytecode, nicht JavaDoc — deshalb kein Verstoß.
## 6. Rest-Risiken und offene Punkte
- **Transitiv-Risiko ArchUnit:** ArchUnit analysiert nur direkten Bytecode. Transitive Abhängigkeiten über Reflection oder dynamisches Laden werden nicht erkannt. Für M1 ausreichend.
- **Regel D auf Namensbasis:** Regel D prüft über `haveSimpleNameContaining("DefaultStructureValidator")`. Falls ab M3 neue Klassen mit ähnlichem Namen entstehen, könnte die Regel unbeabsichtigt greifen. Bei M3-Aktivierung überprüfen und ggf. auf Paketnamen-Ebene umstellen.
- **Log-Rauschen in Tests:** Die ERROR/WARN-Zeilen aus `CliRunnerOperationalErrorTest` sind fachlich korrekt (sie testen Bedienfehler-Verhalten), erscheinen aber im Maven-Konsolenoutput. Das ist ein bekanntes Muster bei Tests, die Log4j2-konfigurierte Logger verwenden. Eine vollständige Unterdrückung würde auch echte Fehler verschlucken und ist bewusst nicht angestrebt.
- **SLF4J-Versionsdiskrepanz:** Das Projekt verwendet SLF4J 2.0.7, ArchUnit 1.3.0 zieht SLF4J 2.0.12 als transitive Dependency. Maven wählt 2.0.7 (nächste deklarierte gewinnt). Kein funktionales Problem, aber mittelfristig wäre eine Version-Angleichung empfehlenswert.
## 7. Empfehlungen für Folge-Arbeitspakete
- **AP11 (M1-Abnahme):** Die vier Architekturregeln können als Abnahmekriterium im Bericht gelistet werden — Nachweis: `ArchitectureTest` grün in CI.
- **Ab M3:** Regel D anpassen oder durch eine Paket-basierte Regel ersetzen, wenn `DefaultStructureValidator` und `DefaultFieldValidator` aktiv verdrahtet werden. Dabei sicherstellen, dass kein Adapter direkt auf die Implementierung, sondern nur auf die Interfaces (`StructureValidator`, `FieldValidator`) zugreift.
- **SLF4J-Version:** Bei nächster Dependency-Pflege auf SLF4J 2.0.12 anheben.
## 8. Reviewer-Checkliste
- [x] Alle im Arbeitspaket genannten Scope-IN-Punkte sind nachweislich umgesetzt
- [x] Keine Scope-OUT-Punkte wurden angefasst
- [x] Abnahmekriterien sind mit konkreten Nachweisen belegt (Tests, Dateipfade)
- [x] `mvn clean verify` ist grün (BUILD SUCCESS, 222 Tests, 0 Failures)
- [ ] Der Commit für dieses AP hat eine sprechende Message (`M1-AP10: ...`)
- [x] Keine Regeln der Grunddokumente (Spec, Fachliche, Technik) wurden verletzt
- [x] Rest-Risiken sind ehrlich dokumentiert
@@ -0,0 +1,151 @@
# Abschlussbericht Arbeitspaket AP11 M1-Abnahme
> **Bezug:** `docs/arbeitspakete/m1/AP11-m1-abnahme.md`
> **Bearbeiter:** Claude Code (claude-sonnet-4-6), Subagent-Lauf
> **Datum:** 2026-04-20
> **Commit(s):** ausstehend (Mensch committet nach Sichtung)
> **Status:** ✅ abgeschlossen
## 1. Zusammenfassung
M1 wurde formal abgenommen. Alle sechs Abnahmekriterien aus `meilensteine.md` §„Abnahme von M1" sind erfüllt und nachweisbar dokumentiert. Das Test-Artefakt `test-artefakte/m1/minimal.txt` wurde angelegt, alle fünf End-to-End-Läufe durchgeführt und protokolliert, und der konsolidierte M1-Abschlussbericht unter `docs/arbeitspakete/m1/berichte/M1-abschlussbericht.md` erstellt. `mvn clean verify` ist grün (222 Tests, 0 Failures, 1 Skipped).
## 2. Umgesetzte Änderungen
- `test-artefakte/m1/minimal.txt` — neu angelegt; ISO-8859-15-kompatible Dummy-Textdatei, 5 Zeilen, keine echten ASV-Daten, kein gültiges EDIFACT.
- `docs/arbeitspakete/m1/berichte/AP11-bericht.md` — dieser Bericht.
- `docs/arbeitspakete/m1/berichte/M1-abschlussbericht.md` — konsolidierter M1-Abschlussbericht mit allen Pflichtabschnitten.
Keine Produktionscode-Änderungen. Keine Test-Änderungen. Kein `git tag` gesetzt (CLAUDE.md-Regel, kein commit/tag durch Subagenten).
## 3. Scope-Treue
| Scope-Punkt aus dem Arbeitspaket | Erfüllt? | Bemerkung |
|---|---|---|
| `test-artefakte/m1/minimal.txt` anlegen | ✅ | ISO-8859-15-kompatibel, 5 Zeilen, kein echtes EDIFACT |
| `mvn clean package` ausführen | ✅ | BUILD SUCCESS, JAR `target/asv-format-validator-0.0.1-SNAPSHOT.jar` |
| Alle 5 End-to-End-Läufe mit Exit-Code-Nachweis | ✅ | Alle 5 Läufe protokolliert (§ End-to-End) |
| Meilenstein-Abnahmetabelle vollständig ausgefüllt | ✅ | Im M1-Abschlussbericht |
| Konsolidierter M1-Abschlussbericht mit allen Pflichtabschnitten | ✅ | `M1-abschlussbericht.md` |
| AP11-Bericht nach Vorlage | ✅ | Dieser Bericht |
| Git-Tag `m1-done` NICHT setzen (CLAUDE.md-Regel) | ✅ | Im Bericht dokumentiert |
| Vorgriffe auf M2 (Scope OUT) | ✅ nicht gemacht | — |
| Release-Builds, Signierung (Scope OUT) | ✅ nicht gemacht | — |
**Wurde der Scope eingehalten?** Ja, vollständig.
**Wurden Dinge außerhalb des Scopes gemacht?** Nein.
## 4. Abnahmekriterien
| Abnahmekriterium aus dem Arbeitspaket | Erfüllt? | Nachweis |
|---|---|---|
| `test-artefakte/m1/minimal.txt` existiert | ✅ | `test-artefakte/m1/minimal.txt` angelegt |
| Alle fünf Läufe sind protokolliert | ✅ | Abschnitt 5 unten; vollständig im M1-Abschlussbericht |
| `M1-abschlussbericht.md` existiert mit allen Pflichtabschnitten | ✅ | `docs/arbeitspakete/m1/berichte/M1-abschlussbericht.md` |
| Meilenstein-Abnahmetabelle vollständig, jede Zeile mit Nachweis | ✅ | M1-Abschlussbericht §„Meilenstein-Abnahmetabelle" |
| Kein Exit-Code 3 mehr erreichbar | ✅ | CliRunner-Switch über `Verdict`; keine `return 3`-Stelle im Produktionscode (AP06-Nachweis) |
| `mvn clean verify` grün | ✅ | BUILD SUCCESS, 222 Tests, 0 Failures, 1 Skipped |
| Git-Tag `m1-done` — nicht gesetzt | ✅ | Dokumentiert: Tag wird vom Entwickler nach finaler Sichtung gesetzt |
| Freigabe-Vermerk ist explizit | ✅ | M1-Abschlussbericht §„Freigabe-Vermerk" |
| Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP11-bericht.md` | ✅ | Dieser Bericht |
## 5. End-to-End-Protokoll
Alle Läufe mit JAR `target/asv-format-validator-0.0.1-SNAPSHOT.jar` vom Projekt-Root aus.
### Lauf 1 — Eingabedatei vorhanden (erster Lauf)
```
java -jar target/asv-format-validator-0.0.1-SNAPSHOT.jar test-artefakte/m1/minimal.txt
```
- **Exit-Code:** `0`
- **Ausgabe (stdout):** Prüfbericht mit `Urteil: GÜLTIG`, `Keine Befunde.`, M1-Platzhalter-Hinweis
- **Erzeugte Dateien:** `test-artefakte/m1/minimal.txt.txt`, `test-artefakte/m1/minimal.txt.log`
### Lauf 2 — identischer Aufruf (Suffix-Logik)
```
java -jar target/asv-format-validator-0.0.1-SNAPSHOT.jar test-artefakte/m1/minimal.txt
```
- **Exit-Code:** `0`
- **Ausgabe (stdout):** identisch zu Lauf 1
- **Erzeugte Dateien:** `test-artefakte/m1/minimal.txt_v1.txt`, `test-artefakte/m1/minimal.txt_v1.log`
Nach Lauf 2 vorhandene Dateien im Verzeichnis: `minimal.txt`, `minimal.txt.txt`, `minimal.txt.log`, `minimal.txt_v1.txt`, `minimal.txt_v1.log`
### Lauf 3 — nicht existierende Datei
```
java -jar target/asv-format-validator-0.0.1-SNAPSHOT.jar nicht-vorhanden.txt
```
- **Exit-Code:** `2`
- **Ausgabe (stderr):** `Bedienfehler: Datei nicht gefunden: nicht-vorhanden.txt`
- **Ausgabe (stdout):** Prüfbericht mit `Urteil: BEDIENFEHLER`, `Regel=OPERATIONAL-FILE-NOT-FOUND`
- **Berichtdatei:** `nicht-vorhanden.txt.txt` im aktuellen Verzeichnis (übergeordnetes Verzeichnis bekannt)
### Lauf 4 — kein Argument
```
java -jar target/asv-format-validator-0.0.1-SNAPSHOT.jar
```
- **Exit-Code:** `2`
- **Ausgabe (stderr):** `Bedienfehler: Kein Argument übergeben.`
- **Ausgabe (stdout):** Prüfbericht mit `Urteil: BEDIENFEHLER`, `Regel=OPERATIONAL-MISSING-ARG`
- **Keine Berichtdatei** (kein Verzeichnis bekannt)
### Lauf 5 — zu viele Argumente
```
java -jar target/asv-format-validator-0.0.1-SNAPSHOT.jar datei1.txt datei2.txt
```
- **Exit-Code:** `2`
- **Ausgabe (stderr):** `Bedienfehler: Zu viele Argumente (2).`
- **Ausgabe (stdout):** Prüfbericht mit `Urteil: BEDIENFEHLER`, `Regel=OPERATIONAL-TOO-MANY-ARGS`
- **Keine Berichtdatei** (kein Verzeichnis bekannt)
## 6. Build- und Teststatus
- `mvn clean verify`: ✅ grün (`BUILD SUCCESS`)
- Anzahl Tests: **222** (davon 0 neu in AP11 — kein Produktionscode geändert)
- Fehler / Skipped: 0 Failures / 1 Skipped (Windows-bedingt: `fall5_dateiNichtLesbar_exitCode2` aus AP08)
- Coverage (JaCoCo, informativ): **87 % Line Coverage** (704 / 806 Zeilen), keine Schwellwerte aktiv (M9-Scope)
- Warnungen: Shade-Plugin META-INF-Überlappungen (unverändert seit AP02); `sun.reflect.Reflection.getCallerClass` (Log4j2-interne Warnung beim JAR-Start)
## 7. Rest-Risiken und offene Punkte
- **Git-Tag `m1-done` nicht gesetzt:** Tag wird vom Entwickler nach finaler Sichtung manuell gesetzt (CLAUDE.md §„Harte Regeln: kein git commit/add/push durch Subagenten").
- **Konsolenausgabe-Encoding auf Windows:** Die stdout-Ausgabe erscheint auf Windows-Konsolen mit CP1252/OEM437 mit Mojibake (`G?LTIG` statt `GÜLTIG`). Die Berichtdatei selbst ist korrekt UTF-8. Bekanntes Windows-Konsolen-Problem. Empfehlung: In M9-Dokumentation erwähnen (`chcp 65001` als Workaround).
- **`nicht-vorhanden.txt.txt`** entsteht im Projekt-Root durch Lauf 3. Dies ist korrekt (übergeordnetes Verzeichnis = Projekt-Root war bekannt). Datei kann nach Sichtung gelöscht werden.
- **`logs/asv-format-validator-fallback.log`:** Log4j2-Fallback-Datei aus `log4j2.xml`, entsteht bei Läufen ohne Eingabedatei-Pfad (Lauf 4, 5). Durch `.gitignore`-Eintrag `logs/` nicht versioniert.
- **Konsolidierte Rest-Risiken aus AP01AP10** sind im M1-Abschlussbericht §„Rest-Risiken" vollständig dokumentiert.
## 8. Empfehlungen für Folge-Arbeitspakete
Siehe M1-Abschlussbericht §„Empfehlungen für M2". Wesentliche Punkte:
- M2 baut auf dem ISO-8859-15-Encoding auf, das in AP06 eingeführt wurde.
- Dateinamensschemata und globale Rahmenregeln kommen in M2.
- Architekturtest (ArchUnit) ist aktiv — bei M2-Klassen in `adapter` oder `bootstrap` sicherstellen, dass keine Log4j2-Typen direkt importiert werden.
## 9. Git-Tag-Vermerk
**Tag `m1-done` wurde NICHT gesetzt.** Gemäß CLAUDE.md §„Harte Regeln": Kein `git commit`, `git add` oder `git push` durch den Subagenten. Der Entwickler setzt den Tag nach finaler Sichtung manuell:
```bash
git tag -a m1-done -m "Meilenstein 1 abgeschlossen, siehe docs/arbeitspakete/m1/berichte/M1-abschlussbericht.md"
```
## 10. Reviewer-Checkliste
- [x] Alle im Arbeitspaket genannten Scope-IN-Punkte sind nachweislich umgesetzt
- [x] Keine Scope-OUT-Punkte wurden angefasst
- [x] Abnahmekriterien sind mit konkreten Nachweisen belegt (Tests, Exit-Codes, Dateipfade)
- [x] `mvn clean verify` ist grün (222 Tests, BUILD SUCCESS)
- [ ] Der Commit für dieses AP hat eine sprechende Message (`M1-AP11: M1-Abnahme abgeschlossen`) — ausstehend, Mensch committet
- [x] Keine Regeln der Grunddokumente (Spec, Fachliche, Technik) wurden verletzt
- [x] Rest-Risiken sind ehrlich dokumentiert
@@ -0,0 +1,193 @@
# M1-Abschlussbericht Projektfundament, Logging und Ergebnismodell
> **Meilenstein:** M1
> **Grundlage:** `docs/specs/meilensteine.md` v3
> **Bearbeiter:** Claude Code (claude-sonnet-4-6), Subagenten-Reihe AP01AP11
> **Datum:** 2026-04-20
> **Commit(s):** ausstehend — Mensch committet und taggt nach finaler Sichtung
> **Status:** ✅ abnahmebereit
---
## 1. Zusammenfassung
Meilenstein M1 stellt den tragfähigen technischen Sockel des ASV-Format-Validators bereit. Es wurden in elf aufeinander aufbauenden Arbeitspaketen das Maven-Projekt gehärtet, die hexagonale Paketstruktur etabliert, die SLF4J/Log4j2-Fassade eingeführt, das Befundmodell mit Spec-/Diagnose-Trennung aufgebaut, CLI-Bootstrap und Exit-Codes normiert, Ausgabeartefakte mit Suffix-Logik implementiert, Ministralbericht für Bedienfehler ergänzt, Preview-Altlogik eingefroren sowie ein vollständiger ArchUnit-Architekturtest hinterlegt.
M1 enthält bewusst **keine** EDIFACT-Fachvalidierung. Der `DummyFileValidationService` liest jede Eingabedatei mit ISO-8859-15, gibt einen leeren Validierungsbericht zurück und liefert Exit-Code 0 (GÜLTIG). Die fachliche Tiefe beginnt ab M2 (Artefaktschicht, Dateinamen) und M3 (EDIFACT-Serviceebene). Die Preview-Validatoren (`DefaultStructureValidator`, `DefaultFieldValidator`) sind eingefroren und durch No-Op-Platzhalter ersetzt — sie werden ab M3 reaktiviert und gegen die finalen V1-Regelklassifikationen bewertet.
---
## 2. AP-Übersicht
| AP | Titel | Status | Commit |
|---|---|---|---|
| AP01 | Ist-Stand-Inventar und Delta-Analyse | ✅ | nicht committet — Entwickler committet final |
| AP02 | Build-Infrastruktur härten (SLF4J, JaCoCo, PIT, Shade-Plugin, Mockito-Agent) | ✅ | `d0aac6a` / `61935df` |
| AP03 | Hexagonale Paketstruktur anlegen und Ist-Code migrieren | ✅ | `bd45de8` |
| AP04 | Logging-Adapter: SLF4J-Fassade etabliert | ✅ | `a1a48e9` |
| AP05 | Befundmodell mit Spec-/Diagnose-Trennung | ✅ | ausstehend — Entwickler committet final |
| AP06 | Bootstrap und CLI-Adapter (Exit-Codes 0/1/2, ISO-8859-15, Shade-JAR) | ✅ | ausstehend |
| AP07 | Ausgabeartefakte: Berichtdatei + Log-Datei mit Suffix-Logik | ✅ | ausstehend |
| AP08 | Minimalbericht bei Bedienfehlern (Exit-Code 2) | ✅ | ausstehend |
| AP09 | Altlogik einfrieren (Preview-Validatoren deaktivieren) | ✅ | ausstehend |
| AP10 | Architekturtest (ArchUnit, 4 Regeln) | ✅ | ausstehend |
| AP11 | M1-Abnahme (dieser Bericht) | ✅ | ausstehend |
Hinweis: AP02AP04 haben bereits committete Hashes aus dem Git-Log (`cd6e522`, `a1a48e9`, `bd45de8`, `d0aac6a`, `61935df`). AP05AP11 wurden in einem späteren Subagenten-Lauf bearbeitet; die Commits werden vom Entwickler nach finaler Sichtung gesetzt.
---
## 3. Meilenstein-Abnahmetabelle
| Kriterium | Nachweis | Status |
|---|---|---|
| Anwendung ist als JAR unter Windows mit Java 21 startbar | Lauf 1: `java -jar target/asv-format-validator-0.0.1-SNAPSHOT.jar test-artefakte/m1/minimal.txt` → Exit 0 | ✅ |
| Falsches oder fehlendes Argument → Exit-Code 2 mit Minimalbericht | Lauf 3 (Datei nicht vorhanden → Exit 2), Lauf 4 (kein Arg → Exit 2), Lauf 5 (2 Args → Exit 2) | ✅ |
| Bericht- und Log-Datei im Eingabeverzeichnis mit korrekter Suffix-Logik | Lauf 1: `minimal.txt.txt` + `minimal.txt.log`; Lauf 2: `minimal.txt_v1.txt` + `minimal.txt_v1.log` | ✅ |
| Log4j2-Bindung ist außerhalb von Bootstrap und Logging-Adapter nicht sichtbar | ArchUnit-Test AP10 Regel A: `keinLog4j2AusserInErlaubtenPaketen` → GRÜN; Grep auf `import org.apache.logging.log4j` außerhalb `adapter.out.logging` und `bootstrap` → leer | ✅ |
| Befundmodell trennt Spec-Urteil und diagnostische Weiteranalyse strukturell | Unit-Test AP05: `ValidationReportTest#diagnosticErrorLiefertVALID()` → GRÜN; `FindingKind.SPEC` vs. `FindingKind.DIAGNOSTIC`; `computeVerdict()` ignoriert DIAGNOSTIC | ✅ |
| Build und Tests sind grün | `mvn clean verify` → BUILD SUCCESS, 222 Tests, 0 Failures, 1 Skipped (Windows-bedingt) | ✅ |
---
## 4. End-to-End-Protokoll
JAR: `target/asv-format-validator-0.0.1-SNAPSHOT.jar`
Ausführungsverzeichnis: Projekt-Root `D:\Dev\Projects\asv-format-validator`
### Lauf 1 — Eingabedatei vorhanden, erster Lauf
```
java -jar target/asv-format-validator-0.0.1-SNAPSHOT.jar test-artefakte/m1/minimal.txt
```
| Merkmal | Wert |
|---|---|
| Exit-Code | `0` (GÜLTIG) |
| stdout | Prüfbericht: `Urteil: GÜLTIG`, `Keine Befunde.`, M1-Platzhalter-Hinweis |
| erzeugte Dateien | `test-artefakte/m1/minimal.txt.txt` (UTF-8, ~430 Byte), `test-artefakte/m1/minimal.txt.log` |
### Lauf 2 — identischer Aufruf (Suffix-Logik)
```
java -jar target/asv-format-validator-0.0.1-SNAPSHOT.jar test-artefakte/m1/minimal.txt
```
| Merkmal | Wert |
|---|---|
| Exit-Code | `0` (GÜLTIG) |
| stdout | identisch zu Lauf 1 |
| erzeugte Dateien | `test-artefakte/m1/minimal.txt_v1.txt`, `test-artefakte/m1/minimal.txt_v1.log` |
**Dateien nach Lauf 2:** `minimal.txt`, `minimal.txt.txt`, `minimal.txt.log`, `minimal.txt_v1.txt`, `minimal.txt_v1.log`
### Lauf 3 — nicht existierende Datei
```
java -jar target/asv-format-validator-0.0.1-SNAPSHOT.jar nicht-vorhanden.txt
```
| Merkmal | Wert |
|---|---|
| Exit-Code | `2` (BEDIENFEHLER) |
| stderr | `Bedienfehler: Datei nicht gefunden: nicht-vorhanden.txt` |
| stdout | Prüfbericht: `Urteil: BEDIENFEHLER`, `Regel=OPERATIONAL-FILE-NOT-FOUND` |
| Berichtdatei | `nicht-vorhanden.txt.txt` im Projekt-Root (übergeordnetes Verzeichnis bekannt) |
### Lauf 4 — kein Argument
```
java -jar target/asv-format-validator-0.0.1-SNAPSHOT.jar
```
| Merkmal | Wert |
|---|---|
| Exit-Code | `2` (BEDIENFEHLER) |
| stderr | `Bedienfehler: Kein Argument übergeben.` |
| stdout | Prüfbericht: `Urteil: BEDIENFEHLER`, `Regel=OPERATIONAL-MISSING-ARG` |
| Berichtdatei | keine (kein Eingabeverzeichnis bekannt) |
### Lauf 5 — zu viele Argumente
```
java -jar target/asv-format-validator-0.0.1-SNAPSHOT.jar datei1.txt datei2.txt
```
| Merkmal | Wert |
|---|---|
| Exit-Code | `2` (BEDIENFEHLER) |
| stderr | `Bedienfehler: Zu viele Argumente (2).` |
| stdout | Prüfbericht: `Urteil: BEDIENFEHLER`, `Regel=OPERATIONAL-TOO-MANY-ARGS` |
| Berichtdatei | keine (kein Eingabeverzeichnis bekannt) |
---
## 5. Quality-Metriken
> Alle Metriken informativ. Quality-Gates mit Schwellwerten gelten erst ab M9.
| Metrik | Wert |
|---|---|
| Testanzahl gesamt | 222 |
| Failures | 0 |
| Errors | 0 |
| Skipped | 1 (Windows-bedingt: `fall5_dateiNichtLesbar_exitCode2` aus AP08; `setReadable(false)` ohne Wirkung für eigenen Prozess) |
| Line Coverage (JaCoCo, gesamt) | **87 %** (704 / 806 Zeilen) |
| Instruction Coverage (JaCoCo) | informativ, kein Gate |
| PIT Mutation-Score (einmalig AP02) | 83 % (249 Mutationen, 207 getötet) — Stand vor AP05AP10 |
| Build-Dauer (`mvn clean verify`) | ~16 s |
---
## 6. Rest-Risiken (konsolidiert aus AP01AP10)
| Risiko | Quelle | Auswirkung | M2/M3-Handlungsbedarf |
|---|---|---|---|
| `DefaultSegmentLineTokenizer` trennt starr an `+`; UNA-Segment nicht ausgewertet | AP01, AP00 | Falscher Parse für nicht-EDIFACT-Dateien ab M3 | M3: Tokenizer gegen UNA-bewusstes Pendant ersetzen |
| `DefaultInputFileParser` erzeugt immer genau eine Message pro Datei | AP01 | Nur Preview-Parser; nicht real für mehrere UNH/UNT-Paare | M3: Parser auf Nachrichtenerkennung erweitern |
| `DefaultStructureValidatorTestAdditional` hat 3 aktive Tests — nicht aus AP09 gelöscht | AP09, AP10 | Minimales Rauschen; Tests sind inhaltlich korrekt (STRUCTURE_012-Logik) | M3: bei Reaktivierung der Preview-Validatoren entscheiden |
| Preview-Regeln (`DefaultStructureValidator`) noch nicht gegen V1-V/T/N/K bewertet | AP09 | Einige der 19 Regeln könnten bei M3-Aktivierung zu rigide sein | M3: jede Regel neu klassifizieren |
| `ValidationResult`/`ValidationSeverity` (Altmodell in `application.model`) koexistieren mit neuem `domain.finding` | AP05, AP09 | Zwei parallele Ergebnistypen; Preview-Code nutzt Altmodell | M3: Altmodell ablösen oder vollständig migrieren |
| `LoggingConfigurator.configureLogFile(Path)` erzeugt Windows-TempDir-Lock in Tests | AP07 | Lösung durch Mockito-Mock in `CliRunnerTest` / `CliRunnerOutputArtifactsTest`; echte Konfiguration durch JAR-Test bestätigt | AP10 (erledigt): Mock ist Workaround; bei M9-Testausbau beachten |
| Konsolenausgabe-Encoding auf Windows (Mojibake bei Umlauten) | AP07, AP08 | Berichtdatei korrekt UTF-8; nur sichtbares Darstellungsproblem in `cmd.exe`/`powershell.exe` | M9: Dokumentation (`chcp 65001`-Hinweis) |
| SLF4J-Versionsdiskrepanz: Projekt 2.0.7, ArchUnit zieht 2.0.12 | AP10 | Kein funktionales Problem; Maven wählt 2.0.7 | M9 oder früher: Versions-Angleichung bei Dependency-Pflege |
| `sun.reflect.Reflection.getCallerClass`-Warnung im JAR-Betrieb | AP06 | Log4j2-interne Performance-Warnung; kein Fehler | M9: Log4j2-Upgrade auf 2.23+ optional |
| Shade-Plugin erzeugt Überlappungswarnungen bei META-INF-Ressourcen | AP06 | Kosmetisch; kein Fehler; bekanntes Fat-JAR-Verhalten | bleibt bis M9; kein Handlungsbedarf |
| Fall 5 (Datei nicht lesbar) nur auf Unix testbar | AP08 | Windows: `setReadable(false)` ohne Wirkung für eigenen Prozess; Test explizit übersprungen | M9: NTFS-ACL-basierter Testansatz falls benötigt |
---
## 7. Empfehlungen für M2
- **ISO-8859-15 ist etabliert** (AP06): M2 kann darauf aufbauen. `DummyFileValidationService.INPUT_CHARSET = Charset.forName("ISO-8859-15")` ist paketöffentlich für Testbarkeit.
- **Dateinamensschemata** (unverschlüsselt: `B<VKNR>...`, verschlüsselt: `<IK>_<IK>_<E|T>ASV0<Zähler>`, Auftragsdatei: `.AUF`) kommen in M2 als harte Prüfregeln.
- **`adapter.out.filesystem`** ist angelegt aber leer. M2 füllt es mit dem Dateizugriffs-Adapter (read-only, ISO-8859-15, Artefaktklassifikation).
- **ArchUnit-Regeln AD** sind aktiv. Bei neuen M2-Klassen in `adapter` oder `bootstrap` sicherstellen, dass keine Log4j2-Direktimporte vorkommen (Regel A) und dass `domain`/`application` keine Adapter-Abhängigkeiten bekommen (Regeln B/C).
- **Regel D** (Preview-Isolation) referenziert `DefaultStructureValidator` und `DefaultFieldValidator` namentlich. Ab M3, wenn diese Klassen reaktiviert werden, Regel D auf Paket-Basis umstellen.
- **`ValidationResult`/`ValidationReport` Koexistenz**: M2 sollte ausschließlich `ValidationReport` (neues Befundmodell) für neue Befunde verwenden. Die Ablösung des Altmodells ist M3-Scope.
- **Exit-Code 3 nicht mehr erreichbar** (AP06-Nachweis). M2 muss diesen Zustand bewahren.
- **Partnerdatei-Ableitung** (deterministisch, nicht heuristisch) ist M2-Scope — AP11 liefert keine Vorarbeit dafür.
- **Übermittlungszähler-Prüfung** (001999, keine quartalsübergreifende Sequenz in V1) kommt in M2.
---
## 8. Freigabe-Vermerk
**M1 ist abnahmebereit.**
Alle sechs Abnahmekriterien aus `meilensteine.md` v3 §„Abnahme von M1" sind erfüllt:
1. Anwendung als JAR unter Windows mit Java 21 startbar — ✅ (Lauf 1, Exit-Code 0)
2. Falsches/fehlendes Argument → Exit-Code 2 mit Minimalbericht — ✅ (Läufe 3, 4, 5)
3. Bericht- und Log-Datei im Eingabeverzeichnis mit korrekter Suffix-Logik — ✅ (Läufe 1+2)
4. Log4j2-Bindung außerhalb Bootstrap/Logging-Adapter nicht sichtbar — ✅ (ArchUnit Regel A)
5. Befundmodell trennt Spec-Urteil und Diagnose strukturell — ✅ (`diagnosticErrorLiefertVALID` GRÜN)
6. Build und Tests grün — ✅ (222 Tests, 0 Failures)
Der einzige Skipped-Test (`fall5_dateiNichtLesbar_exitCode2`) ist Windows-plattformbedingt und enthält ein explizites `assumeTrue(...)`. Er ist kein Blocker.
**Git-Tag `m1-done` wurde NICHT gesetzt.** Gemäß CLAUDE.md §„Harte Regeln" setzt kein Subagent `git commit`, `git add` oder `git push`. Der Entwickler setzt den Tag nach finaler Sichtung der Berichte manuell:
```bash
git tag -a m1-done -m "Meilenstein 1 abgeschlossen, siehe docs/arbeitspakete/m1/berichte/M1-abschlussbericht.md"
```