From 81ae3c39025888abbe825fbfc0310c04eb5dd20a Mon Sep 17 00:00:00 2001 From: team 1 Date: Wed, 6 May 2026 16:58:01 +0200 Subject: [PATCH] fix p55 --- ..._CONFIG_VALUES_VALIDATION_HOTFIX_README.md | 89 + ...CH_55_SINGLE_GENRE_CONFIG_VALUES_README.md | 148 ++ config/retriex/genre.yaml | 1793 ++++++++++++++++- public/assets/styles/base.css | 3 + src/Config/GenreConfig.php | 21 + src/Config/RetriexEffectiveConfigProvider.php | 28 + 6 files changed, 2011 insertions(+), 71 deletions(-) create mode 100644 RETRIEX_PATCH_55B_GENRE_CONFIG_VALUES_VALIDATION_HOTFIX_README.md create mode 100644 RETRIEX_PATCH_55_SINGLE_GENRE_CONFIG_VALUES_README.md diff --git a/RETRIEX_PATCH_55B_GENRE_CONFIG_VALUES_VALIDATION_HOTFIX_README.md b/RETRIEX_PATCH_55B_GENRE_CONFIG_VALUES_VALIDATION_HOTFIX_README.md new file mode 100644 index 0000000..a9cb6cb --- /dev/null +++ b/RETRIEX_PATCH_55B_GENRE_CONFIG_VALUES_VALIDATION_HOTFIX_README.md @@ -0,0 +1,89 @@ +# RetrieX Patch p55b - Genre Config Values Validation Hotfix + +## Purpose + +Small follow-up hotfix for p55 Single-Genre Config Values. + +p55 correctly added `configuration_values` to `config/retriex/genre.yaml`, but the effective config output used by `mto:agent:config:validate` did not expose this block. As a result, validation reported: + +```text +Config validation failed: genre.configuration_values must be a non-empty map. +``` + +The patch also corrects two stale `adaptation_surface.product_roles` path references for the `no_llm_fallback` product role vocabulary-view indirection. + +## Scope + +Changed files: + +- `config/retriex/genre.yaml` +- `src/Config/RetriexEffectiveConfigProvider.php` + +## Changes + +### Effective config exposure + +`RetriexEffectiveConfigProvider::genreConfig()` now includes: + +```php +'configuration_values' => $this->genreConfig->getConfigurationValues(), +``` + +This makes the p55 value surface visible to the existing config validation path. + +### Path reference cleanup + +The stale paths: + +```text +agent.no_llm_fallback.product_roles.main_device_request_keywords +agent.no_llm_fallback.product_roles.accessory_product_keywords +``` + +were replaced with the current vocabulary-view config paths: + +```text +agent.no_llm_fallback.product_roles.vocabulary_views.main_device_request_keywords +agent.no_llm_fallback.product_roles.vocabulary_views.accessory_product_keywords +``` + +The same path spelling was corrected in the corresponding `configuration_values.product_roles.no_llm_fallback_terms.source_paths` metadata. + +## Non-goals + +This patch does not: + +- wire runtime behavior to `genre.yaml` +- introduce multi-genre or tenant logic +- add new product terms +- add new defaults +- change ranking, retrieval, Shopware criteria or LLM behavior +- move legacy values out of their existing files + +## Local checks + +Performed locally in the extracted project without `vendor/`: + +```bash +php -l src/Config/GenreConfig.php +php -l src/Config/RetriexEffectiveConfigProvider.php +php -l src/Config/ConfigSourceAuditProvider.php +``` + +YAML parsing was also checked for all files under `config/retriex/*.yaml`. + +A lightweight path check verified that the two corrected `no_llm_fallback` paths now point to existing raw config locations. + +Full Symfony console checks could not be executed locally because the ZIP does not contain `vendor/`. + +## Recommended project checks + +After applying the patch in the full project, run: + +```bash +bin/console cache:clear +bin/console mto:agent:config:validate +bin/console mto:agent:regression:test +bin/console mto:agent:config:audit-source --details +bin/console mto:agent:config:audit-patterns --details +``` diff --git a/RETRIEX_PATCH_55_SINGLE_GENRE_CONFIG_VALUES_README.md b/RETRIEX_PATCH_55_SINGLE_GENRE_CONFIG_VALUES_README.md new file mode 100644 index 0000000..5dfdda4 --- /dev/null +++ b/RETRIEX_PATCH_55_SINGLE_GENRE_CONFIG_VALUES_README.md @@ -0,0 +1,148 @@ +# RetrieX Patch p55 - Single-Genre Config Values + +## Ziel + +Dieser Patch ist der erste Schritt nach p54, um RetrieX fuer eine **eine Installation = ein Genre**-Konfiguration vorzubereiten. + +p54 war die Landkarte (`adaptation_surface`). p55 fuegt nun in `config/retriex/genre.yaml` eine erste zentrale Werteflaeche hinzu: + +```yaml +retriex.genre.config: + configuration_values: + product_roles: + product_attributes: + brands_and_canonical_terms: + intent_and_routing: + context_resolution: + shop_query_runtime: + result_identity_and_answer_policy: + search_repair: + retrieval_and_language: + shop_data_mapping: + governance_and_regression: +``` + +Die Werte sind aus dem aktuellen stabilen Wasseranalyse-/Messgeraete-Genre uebernommen. Dadurch ist erstmals an einer zentralen Stelle sichtbar, welche konkreten fachlichen Werte bei einer spaeteren Umwidmung, z. B. auf Fashion, Moebel, Ersatzteile oder Elektronik, ersetzt werden muessten. + +## Bewusste Nicht-Ziele + +- Keine Multi-Genre-Loesung +- Keine Tenant-Logik +- Keine Runtime-Umschaltung pro Request +- Keine SaaS-/Host-/API-Key-Auswahl +- Keine fachliche Logikaenderung +- Keine neuen fachlichen Tokenlisten im PHP-Core +- Keine Ranking-, Retrieval- oder Shopware-Kriterienaenderung +- Keine LLM-Verhaltensaenderung +- Keine Entfernung alter Config-Pfade +- Kein p56-Wiring + +Die Runtime liest nach diesem Patch weiterhin die bisherigen Config-Dateien und Pfade. `configuration_values` ist die neue zentrale Pflege-/Migrationsflaeche, aber noch nicht die fuehrende Runtime-Quelle. + +## Geaenderte Dateien + +```text +config/retriex/genre.yaml +src/Config/GenreConfig.php +src/Config/RetriexEffectiveConfigProvider.php +RETRIEX_PATCH_55_SINGLE_GENRE_CONFIG_VALUES_README.md +``` + +## Wichtigste Aenderungen + +### `config/retriex/genre.yaml` + +Neu ist der Block: + +```yaml +configuration_values: + ... +``` + +Er enthaelt die aktuellen genreabhaengigen Werte gruppiert nach denselben Bereichen wie `adaptation_surface`: + +- Produktrollen und Shop-/Prompt-Views +- Produktattribute und numerische Constraints +- Marken, Canonical Terms und Query-Enrichment +- Intent- und Routing-Signale +- Follow-up-/Kontextanker +- Shopquery-Runtime +- Result-Identity und Antwort-/Grounding-Regeln +- Search Repair +- Retrieval-/Language-Begriffe +- Shopdaten-Mapping +- Governance-/Regression-Guardrails + +Jeder Unterbereich enthaelt `source_paths`, damit nachvollziehbar bleibt, aus welchen bestehenden Runtime-Pfaden die Werte stammen. + +### `GenreConfig` + +Neue Zugriffsmethoden: + +```php +getConfigurationValues(): array +getConfigurationValueGroup(string $group): array +``` + +Diese Methoden stellen die neue Werteflaeche bereit, ohne die Runtime bereits darauf umzustellen. + +### `RetriexEffectiveConfigProvider` + +Die Config-Validierung prueft nun zusaetzlich: + +- `genre.configuration_values` ist eine nicht-leere Map +- jede Werte-Gruppe ist eine nicht-leere Map +- fuer jede `adaptation_surface`-Gruppe existiert eine passende `configuration_values`-Gruppe + +Fehlende Value-Gruppen wuerden als Warnung sichtbar; strukturell falsche Value-Gruppen als Fehler. + +## Warum p55 noch kein Wiring macht + +p55 soll bewusst risikoarm bleiben. Die alten Pfade bleiben fuehrend, damit bestehende Regressionen und Shop-/RAG-Verhalten unveraendert bleiben. + +Der naechste Schritt waere ein separater Patch: + +```text +p56 Single-Genre Config Wiring +``` + +Dort koennen ausgewaehlte Getter oder ein zentraler Effective-Provider bevorzugt aus `genre.configuration_values` lesen und bei fehlenden Werten auf die alten Pfade zurueckfallen. + +## Lokale Pruefungen + +Ausgefuehrt im entpackten Patch-Arbeitsstand: + +```bash +php -l src/Config/GenreConfig.php +php -l src/Config/RetriexEffectiveConfigProvider.php +``` + +Ergebnis: beide PHP-Lints gruen. + +Zusaetzlich wurden alle YAML-Dateien unter `config/retriex/*.yaml` per Python/YAML-Parser geprueft. + +Ergebnis: YAML-Parsing gruen. + +Zusaetzlich wurde geprueft: + +- `adaptation_surface` hat 11 Gruppen +- `configuration_values` hat dieselben 11 Gruppen +- keine `adaptation_surface`-Gruppe ohne entsprechende Werte-Gruppe + +## Nicht lokal ausfuehrbar + +`bin/console` konnte lokal nicht ausgefuehrt werden, weil im ZIP kein `vendor/` enthalten ist: + +```text +Dependencies are missing. Try running "composer install". +``` + +## Empfohlene Projektchecks nach dem Einspielen + +```bash +bin/console cache:clear +bin/console mto:agent:config:validate +bin/console mto:agent:regression:test +bin/console mto:agent:config:audit-source --details +bin/console mto:agent:config:audit-patterns --details +``` diff --git a/config/retriex/genre.yaml b/config/retriex/genre.yaml index 994cddd..3ea1a9c 100644 --- a/config/retriex/genre.yaml +++ b/config/retriex/genre.yaml @@ -5,49 +5,647 @@ # configuration areas that must be reviewed when the same software is repurposed # for another genre such as fashion, furniture, spare parts or electronics. # -# The `paths` values reference the effective config dump keys used by -# mto:agent:config:validate. They are guardrailed so stale or renamed paths are -# detected during config validation. +# p54 introduced `adaptation_surface` as the path inventory. p55 adds +# `configuration_values` as the first central value surface. Runtime code still +# reads the legacy YAML paths until a later wiring patch migrates selected +# getters to this file. parameters: retriex.genre.config: id: water_analysis - label: 'Water analysis / measurement devices' + label: Water analysis / measurement devices mode: single_installation_single_genre - description: 'Genre-specific configuration surface for one RetrieX installation.' - + description: Genre-specific configuration surface for one RetrieX installation. adaptation_surface: product_roles: - description: 'Main product, accessory and consumable role vocabulary used for routing, shop matching and answer guards.' + description: Main product, accessory and consumable role vocabulary used for routing, shop matching and answer guards. paths: + - vocabulary.classes.device + - vocabulary.classes.accessory + - vocabulary.classes.requested_accessory_code_terms + - vocabulary.views.shop.device_query.add + - vocabulary.views.shop.accessory_query.add + - vocabulary.views.shop.device_product.add + - vocabulary.views.shop.accessory_product.add + - vocabulary.views.prompt.main_device_request_keywords.add + - vocabulary.views.prompt.accessory_request_keywords.add + - vocabulary.views.prompt.main_device_product_keywords.add + - vocabulary.views.prompt.accessory_product_keywords.add + - agent.no_llm_fallback.product_roles.vocabulary_views.main_device_request_keywords + - agent.no_llm_fallback.product_roles.vocabulary_views.accessory_product_keywords + - prompt.detection.technical_product_keywords + - prompt.detection.accessory_request_keywords + product_attributes: + description: Genre-specific attributes and constraints, for example measurement values now or size/color/material later. + paths: + - vocabulary.classes.direct_product_attribute_stop_terms + - vocabulary.views.search_repair.direct_product_type_terms.add + - vocabulary.views.search_repair.direct_product_attribute_stop_terms.include + - agent.shop_runtime.attribute_cleanup.product_type_terms + - agent.shop_runtime.attribute_cleanup.stop_terms + - agent.shop_runtime.attribute_cleanup.comparative_constraint_patterns + - agent.shop_runtime.answer_constraints.length_sort.trigger_patterns + - agent.shop_runtime.answer_constraints.length_sort.value_patterns + - agent.shop_runtime.answer_constraints.length_filter.min_patterns + - agent.shop_runtime.answer_constraints.length_filter.max_patterns + - intent.commerce.size_token_terms + - intent.commerce.size_terms + - intent.commerce.color_terms + - intent.commerce.patterns.size_extraction_template + - intent.commerce.patterns.size_value_template + - intent.commerce.patterns.size_token_value_template + - intent.commerce.patterns.color_value_template + brands_and_canonical_terms: + description: Known brands, canonical token mappings and query enrichment rules that change with the shop genre. + paths: + - commerce_query.known_brands + - commerce_query.search_token_canonical_map + - query_enrichment.rules + - vocabulary.maps.shop.accessory_focus_variants + - vocabulary.maps.agent.rag_evidence_guard.synonyms + intent_and_routing: + description: Genre-specific commerce/advisory signals and fuzzy routing terms. + paths: + - vocabulary.classes.input_normalization_fuzzy_routing_terms + - agent.input_normalization.fuzzy_routing.terms + - intent.commerce.strong_signals + - intent.commerce.advisory_signals + - intent.commerce.advisory_product_selection_patterns + - intent.commerce.explicit_commerce_intent_patterns + - intent.commerce.patterns.model_like_product + - intent.sales.sales_signals + - intent.sales.comparison_signals + - intent.sales.objection_signals + - intent.sales.implementation_signals + - intent.sales.roi_signals + context_resolution: + description: Follow-up anchors and meta-query handling for referential shop questions in the current genre. + paths: + - agent.follow_up_context.commercial_table_follow_up.history_anchor_patterns + - agent.follow_up_context.commercial_table_follow_up.indicator_marker_patterns + - agent.follow_up_context.commercial_table_follow_up.query_template_with_model + - agent.follow_up_context.commercial_table_follow_up.query_template_without_model + - agent.shop_runtime.context_resolution.context_usage.referential_terms + - agent.shop_runtime.context_resolution.history_anchor_enrichment.trigger_terms + - agent.shop_runtime.context_resolution.history_anchor_enrichment.anchor_patterns + - agent.shop_runtime.context_resolution.history_anchor_enrichment.template + - agent.shop_runtime.context_resolution.meta_query_guard.meta_only_terms + - agent.shop_runtime.context_resolution.meta_query_guard.context_fallback_filter_terms + - agent.shop_runtime.context_resolution.rag_anchor_enrichment.numeric_focus_patterns + - agent.shop_runtime.context_resolution.rag_anchor_enrichment.product_title_patterns + - agent.shop_runtime.context_resolution.rag_anchor_enrichment.anchor_bonus_patterns + - agent.shop_runtime.context_resolution.rag_anchor_enrichment.subject_terms + shop_query_runtime: + description: Shop query cleanup and direct Shopware search behavior that needs genre-specific terms but no PHP branching. + paths: + - vocabulary.classes.agent_shop_current_input_preservation_terms + - vocabulary.classes.agent_shop_context_anchor_trigger_terms + - agent.shop_runtime.query_cleanup.current_input_preservation.terms + - agent.shop_runtime.query_cleanup.stopword_cleanup.terms + - agent.shop_runtime.result_identity.compound_prefix_match.terms + - agent.shop_runtime.result_identity.primary_identity_repair.stop_terms + - agent.shop_runtime.direct_answer.intro + - agent.shop_runtime.direct_answer.no_results + - agent.shop_runtime.direct_answer.sorted_by_length_note + - agent.shop_runtime.direct_answer.min_length_filter_note + - agent.shop_runtime.direct_answer.max_length_filter_note + result_identity_and_answer_policy: + description: Grounding, role separation and atomicity rules that must match the active product genre. + paths: + - prompt.rules.output_priority_technical + - prompt.rules.response_format_technical + - prompt.rules.response_format_accessory + - prompt.rules.fact_grounding_technical + - prompt.rules.fact_grounding_with_shop + - vocabulary.views.prompt.measurement_evidence_guard.accessory_lookup_guard_terms.add + - vocabulary.views.prompt.measurement_evidence_guard.accessory_lookup_passthrough_terms.add + - vocabulary.views.prompt.measurement_evidence_guard.generic_positive_context_terms.add + - vocabulary.views.prompt.measurement_evidence_guard.generic_negative_context_terms.add + search_repair: + description: Genre-specific repair tokens, candidate patterns and exact identifier behavior. + paths: + - search_repair.direct_product_attribute_lookup + - vocabulary.views.search_repair.requested_accessory_code_terms.include + - search_repair.specific_model_candidate_patterns + - vocabulary.views.search_repair.model_candidate_exclude_terms.include + - vocabulary.views.search_repair.generic_candidate_tokens.add + - vocabulary.views.search_repair.accessory_candidate_terms.add + - vocabulary.views.search_repair.accessory_or_bundle_terms.add + - vocabulary.views.search_repair.specificity_boost_terms.add + - search_repair.patterns.model_candidate + - search_repair.patterns.accessory_candidate_template + - search_repair.patterns.requested_accessory_code + - search_repair.patterns.accessory_or_bundle_template + - search_repair.patterns.model_like + - search_repair.patterns.specificity_boost_template + retrieval_and_language: + description: Genre-specific protected terms, exact selection helpers and retrieval vocabulary. Engine parameters stay outside this surface. + paths: + - language.protected_terms + - language.cleanup_profiles.commerce_query + - language.cleanup_profiles.rag_evidence + - language.cleanup_profiles.shop_context_fallback + - retrieval.vocabulary.generic_product_tokens + - retrieval.vocabulary.important_short_model_tokens + - retrieval.vocabulary.family_descriptor_tokens + - retrieval.vocabulary.looks_like_reagent_tokens + - retrieval.vocabulary.looks_like_device_words + - retrieval.vocabulary.looks_like_document_words + - retrieval.exact_selection_token_variant_prefixes + - retrieval.exact_selection_indicator_question_tokens + - retrieval.exact_selection_indicator_question_phrases + - retrieval.exact_selection_indicator_table_heading_patterns + - retrieval.exact_selection_indicator_table_header_patterns + - retrieval.exact_selection_indicator_table_row_patterns + - retrieval.exact_selection_indicator_table_required_primary_terms + - retrieval.exact_selection_indicator_table_required_context_terms + shop_data_mapping: + description: Shop record fields and matching text fields that are installation-/genre-specific. + paths: + - shop_matching.custom_fields + - shop_matching.text.custom_field_join_separator + - shop_matching.text.primary_secondary_separator + - shop_matching.role_guard + - commerce.store_api_base_url + - commerce.max_shop_results + governance_and_regression: + description: Guardrails and regression expectations that intentionally protect the active genre. + paths: + - governance.regression_baseline.protected_short_model_tokens + - governance.regression_baseline.protected_measurement_values + - governance.regression_baseline.protected_technical_prompt_keywords + - governance.regression_baseline.protected_accessory_prompt_keywords + - governance.vocabulary + - governance.core_pattern_audit + configuration_values: + product_roles: + description: Current water-analysis product role vocabulary. For another genre, replace these terms with that genre's main-product, accessory and consumable roles. + primary_product_terms: + source_paths: - vocabulary.classes.device + terms: + - analysegerät + - analysegeraet + - analysegeräte + - analysegeraete + - messgerät + - messgeraet + - messgeräte + - messgeraete + - analysator + - analysatoren + - analyzer + - gerät + - geraet + - geräte + - geraete + - modell + - monitor + - monitore + - controller + - system + - systeme + - anlage + - anlagen + accessory_product_terms: + source_paths: - vocabulary.classes.accessory + terms: + - zubehör + - zubehor + - reagenz + - reagenzien + - reagent + - indikator + - indikatoren + - indicator + - kit + - set + - ersatz + - ersatzteil + - ersatzteile + - verbrauchsmaterial + - consumable + - filter + - pumpenkopf + - motorblock + - service set + - serviceset + - service-set + requested_accessory_code_terms: + source_paths: - vocabulary.classes.requested_accessory_code_terms + terms: + - indikatortyp + - indikator + - indicator + - reagenz + - reagent + shop_views: + source_paths: - vocabulary.views.shop.device_query.add - vocabulary.views.shop.accessory_query.add - vocabulary.views.shop.device_product.add - vocabulary.views.shop.accessory_product.add + - vocabulary.views.shop.device_focus.add + - vocabulary.views.shop.accessory_focus.add + device_query_terms: + - analysegerät + - analysegeraet + - analysegeräte + - analysegeraete + - messgerät + - messgeraet + - messgeräte + - messgeraete + - analysator + - analysatoren + - analyzer + - gerät + - geraet + - geräte + - geraete + - modell + - modelle + - monitor + - monitore + - controller + - gerät für + - geraet fuer + - geräte für + - geraete fuer + - system + - systeme + - anlage + - anlagen + accessory_query_terms: + - zubehör + - zubehor + - reagenz + - reagenzien + - reagent + - indikator + - indikatoren + - indicator + - kit + - set + - ersatz + - ersatzteil + - ersatzteile + - verbrauchsmaterial + - consumable + - dazu + - passend + - passende + - passendes + - nachfüll + - nachfuell + - refill + - filter + - pumpenkopf + - motorblock + - service set + - serviceset + - service-set + - puffer + - pufferlösung + - pufferloesung + - kalibrierpuffer + - kalibrierlösung + - kalibrierloesung + device_product_terms: + - analysegerät + - analysegeraet + - analysegeräte + - analysegeraete + - messgerät + - messgeraet + - messgeräte + - messgeraete + - analysator + - analysatoren + - analyzer + - monitor + - monitore + - controller + - online-analysator + - online analysator + - online-analysegerät + - online analysegeraet + - online-analysegeräte + - online analysegeraete + - online analyzer + - online monitor + - system + - systeme + - anlage + - anlagen + - gerät + - geraet + - geräte + - geraete + accessory_product_terms: + - reagenz + - reagenzien + - reagent + - indikator + - indikatoren + - indicator + - kit + - set + - verbrauchsmaterial + - consumable + - zubehör + - zubehor + - ersatz + - ersatzteil + - ersatzteile + - nachfüll + - nachfuell + - refill + - lösung + - loesung + - solution + - teststreifen + - test strip + - filter + - pumpenkopf + - motorblock + - service set + - serviceset + - service-set + - puffer + - pufferlösung + - pufferloesung + - kalibrierpuffer + - kalibrierlösung + - kalibrierloesung + device_focus_terms: + - geräte + - geraete + - gerät + - geraet + - analysegerät + - analysegeraet + - messgerät + - messgeraet + - analysator + - controller + - monitor + accessory_focus_terms: + - indikator + - indikatoren + - reagenz + - reagenzien + - zubehör + - zubehor + - ersatzteil + - ersatzteile + - verbrauchsmaterial + - service set + - serviceset + - filter + - pumpenkopf + - motorblock + - puffer + - pufferlösung + - pufferloesung + - kalibrierpuffer + - kalibrierlösung + - kalibrierloesung + prompt_views: + source_paths: - vocabulary.views.prompt.main_device_request_keywords.add - vocabulary.views.prompt.accessory_request_keywords.add - vocabulary.views.prompt.main_device_product_keywords.add - vocabulary.views.prompt.accessory_product_keywords.add - - agent.no_llm_fallback.product_roles.main_device_request_keywords - - agent.no_llm_fallback.product_roles.accessory_product_keywords - - prompt.detection.technical_product_keywords - - prompt.detection.accessory_request_keywords - + main_device_request_keywords: + - messanlage + - messanlagen + - anlage + - anlagen + - messgerät + - messgeraet + - analysegerät + - analysegeraet + - analysator + - analyzer + - gerät + - geraet + - system + - monitor + - controller + - testomat + - testoamt + accessory_request_keywords: + - passend + - passende + - passendes + - zubehör + - zubehor + - dazu + - indikator + - indikatoren + - ph-indikator + - ph indikator + - ph-indikatoren + - ph indikatoren + - reagenz + - kit + - set + - zusatz + - ergänzung + - ergaenzung + - anschlusskabel + - kabel + - sensorkabel + - elektrodenkabel + - elektrode + - puffer + - kalibrierpuffer + - kalibrierlösung + - kalibrierloesung + main_device_product_keywords: + - messanlage + - messanlagen + - messgerät + - messgeraet + - analysegerät + - analysegeraet + - analysator + - analyzer + - online-analysator + - online analysegerät + - gerät + - geraet + - system + - monitor + - controller + - testomat + accessory_product_keywords: + - indikator + - indikatoren + - indicator + - reagenz + - reagenzien + - reagent + - zubehör + - zubehor + - ersatzteil + - ersatzteile + - kit + - set + - verbrauchsmaterial + - consumable + - nachfüll + - nachfuell + - refill + - lösung + - loesung + - solution + - teststreifen + - anschlusskabel + - kabel + - sensorkabel + - elektrodenkabel + - elektrode + - puffer + - kalibrierpuffer + - kalibrierlösung + - kalibrierloesung + - filter + - pumpenkopf + - motorblock + - service set + - serviceset + - service-set + - ph-indikator + - ph indikator + - ph-indikatoren + - ph indikatoren + no_llm_fallback_terms: + source_paths: + - vocabulary.classes.agent_no_llm_main_device_request_keywords + - vocabulary.classes.agent_no_llm_accessory_product_keywords + - agent.no_llm_fallback.product_roles.vocabulary_views.main_device_request_keywords + - agent.no_llm_fallback.product_roles.vocabulary_views.accessory_product_keywords + main_device_request_keywords: + - anlage + - messanlage + - gerät + - geraet + - messgerät + - messgeraet + - analysegerät + - analysegeraet + - analysator + - analyzer + - system + - testomat + - testomaten + - testoamt + - testomate + - pockettester + accessory_product_keywords: + - indikator + - indicator + - indikatortyp + - reagenz + - reagent + - reagenzsatz + - kalibrierlösung + - kalibrierloesung + - pufferlösung + - pufferloesung + - reinigungslösung + - reinigungsloesung + - kalibrier + - puffer + - zubehör + - zubehor + - accessory + - ersatzteil + - verbrauch + - consumable + - kit + - set + - flasche + - bottle + - 100 ml + - 500 ml + - 100ml + - 500ml product_attributes: - description: 'Genre-specific attributes and constraints, for example measurement values now or size/color/material later.' - paths: + description: Current genre attributes and constraint terms. Fashion would typically replace these with size, color, material, fit and variant constraints. + direct_attribute_cleanup: + source_paths: - vocabulary.classes.direct_product_attribute_stop_terms - vocabulary.views.search_repair.direct_product_type_terms.add - vocabulary.views.search_repair.direct_product_attribute_stop_terms.include - - agent.shop_runtime.attribute_cleanup.product_type_terms - - agent.shop_runtime.attribute_cleanup.stop_terms + - agent.shop_runtime.attribute_cleanup.vocabulary_views.product_type_terms + - agent.shop_runtime.attribute_cleanup.vocabulary_views.stop_terms - agent.shop_runtime.attribute_cleanup.comparative_constraint_patterns - - agent.shop_runtime.answer_constraints.length_sort.trigger_patterns - - agent.shop_runtime.answer_constraints.length_sort.value_patterns - - agent.shop_runtime.answer_constraints.length_filter.min_patterns - - agent.shop_runtime.answer_constraints.length_filter.max_patterns + product_type_terms: + - anschlusskabel + - kabel + - sensorkabel + - elektrodenkabel + - elektrodenanschlusskabel + - messkabel + - verbindungskabel + - steckerkabel + - elektrode + - sensor + - puffer + - kalibrierpuffer + - pufferlösung + - pufferloesung + - kalibrierlösung + - kalibrierloesung + stop_terms: + - zeige + - zeig + - suche + - such + - mir + - bitte + - für + - fuer + - nach + - mit + - ohne + - von + - zum + - zur + - der + - die + - das + - ein + - eine + - einen + - länger + - laenger + - lang + - kürzer + - kuerzer + - größer + - groesser + - kleiner + - über + - ueber + - unter + - mindestens + - maximal + - maximum + - minimum + - ab + - bis + - mehr + - weniger + - als + comparative_constraint_patterns: + - /\b(?:länger|laenger|kürzer|kuerzer|größer|groesser|kleiner|über|ueber|unter|mindestens|maximal|maximum|minimum|ab|bis|mehr\s+als|weniger\s+als)\s+(?P\d+(?:[,.]\d+)?\s*[\p{L}µ°%]*)\b/iu + size_and_color_terms: + source_paths: - intent.commerce.size_token_terms - intent.commerce.size_terms - intent.commerce.color_terms @@ -55,109 +653,997 @@ parameters: - intent.commerce.patterns.size_value_template - intent.commerce.patterns.size_token_value_template - intent.commerce.patterns.color_value_template - + size_token_terms: + - xs + - s + - m + - l + - xl + - xxl + - xxxxl + size_terms: + - größe + - groesse + - grösse + color_terms: + - schwarz + - weiß + - weis + - blau + - grau + - beige + - rosa + - pink + - gruen + - orange + - braun + patterns: + sku_like: /\b\d{4,10}\b/u + price_value_template: /\b\d+(?:[.,]\d+)?\s*(?:{price_pattern})\b/u + size_extraction_template: /\b(?:{size_pattern})\s*([a-z0-9.-]+)\b/u + size_value_template: /\b(?:{size_pattern})\s*[a-z0-9.-]+\b/u + size_token_value_template: /\b(?:{size_token_pattern})\b/u + color_value_template: /\b(?:{color_pattern})\b/u + model_like_product: /\b[a-zäöüß][a-zäöüß®\-]*(?:\s+[a-zäöüß][a-zäöüß®\-]*){0,2}\s+\d{2,5}[a-z0-9\-]*\b/u + numeric_length_constraints: + source_paths: + - agent.shop_runtime.answer_constraints.length_sort + - agent.shop_runtime.answer_constraints.length_filter + length_sort: + enabled: true + trigger_patterns: + - /\b(?:ordne|sortiere|sortiert|sortierung)\b.{0,80}\b(?:meter|metern|m)\b/iu + - /\bnach\s+(?:meter|metern|m)\b/iu + value_patterns: + - /(?P\d+(?:[,.]\d+)?)\s*(?:m|meter|metern)\b/iu + length_filter: + enabled: true + min_patterns: + - /\b(?:ab|mindestens|minimum|min\.?|>=|größer\s+gleich|groesser\s+gleich)\s*(?P\d+(?:[,.]\d+)?)\s*(?:m|meter|metern)\b/iu + - /\b(?:länger|laenger|größer|groesser|mehr)\s+(?:als\s+)?(?P\d+(?:[,.]\d+)?)\s*(?:m|meter|metern)\b/iu + - /(?P\d+(?:[,.]\d+)?)\s*(?:m|meter|metern)\s*(?:oder\s+)?(?:länger|laenger|mehr)\b/iu + max_patterns: + - /\b(?:bis|maximal|maximum|max\.?|höchstens|hoechstens|<=|kleiner\s+gleich)\s*(?P\d+(?:[,.]\d+)?)\s*(?:m|meter|metern)\b/iu + - /\b(?:kürzer|kuerzer|kleiner|weniger)\s+(?:als\s+)?(?P\d+(?:[,.]\d+)?)\s*(?:m|meter|metern)\b/iu + - /(?P\d+(?:[,.]\d+)?)\s*(?:m|meter|metern)\s*(?:oder\s+)?(?:kürzer|kuerzer|weniger)\b/iu brands_and_canonical_terms: - description: 'Known brands, canonical token mappings and query enrichment rules that change with the shop genre.' - paths: + description: Genre-specific brands, canonical tokens and query enrichment rules. + known_brands: + source_paths: - commerce_query.known_brands + terms: + - heyl + - horiba + - neomeris + canonical_terms: + source_paths: - commerce_query.search_token_canonical_map + map: + indikatoren: indikator + indicators: indikator + indicator: indikator + reagenzien: reagenz + reagents: reagenz + reagent: reagenz + produkte: produkt + query_enrichment_rules: + source_paths: - query_enrichment.rules + rules: + Wasserhärte: Resthärte + Gerät: Modell + Indikator: Chemie + Seminar: Webinar + Schulung: Seminar + Indikatoren: Indikator + Wasserhärte-Grenzwert: Resthärte + Resthärte-Grenzwert: Wasserhärte + Grenzwert: Überwachungsbereich + store: shop + Indikatortyp: Indikator + accessory_focus_variants: + source_paths: - vocabulary.maps.shop.accessory_focus_variants + map: + values: + indicator_terms: + - indikator + - indikatoren + reagent_terms: + - reagenz + - reagenzien + spare_part_terms: + - ersatzteil + - ersatzteile + service_set_terms: + - service set + - serviceset + - service-set + aliases: + indikator: indicator_terms + indikatoren: indicator_terms + reagenz: reagent_terms + reagenzien: reagent_terms + ersatzteil: spare_part_terms + ersatzteile: spare_part_terms + service set: service_set_terms + serviceset: service_set_terms + service-set: service_set_terms + rag_evidence_synonyms: + source_paths: - vocabulary.maps.agent.rag_evidence_guard.synonyms - + map: + values: + salinity_terms: + - salinität + - salinitaet + - salinity + - salzgehalt + - tds + - leitfähigkeit + - leitfaehigkeit + redox_terms: + - redox + - orp + - oxidations-reduktionspotential + - oxidations reduktionspotential + ph_terms: + - ph + - ph-wert + - ph wert + chlorine_terms: + - chlor + - freies chlor + - gesamtchlor + - chlorine + aliases: + salinität: salinity_terms + salinitaet: salinity_terms + salinity: salinity_terms + redox: redox_terms + orp: redox_terms + ph: ph_terms + chlor: chlorine_terms intent_and_routing: - description: 'Genre-specific commerce/advisory signals and fuzzy routing terms.' - paths: + description: Genre-specific words and patterns that steer commerce/advisory routing. + fuzzy_routing_terms: + source_paths: - vocabulary.classes.input_normalization_fuzzy_routing_terms - - agent.input_normalization.fuzzy_routing.terms + - agent.input_normalization.fuzzy_routing.vocabulary_views.terms + terms: + - shop + - suche + - suchen + - such + - finde + - finden + - kostet + - kosten + - preis + - preise + - preisen + - preiswert + - preiswerte + - günstig + - guenstig + - kaufen + - bestellen + - produkt + - produkte + - artikel + - sku + - online + - analysegerät + - analysegeraet + - messgerät + - messgeraet + - handmessgerät + - handmessgeraet + - pockettester + - analysator + - analyzer + - indikator + - indikatoren + - reagenz + - reagenzien + - verbrauchsmaterial + - zubehör + - zubehoer + - ersatzteil + - ersatzteile + - anschlusskabel + - kabel + - sensorkabel + - elektrode + - elektrodenkabel + - puffer + - kalibrierpuffer + - kalibrierlösung + - kalibrierloesung + - kalibrierung + - lösung + - loesung + - messen + - messung + - überwachen + - ueberwachen + - kontrollieren + - schwimmbad + - pool + - becken + - wasseranalyse + - geeignet + - passend + - empfehlung + - empfehlen + - empfiehl + commerce_intent: + source_paths: - intent.commerce.strong_signals - intent.commerce.advisory_signals - intent.commerce.advisory_product_selection_patterns - intent.commerce.explicit_commerce_intent_patterns - intent.commerce.patterns.model_like_product + strong_signals: + - shop + - alle + - preis + - preise + - preisen + - kunde + - online + - produkt + - artikel + - sku + - kaufen + - kostet + - suche + - such + - finde + - finden + - analysegerät + - analysegeraet + - messgerät + - messgeraet + - pockettester + - pocket tester + - handmessgerät + - handmessgeraet + - analysator + - analyzer + - puffer + - kalibrierpuffer + - kalibrierlösung + - kalibrierloesung + - kalibrierung + - chemie + - reagenz + - reagenzien + - verbrauchsmaterial + - zubehör + - zubehoer + - ersatzteil + - anschlusskabel + - kabel + - sensorkabel + - elektrode + - elektrodenkabel + advisory_signals: + - passt + - eignet + - besser + - besten + - gut + - gut für + - gut fuer + - passend für + - passend fuer + - geeignet + - geeigent + - empfiehl + - empfehl + advisory_product_selection_patterns: + - /\bmit\s+welche(?:m|n|r|s)?\s+(?:testomat(?:en)?|pockettester|pocket\s+tester|analysegerät|analysegeraet|messgerät|messgeraet|analysator|analyzer)\b.*\b(?:messen|messung|überwach(?:en|ung)?|ueberwach(?:en|ung)?)\b/u + - /\bwelche(?:r|s|n|m)?\s+(?:testomat(?:en)?|pockettester|pocket\s+tester|analysegerät|analysegeraet|messgerät|messgeraet|analysator|analyzer)\b.*\b(?:kann|können|koennen|misst|messen|überwacht|ueberwacht|eignet|geeignet|passt|gut|empfehl)\b.*\b(?:messen|messung|überwach(?:en|ung)?|ueberwach(?:en|ung)?)\b/u + - /\b(?:testomat(?:en)?|pockettester|pocket\s+tester|analysegerät|analysegeraet|messgerät|messgeraet|analysator|analyzer)\b.*\b(?:für|fuer)\b.*\b(?:messung|messen|überwachung|ueberwachung)\b/u + - /\b(?:ich\s+)?(?:würde|wuerde|möchte|moechte|will|brauche|benötige|benoetige)\b.{0,80}\b(?:messen|messung|überwachen|ueberwachen|kontrollieren)\b/u + - /\b(?:ich\s+)?(?:suche|finde)\b.{0,120}\b(?:lösung|loesung|gerät|geraet|messgerät|messgeraet|handmessgerät|handmessgeraet|pockettester|analysegerät|analysegeraet|analysator|produkt|artikel)\b.{0,120}\b(?:messen|messung|überwachen|ueberwachen|kontrollieren|wasseranalyse|schwimmbad|pool|becken)\b/u + - /\b(?:messen|messung|überwachen|ueberwachen|kontrollieren)\b.{0,80}\b(?:schwimmbad|pool|becken|wasseranalyse)\b/u + explicit_commerce_intent_patterns: + - /\bshop\b/u + - /\bpreis(?:e|en)?\b/u + - /\bkosten\b/u + - /\bkostet\b/u + - /\bkaufen\b/u + - /\bbestellen\b/u + - /\bprodukt\b/u + - /\bartikel\b/u + - /\bsku\b/u + - /\bonline\b/u + - /\bchemie\b/u + - /\breagenz(?:ien)?\b/u + - /\bverbrauchsmaterial(?:ien)?\b/u + - /\bzubehör\b/u + - /\bzubehoer\b/u + - /\bersatzteil(?:e)?\b/u + - /\banschlusskabel\b/u + - /\bkabel\b/u + - /\bsensorkabel\b/u + - /\belektrodenkabel\b/u + model_like_product_pattern: /\b[a-zäöüß][a-zäöüß®\-]*(?:\s+[a-zäöüß][a-zäöüß®\-]*){0,2}\s+\d{2,5}[a-z0-9\-]*\b/u + sales_intent: + source_paths: - intent.sales.sales_signals - intent.sales.comparison_signals - intent.sales.objection_signals - intent.sales.implementation_signals - intent.sales.roi_signals - + sales_signals: + - preis + - preise + - kosten + - lizenz + - lizenzmodell + - tarif + - tarife + - gebuehr + - gebühr + - monatlich + - jaehrlich + - jährlich + - abo + - subscription + comparison_signals: + - /\bvergleich(en)?\b/u + - /\bvs\b/u + - /\bgegenueber\b/u + - /\balternative(n)?\b/u + - /\bunterschied(e)?\b/u + - /\bbesser\b/u + objection_signals: + - problem + - risiko + - nachteil + - datenschutz + - dsgvo + - sicherheit + - compliance + - kritik + - zweifel + - unsicher + implementation_signals: + - implementierung + - implementieren + - integration + - integrieren + - einführung + - einfuehrung + - aufwand + - setup + - rollout + - migration + - installation + - api + - schnittstelle + roi_signals: + - roi + - rentabilitaet + - rentabilität + - business case + - einsparung + - kosten senken + - umsatz steigern + - effizienz steigern context_resolution: - description: 'Follow-up anchors and meta-query handling for referential shop questions in the current genre.' - paths: + description: Current follow-up anchors and shop meta-query handling for this genre. + commercial_table_follow_up: + source_paths: - agent.follow_up_context.commercial_table_follow_up.history_anchor_patterns - agent.follow_up_context.commercial_table_follow_up.indicator_marker_patterns - agent.follow_up_context.commercial_table_follow_up.query_template_with_model - agent.follow_up_context.commercial_table_follow_up.query_template_without_model + history_anchor_patterns: + - /\bTestomat(?:®)?\s+\d{3,4}\b/iu + - /\b(?:Indikatortyp|Indikator|Indikatoren|Reagenz|Reagenzien|Zubehör|Zubehoer)\b/iu + indicator_marker_patterns: + - /\b(?:Indikatortyp|Indikator(?:en)?|indicator(?:\s+type)?|Reagenz(?:ien)?)\b/iu + query_template_with_model: '{model} indikator' + query_template_without_model: indikator + referential_terms: + source_paths: - agent.shop_runtime.context_resolution.context_usage.referential_terms - - agent.shop_runtime.context_resolution.history_anchor_enrichment.trigger_terms + terms: + - der + - die + - das + - den + - dem + - dazu + - davon + - dafür + - dafuer + - dieser + - diese + - dieses + - obige + - obigen + - oben + - vorher + - zuvor + - gleiche + - gleichen + - selbe + - selben + history_anchor_enrichment: + source_paths: + - vocabulary.classes.agent_shop_context_anchor_trigger_terms + - agent.shop_runtime.context_resolution.history_anchor_enrichment.vocabulary_views.trigger_terms - agent.shop_runtime.context_resolution.history_anchor_enrichment.anchor_patterns - agent.shop_runtime.context_resolution.history_anchor_enrichment.template + trigger_terms: + - indikator + - indikatortyp + - indicator + - reagenz + - reagenzsatz + - reagent + - zubehör + - zubehor + - accessory + anchor_patterns: + - /\b(?:indikator(?:typ)?|indicator(?:\s+type)?|reagenz(?:satz|typ)?|reagent(?:\s+set|\s+type)?|typ|type)\s+[A-Za-zÄÖÜäöüß]{0,8}\s*\d{1,5}(?:\s*[A-ZÄÖÜ]{1,4})?(?:\s*%)?\b/iu + template: '{anchor} {query}' + max_query_terms: 2 + meta_query_guard: + source_paths: - agent.shop_runtime.context_resolution.meta_query_guard.meta_only_terms - agent.shop_runtime.context_resolution.meta_query_guard.context_fallback_filter_terms + meta_only_terms: + - shop + - preis + - preise + - preisen + - kosten + - kostet + - shopsuche + - shop-suche + context_fallback_filter_terms: + - preis + - preise + - preisen + - kosten + - kostet + - grenzwert + - grenzwerte + - grenzwerten + - welche + - gut + - geeignet + - messen + - gemessen + rag_anchor_enrichment: + source_paths: - agent.shop_runtime.context_resolution.rag_anchor_enrichment.numeric_focus_patterns - agent.shop_runtime.context_resolution.rag_anchor_enrichment.product_title_patterns - agent.shop_runtime.context_resolution.rag_anchor_enrichment.anchor_bonus_patterns - agent.shop_runtime.context_resolution.rag_anchor_enrichment.subject_terms - + numeric_focus_patterns: + - /(?P\d+(?:[,.]\d+)?)\s*(?P°?\s*d\s*h|dh|dH)/iu + product_title_patterns: + - /#\s*Produkt\s+Titel:\s*`(?P[^`]+)`/iu + - /\*\*Produktname:\*\*\s*(?P<title>[^\r\n]+)/iu + anchor_bonus_patterns: + - /\b[\p{L}][\p{L}\p{N}®+._-]*(?:\s+|[-_])\d{2,5}\b/u + subject_terms: + - resthärte + - resthaerte + - wasserhärte + - wasserhaerte + - gesamthärte + - gesamthaerte + - härte + - haerte + - grenzwert + - messung shop_query_runtime: - description: 'Shop query cleanup and direct Shopware search behavior that needs genre-specific terms but no PHP branching.' - paths: + description: Current direct Shopware query cleanup and deterministic answer wording for this genre. + current_input_preservation_terms: + source_paths: - vocabulary.classes.agent_shop_current_input_preservation_terms - - vocabulary.classes.agent_shop_context_anchor_trigger_terms - - agent.shop_runtime.query_cleanup.current_input_preservation.terms + - agent.shop_runtime.query_cleanup.current_input_preservation.vocabulary_views.terms + terms: + - ph + - rx + - th + - tc + - redox + - orp + - 0,02 + stopword_cleanup: + source_paths: - agent.shop_runtime.query_cleanup.stopword_cleanup.terms + terms: + - zeige + - zeig + - suche + - such + - finde + - find + - gib + - gebe + - nenne + - mir + - bitte + - ich + - wir + - im + - in + - shop + - für + - fuer + - nach + - mit + - ohne + - von + - zum + - zur + - der + - die + - das + - ein + - eine + - einen + - ordne + - sortiere + - sortiert + - sortierung + - liste + - tabelle + - übersicht + - uebersicht + - auflistung + - meter + - metern + compound_prefix_match: + source_paths: - agent.shop_runtime.result_identity.compound_prefix_match.terms + terms: + - puffer + - kalibrierpuffer + primary_identity_repair: + source_paths: - agent.shop_runtime.result_identity.primary_identity_repair.stop_terms + stop_terms: + - messgerät + - messgeraet + - messgeräte + - messgeraete + - messgeräten + - messgeraeten + - gerät + - geraet + - geräte + - geraete + - geräten + - geraeten + - handmessgerät + - handmessgeraet + - handmessgeräte + - handmessgeraete + - messkoffer + - koffer + direct_answer: + source_paths: - agent.shop_runtime.direct_answer.intro - agent.shop_runtime.direct_answer.no_results - agent.shop_runtime.direct_answer.sorted_by_length_note - agent.shop_runtime.direct_answer.min_length_filter_note - agent.shop_runtime.direct_answer.max_length_filter_note - + enabled: true + max_results: 10 + intro: 'Aus den Shopdaten ergeben sich folgende passende Treffer:' + no_results: Ich finde in den Shopdaten keine passenden Treffer für die angefragte Produktsuche. Ich liste deshalb keine fachfremden Ersatzprodukte auf. + sorted_by_length_note: 'Sortierung: aufsteigend nach erkannter Kabellänge.' + min_length_filter_note: 'Filter: nur Treffer ab {value} m.' + max_length_filter_note: 'Filter: nur Treffer bis {value} m.' result_identity_and_answer_policy: - description: 'Grounding, role separation and atomicity rules that must match the active product genre.' - paths: - - prompt.rules.output_priority_technical - - prompt.rules.response_format_technical - - prompt.rules.response_format_accessory - - prompt.rules.fact_grounding_technical - - prompt.rules.fact_grounding_with_shop + description: Current role separation, fact-grounding and response-format rules that are genre-sensitive. + prompt_rules: + source_paths: + - prompt.output_priority.technical_rules + - prompt.response_format.technical_rules + - prompt.response_format.accessory_rules + - prompt.fact_grounding.technical_rules + - prompt.fact_grounding.with_shop_rules + output_priority_technical: + - '- For technical questions, answer the exact requested fact first and keep it as the main answer.' + - '- If one source chunk contains both the best matching value and nearby comparison values, use the nearby values only as context and do not include them unless the user asks for comparison or alternatives.' + - '- For lowest/highest/minimum/maximum questions, answer only the requested extreme value and the product/device explicitly connected to it.' + - '- Do not add runner-up products, second-lowest values, adjacent ranges, broader tables, or explanatory comparisons unless explicitly requested.' + - '- For a product recommendation tied to an exact numeric value, keep the recommendation anchored to records that contain that exact value/unit. Do not pull indicator codes or ranges from records for other products.' + - '- If the user asks for a suitable device/product and not for an indicator, do not add indicator names unless a same-record device-value-indicator mapping is visible.' + response_format_technical: + - '- Write like technical documentation: precise, neutral, and source-close.' + - '- Prefer exact values, ranges, thresholds, compatibility notes, and application areas over general explanation.' + - '- For direct follow-up questions about an indicator, value, threshold, or device, answer the resolved mapping first before any table or explanation.' + - '- If the sources only support a negative finding, output only that negative finding and do not add speculative alternatives.' + - '- For product-selection answers, keep the answer minimal: suitable product if explicitly supported, exact evidence, current shop fields if same product identity is clear. Do not add sections for Vorteile, Einsatzbereiche, Messprinzip, or Hinweise unless directly asked and explicitly sourced.' + - '- For product-selection answers tied to a numeric value/range, do not include an indicator field unless the same retrieved record explicitly connects the selected product, numeric value/range, and indicator code.' + response_format_accessory: + - '- If the user directly asks for accessories, cables, electrodes, buffers, kits, sets, indicators, reagents, or consumables, answer the accessory request first instead of reframing it as a request for a measuring device.' + - '- For direct accessory shop searches, do not introduce Testomat, measuring-device, or main-device caveats unless the user asks for a device or the provided sources explicitly require a device context.' + - '- For direct accessory shop searches with matching shop hits, never begin with a missing-device statement; begin with the accessory hits or a short shop-only fallback sentence.' + - '- If the shop product name itself explicitly contains the requested accessory type and parameter, such as pH/Redox, treat it as a commercial accessory match and list the exact shop fields. Do not demand separate proof that the accessory itself measures the parameter.' + - '- If the user asks for a matching accessory for a named main device, separate the answer into: main device and matching accessory.' + - '- The main device must come first only when a main device is explicitly requested or named.' + - '- Only name an accessory as matching if compatibility is explicitly grounded in the provided sources.' + - '- Do not call accessories, indicators, reagents, kits, sets, or consumables a device, measuring device, or main product unless the source explicitly says so.' + fact_grounding_technical: + - '- For technical product questions, answer primarily with explicitly stated facts.' + - '- For measurement-parameter questions, do not treat similar or neighboring abbreviations as equivalent. In particular, p-Wert is not pH-Wert unless the source explicitly says pH or pH-Wert.' + - '- Do not invent or infer measurement principles, methods, calibration functions, benefits, advantages, application areas, or alternative products from product family names, search rank, or shop query wording.' + - '- Behave like a technical documentation assistant, not like a sales advisor.' + - '- Keep interpretations minimal and do not generalize application areas beyond the provided sources.' + - '- Do not describe benefits, consequences, risks, or operational outcomes unless they are explicitly stated in the sources.' + - '- Do not translate technical facts into business value unless the source explicitly does so.' + - '- Do not recommend process changes unless explicitly present in the source.' + - '- Do not use persuasive summaries or advisory conclusions.' + - '- If the retrieved knowledge describes one specific named product, stay within that product and do not merge related product families or variants.' + - '- Use neutral engineering language.' + - '- Do not name specific chemicals, indicator substances, standards, or mechanisms unless explicitly stated in the source.' + - '- If the source states signal logic such as green/red, output that signal logic only and do not expand it into operational recommendations or alarm semantics unless explicitly stated.' + - '- If the source lists application areas, repeat only those areas and do not broaden them.' + - '- If the source names an indicator and threshold, reproduce that exactly without extrapolation.' + - '- For lowest, highest, smallest, largest, minimum, maximum, Grenzwert, Messbereich or Aufloesung questions, first identify the exact numeric extreme from the retrieved knowledge and answer that value directly.' + - '- For lowest/highest/minimum/maximum questions, answer only the requested extreme unless the user explicitly asks for a comparison or alternatives.' + - '- For direct numeric lookup questions such as which device measures a given threshold, answer with the exact matching device/value pair first and avoid advisory caveats.' + - '- For product recommendations based on an exact numeric value, use only same-record evidence for the recommended product. Do not import indicator names, ranges, or variants from higher-ranked records that describe different products.' + - '- Do not add the runner-up product, second-lowest value, or adjacent range unless the user asks for it.' + - '- Do not add calibration, accuracy, pretreatment, temperature, or application notes unless those exact notes are requested and explicitly present in the retrieved source.' + - '- For follow-up questions such as "which indicator measures that value", first resolve the referenced value/device, then use the retrieved source entry that explicitly connects value, device and indicator.' + - '- For direct follow-up indicator/value questions, start with the exact mapping in one sentence, for example: Der Wert 0,02 °dH wird beim Testomat 808 mit Indikatortyp 300 gemessen.' + - '- Do not output the full indicator table, measurement principle, application areas, or advisory notes unless the user explicitly asks for all indicators, details, a table, or device information.' + - '- For numeric extreme questions, do not combine a value, device name, indicator name, range or product variant from different chunks unless the same retrieved entry explicitly connects them.' + - '- For exact-value product recommendations, if the retrieved record only supports product plus value/range, answer product plus value/range only; indicator details require an explicit same-record product-value-indicator mapping.' + - '- If several devices or indicators are present, keep each device-indicator-range assignment separate and do not transfer an indicator from one product to another.' + - '- For Testomat CAL or Testomat 2000 CAL threshold/range questions, use only source entries that explicitly name CAL or Testomat 2000 CAL in the same product record. Do not answer with Testomat 808 indicator ranges or the generic 0,02 °dH to 5 °dH range unless a CAL source record explicitly contains that exact assignment.' + - '- If the retrieved CAL-specific source records do not explicitly state numeric CAL threshold values, say that the exact CAL Grenzwerte are not belegbar from the provided sources instead of giving 0,02 °dH to 5 °dH as a typical range.' + - '- For Testomat CAL, do not transfer plain numeric 808 indicator types such as 300, 300 S, 301, 302, 303, 305, 310, 320, 330, or 350. CAL indicator statements must remain CAL-specific, for example TH-prefixed indicator codes when those are explicitly present in the CAL source.' + - '- If the source states only a threshold function, do not expand it into broader control logic.' + - '- If a detail is not explicitly stated in the provided sources, say so plainly.' + - '- Prefer short, source-close sentences over explanatory expansion.' + - '- If the sources only support that a product family is not suitable, output only that unsuitability and stop there.' + fact_grounding_with_shop: + - '- Use shop data as highest priority for current commercial fields: price, availability, URL, current shop-visible naming, and explicitly shop-visible product suitability for product-selection questions.' + - '- Use retrieved knowledge as highest priority for technical matching, thresholds, measurement principles, and technical explanation when it contains a matching product or fact.' + - '- If retrieved knowledge is silent or only contains unrelated products, but live shop results explicitly match the requested parameter/application, use the shop results and do not answer with a negative RAG-only conclusion.' + - '- If the user asks for Schwimmbad, Schwimmbecken, Pool, or typo-like pool wording, a product may only be recommended for that application when the same RAG or SHOP PRODUCT RECORD explicitly names that application. Chlor measurement alone is not proof of swimming-pool suitability.' + - '- If a product record proves Chlor measurement but not Schwimmbad, Schwimmbecken or Pool use, say exactly that distinction and avoid recommendation wording such as empfiehlt sich, geeignet für Schwimmbad, Anwendung im Schwimmbad, or für Schwimmbäder.' + - '- For product-selection questions, a shop result proves technical suitability only when the same SHOP PRODUCT RECORD explicitly states the requested measurement parameter, application, or compatibility. Search ranking, generated query terms, generic category matches, and similar wording are not proof.' + - '- If the requested parameter appears only in the generated shop query, metadata, unrelated highlights, or another product record, treat suitability as unverified and say that the shop hit requires technical verification.' + - '- Do not convert p-Wert, m-Wert, minus m-Wert, alkalinity, acid capacity, or other water-treatment parameters into pH or pH-Wert unless the same source explicitly says pH or pH-Wert.' + - '- When shop results are present and relevant, include current price and the actual URL if available.' + - '- If the shop data does not provide a positive price for a result, do not output any price for that result.' + - '- Do not let accessories, bundles, or service items override a technically better product match unless the user explicitly asks for them.' + - '- Do not call accessories, indicators, reagents, kits, sets, or consumables a device, measuring device, or main product unless the source explicitly says so.' + - '- Do not claim that an accessory is required, necessary, used for calibration, or sets the measurement range unless this is explicitly stated in the provided sources.' + - '- Do not assign the product number, price, URL, or availability of a reagent, accessory, kit, set, consumable, or service item to a device identified in retrieved knowledge.' + - '- Only use commercial fields for the main product when the shop item and the technically identified product clearly refer to the same product identity.' + - '- If the shop match is ambiguous, keep the technical identification and commercial details separate.' + - '- Shop product names are authoritative for their own shop URL, product number, price, availability, image, description, and metadata.' + - '- Do not rewrite a shop record heading with a similar device name from retrieved knowledge. If identities differ or are uncertain, separate the RAG device from the shop hit.' + - '- If the user asks for a main device, measuring device, analyzer, system, or measuring installation, do not present an accessory, indicator, reagent, kit, set, consumable, or service item as the requested main solution.' + - '- If the user asks for an accessory, indicator, reagent, consumable, kit, or solution with a specific measurement parameter, do not replace the requested parameter with another parameter. A hardness indicator is not a valid answer to a pH-indicator request unless the same source explicitly states pH measurement, pH determination, pH measuring range, or an equivalent parameter-specific purpose.' + - '- Mentions of operating conditions, allowed sample pH, reagent-solution pH, storage pH, or pH values at a temperature are not measurement-parameter evidence by themselves.' + - '- If the only shop hit is role-incompatible with the requested product role, state that no matching main-device shop hit is available in the provided shop data; mention the incompatible hit only as a separate accessory/consumable hit if useful.' + - '- If a SHOP PRODUCT RECORD says Commercial fields suppressed, do not output its price, availability, URL, product number, image, or metadata anywhere in the answer.' + - '- Never write shop-hit lines such as price, availability, URL, product number, or Shop-Treffer below a RAG device unless the same exact SHOP PRODUCT RECORD names that device as the exact shop product.' + - '- Never rename a role-incompatible accessory shop record into a main device in headings, summaries, or shop-hit lines.' + - '- If the user asks for the price or availability of a referenced accessory, indicator, reagent, kit, set, or consumable, use commercial fields only from a shop result that clearly matches that accessory identity and code.' + - '- For such accessory price follow-ups, do not answer with the price, URL, product number, or availability of the main device or of unrelated reagents; if no matching accessory shop item is present, say that the price is not available in the provided shop data.' + measurement_evidence_guard_terms: + source_paths: - vocabulary.views.prompt.measurement_evidence_guard.accessory_lookup_guard_terms.add - vocabulary.views.prompt.measurement_evidence_guard.accessory_lookup_passthrough_terms.add - vocabulary.views.prompt.measurement_evidence_guard.generic_positive_context_terms.add - vocabulary.views.prompt.measurement_evidence_guard.generic_negative_context_terms.add - + accessory_lookup_guard_terms: + - indikator + - indikatoren + - indicator + - reagenz + - reagenzien + - reagent + - teststreifen + accessory_lookup_passthrough_terms: + - anschlusskabel + - kabel + - sensorkabel + - elektrodenkabel + - elektrode + - puffer + - kalibrierpuffer + - kalibrierlösung + - kalibrierloesung + generic_positive_context_terms: + - Messung + - messen + - misst + - Messbereich + - Messparameter + - Messgröße + - Messgroesse + - Bestimmung + - bestimmen + - Analyse + - analysiert + - überwachen + - ueberwachen + - Indikator für + - Indikator fuer + - Reagenz für + - Reagenz fuer + - Sensor + - Elektrode + generic_negative_context_terms: + - Betriebsbereich + - Betriebsumgebung + - Einsatzbedingungen + - störungsfrei + - stoerungsfrei search_repair: - description: 'Genre-specific repair tokens, candidate patterns and exact identifier behavior.' - paths: + description: Current search repair tokens, candidate patterns and exact identifier helpers. + direct_product_attribute_lookup: + source_paths: - search_repair.direct_product_attribute_lookup + enabled: true + min_query_tokens_after_cleanup: 2 + comparative_constraint_patterns: + - /\b(?:länger|laenger|kürzer|kuerzer|größer|groesser|kleiner|über|ueber|unter|mindestens|maximal|maximum|minimum|ab|bis|mehr\s+als|weniger\s+als)\s+(?P<value>\d+(?:[,.]\d+)?\s*[\p{L}µ°%]*)\b/iu + requested_accessory_code_terms: + source_paths: - vocabulary.views.search_repair.requested_accessory_code_terms.include + terms: + - requested_accessory_code_terms + candidate_patterns: + source_paths: - search_repair.specific_model_candidate_patterns - - vocabulary.views.search_repair.model_candidate_exclude_terms.include - - vocabulary.views.search_repair.generic_candidate_tokens.add - - vocabulary.views.search_repair.accessory_candidate_terms.add - - vocabulary.views.search_repair.accessory_or_bundle_terms.add - - vocabulary.views.search_repair.specificity_boost_terms.add - search_repair.patterns.model_candidate - search_repair.patterns.accessory_candidate_template - search_repair.patterns.requested_accessory_code - search_repair.patterns.accessory_or_bundle_template - search_repair.patterns.model_like - search_repair.patterns.specificity_boost_template - + specific_model_candidate_patterns: + - /\b([A-Za-zÄÖÜäöüß][A-Za-zÄÖÜäöüß®\-]*(?:\s+[A-Za-zÄÖÜäöüß0-9][A-Za-zÄÖÜäöüß0-9®\-]*){0,3}\s+\d{2,5}(?:\s+[A-ZÄÖÜ]{1,8})?)\b/u + patterns: + model_candidate: /\b([A-Za-zÄÖÜäöüß][A-Za-zÄÖÜäöüß®\-]*(?:\s+[A-Za-zÄÖÜäöüß][A-Za-zÄÖÜäöüß®\-]*){0,2}\s+\d{2,5}[A-Za-z0-9\-]*)\b/u + accessory_candidate_template: /\b((?:{terms})\s+\d{1,5}[A-Za-z0-9\-]*)\b/iu + requested_accessory_code: /\b(?:indikator(?:typ)?|indicator(?:\s*type)?|reagenz|reagent)\s*([A-Za-z]{0,3}\s*\d{1,5}[A-Za-z0-9\-]*)\b/iu + accessory_or_bundle_template: /\b({terms})\b/iu + model_like: /\b[A-Za-zÄÖÜäöüß][A-Za-zÄÖÜäöüß®\-]*(?:\s+[A-Za-zÄÖÜäöüß][A-Za-zÄÖÜäöüß®\-]*){0,2}\s+\d{2,5}[A-Za-z0-9\-]*\b/u + specificity_boost_template: /\b(?:{terms})\b/iu + contains_digit: /\d/u + whitespace_collapse: /\s+/u + tokenize_cleanup: /[^\p{L}\p{N}\s\-]+/u + candidate_terms: + source_paths: + - vocabulary.views.search_repair.model_candidate_exclude_terms.include + - vocabulary.views.search_repair.generic_candidate_tokens.add + - vocabulary.views.search_repair.accessory_candidate_terms.add + - vocabulary.views.search_repair.accessory_or_bundle_terms.add + - vocabulary.views.search_repair.specificity_boost_terms.add + model_candidate_exclude_terms: + - requested_accessory_code_terms + - shop_meta_terms + generic_candidate_tokens: + - wasser + - messgerät + - messgeraet + - produkt + - geräte + - geraete + - gerät + - geraet + - resthärte + - resthaerte + - preis + - infos + - wissen + accessory_candidate_terms: + - indikator + - indicator + - reagenz + - reagent + - kit + - set + accessory_or_bundle_terms: + - passend + - passende + - zubehor + - zubehör + - dazu + - zusatz + - erganzung + - ergänzung + - indikator + - reagenz + - kit + - set + - auch\s+das + - mit\s+preis\s+und\s+allen\s+infos + specificity_boost_terms: + - indikator + - indicator + - testomat + - tritromat + - titromat + - reagenz + - reagent retrieval_and_language: - description: 'Genre-specific protected terms, exact selection helpers and retrieval vocabulary. Engine parameters stay outside this surface.' - paths: + description: Current protected terms, cleanup profiles and exact-selection helpers that are genre-sensitive. Retrieval engine parameters remain outside this area. + protected_terms: + source_paths: - language.protected_terms + terms: + - nicht + - kein + - keine + - welche + - testomat + - indikator + - indikatortyp + - ph + - rx + - redox + - orp + - th + - tc + - 0,02 + cleanup_profiles: + source_paths: - language.cleanup_profiles.commerce_query - language.cleanup_profiles.rag_evidence - language.cleanup_profiles.shop_context_fallback - - retrieval.vocabulary.generic_product_tokens - - retrieval.vocabulary.important_short_model_tokens - - retrieval.vocabulary.family_descriptor_tokens - - retrieval.vocabulary.looks_like_reagent_tokens - - retrieval.vocabulary.looks_like_device_words - - retrieval.vocabulary.looks_like_document_words + commerce_query: + stopword_group_sets: + - de_conversation + stopword_groups: + - pronouns + - user_instruction_terms + - response_style + phrase_group_sets: + - user_instruction + rag_evidence: + stopword_group_sets: + - de_conversation + stopword_groups: + - user_instruction_terms + shop_context_fallback: + stopword_group_sets: + - de_conversation + stopword_groups: + - pronouns + - user_instruction_terms + - question_terms + - usage_terms + - reference_fillers + - response_style + phrase_group_sets: + - user_instruction + meta_term_groups: + - presentation + retrieval_vocabulary_views: + source_paths: + - vocabulary.views.retrieval.generic_product_tokens.add + - vocabulary.views.retrieval.important_short_model_tokens.add + - vocabulary.views.retrieval.family_descriptor_tokens.add + - vocabulary.views.retrieval.looks_like_reagent_tokens.add + - vocabulary.views.retrieval.looks_like_device_words.add + - vocabulary.views.retrieval.looks_like_document_words.add + generic_product_tokens: + - produkt + - produkte + - produktkarte + - titel + - geraet + - gerät + - messgeraet + - messgerät + - wasser + - haerte + - härte + - resthaerte + - resthärte + - analyse + - analysator + - automat + - online + - messung + - messen + - preis + - preise + - kosten + - info + - infos + - passend + - richtige + - richtiges + - geeignet + - geeignete + - welche + - welcher + - welches + - brauche + - suche + important_short_model_tokens: + - th + - tc + - tp + - tm + - ph + - rx + family_descriptor_tokens: + - evo + - eco + - self + - clean + - mini + - pro + - plus + - basic + - lab + - inline + - compact + - panel + - sc + looks_like_reagent_tokens: + - indikator + - reagenz + - laborchemikalie + - chemikalie + - sicherheitsdatenblatt + - sdb + - msds + - ufi + - gebinde + - flasche + - ersatzteil + - zubehoer + - zubehör + - service set + - filtereinsatz + - kerzenfilter + - druckregler + - ph + looks_like_device_words: + - geraet + - gerät + - messgeraet + - messgerät + - analysator + - automat + - messung + - messen + - ueberwachung + - überwachung + - online + - monitor + - modell + - analysegerät + - tester + looks_like_document_words: + - datenblatt + - dokument + - pdf + - handbuch + - manual + - beschreibung + - sdb + - sicherheitsdatenblatt + - msds + exact_selection: + source_paths: - retrieval.exact_selection_token_variant_prefixes - retrieval.exact_selection_indicator_question_tokens - retrieval.exact_selection_indicator_question_phrases @@ -166,23 +1652,188 @@ parameters: - retrieval.exact_selection_indicator_table_row_patterns - retrieval.exact_selection_indicator_table_required_primary_terms - retrieval.exact_selection_indicator_table_required_context_terms - + token_variant_prefixes: + indikator: + - indikator + - indikatortyp + grenzwert: + - grenzwert + messbereich: + - messbereich + testomat: + - testomat + indicator_question_tokens: + - indikator + - indikatortyp + - reagenz + - reagens + - chemie + indicator_question_phrases: + - mit welchem + - womit + indicator_table_heading_patterns: + - /verf(?:ü|ue)gbare\s+indikatortypen|indikatortypen|indikatorvarianten/iu + indicator_table_header_patterns: + - /\|\s*(?:typ|indikator)\s*\|\s*(?:grenzwert|messbereich|bereich)/iu + indicator_table_row_patterns: + - /\|\s*[A-Z]{0,4}\s*\d{2,4}\s*[A-Z]?\s*\|\s*\d/iu + indicator_table_required_primary_terms: + - indikator + indicator_table_required_context_terms: + - grenzwert + - messbereich + - bereich shop_data_mapping: - description: 'Shop record fields and matching text fields that are installation-/genre-specific.' - paths: + description: Current Shopware field mapping and matching text behavior that changes per installation/genre. + custom_fields: + source_paths: - shop_matching.custom_fields + primary: migration_Backup_product_attr1 + secondary: migration_Backup_product_attr2 + use_cases: migration_Backup_product_attr4 + languages: migration_Backup_product_attr5 + text: + source_paths: - shop_matching.text.custom_field_join_separator - shop_matching.text.primary_secondary_separator + primary_secondary_separator: ': ' + use_cases_label: 'Einsatzgebiete: ' + languages_label: 'Sprachen: ' + custom_field_join_separator: ' | ' + role_guard: + source_paths: - shop_matching.role_guard + filter_accessory_products_for_device_queries: true + keep_ambiguous_products_for_device_queries: true + commerce_connection: + source_paths: - commerce.store_api_base_url - commerce.max_shop_results - + store_api_base_url: '%env(SHOPWARE_STORE_API_BASE_URL)%' + max_shop_results: '%env(SHOPWARE_STORE_API_MAX_RESULT)%' governance_and_regression: - description: 'Guardrails and regression expectations that intentionally protect the active genre.' - paths: - - governance.regression_baseline.protected_short_model_tokens - - governance.regression_baseline.protected_measurement_values - - governance.regression_baseline.protected_technical_prompt_keywords - - governance.regression_baseline.protected_accessory_prompt_keywords + description: Current guardrail terms that intentionally protect this genre during audits and regression checks. + regression_baseline: + source_paths: + - governance.regression_baseline + protected_short_model_tokens: + - th + - tc + - tp + - tm + - ph + - rx + protected_measurement_values: + - 0,02 + - 0,05 + - 0,1 + - 0,25 + - 0,5 + - 1,0 + - 2,0 + - 2,5 + - 5,0 + protected_technical_prompt_keywords: + - testomat + - indikator + - grenzwert + - messbereich + - gemessen + technical_priority_required_markers: + - runner-up + - second-lowest + - comparison + protected_accessory_prompt_keywords: + - indikator + - reagenz + protected_search_repair_specificity_terms: + - indikator + - testomat + - reagenz + protected_retrieval_reagent_words: + - indikator + - reagenz + protected_retrieval_device_word_groups: + geraet: + - geraet + - gerät + shop_prompt_regression_original_query: testomat 808 0,02 + shop_prompt_required_output_instruction_markers: + - Output only the final search query. + - 'Output format:' + shop_query_meta_guard_terms: + - shop + - suche + shop_query_context_fallback_filter_terms: + - welchem + - kann + - messen + shop_query_current_input_preservation_terms: + - ph + - redox + vocabulary_guardrails: + source_paths: - governance.vocabulary + core_pattern_audit: + source_paths: - governance.core_pattern_audit + source_roots: + - src + excluded_path_prefixes: + - src/Config/CorePatternAuditProvider.php + - src/Command/ConfigPatternAuditCommand.php + - src/Entity/ + excluded_path_patterns: + - ~(^|/)vendor(/|$)~ + - ~(^|/)var(/|$)~ + - ~(^|/)node_modules(/|$)~ + warning_path_prefixes: + - src/Agent/ + - src/Commerce/ + - src/Intent/ + - src/Knowledge/Retrieval/ + suspicious_calls: + - preg_match + - preg_match_all + - preg_replace + - preg_split + - str_contains + - stripos + - strpos + - str_starts_with + - str_ends_with + - in_array + - array_intersect + - array_intersect_key + domain_marker_terms: + - testomat + - indikator + - indikatortyp + - grenzwert + - messbereich + - reagenz + - reagens + - shop + - produkt + - artikel + - kaufen + - bestellen + - geraet + - gerät + - messgerät + - messgeraet + - analysegerät + - analysegeraet + - analysator + - wasserhärte + - wasserhaerte + - chlor + - redox + allowed_literal_patterns: + - path: src/Knowledge/Retrieval/NdjsonChunkLookup.php + pattern: /Produkt\\s\+Titel/iu + reason: Technical markdown heading parser for product-title metadata. + - path: src/Knowledge/Retrieval/NdjsonHybridRetriever.php + pattern: /Produkt\\s\+Titel/iu + reason: Technical markdown heading parser for product-title metadata. + max_snippet_length: 180 diff --git a/public/assets/styles/base.css b/public/assets/styles/base.css index 2b37492..cd0eff0 100644 --- a/public/assets/styles/base.css +++ b/public/assets/styles/base.css @@ -17,6 +17,7 @@ body { margin: 0; padding: 2rem; font-size: 0.85rem; + } h1, .h1 { @@ -266,6 +267,8 @@ button:disabled { body { color: #cacad5; + background: #16202F; + background: linear-gradient(180deg,rgba(10, 14, 20, 1) 0%, rgba(22, 32, 47, 1) 24%, rgba(10, 14, 20, 1) 100%); } .bg-black { diff --git a/src/Config/GenreConfig.php b/src/Config/GenreConfig.php index 560dc75..b090d69 100644 --- a/src/Config/GenreConfig.php +++ b/src/Config/GenreConfig.php @@ -43,6 +43,27 @@ final class GenreConfig return is_array($surface) ? $surface : []; } + /** + * @return array<string, mixed> + */ + public function getConfigurationValues(): array + { + $values = $this->value('configuration_values', []); + + return is_array($values) ? $values : []; + } + + /** + * @return array<string, mixed> + */ + public function getConfigurationValueGroup(string $group): array + { + $values = $this->getConfigurationValues(); + $groupValues = $values[$group] ?? []; + + return is_array($groupValues) ? $groupValues : []; + } + /** * @return array<string, mixed> */ diff --git a/src/Config/RetriexEffectiveConfigProvider.php b/src/Config/RetriexEffectiveConfigProvider.php index 6ec636b..6d2e323 100644 --- a/src/Config/RetriexEffectiveConfigProvider.php +++ b/src/Config/RetriexEffectiveConfigProvider.php @@ -448,6 +448,7 @@ final readonly class RetriexEffectiveConfigProvider 'mode' => $this->genreConfig->getMode(), 'description' => $this->genreConfig->getDescription(), 'adaptation_surface' => $this->genreConfig->getAdaptationSurface(), + 'configuration_values' => $this->genreConfig->getConfigurationValues(), ]; } @@ -1160,6 +1161,33 @@ final readonly class RetriexEffectiveConfigProvider } } } + + $configurationValues = $genre['configuration_values'] ?? null; + if (!is_array($configurationValues) || $configurationValues === []) { + $errors[] = 'genre.configuration_values must be a non-empty map.'; + return; + } + + foreach ($configurationValues as $group => $valueDefinition) { + if (!is_string($group) || trim($group) === '') { + $errors[] = 'genre.configuration_values keys must be non-empty strings.'; + continue; + } + + if (!is_array($valueDefinition) || $valueDefinition === []) { + $errors[] = sprintf('genre.configuration_values.%s must be a non-empty map.', $group); + } + } + + foreach (array_keys($surface) as $group) { + if (!is_string($group) || $group === '') { + continue; + } + + if (!array_key_exists($group, $configurationValues)) { + $warnings[] = sprintf('genre.configuration_values is missing value group for adaptation_surface.%s.', $group); + } + } } /**