# CTX-001D – Candidate Qualifier Propagation

**Status:** Implementation
**Date:** 2026-08-16

## Ziel

Qualifier von gefundenen Candidates werden strukturiert durch Discovery, Domain/Persistenz und OpenRefine-Ausgabe transportiert.

## Modell

Intern bleibt die Trennung erhalten:

```text
label     = Bogen
qualifier = Architektur
```

Nur die OpenRefine-Präsentation erzeugt:

```text
Bogen (Architektur)
```

## Änderungen

- `XtreeJsonApiResultMapper`: übernimmt `Term.qualifier` des tatsächlich ausgewählten bevorzugten Terms in `Candidate.meta['qualifier']`.
- `ReconciliationApplicationService`: überträgt `metadata['qualifier']` nach `CandidateItem.qualifier`.
- `ReconciliationStoreProvider`: hängt den Qualifier nicht mehr an `Candidate.label`; der bestehende strukturierte `meta['qualifier']` bleibt maßgeblich.
- `OpenRefineResponseMapper`: bildet den OpenRefine-Anzeigenamen aus `label` plus optionalem `metadata['qualifier']`.

## Invarianten

- `CandidateItem.displayLabel` bleibt qualifier-frei.
- `CandidateItem.qualifier` enthält den strukturierten Homonymzusatz.
- Kandidaten ohne Qualifier behalten ihr bisheriges Anzeigeverhalten.
- CTX-001C Qualifier-aware Discovery bleibt unverändert.

## Tests

Erfolgreich in der ED-Laufzeit:

```text
php tests/Provider/Xtree/XtreeJsonApiResultMapperQualifierTest.php
php tests/Application/Reconciliation/ApplicationFlowTest.php
```

Der vorhandene LocalStore-Integrationstest wurde an die strukturierte Label/Qualifier-Trennung angepasst. In der ED-Container-Laufzeit kann er wegen fehlendem `mbstring` nicht vollständig ausgeführt werden; Syntaxprüfung ist erfolgreich. Er ist in der regulären Reconcilix-Laufzeit auszuführen.

## Erwarteter OpenRefine-Response

```json
{
  "id": "http://lvr.vocnet.org/wnk/wk002306",
  "name": "Bogen (Architektur)",
  "type": [],
  "score": 80,
  "match": false
}
```
