# WP3-001-002 – Discovery Configuration Registry
## Implementation Plan

- **Status:** Ready for PL Review
- **Version:** 0.1
- **Scope:** WP3 – Discovery Framework Foundation
- **Basis:** aktueller Projektstand `reconcile_ADR002.WP2_20260801_0.zip`, erfolgreich integriertes WP3-001-001 und `WP3-001-002 – Discovery Configuration Registry v0.2`
- **Owner:** ED
- **Review:** PL

---

# 1. Ziel

WP3-001-002 führt die Klasse `DiscoveryConfigurationRegistry` ein.

Die Registry erhält beim Erzeugen eine Sammlung von `DiscoveryRoute`-Instanzen und stellt für eine angefragte `scopeVocabularyUri` alle passenden aktivierten Routes als `DiscoveryRoute[]` bereit.

Die Registry

- trifft keine Auswahlentscheidung,
- kennt keine Adapter,
- führt keine Candidate Discovery aus,
- besitzt keine persistente Speicherung,
- und verändert registrierte Routes nicht.

---

# 2. Voraussetzung

WP3-001-001 muss im Projektstand vorhanden sein:

```text
src/Infrastructure/Discovery/Configuration/DiscoveryRoute.php
```

Die bestehende Klasse `DiscoveryRoute` bleibt unverändert.

WP3-001-002 baut ausschließlich auf ihrem öffentlichen Property Contract auf:

```text
targetVocabularyUri
scopeVocabularyUri
candidateSource
discoveryMethod
adapterKey
enabled
```

---

# 3. Projektanalyse

Der aktuelle Projektstand enthält bereits zwei Registry-Muster:

```text
src/Registry/VocabularyRegistry.php
src/Provider/ProviderRegistry.php
```

Für WP3-001-002 wird keines dieser Muster direkt erweitert:

- `VocabularyRegistry` verwaltet fachliche `Vocabulary`- und `SubVocabulary`-Objekte.
- `ProviderRegistry` verwaltet die bisherige Legacy-Provider-Struktur.
- `DiscoveryConfigurationRegistry` gehört zur neuen Discovery-Framework-Infrastruktur und verwaltet ausschließlich `DiscoveryRoute`-Instanzen.

Die neue Registry wird deshalb im gleichen Discovery-Konfigurationsbereich wie `DiscoveryRoute` abgelegt.

---

# 4. Ziel-Dateien

## Neue Produktionsklasse

```text
src/Infrastructure/Discovery/Configuration/DiscoveryConfigurationRegistry.php
```

Namespace:

```php
App\Infrastructure\Discovery\Configuration
```

## Neuer Unit Test

```text
tests/Infrastructure/Discovery/Configuration/DiscoveryConfigurationRegistryTest.php
```

WP3-001-002 verändert keine bestehenden Dateien.

---

# 5. Klassenform

Vorgesehen ist eine unveränderliche Registry:

```php
final readonly class DiscoveryConfigurationRegistry
```

Begründung:

- Die Route-Sammlung wird beim Erzeugen vollständig übergeben.
- Nachträgliche Registrierung ist in WP3-001-002 nicht erforderlich.
- Die Registry soll keine veränderliche Runtime-Konfiguration darstellen.
- Eine spätere Factory oder Runtime-Verdrahtung kann jederzeit eine neue Registry-Instanz erzeugen.

Damit wird bewusst **keine** öffentliche Methode wie

```php
register(...)
```

oder

```php
add(...)
```

eingeführt.

---

# 6. Constructor Contract

Geplanter Konstruktor:

```php
/**
 * @param DiscoveryRoute[] $routes
 */
public function __construct(
    private array $routes,
)
```

Beim Erzeugen wird geprüft, dass jedes Element eine `DiscoveryRoute` ist.

Ein ungültiges Element führt zu einer `InvalidArgumentException` mit einer stabilen Fehlermeldung.

Vorgeschlagene Meldung:

```text
DiscoveryConfigurationRegistry routes must contain only DiscoveryRoute instances.
```

Eine leere Route-Sammlung ist zulässig.

Begründung:

- Die Registry soll auch in einem noch nicht konfigurierten Runtime-Zustand erzeugt werden können.
- Eine fehlende Route wird fachlich erst beim Lookup sichtbar.
- Der Router behandelt später die Kardinalität `0 / 1 / >1`.

---

# 7. Öffentliche API

Die Registry erhält genau eine öffentliche Lookup-Methode:

```php
/**
 * @return DiscoveryRoute[]
 */
public function routesForScope(string $scopeVocabularyUri): array
```

Verhalten:

1. Vergleich erfolgt exakt gegen `DiscoveryRoute.scopeVocabularyUri`.
2. Nur Routes mit `enabled === true` werden zurückgegeben.
3. Alle passenden aktivierten Routes werden zurückgegeben.
4. Die ursprüngliche Registrierungsreihenfolge bleibt erhalten.
5. Bei unbekanntem Scope wird `[]` zurückgegeben.
6. Die Registry normalisiert weder Suchwert noch gespeicherte Werte.

Ein leerer oder ausschließlich aus Whitespace bestehender Suchwert wird mit `InvalidArgumentException` abgelehnt.

Vorgeschlagene Meldung:

```text
DiscoveryConfigurationRegistry.scopeVocabularyUri must not be empty.
```

---

# 8. Interne Datenstruktur

Für WP3-001-002 genügt eine einfache, unveränderliche Liste:

```php
private array $routes;
```

Der Lookup erfolgt durch lineares Filtern.

Bewusst nicht vorgesehen:

- Index nach `scopeVocabularyUri`
- Hash Map
- Cache
- Deduplizierung
- Sortierung
- Priorisierung
- Default Route
- Fallback Route

Begründung:

Die aktuelle Zahl der Discovery Routes ist klein. Eine optimierte Indexstruktur wäre ohne messbaren Bedarf Overengineering.

---

# 9. Semantische Abgrenzung

Die Registry prüft ausschließlich:

```text
scopeVocabularyUri equality
+ enabled status
```

Sie prüft nicht:

- ob `scopeVocabularyUri` zu `targetVocabularyUri` gehört,
- ob ein Scope ein Vocabulary oder SubVocabulary ist,
- ob `candidateSource` bekannt ist,
- ob `adapterKey` registriert ist,
- ob mehrere Routes mehrdeutig sind.

Diese Semantik gehört nicht zur Registry:

```text
DiscoveryConfigurationRegistry
= finden und filtern

CandidateDiscoveryRouter
= Kardinalität prüfen und Route verwenden
```

---

# 10. Fehlerverhalten

| Situation | Ergebnis |
|---|---|
| ungültiges Element im Konstruktor | `InvalidArgumentException` |
| leerer Lookup-Scope | `InvalidArgumentException` |
| unbekannter Scope | `[]` |
| nur deaktivierte Routes vorhanden | `[]` |
| genau eine aktivierte Route | Array mit einer Route |
| mehrere aktivierte Routes | Array mit allen passenden Routes |

WP3-001-002 führt ausdrücklich noch keine

```text
DiscoveryConfigurationException
AmbiguousDiscoveryRouteException
```

ein. Diese Fehler gehören zu WP3-001-004, weil erst der Router die Kardinalitätsregel auswertet.

---

# 11. Unit-Test-Plan

Der Test folgt dem vorhandenen projektinternen Stil ohne PHPUnit und wird direkt über `src/bootstrap.php` ausgeführt.

## T001 – Eine passende aktivierte Route

- Registry enthält eine Route für den angefragten Scope.
- Ergebnis enthält genau diese Route.
- Objektidentität bleibt erhalten.

## T002 – Mehrere passende aktivierte Routes

- Registry enthält zwei aktivierte Routes mit identischer `scopeVocabularyUri`.
- Ergebnis enthält beide Routes.
- Reihenfolge entspricht der Konstruktorreihenfolge.
- Es erfolgt keine Auswahl und keine Deduplizierung.

## T003 – Andere Discovery Scopes werden ausgeschlossen

- Registry enthält Routes für mehrere Scopes.
- Ergebnis enthält ausschließlich Routes des angefragten Scopes.

## T004 – Deaktivierte Routes werden ausgeschlossen

- Aktivierte und deaktivierte Route besitzen denselben Scope.
- Ergebnis enthält nur die aktivierte Route.

## T005 – Unbekannter Scope

- Ergebnis ist ein leeres Array.
- Es wird keine Exception ausgelöst.

## T006 – Leere Registry

- Registry kann mit `[]` erzeugt werden.
- Lookup liefert `[]`.

## T007 – Leerer Lookup-Scope

Folgende Werte werden abgelehnt:

```text
""
"   "
"\t\n"
```

Die dokumentierte Fehlermeldung wird geprüft.

## T008 – Ungültiges Konstruktor-Element

- Eine Route-Sammlung mit einem Nicht-`DiscoveryRoute`-Element wird abgelehnt.
- Die dokumentierte Fehlermeldung wird geprüft.

## T009 – Keine Normalisierung

- Ein Suchwert mit zusätzlichen Leerzeichen matcht keine Route ohne diese Leerzeichen.
- Die Registry verändert weder den Query-Wert noch die gespeicherte Route.

Erwartete Abschlussmeldung:

```text
WP3-001-002 Discovery Configuration Registry: OK
```

---

# 12. Regression

Nach Implementierung werden ausgeführt:

```text
tests/Infrastructure/Discovery/Configuration/DiscoveryRouteTest.php
tests/Infrastructure/Discovery/Configuration/DiscoveryConfigurationRegistryTest.php
```

Zusätzlich wird die vorhandene Testsuite ausgeführt, soweit die lokale Konfiguration dies zulässt.

WP3-001-002 besitzt keine Abhängigkeit zu Datenbank, Runtime, Composition Root oder externen Diensten.

---

# 13. Erwarteter Änderungsumfang

Ausschließlich zwei neue Dateien:

```text
src/Infrastructure/Discovery/Configuration/DiscoveryConfigurationRegistry.php
tests/Infrastructure/Discovery/Configuration/DiscoveryConfigurationRegistryTest.php
```

Keine bestehenden Produktions- oder Testdateien werden geändert.

---

# 14. Out of Scope

Nicht implementiert werden:

- `CandidateDiscoveryRouter`
- `CandidateDiscoveryAdapter`
- `CandidateDiscoveryAdapterRegistry`
- Adapter-Auflösung
- Runtime Integration
- persistente Discovery Configuration
- Priorität
- Fallback
- Default Route
- Tenant-Regeln
- Hybrid Discovery
- fachliche Validierung der Vocabulary-Beziehungen

---

# 15. Umsetzung nach Freigabe

Nach Freigabe dieses Plans setzt ED WP3-001-002 vollständig um, führt die Tests aus und liefert ausschließlich die beiden neuen Dateien in bestehender Ordnerstruktur als ZIP.
