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
@@ -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"
```