37 KiB
V1.1 – Arbeitspakete
Aktive Erweiterung: Zusätzliche KI-Provider-Familie Anthropic Claude über die native Messages API, neben der bestehenden OpenAI-kompatiblen Anbindung. Bewusst minimale Erweiterung des freigegebenen Basisstands.
Ablage im Repository:
docs/workpackages/V1.1 - Arbeitspakete.md
0. Lesereihenfolge für jedes Arbeitspaket
Vor jedem AP vollständig lesen:
CLAUDE.mddocs/specs/technik-und-architektur.mddocs/specs/fachliche-anforderungen.md- dieses Dokument: Abschnitte 1 bis 6
- nur das aktive Arbeitspaket aus Abschnitt 7
Nicht vorgreifen. Nicht raten. Bei echter Unklarheit knapp benennen statt erfinden.
1. Arbeitsweise (verbindlich)
Diese Regeln ersetzen die nicht vorhandene WORKFLOW.md und gelten für alle APs in diesem Dokument.
1.1 Scope-Disziplin
- Es wird ausschließlich das aktive Arbeitspaket umgesetzt.
- Keine Inhalte späterer Arbeitspakete vorwegnehmen.
- Keine kosmetischen Refactorings ohne direkten Bezug zum AP.
- Keine Umbenennungen außerhalb des AP-Scopes.
- Vor Änderungen die betroffenen Klassen über Typsuche im Repo lokalisieren, nicht über vermutete Pfade.
1.2 Build- und Testpflicht
Build-Kommando vom Projekt-Root, identisch für alle APs:
.\mvnw.cmd clean verify -pl pdf-umbenenner-domain,pdf-umbenenner-application,pdf-umbenenner-adapter-out,pdf-umbenenner-adapter-in-cli,pdf-umbenenner-bootstrap --also-make
- Nach jeder substanziellen Änderung: Build ausführen.
- Vor Abschluss eines AP: Build muss fehlerfrei sein, alle Tests grün.
- Schlägt der Build fehl: Ursache sauber beheben, nicht kaschieren.
- Bestehende Tests dürfen nicht stillschweigend gelöscht oder deaktiviert werden. Sie werden bei Bedarf angepasst und der Grund wird im AP-Output dokumentiert.
1.3 Pflicht-Tests pro AP
- Jede neue Klasse mit fachlich oder technisch relevanter Logik bekommt mindestens einen Unit-Test.
- Jede in einem AP geänderte Klasse, die bisher Tests hatte, behält Tests; betroffene Tests werden angepasst.
- Pro AP gibt es eine Liste kritischer Pflicht-Testfälle (siehe jeweiliges AP). Diese sind namentlich umzusetzen.
- Darüber hinaus gilt die übliche Repo-Praxis (Coverage, PIT-Mutationstests in den unmittelbar betroffenen Modulen, soweit bereits etabliert).
1.4 Dokumentation
Pro AP werden mitgepflegt, soweit relevant:
- JavaDoc und
package-infoder berührten Klassen - Konfigurationsbeispiele
- unmittelbar betroffene Repository-Dokumente
1.5 Naming-Regel
In Code, Kommentaren und JavaDoc dürfen keine Versions- oder AP-Bezeichner erscheinen:
- Verboten:
V1.0,V1.1,M1–M8,AP-001…AP-006 - Stattdessen: zeitlose technische Bezeichnungen.
1.6 Pflicht-Output-Format am Ende jedes AP
Am Ende der AP-Bearbeitung gibt Sonnet genau diesen Block aus:
- Scope erfüllt: ja/nein
- Geänderte Dateien:
- <Pfad>
- ...
- Neue Dateien:
- <Pfad>
- ...
- Build-Kommando: <verwendetes Kommando>
- Build-Status: ERFOLGREICH / FEHLGESCHLAGEN
- Pflicht-Tests umgesetzt: <Liste der namentlich geforderten Testfälle>
- Offene Punkte: keine / <Beschreibung>
- Risiken: keine / <Beschreibung>
2. Erweiterungsziel und Nicht-Ziele
2.1 Ziel
- Der bestehende OpenAI-kompatible KI-Weg bleibt unverändert nutzbar.
- Zusätzlich wird die native Anthropic Messages API als zweite, gleichwertig unterstützte Provider-Familie integriert.
- Genau ein Provider ist pro Lauf aktiv – ausschließlich über Konfiguration.
- Kein automatischer Fallback, keine Parallelnutzung, keine Profilverwaltung.
- Der fachliche KI-Vertrag (
NamingProposal) bleibt unverändert. - Bestehende Properties-Dateien werden beim ersten Start kontrolliert ins neue Schema migriert; vorher wird automatisch eine
.bak-Sicherung angelegt.
2.2 Explizit nicht Bestandteil
- Provider-Familien jenseits der zwei explizit unterstützten
- Profilverwaltung mit mehreren Konfigurationen je Provider-Familie
- automatische Fallback-Umschaltung
- parallele Nutzung mehrerer Provider in einem Lauf
- Änderung des fachlichen Ergebnisvertrags
- Änderung der Dateinamensregeln, Retry-Regeln, Batch-Betriebsmodells
- Persistenz- oder Schemaänderungen jenseits der einen additiven Provider-Identifikator-Spalte
2.3 Architekturtreue (unverhandelbar)
- strikte hexagonale Architektur, Abhängigkeiten zeigen nach innen
AiNamingPortbleibt provider-neutral- provider-spezifische Endpunkte, Header, Auth, Request-/Response-Formate leben ausschließlich im jeweiligen Adapter-Out
- keine direkte Adapter-zu-Adapter-Kopplung, keine gemeinsame „abstrakte KI-Adapter"-Zwischenschicht
- die Provider-Auswahl ist eine Bootstrap-Verdrahtungsentscheidung
3. Zielzustand der Konfiguration (verbindlich)
3.1 Properties-Schema
# bestehende, unveränderte Parameter
source.folder=...
target.folder=...
sqlite.file=...
max.retries.transient=...
max.pages=...
max.text.characters=...
prompt.template.file=...
runtime.lock.file=...
log.directory=...
log.level=...
log.ai.sensitive=...
# neue Provider-Auswahl (Pflicht)
ai.provider.active=openai-compatible
# OpenAI-kompatible Provider-Familie
ai.provider.openai-compatible.baseUrl=...
ai.provider.openai-compatible.model=...
ai.provider.openai-compatible.timeoutSeconds=...
ai.provider.openai-compatible.apiKey=...
# Anthropic-Provider-Familie (Claude)
ai.provider.claude.baseUrl=https://api.anthropic.com
ai.provider.claude.model=...
ai.provider.claude.timeoutSeconds=...
ai.provider.claude.apiKey=...
3.2 Zulässige Werte für ai.provider.active
openai-compatibleclaude
Jeder andere Wert ist eine ungültige Startkonfiguration und führt zu Exit-Code 1.
3.3 Pflichtwerte je aktivem Provider
| Provider | Pflicht | Optional / mit Default |
|---|---|---|
openai-compatible |
baseUrl, model, timeoutSeconds, apiKey (Env hat Vorrang) |
– |
claude |
model, timeoutSeconds, apiKey (Env hat Vorrang) |
baseUrl (Default https://api.anthropic.com) |
Für den inaktiven Provider werden keine Pflichtwerte erzwungen.
3.4 Umgebungsvariablen für API-Schlüssel
| Provider | Umgebungsvariable |
|---|---|
openai-compatible |
OPENAI_COMPATIBLE_API_KEY |
claude |
ANTHROPIC_API_KEY |
- Pro Provider gilt: Umgebungsvariable hat Vorrang vor dem Properties-Wert derselben Provider-Familie.
- Schlüssel verschiedener Provider werden niemals vermischt.
- Wenn der Betrieb bisher eine andere Umgebungsvariable für den OpenAI-kompatiblen Key genutzt hat, ist diese vom Betreiber auf
OPENAI_COMPATIBLE_API_KEYumzustellen. Das ist im Abschlussnachweis (AP-006) zu dokumentieren.
3.5 Legacy-Form (vor V1.1)
Eindeutig erkennbar an mindestens einem der flachen Schlüssel:
api.baseUrl
api.model
api.timeoutSeconds
api.key
ohne Vorhandensein von ai.provider.active.
4. Anthropic Messages API – verbindlicher technischer Faktenblock
Quelle: offizielle Claude API-Dokumentation. Diese Werte sind verbindlich und nicht zu erfinden, abzuleiten oder zu „verbessern".
4.1 Endpoint und Methode
- Methode:
POST - URL:
{baseUrl}/v1/messages - Default-
baseUrl:https://api.anthropic.com
4.2 Pflicht-Header
| Header | Wert |
|---|---|
x-api-key |
API-Schlüssel aus ANTHROPIC_API_KEY (Env) bzw. ai.provider.claude.apiKey (Properties) |
anthropic-version |
2023-06-01 |
content-type |
application/json |
Nicht Authorization: Bearer … verwenden. Anthropic nutzt x-api-key.
4.3 Request-Body (relevante Felder)
{
"model": "<modellname aus ai.provider.claude.model>",
"max_tokens": <Integer, > 0, Pflicht>,
"system": "<optional, top-level Feld - NICHT als Message mit role=system>",
"messages": [
{ "role": "user", "content": "<Prompt-Text>" }
]
}
max_tokensist Pflicht (Unterschied zu OpenAI). Konkreter Wert: zweckmäßig fest verdrahtet im Adapter, ausreichend groß für die JSON-Antwort der Anwendung. Kein neuer Properties-Schlüssel.systemwird nicht als Message mitrole=systemmodelliert. Anthropic akzeptiert nuruserundassistantimmessages-Array; ein System-Prompt geht ausschließlich ins Top-Level-Feldsystem.- Der bestehende Prompt der Anwendung wird unverändert als Inhalt der einen
user-Message übergeben. Falls der bestehende Prompt-Mechanismus eine System-Komponente kennt, wandert diese in dassystem-Feld; sonst bleibtsystemweg.
4.4 Response-Body (relevante Felder)
{
"id": "...",
"type": "message",
"role": "assistant",
"content": [
{ "type": "text", "text": "<die eigentliche Antwort>" }
],
"stop_reason": "...",
"usage": { "input_tokens": 0, "output_tokens": 0 }
}
- Der für die Anwendung relevante Text wird konkateniert aus allen Blöcken in
contentmittype == "text"in Reihenfolge gewonnen. - Andere Block-Typen werden ignoriert.
- Liefert die API kein einziges
text-Block, ist das ein technischer Fehler des Adapters (klassifiziert wie ein leerer/unbrauchbarer Antwortinhalt).
4.5 Fehlerklassifikation im Claude-Adapter
| Symptom | Klassifikation | Anmerkung |
|---|---|---|
| HTTP 4xx (außer 429) | technischer Fehler | Auth-Fehler (401/403) zählen hier rein |
| HTTP 429 | technischer Fehler | rate limit |
| HTTP 5xx | technischer Fehler | |
| Timeout | technischer Fehler | |
| Verbindung fehlgeschlagen | technischer Fehler | |
| JSON nicht parsebar | technischer Fehler | |
Kein content[*].text-Block |
technischer Fehler | |
Antworttext nicht nach NamingProposal parsebar |
greift bestehende Antwort-Validierung der Application | nicht im Adapter behandeln |
Alle technischen Adapterfehler werden auf die bestehende transiente Fehlersemantik der Anwendung abgebildet. Es entsteht keine neue Fehlerkategorie.
5. Verbindliche Regeln für jedes AP
- Minimale Erweiterung. Nichts ändern, was nicht für die Erweiterung zwingend erforderlich ist.
- Einheitlicher fachlicher KI-Vertrag.
NamingProposalbleibt unverändert. Keine provider-spezifische Verzweigung in Application/Domain. - Genau ein aktiver Provider. Kein Fallback, keine Profilverwaltung.
- Properties-Datei bleibt führend. Keine alternative Konfigurationsquelle.
- Bestehender OpenAI-Pfad bleibt funktional unverändert.
- Architekturgrenzen (siehe 2.3) werden niemals durchbrochen.
- Rückwärtsverträglichkeit der SQLite-Daten bleibt erhalten.
- Build muss am Ende jedes AP fehlerfrei sein.
- Alle Pflicht-Testfälle des AP sind umgesetzt.
6. Granularität und Reihenfolge
Sechs Arbeitspakete in dieser zwingenden Reihenfolge:
| AP | Thema | Risiko | Charakter |
|---|---|---|---|
| AP-001 | Konfigurations-Schema einführen (additiv) | niedrig | reine Erweiterung |
| AP-002 | Legacy-Migration mit .bak |
mittel | Datei-Umschreibung, geschützt durch Sicherung |
| AP-003 | Bootstrap-Provider-Auswahl + bestehender Adapter umschalten | hoch | Verhaltensänderung im Wiring |
| AP-004 | Persistenz: Provider-Identifikator additiv | mittel | additive DB-Schema-Migration |
| AP-005 | Nativer Anthropic-Adapter implementieren und verdrahten | mittel | neue Adapter-Klasse |
| AP-006 | Regression, Smoke, Doku, Abschlussnachweis | niedrig | Absicherung |
7. Arbeitspakete
AP-001 – Konfigurations-Schema einführen (additiv)
Voraussetzung
Keine.
Ziel
Das neue, verschachtelte Properties-Schema (Abschnitt 3.1) wird im Code als parsbare und validierbare Struktur eingeführt. Der bestehende Lese- und Validierungspfad bleibt unangetastet – das neue Schema wird parallel additiv eingeführt. Es findet kein Wechsel im Bootstrap und keine Migration in diesem AP.
Konkret zu erledigende Schritte
- Im Modul
pdf-umbenenner-application(oder dem Modul, in dem die heutigen Configuration-Klassen leben – per Typsuche lokalisieren) neue Konfigurationstypen einführen, mindestens:- eine Repräsentation einer einzelnen Provider-Konfiguration (Felder:
model,timeoutSeconds,baseUrl,apiKey) - eine Repräsentation der Provider-Auswahl (
activeProviderId) plus Map oder zwei Felder für die beiden Provider-Familien - einen klar benannten Aufzählungstyp oder konstanten String-Set für die zulässigen Werte
openai-compatibleundclaude
- eine Repräsentation einer einzelnen Provider-Konfiguration (Felder:
- Im Adapter-Out-Modul den Properties-Parser so erweitern, dass er die neuen Schlüssel aus Abschnitt 3.1 erkennt und in die neuen Typen aus Schritt 1 einliest. Der bestehende Parser für die alten flachen Schlüssel bleibt unverändert lauffähig (parallele Erkennung).
- Eine Validierung für die neuen Typen einführen. Sie prüft:
ai.provider.activeist gesetzt und ein zulässiger Wert- alle Pflichtwerte des aktiven Providers sind vorhanden (Tabelle 3.3)
timeoutSecondsist eine positive Ganzzahl- für Claude: Default-
baseUrlwird gesetzt, wenn der Wert fehlt - für den inaktiven Provider werden keine Pflichtwerte erzwungen
- API-Schlüssel-Auflösung: Umgebungsvariable des aktiven Providers (Tabelle 3.4) hat Vorrang vor dem Properties-Wert; ist beides leer, ist die Konfiguration ungültig
- Bootstrap und bestehende Adapter werden in diesem AP nicht umgestellt. Die neuen Typen sind ausschließlich über neue Tests erreichbar. Der Default-Lauf der Anwendung verwendet weiterhin die alten Klassen.
- JavaDoc für alle neuen Klassen und Methoden ergänzen.
- Konfigurationsbeispiel (
*.example.propertieso.ä.) nicht in diesem AP ändern. Folgt in AP-002 zusammen mit der Migration.
Pflicht-Testfälle (kritisch, namentlich umzusetzen)
parsesNewSchemaWithOpenAiCompatibleActive– vollständiges neues Schema, OpenAI aktiv, alle Pflichtwerte gesetzt → erfolgreich geparst, Validierung grün.parsesNewSchemaWithClaudeActive– vollständiges neues Schema, Claude aktiv, alle Pflichtwerte gesetzt → erfolgreich geparst, Validierung grün.claudeBaseUrlDefaultsWhenMissing– Claude aktiv,ai.provider.claude.baseUrlfehlt → Defaulthttps://api.anthropic.comwird gesetzt, Validierung grün.rejectsMissingActiveProvider–ai.provider.activefehlt → Validierung schlägt fehl mit klarer Meldung.rejectsUnknownActiveProvider–ai.provider.active=foo→ Validierung schlägt fehl.rejectsMissingMandatoryFieldForActiveProvider– aktiver Provider hat ein Pflichtfeld leer → Validierung schlägt fehl.acceptsMissingMandatoryFieldForInactiveProvider– inaktiver Provider unvollständig → Validierung grün.envVarOverridesPropertiesApiKeyForActiveProvider–OPENAI_COMPATIBLE_API_KEYgesetzt, Properties-Key ebenfalls gesetzt → effektiver Key ist der aus der Env-Var. Analog fürANTHROPIC_API_KEY.envVarOnlyResolvesForActiveProvider– Env-Var nur für inaktiven Provider gesetzt, aktiver Provider hat Properties-Key → effektiver Key ist der Properties-Key des aktiven Providers; die Env-Var des inaktiven Providers wird ignoriert.bestehende Tests bleiben grün– alle bisherigen Configuration-Tests laufen weiter.
Test-Kategorien zusätzlich: Unit-Tests für die neuen Typen (Equality, Defaults), Parser-Tests, Validator-Tests.
Explizit NICHT Teil dieses AP
- Migration der Legacy-Datei
.bak-Sicherung- Bootstrap-Umstellung
- Änderung am bestehenden OpenAI-Adapter
- nativer Claude-Adapter
- Persistenz-Änderungen
- Logging-Änderungen
Definition of Done
- Build fehlerfrei
- alle Pflicht-Testfälle umgesetzt und grün
- bestehende Tests grün
- JavaDoc vollständig für neue Klassen
- Pflicht-Output-Block ausgegeben
AP-002 – Legacy-Migration mit .bak
Voraussetzung
AP-001 abgeschlossen.
Ziel
Beim ersten Start mit erkannter Legacy-Form wird die Properties-Datei kontrolliert in das neue Schema überführt. Vor jeder Migration wird eine .bak-Sicherung angelegt. Nach erfolgreicher Migration läuft die Anwendung noch auf dem alten Bootstrap-Pfad weiter (Umschaltung folgt in AP-003); aber die Datei auf der Platte ist bereits im neuen Format und beim nächsten Start sofort durch das neue Schema lesbar.
Konkret zu erledigende Schritte
- Eine neue Komponente im Adapter-Out-Modul anlegen, die rein auf Properties-Datei-Ebene arbeitet (kein HTTP, kein DB-Zugriff). Verantwortlichkeiten:
- Erkennen der Legacy-Form (Abschnitt 3.5)
.bak-Sicherung anlegen:<dateiname>.bak. Wenn.bakschon existiert, mit aufsteigendem numerischen Suffix sichern (<dateiname>.bak,<dateiname>.bak.1, …) – niemals überschreiben.- Werte umschreiben gemäß Tabelle:
Legacy Ziel api.baseUrlai.provider.openai-compatible.baseUrlapi.modelai.provider.openai-compatible.modelapi.timeoutSecondsai.provider.openai-compatible.timeoutSecondsapi.keyai.provider.openai-compatible.apiKey ai.provider.active=openai-compatibleergänzen.- Leere/auskommentierte Platzhalter für die Claude-Sektion einfügen mit kurzem Hinweis-Kommentar (ein Block, max. 6 Zeilen).
- Alle übrigen Schlüssel (
source.folder,target.folder,sqlite.file,max.*,prompt.template.file,runtime.lock.file,log.*) unverändert und in stabiler Reihenfolge übernehmen. - Die migrierte Datei in-place schreiben (
.tmp+ atomischer Move/Rename, kein Truncate-and-write auf das Original). - Anschließend die Datei erneut über den neuen Parser aus AP-001 laden und über den neuen Validator validieren. Schlägt das fehl, ist dies ein harter Startfehler (Exit-Code 1, klare Meldung,
.bakbleibt erhalten).
- Die Migration wird beim Programmstart vor dem bestehenden Konfigurationsladen aufgerufen, sobald die Datei bekannt ist. Dieser Aufruf passiert im Bootstrap genau an einer Stelle und ist als eigene Methode klar benennbar.
- Wird kein Legacy erkannt (also bereits neues Schema), passiert nichts: keine
.bak, keine Schreibvorgänge. - Bestehende ConfigurationPort-Implementierung nicht umstellen – das passiert in AP-003. Die Anwendung läuft nach AP-002 fachlich weiter wie zuvor; ihr Eingangs-File ist nur jetzt in beiden Formen lesbar.
- Konfigurationsbeispiel im Repo (z. B.
*.example.properties) auf das neue Schema umstellen. Die Datei zeigt beide Provider-Sektionen mit sprechenden Platzhalterwerten. - JavaDoc und kurzer Abschnitt in der Repo-Doku zur Migration ergänzen (was passiert, wann, wie wird gesichert, was bei Fehler).
Pflicht-Testfälle
migratesLegacyFileWithAllFlatKeys– Legacy-Datei mit allen vierapi.*-Schlüsseln wird korrekt ins neue Schema überführt; Werte bleiben inhaltlich identisch; übrige Schlüssel bleiben unverändert.createsBakBeforeOverwriting– vor Migration existiert keine.bak, danach existiert sie mit dem Original-Inhalt.bakSuffixIsIncrementedIfBakExists–.bakexistiert bereits → neue Sicherung als.bak.1. Keine Sicherung wird überschrieben.noOpForAlreadyMigratedFile– Datei bereits im neuen Schema → kein Schreibvorgang, kein.bak.reloadAfterMigrationSucceeds– nach Migration kann der neue Parser/Validator aus AP-001 die Datei fehlerfrei laden.migrationFailureKeepsBak– Migration schreibt fehlerhafte Datei (Test-Mock erzwingt Validierungsfehler nach Schreiben) → Bootstrap meldet harten Startfehler,.bakist unangetastet.legacyDetectionRequiresAtLeastOneFlatKey– Datei mitai.provider.active=...und ohneapi.*→ kein Legacy, keine Migration.legacyValuesEndUpInOpenAiCompatibleNamespace– Werteapi.baseUrl,api.model,api.timeoutSeconds,api.keylanden exakt in den vier Zielschlüsseln;ai.provider.active=openai-compatibleist gesetzt.unrelatedKeysSurviveUnchanged– Schlüssel wiesource.folder,max.pages,log.levelbleiben mit identischem Wert erhalten.inPlaceWriteIsAtomic– Test-Doppel für das Dateisystem belegt: erst.tmpschreiben, dann atomic move; kein Punkt, an dem das Original teilbeschrieben ist.
Test-Kategorien zusätzlich: temporäre Dateien in @TempDir, Repository-/Integrationstests für die Migrations-Komponente.
Explizit NICHT Teil
- Bootstrap-Umstellung des aktiven Konfigurationspfads
- Änderung am bestehenden OpenAI-Adapter
- Claude-Adapter
- Persistenz
- Logging-Änderungen über die Migrations-Meldungen hinaus
Definition of Done
- Build fehlerfrei, alle Pflicht-Testfälle grün
- Beispiel-Properties-Datei im neuen Schema
- Kurz-Doku zur Migration im Repo
- Pflicht-Output-Block ausgegeben
AP-003 – Bootstrap-Provider-Auswahl und Umstellung des bestehenden OpenAI-Adapters
Voraussetzung
AP-001 und AP-002 abgeschlossen.
Ziel
Das Bootstrap-Modul wählt anhand von ai.provider.active genau eine AiNamingPort-Implementierung als aktive Implementierung aus und verdrahtet sie. Der bestehende OpenAI-kompatible Adapter konsumiert ab jetzt seine Werte aus dem Namensraum ai.provider.openai-compatible.*. Sein fachliches Verhalten bleibt unverändert. Der aktive Provider wird beim Laufstart geloggt.
Konkret zu erledigende Schritte
- Im Bootstrap-Modul eine Provider-Selektor-Komponente einführen, die als Eingabe den Wert von
ai.provider.activeund alle bekanntenAiNamingPort-Implementierungen erhält und genau eine zurückgibt. Initial kennt sie nur die OpenAI-Implementierung; die Erweiterung um Claude erfolgt in AP-005 an genau dieser Stelle. - Bestehende
AiNamingPort-Implementierung für die OpenAI-kompatible Schnittstelle so anpassen, dass sie die Werte ausai.provider.openai-compatible.*konsumiert. Der bisherige fachliche Vertrag, das Request-/Response-Mapping und das Fehlerverhalten bleiben identisch. - Bestehenden ConfigurationPort/
Configuration-Lesepfad so umstellen, dass intern nur noch das neue Schema verwendet wird. Die alten flachen Klassen/Methoden, die nur zum Lesen vonapi.*dienten, werden entfernt – aber nur, wenn sie nirgends sonst benötigt werden (per Suche prüfen). Falls noch Verweise existieren, wird der entsprechende Konsument im selben AP auf das neue Schema umgestellt. - Bestehende Konfigurations-Tests des Repos auf das neue Schema umstellen. Tests, die explizit das alte flache Schema geprüft haben, werden zu Migrations-Tests verschoben (gehört bereits zu AP-002) oder auf das neue Schema umgeschrieben. Kein Test wird stillschweigend gelöscht.
- Logging-Anbindung erweitern: beim Laufstart wird der aktive Provider-Identifikator geloggt (Standard-Loglevel
INFO). Alle übrigen geforderten Log-Inhalte (sieheCLAUDE.md, Logging-Mindestumfang) bleiben unverändert. - Sicherstellen, dass die Sensibilitätsregel für KI-Inhalte unverändert greift und provider-unabhängig gilt.
- Adapter-zu-Adapter-Kopplung aktiv vermeiden: Der Provider-Selektor lebt im Bootstrap, nicht im Adapter-Out-Modul.
- JavaDoc für Selektor und betroffene Klassen ergänzen.
Pflicht-Testfälle
bootstrapWiresOpenAiCompatibleAdapterWhenActive–ai.provider.active=openai-compatible→ Selektor liefert die OpenAI-Implementierung.bootstrapFailsHardWhenActiveProviderUnknown– Wert ist syntaktisch gesetzt, aber kein gültiger Provider → harter Startfehler, Exit-Code 1.bootstrapFailsHardWhenSelectedProviderHasNoImplementation– Wert istclaude, aber Implementierung noch nicht registriert (Zustand nach AP-003) → harter Startfehler mit klarer Meldung. Dieser Test wird in AP-005 angepasst, sobald Claude registriert ist.openAiAdapterReadsValuesFromNewNamespace– Adapter-Test: gegebeneai.provider.openai-compatible.*-Werte landen 1:1 im HTTP-Request an die bisherige Endpoint-URL.openAiAdapterBehaviorIsUnchanged– bestehender Adapter-Verhaltenstest (Request-Form, Response-Mapping, Fehlerklassifikation) wird auf die neue Konfigurationsquelle umgestellt und bleibt grün.activeProviderIsLoggedAtRunStart– Smoke- oder Bootstrap-Test belegt, dass der aktive Provider bei Laufstart in einem definierten Log-Eintrag erscheint.existingDocumentProcessingTestsRemainGreen– sämtliche bestehenden End-to-End-/Integrations-Tests des bestehenden OpenAI-Pfads bleiben grün, ggf. mit angepasster Konfiguration.legacyFileEndToEndStillRuns– Test-Doppel: Anwendung startet mit Legacy-Datei → Migration aus AP-002 läuft → Bootstrap aus AP-003 wählt OpenAI → Lauf läuft fachlich durch wie zuvor.
Test-Kategorien zusätzlich: Bootstrap-/Wiring-Tests, ggf. Smoke-Test ohne realen externen Aufruf.
Explizit NICHT Teil
- Claude-Adapter
- Persistenz-Erweiterung um Provider-Identifikator
- neue Fehlersemantik
- Refactoring außerhalb der Adapter-Anbindung
Definition of Done
- Build fehlerfrei, Pflicht-Testfälle grün
- bestehender OpenAI-Pfad fachlich unverändert
- aktiver Provider wird beim Laufstart geloggt
- keine Verweise mehr auf das alte flache Schema im Produktivpfad
- Pflicht-Output-Block ausgegeben
AP-004 – Persistenz: Provider-Identifikator additiv
Voraussetzung
AP-003 abgeschlossen.
Ziel
Das SQLite-Schema wird additiv um eine Spalte für den Provider-Identifikator je Versuch erweitert. Bestehende Datensätze bleiben lesbar und korrekt interpretierbar (Default-Wert für Altdaten). Neue Versuche schreiben den Identifikator des für den Versuch aktiven Providers.
Konkret zu erledigende Schritte
- Im SQLite-Schema der Versuchshistorie eine neue Spalte hinzufügen, z. B.
ai_provider TEXT NULL(Spaltenname per bestehender Repo-Konvention wählen, sonst wie hier vorgeschlagen). Die Spalte ist nullable. - Schema-Migration umsetzen:
- Bei Programmstart prüfen, ob die Spalte existiert; wenn nein, per
ALTER TABLEergänzen. - Vorhandene Zeilen behalten den Wert
NULL. - Migration muss idempotent sein (mehrfacher Start ohne Fehler).
- Bei Programmstart prüfen, ob die Spalte existiert; wenn nein, per
- Die Versuchshistorie-Schreiblogik so erweitern, dass beim Anlegen eines neuen Versuchs der Identifikator des aktiv ausgewählten Providers mitgeschrieben wird (
openai-compatibleoderclaude). Der Wert kommt aus der bereits in AP-003 verfügbaren Provider-Auswahl. - Dokument-Stammsatz wird nicht verändert.
- Lesepfad anpassen, sodass der neue Wert mitausgelesen wird; bestehende Mapper/Domain-Typen werden minimal um ein optionales Feld erweitert. Application und Domain bekommen dadurch keinen provider-spezifischen Code – das Feld bleibt ein opaker String.
- JavaDoc und kurzer Abschnitt zur Schema-Erweiterung in der Repo-Doku ergänzen.
Pflicht-Testfälle
addsProviderColumnOnFreshDb– frische DB → Schema enthält neue Spalte.addsProviderColumnOnExistingDbWithoutColumn– DB ohne Spalte (Simulation Altbestand) → Migration legt Spalte nullable an.migrationIsIdempotent– mehrfacher Start ändert nichts und wirft keinen Fehler.existingRowsKeepNullProvider– Altzeilen behaltenNULL.newAttemptsWriteOpenAiCompatibleProvider– aktiver Provider OpenAI → neuer Versuch hatai_provider='openai-compatible'.newAttemptsWriteClaudeProvider– aktiver Provider Claude (für diesen Test wird die Provider-Auswahl gemockt; in AP-005 wird derselbe Test mit echtem Claude-Adapter wiederholt) →ai_provider='claude'.repositoryReadsProviderColumn– Repository-Test: gespeicherter Wert wird korrekt zurückgelesen.legacyDataReadingDoesNotFail– Test mit DB-Datei aus dem Vor-V1.1-Stand: Lesen ohne Fehler, neuer Wert ist Optional/leer.existingHistoryTestsRemainGreen– alle bestehenden Tests rund um die Versuchshistorie bleiben grün, ggf. mit minimaler Anpassung.
Test-Kategorien zusätzlich: Repository-Tests gegen echte SQLite-Instanz (in-memory oder temporär), Schema-Migrations-Tests.
Explizit NICHT Teil
- Claude-Adapter (folgt in AP-005)
- Änderungen am Dokument-Stammsatz
- neue Wahrheitsquellen
- Reporting/Statistiken
Definition of Done
- Build fehlerfrei, Pflicht-Testfälle grün
- bestehende Datenbestände bleiben lesbar
- Provider-Identifikator wird für neue Versuche geschrieben
- Pflicht-Output-Block ausgegeben
AP-005 – Nativer Anthropic-Adapter implementieren und verdrahten
Voraussetzung
AP-001 bis AP-004 abgeschlossen.
Ziel
Eine zweite AiNamingPort-Implementierung wird im Adapter-Out-Modul angelegt, die die native Anthropic Messages API anspricht (siehe Faktenblock in Abschnitt 4). Sie wird im Provider-Selektor aus AP-003 als zweite Option registriert. Der Adapter bildet die Anthropic-Antwort auf den bestehenden fachlichen Vertrag ab; es entsteht kein Sonderweg in Application oder Domain.
Konkret zu erledigende Schritte
- Im Adapter-Out-Modul eine neue Klasse anlegen, die
AiNamingPortimplementiert. Naming nach bestehender Repo-Konvention; per Typsuche prüfen, wie die OpenAI-Implementierung benannt ist, und analog vorgehen. - HTTP-Aufruf gemäß Faktenblock 4 umsetzen:
- URL aus
ai.provider.claude.baseUrl(Defaulthttps://api.anthropic.com) plus Pfad/v1/messages - Methode
POST - Header
x-api-key,anthropic-version: 2023-06-01,content-type: application/json - Request-Body mit
model,max_tokens,messages(eineuser-Message mit dem bestehenden Prompt-Text), optionalsystemfalls die bestehende Prompt-Mechanik ein System-Segment kennt - Timeout aus
ai.provider.claude.timeoutSeconds
- URL aus
- API-Schlüssel-Auflösung exakt nach Tabelle 3.4: zuerst
ANTHROPIC_API_KEY, dannai.provider.claude.apiKey. - Antwortverarbeitung gemäß 4.4: Konkatenation aller
content[*].text-Blöcke in Reihenfolge. Fehlt jedertext-Block oder ist die Antwort nicht parsebar → technischer Adapterfehler nach Tabelle 4.5. - Den so gewonnenen Antworttext unverändert an die bestehende Antwortverarbeitung der Anwendung weitergeben (
NamingProposal-Validierung passiert in Application/Domain wie bisher). - Fehlerklassifikation streng nach Tabelle 4.5. Keine neuen Fehlerklassen.
- Den Provider-Selektor aus AP-003 um die neue Implementierung erweitern. Keine gemeinsame Basisklasse zwischen den beiden Adaptern, keine Hilfsklasse, die HTTP-Logik teilt. Was beide Adapter brauchen, kommt aus dem Repo-üblichen HTTP-/JSON-Standard, nicht aus einer neuen Adapter-Zwischenschicht.
- Den in AP-001 angelegten Test
bootstrapFailsHardWhenSelectedProviderHasNoImplementationso anpassen, dass er ab jetzt auf einen neuen, weiterhin unbekannten Provider-Wert testet (Negativfall bleibt erhalten, aberclaudeist jetzt registriert). - Konfigurationsbeispiel im Repo um sprechende Claude-Beispielwerte ergänzen.
- JavaDoc für die neue Klasse und ggf. neue Hilfstypen.
Pflicht-Testfälle
claudeAdapterBuildsCorrectRequest– gegebener Prompt → HTTP-Request mit korrekter URL (<baseUrl>/v1/messages), Methode POST, allen drei Pflicht-Headern, Body enthältmodel,max_tokens > 0,messagesmit genau eineruser-Message und korrektem Prompt.claudeAdapterUsesEnvVarApiKey–ANTHROPIC_API_KEYgesetzt, Properties-Wert ebenfalls → Headerx-api-keyenthält den Env-Wert.claudeAdapterFallsBackToPropertiesApiKey– Env-Var leer, Properties-Wert gesetzt → Headerx-api-keyenthält den Properties-Wert.claudeAdapterFailsValidationWhenBothKeysMissing– beides leer → Konfigurationsfehler beim Start (greift auf AP-001-Validierung).claudeAdapterParsesSingleTextBlock– Mock-Response mit einem Block{type:"text", text:"..."}→ Antworttext gleich dem Block-Text.claudeAdapterConcatenatesMultipleTextBlocks– mehreretext-Blöcke → Antworttext gleich der Konkatenation in Reihenfolge.claudeAdapterIgnoresNonTextBlocks– Mix austext- und Nicht-text-Blöcken → nur dietext-Inhalte landen im Antworttext.claudeAdapterFailsOnEmptyTextContent– Response ohne jedentext-Block → technischer Adapterfehler.claudeAdapterMapsHttp401AsTechnical– Mock-Response 401 → technischer Fehler nach Tabelle 4.5.claudeAdapterMapsHttp429AsTechnical– Mock-Response 429 → technischer Fehler.claudeAdapterMapsHttp500AsTechnical– Mock-Response 500 → technischer Fehler.claudeAdapterMapsTimeoutAsTechnical– simulierter Timeout → technischer Fehler.claudeAdapterMapsUnparseableJsonAsTechnical– Response-Body ist kein gültiges JSON → technischer Fehler.bootstrapSelectsClaudeWhenActive–ai.provider.active=claude→ Selektor liefert die Claude-Implementierung.claudeProviderIdentifierLandsInAttemptHistory– End-zu-End mit gemocktem HTTP-Layer: nach erfolgreichem Lauf hat der neue Versuchai_provider='claude'(knüpft an AP-004 an).existingOpenAiPathRemainsGreen– sämtliche bestehenden Tests des OpenAI-Pfads bleiben unverändert grün.
Test-Kategorien zusätzlich: Adapter-Tests mit gemocktem HTTP-Client (kein realer Netzwerkzugriff), Bootstrap-Wiring-Tests.
Explizit NICHT Teil
- automatische Fallback-Logik zwischen Providern
- gemeinsame Adapter-Basisklasse
- Erweiterung des Persistenz-Schemas über AP-004 hinaus
- Anpassung des Prompts (eine etwaige System-/User-Trennung der bestehenden Prompt-Datei darf genutzt werden, aber keine inhaltliche Änderung des Prompts)
Definition of Done
- Build fehlerfrei, alle Pflicht-Testfälle grün
- nativer Anthropic-Adapter wird über Konfiguration auswählbar und liefert auf Mock-Basis korrekte Ergebnisse
- bestehender OpenAI-Pfad unverändert grün
- Pflicht-Output-Block ausgegeben
AP-006 – Regression, Smoke, Doku-Konsolidierung, Abschlussnachweis
Voraussetzung
AP-001 bis AP-005 abgeschlossen.
Ziel
Der vollständige Erweiterungsstand wird automatisiert abgesichert, dokumentarisch konsolidiert und als minimale, architekturtreue Erweiterung des Basisstands belastbar nachgewiesen.
Konkret zu erledigende Schritte
- Smoke-Test je Provider: Zwei Smoke-Tests einrichten, die für je eine Provider-Konfiguration den Bootstrap-Pfad bis zur erfolgreichen Verdrahtung des
AiNamingPortdurchlaufen, ohne realen externen HTTP-Aufruf (gemockter HTTP-Layer). Beide müssen grün sein. - Regression OpenAI: Alle bestehenden End-to-End-/Integrations-Tests des OpenAI-Pfads laufen grün. Falls Anpassungen in vorigen APs Tests berührt haben, ist hier der finale Konsistenz-Check.
- Migration Smoke: Ein End-zu-End-Test, der mit einer Legacy-Datei (Inhalt aus der bekannten Demo-Konfig) startet und nach einem ersten Lauf folgendes nachweist:
.bakexistiert mit Original-Inhalt- Properties-Datei ist im neuen Schema
ai.provider.active=openai-compatible- der Lauf hat fachlich gleich funktioniert wie mit dem neuen Schema
- PIT-/Mutationstests in den unmittelbar betroffenen Modulen ausführen, soweit bereits etabliert. Lücken im neuen Code, die deutlich unter dem bestehenden Niveau liegen, gezielt schließen. Keine willkürliche Coverage-Kosmetik.
- Doku-Konsolidierung:
- Beispiel-Properties-Datei zeigt das vollständige neue Schema für beide Provider mit sprechenden Platzhaltern.
- Repo-Doku enthält einen kurzen Abschnitt „KI-Provider auswählen" mit den zulässigen Werten und der Env-Var-Konvention (
OPENAI_COMPATIBLE_API_KEY,ANTHROPIC_API_KEY). - Repo-Doku enthält einen kurzen Abschnitt „Migration von der Vorgängerversion" mit dem Hinweis auf
.bak. - JavaDoc aller in der Erweiterung neu eingeführten oder substanziell geänderten Klassen ist vorhanden.
- Abschlussnachweis: Eine kurze, im Repository verbleibende Markdown-Datei unter
docs/workpackages/V1.1 - Abschlussnachweis.mdanlegen, die mindestens enthält:- Datum, betroffene Module
- Liste der ausgeführten Pflicht-Testfälle pro AP (kann tabellarisch sein)
- Belegte Eigenschaften: zwei Provider unterstützt, genau einer aktiv, kein Fallback, fachlicher Vertrag unverändert, Persistenz rückwärtsverträglich, Migration nachgewiesen,
.baknachgewiesen, aktiver Provider geloggt - explizite Bestätigung: keine Architekturbrüche, keine neuen Bibliotheken außer denen, die für HTTP/JSON ohnehin im Repo etabliert sind
- Hinweis auf die Betreiberaufgabe, ggf. die Umgebungsvariable des OpenAI-Keys auf
OPENAI_COMPATIBLE_API_KEYumzustellen
- Den vollständigen Reactor-Build ausführen und das Ergebnis im AP-Output festhalten.
Pflicht-Testfälle
smokeBootstrapWithOpenAiCompatibleActivesmokeBootstrapWithClaudeActivee2eMigrationFromLegacyDemoConfigregressionExistingOpenAiSuiteGreen(Sammelnachweis, nicht ein einzelner Test)e2eClaudeRunWritesProviderIdentifierToHistorye2eOpenAiRunWritesProviderIdentifierToHistorylegacyDataFromBeforeV11RemainsReadable
Test-Kategorien zusätzlich: Mutationstests in betroffenen Modulen, Konsistenz-Checks der Doku-Beispiele gegen den realen Parser (z. B. „Beispiel-Properties-Datei wird vom Parser ohne Fehler geladen").
Explizit NICHT Teil
- weitere Provider
- Komfortfunktionen
- großflächiges Refactoring
Definition of Done
- vollständiger Reactor-Build fehlerfrei
- alle Pflicht-Testfälle grün
- Smoke-Tests je Provider grün
- Doku konsolidiert
- Abschlussnachweis-Datei im Repo
- Pflicht-Output-Block ausgegeben