194 lines
12 KiB
Markdown
194 lines
12 KiB
Markdown
# M1-Abschlussbericht – Projektfundament, Logging und Ergebnismodell
|
||
|
||
> **Meilenstein:** M1
|
||
> **Grundlage:** `docs/specs/meilensteine.md` v3
|
||
> **Bearbeiter:** Claude Code (claude-sonnet-4-6), Subagenten-Reihe AP01–AP11
|
||
> **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: AP02–AP04 haben bereits committete Hashes aus dem Git-Log (`cd6e522`, `a1a48e9`, `bd45de8`, `d0aac6a`, `61935df`). AP05–AP11 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 AP05–AP10 |
|
||
| Build-Dauer (`mvn clean verify`) | ~16 s |
|
||
|
||
---
|
||
|
||
## 6. Rest-Risiken (konsolidiert aus AP01–AP10)
|
||
|
||
| 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 A–D** 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** (001–999, 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"
|
||
```
|