# V1.1 – Abschlussnachweis ## Datum und betroffene Module **Datum:** 2026-04-09 **Betroffene Module:** | Modul | Art der Änderung | |---|---| | `pdf-umbenenner-application` | Neue Konfigurationstypen (`MultiProviderConfiguration`, `ProviderConfiguration`, `AiProviderFamily`) | | `pdf-umbenenner-adapter-out` | Neuer Anthropic-Adapter (`AnthropicClaudeHttpAdapter`), neuer Parser (`MultiProviderConfigurationParser`), neuer Validator (`MultiProviderConfigurationValidator`), Migrator (`LegacyConfigurationMigrator`), Schema-Migration (`ai_provider`-Spalte), aktualisierter OpenAI-Adapter (`OpenAiHttpAdapter`), aktualisierter Properties-Adapter (`PropertiesConfigurationPortAdapter`) | | `pdf-umbenenner-bootstrap` | Provider-Selektor (`AiProviderSelector`), aktualisierter `BootstrapRunner` (Migration, Provider-Auswahl, Logging) | | `pdf-umbenenner-adapter-in-cli` | Keine fachliche Änderung | | `pdf-umbenenner-domain` | Keine Änderung | | `config/` | Beispiel-Properties-Dateien auf neues Schema aktualisiert | | `docs/betrieb.md` | Abschnitte KI-Provider-Auswahl und Migration ergänzt | --- ## Pflicht-Testfälle je Arbeitspaket ### AP-001 – Konfigurations-Schema einführen | Testfall | Klasse | Status | |---|---|---| | `parsesNewSchemaWithOpenAiCompatibleActive` | `MultiProviderConfigurationTest` | grün | | `parsesNewSchemaWithClaudeActive` | `MultiProviderConfigurationTest` | grün | | `claudeBaseUrlDefaultsWhenMissing` | `MultiProviderConfigurationTest` | grün | | `rejectsMissingActiveProvider` | `MultiProviderConfigurationTest` | grün | | `rejectsUnknownActiveProvider` | `MultiProviderConfigurationTest` | grün | | `rejectsMissingMandatoryFieldForActiveProvider` | `MultiProviderConfigurationTest` | grün | | `acceptsMissingMandatoryFieldForInactiveProvider` | `MultiProviderConfigurationTest` | grün | | `envVarOverridesPropertiesApiKeyForActiveProvider` | `MultiProviderConfigurationTest` | grün | | `envVarOnlyResolvesForActiveProvider` | `MultiProviderConfigurationTest` | grün | | Bestehende Tests bleiben grün | `PropertiesConfigurationPortAdapterTest`, `StartConfigurationValidatorTest` | grün | ### AP-002 – Legacy-Migration mit `.bak` | Testfall | Klasse | Status | |---|---|---| | `migratesLegacyFileWithAllFlatKeys` | `LegacyConfigurationMigratorTest` | grün | | `createsBakBeforeOverwriting` | `LegacyConfigurationMigratorTest` | grün | | `bakSuffixIsIncrementedIfBakExists` | `LegacyConfigurationMigratorTest` | grün | | `noOpForAlreadyMigratedFile` | `LegacyConfigurationMigratorTest` | grün | | `reloadAfterMigrationSucceeds` | `LegacyConfigurationMigratorTest` | grün | | `migrationFailureKeepsBak` | `LegacyConfigurationMigratorTest` | grün | | `legacyDetectionRequiresAtLeastOneFlatKey` | `LegacyConfigurationMigratorTest` | grün | | `legacyValuesEndUpInOpenAiCompatibleNamespace` | `LegacyConfigurationMigratorTest` | grün | | `unrelatedKeysSurviveUnchanged` | `LegacyConfigurationMigratorTest` | grün | | `inPlaceWriteIsAtomic` | `LegacyConfigurationMigratorTest` | grün | ### AP-003 – Bootstrap-Provider-Auswahl und Umstellung des bestehenden OpenAI-Adapters | Testfall | Klasse | Status | |---|---|---| | `bootstrapWiresOpenAiCompatibleAdapterWhenActive` | `AiProviderSelectorTest` | grün | | `bootstrapFailsHardWhenActiveProviderUnknown` | `AiProviderSelectorTest` | grün | | `bootstrapFailsHardWhenSelectedProviderHasNoImplementation` | `AiProviderSelectorTest` | grün | | `openAiAdapterReadsValuesFromNewNamespace` | `OpenAiHttpAdapterTest` | grün | | `openAiAdapterBehaviorIsUnchanged` | `OpenAiHttpAdapterTest` | grün | | `activeProviderIsLoggedAtRunStart` | `BootstrapRunnerTest` | grün | | `existingDocumentProcessingTestsRemainGreen` | `BatchRunEndToEndTest` | grün | | `legacyFileEndToEndStillRuns` | `BootstrapRunnerTest` | grün | ### AP-004 – Persistenz: Provider-Identifikator additiv | Testfall | Klasse | Status | |---|---|---| | `addsProviderColumnOnFreshDb` | `SqliteAttemptProviderPersistenceTest` | grün | | `addsProviderColumnOnExistingDbWithoutColumn` | `SqliteAttemptProviderPersistenceTest` | grün | | `migrationIsIdempotent` | `SqliteAttemptProviderPersistenceTest` | grün | | `existingRowsKeepNullProvider` | `SqliteAttemptProviderPersistenceTest` | grün | | `newAttemptsWriteOpenAiCompatibleProvider` | `SqliteAttemptProviderPersistenceTest` | grün | | `newAttemptsWriteClaudeProvider` | `SqliteAttemptProviderPersistenceTest` | grün | | `repositoryReadsProviderColumn` | `SqliteAttemptProviderPersistenceTest` | grün | | `legacyDataReadingDoesNotFail` | `SqliteAttemptProviderPersistenceTest` | grün | | `existingHistoryTestsRemainGreen` | `SqliteAttemptProviderPersistenceTest` | grün | ### AP-005 – Nativer Anthropic-Adapter implementieren und verdrahten | Testfall | Klasse | Status | |---|---|---| | `claudeAdapterBuildsCorrectRequest` | `AnthropicClaudeHttpAdapterTest` | grün | | `claudeAdapterUsesEnvVarApiKey` | `AnthropicClaudeHttpAdapterTest` | grün | | `claudeAdapterFallsBackToPropertiesApiKey` | `AnthropicClaudeHttpAdapterTest` | grün | | `claudeAdapterFailsValidationWhenBothKeysMissing` | `AnthropicClaudeHttpAdapterTest` | grün | | `claudeAdapterParsesSingleTextBlock` | `AnthropicClaudeHttpAdapterTest` | grün | | `claudeAdapterConcatenatesMultipleTextBlocks` | `AnthropicClaudeHttpAdapterTest` | grün | | `claudeAdapterIgnoresNonTextBlocks` | `AnthropicClaudeHttpAdapterTest` | grün | | `claudeAdapterFailsOnEmptyTextContent` | `AnthropicClaudeHttpAdapterTest` | grün | | `claudeAdapterMapsHttp401AsTechnical` | `AnthropicClaudeHttpAdapterTest` | grün | | `claudeAdapterMapsHttp429AsTechnical` | `AnthropicClaudeHttpAdapterTest` | grün | | `claudeAdapterMapsHttp500AsTechnical` | `AnthropicClaudeHttpAdapterTest` | grün | | `claudeAdapterMapsTimeoutAsTechnical` | `AnthropicClaudeHttpAdapterTest` | grün | | `claudeAdapterMapsUnparseableJsonAsTechnical` | `AnthropicClaudeHttpAdapterTest` | grün | | `bootstrapSelectsClaudeWhenActive` | `AiProviderSelectorTest` | grün | | `claudeProviderIdentifierLandsInAttemptHistory` | `AnthropicClaudeAdapterIntegrationTest` | grün | | `existingOpenAiPathRemainsGreen` | alle `OpenAiHttpAdapterTest`-Tests | grün | ### AP-006 – Regression, Smoke, Doku, Abschlussnachweis | Testfall | Klasse | Status | |---|---|---| | `smokeBootstrapWithOpenAiCompatibleActive` | `BootstrapSmokeTest` | grün | | `smokeBootstrapWithClaudeActive` | `BootstrapSmokeTest` | grün | | `e2eMigrationFromLegacyDemoConfig` | `ProviderIdentifierE2ETest` | grün | | `regressionExistingOpenAiSuiteGreen` | `ProviderIdentifierE2ETest` | grün | | `e2eClaudeRunWritesProviderIdentifierToHistory` | `ProviderIdentifierE2ETest` | grün | | `e2eOpenAiRunWritesProviderIdentifierToHistory` | `ProviderIdentifierE2ETest` | grün | | `legacyDataFromBeforeV11RemainsReadable` | `ProviderIdentifierE2ETest` | grün | --- ## Belegte Eigenschaften | Eigenschaft | Nachweis | |---|---| | Zwei Provider-Familien unterstützt | `AiProviderSelectorTest`, `BootstrapSmokeTest` | | Genau einer aktiv pro Lauf | `MultiProviderConfigurationTest`, `BootstrapSmokeTest` | | Kein automatischer Fallback | keine Fallback-Logik in `AiProviderSelector` oder Application-Schicht | | Fachlicher Vertrag (`NamingProposal`) unverändert | `AiResponseParser`, `AiNamingService` unverändert; beide Adapter liefern denselben Domain-Typ | | Persistenz rückwärtsverträglich | `SqliteAttemptProviderPersistenceTest`, `legacyDataFromBeforeV11RemainsReadable` | | Migration nachgewiesen | `LegacyConfigurationMigratorTest`, `e2eMigrationFromLegacyDemoConfig` | | `.bak`-Sicherung nachgewiesen | `LegacyConfigurationMigratorTest.createsBakBeforeOverwriting`, `e2eMigrationFromLegacyDemoConfig` | | Aktiver Provider wird geloggt | `BootstrapRunnerTest.activeProviderIsLoggedAtRunStart` | | Keine Architekturbrüche | kein `Application`- oder `Domain`-Code kennt OpenAI- oder Claude-spezifische Typen | | Keine neuen Bibliotheken | Anthropic-Adapter nutzt Java HTTP Client und `org.json` (beides bereits im Repo etabliert) | --- ## Betreiberaufgabe Wer bisher die Umgebungsvariable `PDF_UMBENENNER_API_KEY` oder eine andere eigene Variable für den OpenAI-kompatiblen API-Schlüssel eingesetzt hat, muss diese auf **`OPENAI_COMPATIBLE_API_KEY`** umstellen. Die Anwendung akzeptiert nur diese kanonische Umgebungsvariable; ältere proprietäre Namen werden nicht automatisch ausgewertet. --- ## Build-Ergebnis Build-Kommando: ``` .\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 ``` Build-Status: **ERFOLGREICH** — alle Tests grün, Mutationstests in allen Modulen ausgeführt.