558 lines
16 KiB
Markdown
558 lines
16 KiB
Markdown
# README.md
|
||
|
||
# RetrieX v1.6.0
|
||
|
||
> Hinweis: Das System wird fachlich als **RetrieX** bezeichnet.
|
||
> Im Repository existieren aus historischen Gründen noch einzelne Bezeichner wie `RAG`, `rag.zip` oder `RAG_SYSTEM_OVERVIEW.md`.
|
||
|
||
## Überblick
|
||
|
||
RetrieX ist ein dokumentenbasiertes Assistenzsystem auf Basis von Retrieval-Augmented Generation. Version 1.6.0 kombiniert den stabilisierten RAG-/Commerce-Kern mit einer produktionsnäheren Chat-/Admin-Architektur.
|
||
|
||
Das System beantwortet Nutzeranfragen nicht frei, sondern kombiniert:
|
||
|
||
- versionierte Wissensdokumente
|
||
- deterministische Ingest- und Indexierungslogik
|
||
- hybrides Retrieval mit Tag-Routing
|
||
- optionale Shopware-Live-Produktsuche
|
||
- YAML-gestützte Intent-, Language-, Vocabulary-, Prompt- und Commerce-Regeln
|
||
- LLM-basierte Antwortformulierung
|
||
- SSE-Streaming für die Browserausgabe
|
||
- getrennte Chat- und Adminbereiche mit Rollenmodell
|
||
- Admin-Benutzerverwaltung und Access-Denied-/Fehlerseiten
|
||
|
||
Der aktuelle Stand ist kein generischer Chatbot, sondern eine kontrollierte Wissens-, Antwort- und Betriebs-Pipeline.
|
||
|
||
---
|
||
|
||
## Technologiestack
|
||
|
||
### Backend
|
||
|
||
- PHP 8.2
|
||
- Symfony 7.4
|
||
- Doctrine ORM / Doctrine Migrations
|
||
- Symfony Messenger
|
||
- Symfony HttpClient
|
||
- Twig
|
||
|
||
### Python-Layer
|
||
|
||
- SentenceTransformers
|
||
- FAISS
|
||
- FastAPI
|
||
- uvicorn
|
||
|
||
### Zusätzliche Libraries
|
||
|
||
- `fivefilters/readability.php` für URL-Inhaltsauswertung
|
||
- `smalot/pdfparser` für PDF-Textgewinnung
|
||
- `league/commonmark` für Markdown-Rendering
|
||
|
||
---
|
||
|
||
## Kernidee des Systems
|
||
|
||
RetrieX trennt klar zwischen:
|
||
|
||
1. **Primärquellen**
|
||
Dokumente, Dokumentversionen, aktive System-Prompts, Modellkonfigurationen, optionale Shopware-Daten
|
||
|
||
2. **Index- und Retrieval-Ebene**
|
||
`index.ndjson`, `index_meta.json`, `index_runtime.json`, `vector.index`, `tags.ndjson`, `vector_tags.index`
|
||
|
||
3. **Orchestrierung**
|
||
Anfrageannahme, Kontextaufbau, URL-Analyse, Retrieval, Commerce-Erkennung, Shopquery-Reparatur, Prompt-Aufbau, Streaming
|
||
|
||
4. **Ausgabe**
|
||
Chat-Frontend, SSE-Stream, Statuskarten, Shopkarten, Quellenchips und kontextsensitive Folgeaktionen
|
||
|
||
5. **Betrieb und Governance**
|
||
Chat-/Admin-Security, Rollenmatrix, Userverwaltung, Fehlerseiten, Konfigurationsvalidierung, Source-Audits und Regressionstests
|
||
|
||
---
|
||
|
||
## Version 1.6.0 – wesentliche Neuerungen gegenüber 1.5.x
|
||
|
||
### Chat- und Admin-Architektur
|
||
|
||
- Der Chat läuft über `App\Controller\Chat\ChatController`.
|
||
- `/` und `/chat` rendern `templates/chat/index.html.twig`.
|
||
- Die frühere statische `public/index.html` ist entfernt.
|
||
- Admin-Routen bleiben unter `/admin...` getrennt.
|
||
- Chat-Login und Chat-Logout laufen über `/chat/login` und `/chat/logout`.
|
||
|
||
### Rollen und Security
|
||
|
||
RetrieX nutzt weiterhin eine gemeinsame User-Entity, trennt aber die Bereichsrechte:
|
||
|
||
| Rolle | Zweck |
|
||
| --- | --- |
|
||
| `ROLE_CHAT_USER` | Zugriff auf Chat, Ask/SSE, History und Frontend-Messages |
|
||
| `ROLE_ADMIN_AREA` | Zugriff auf Adminbasis, Dashboard, Guides und Jobübersicht |
|
||
| `ROLE_EDITOR` | Dokumente, Versionen, Tags und Dokument-Ingest |
|
||
| `ROLE_KNOWLEDGE_ADMIN` | Modell-/Retrieval-Konfiguration lesen/testen und Ingest-Profile ansehen |
|
||
| `ROLE_SUPER_ADMIN` | Userverwaltung, Systembereiche, Logs, Reset/Delete, Global Reindex und kritische Umschaltungen |
|
||
|
||
Die Hierarchie ist in `config/packages/security.yaml` definiert. `ROLE_USER` ist nur technische Basisrolle und schaltet keinen Bereich allein frei.
|
||
|
||
### Admin-Benutzerverwaltung
|
||
|
||
`ROLE_SUPER_ADMIN` kann Benutzer im Adminbereich verwalten:
|
||
|
||
- Benutzerliste
|
||
- Benutzer anlegen
|
||
- Benutzer bearbeiten
|
||
- Rollen zuweisen
|
||
- Passwort setzen/zurücksetzen
|
||
- Benutzer aktivieren/deaktivieren
|
||
- Schutz gegen Selbst-Aussperren
|
||
- Schutz des letzten aktiven Super-Admins
|
||
|
||
Deaktivierte Benutzer werden beim Login über `ActiveUserChecker` blockiert und bestehende Sessions über `ActiveUserSessionSubscriber` beendet.
|
||
|
||
### Fehler- und Access-Denied-UX
|
||
|
||
Version 1.6.0 enthält konsistente Fehlerseiten für:
|
||
|
||
- 403 / fehlende Rolle
|
||
- 404 / Route nicht gefunden
|
||
- 500 / Serverfehler
|
||
- generische Fehlerfälle
|
||
|
||
Der `AccessDeniedHandler` zeigt bei falschem Bereich die benötigte Rolle, den aktuellen Benutzer und sinnvolle Rücksprung- bzw. Logout-Optionen.
|
||
|
||
### Commerce- und Follow-up-Präzision
|
||
|
||
Die Commerce-Logik wurde weiter gehärtet:
|
||
|
||
- Shopqueries entfernen stärker Sprach-, Satz- und Relationsrauschen.
|
||
- Tippfehlerkorrekturen aus `commerce.yaml` bleiben in der finalen Query erhalten.
|
||
- Direkte Produktnamen wie `chlor select sensor` bleiben erhalten.
|
||
- Modellkürzel wie `Testomat LAB CL` werden nicht mehr auf `testomat` reduziert.
|
||
- Exakte Zubehör-/Indikatorcodes wie `300` werden nicht mit Varianten wie `300 S` vermischt.
|
||
- Mehrprodukt-Follow-ups werden in Einzelqueries aufgeteilt.
|
||
- Preis-Folgeaktionen nutzen sichtbare Produktidentitäten inklusive Produktnummern.
|
||
- Schwache referenzielle Shopfragen wie „suche im Shop nach der Information“ können auf den letzten konkreten Produktanker aus der History zurückfallen.
|
||
- Wiederholende Folgeaktions-Loops werden unterdrückt, wenn die materialisierte Query identisch mit der aktuellen Query ist.
|
||
|
||
---
|
||
|
||
## Unterstützte Dokumentformate
|
||
|
||
Der verifizierte aktuelle Loader unterstützt:
|
||
|
||
- PDF
|
||
- TXT
|
||
- MD
|
||
|
||
Wichtig: Im aktuellen Code-Stand ist kein produktiver DOCX-Loader in der eigentlichen Ingest-Pipeline sichtbar. Dokumentation und Tests sollten deshalb bewusst nur die real verifizierten Formate nennen.
|
||
|
||
---
|
||
|
||
## Laufzeitfluss einer Browser-Anfrage
|
||
|
||
Der aktuelle Chat nutzt bevorzugt den Job-basierten SSE-Flow:
|
||
|
||
1. Frontend sendet `POST /ask-jobs` mit Prompt und optionalem Kontextflag.
|
||
2. `AskSseController` legt einen Antwort-Job an.
|
||
3. Frontend öffnet `GET /ask-sse/{jobId}`.
|
||
4. `AgentRunner` orchestriert die Anfrage.
|
||
5. Optional wird URL-Inhalt aus der Nutzerfrage extrahiert.
|
||
6. `NdjsonHybridRetriever` holt Wissenskontext.
|
||
7. Optional erkennt `CommerceIntentLite` Commerce-/Shop-Intent.
|
||
8. Shopquery wird optimiert, bereinigt, ggf. repariert und über Shopware gesucht.
|
||
9. `PromptBuilder` baut den finalen LLM-Prompt.
|
||
10. `OllamaClient` streamt die Modellantwort.
|
||
11. Chunks werden als SSE-Events ins Frontend gesendet.
|
||
12. Der Turn wird in der Gesprächshistorie persistiert.
|
||
|
||
Zusätzlich existiert weiterhin `POST /ask-sse` als direkter Streaming-Endpunkt.
|
||
|
||
---
|
||
|
||
## Gesprächskontext
|
||
|
||
`ContextService` verwaltet die Konversationshistorie dateibasiert.
|
||
|
||
Eigenschaften:
|
||
|
||
- Historie wird pro stabiler Client-ID gespeichert.
|
||
- abgeschlossene Turns werden append-only geschrieben.
|
||
- regulärer Kontext und Full-Context sind getrennt vorgesehen.
|
||
- Browser-Anfragen nutzen standardmäßig budgetierten bzw. regulären Kontext.
|
||
- Full-Context muss explizit über `fullContext` angefordert werden.
|
||
|
||
Aktuelle Standardwerte aus `config/retriex/runtime.yaml`:
|
||
|
||
- regulärer sichtbarer Kontext: letzte 25 Zeilen
|
||
- Full-Context: letzte 500 Zeilen
|
||
|
||
---
|
||
|
||
## URL-Auswertung
|
||
|
||
Wenn im Prompt eine URL vorkommt, extrahiert `UrlAnalyzer` den Inhalt der ersten URL.
|
||
|
||
Aktuelle Eigenschaften:
|
||
|
||
- Timeout-basiertes Laden
|
||
- `Readability`-basierte Extraktion des lesbaren Inhalts
|
||
- HTML wird entfernt
|
||
- Whitespace wird normalisiert
|
||
- Ausgabe wird auf maximal 5000 Zeichen begrenzt
|
||
|
||
Der extrahierte Text wird als zusätzlicher unterstützender Wissensblock in den finalen Prompt aufgenommen.
|
||
|
||
---
|
||
|
||
## Ingest- und Indexarchitektur
|
||
|
||
### Zielbild
|
||
|
||
RetrieX nutzt eine deterministische Ingest-Architektur mit NDJSON als operativer Wissensbasis und FAISS als Vektorindex.
|
||
|
||
### Zentrale Dateien
|
||
|
||
- `var/knowledge/index.ndjson`
|
||
- `var/knowledge/index_meta.json`
|
||
- `var/knowledge/index_runtime.json`
|
||
- `var/knowledge/vector.index`
|
||
- `var/knowledge/vector.index.meta.json`
|
||
- `var/knowledge/tags.ndjson`
|
||
- `var/knowledge/vector_tags.index`
|
||
- `var/knowledge/vector_tags.index.meta.json`
|
||
|
||
### `index.ndjson`
|
||
|
||
Operative Chunk-Basis des Systems:
|
||
|
||
- eine JSON-Zeile pro Chunk
|
||
- streamingfähig
|
||
- geeignet für append und full rewrite
|
||
- Grundlage für den Vector-Rebuild
|
||
|
||
### `index_meta.json`
|
||
|
||
Struktur-Metadaten des Index, u. a.:
|
||
|
||
- `index_version`
|
||
- `created_at`
|
||
- `chunk_size`
|
||
- `chunk_overlap`
|
||
- `embedding_model`
|
||
- `embedding_dimension`
|
||
- `scoring_version`
|
||
- weitere Strukturfelder aus der aktiven Index-Konfiguration
|
||
|
||
### `index_runtime.json`
|
||
|
||
Laufzeitdaten, u. a.:
|
||
|
||
- `chunk_count`
|
||
- `last_rebuild_at`
|
||
- optionale Commit-Marker wie `last_tags_rebuild_at`
|
||
|
||
---
|
||
|
||
## Dokument-Lifecycle
|
||
|
||
Der aktuelle Dokumentfluss ist technisch so aufgebaut:
|
||
|
||
1. Dokumentversion wird aktiviert oder ingestiert.
|
||
2. Guardrails prüfen die Strukturverträglichkeit.
|
||
3. Alte Chunks des Dokuments werden entfernt.
|
||
4. Neue Chunks werden streamingfähig geschrieben.
|
||
5. Der komplette Vektorindex wird neu gebaut.
|
||
6. Runtime-Stats werden atomar aktualisiert.
|
||
7. Status der Version wird auf `INDEXED` gesetzt.
|
||
|
||
Wichtige Eigenschaft:
|
||
|
||
- Pro Dokument gibt es fachlich eine aktive Version.
|
||
- Chunks sind abgeleitete Artefakte, keine Primärdaten.
|
||
|
||
---
|
||
|
||
## Ingest-Services
|
||
|
||
### `GuardrailValidator`
|
||
|
||
Prüft über `IndexMetaManager`, ob der aktuelle Index strukturell zur aktiven Konfiguration passt. Wenn relevante Strukturparameter geändert wurden, wird lokaler Ingest blockiert.
|
||
|
||
### `ChunkWriteService`
|
||
|
||
Kapselt die Schreibzugriffe auf den Chunk-Bestand:
|
||
|
||
- Gesamtanzahl zählen
|
||
- Chunks nach `document_id` kompaktieren
|
||
- neue Chunks anhängen
|
||
- vollständigen Rewrite durchführen
|
||
|
||
### `VectorRebuildService`
|
||
|
||
Führt den vollständigen FAISS-Rebuild aus und aktualisiert anschließend die Runtime-Metadaten.
|
||
|
||
### `IngestFlow`
|
||
|
||
Orchestriert:
|
||
|
||
- Dokument-Ingest
|
||
- Global Reindex
|
||
- Dokumentlöschung inklusive Rebuild
|
||
|
||
---
|
||
|
||
## Retrieval
|
||
|
||
Der aktive Retriever ist:
|
||
|
||
- `App\Knowledge\Retrieval\NdjsonHybridRetriever`
|
||
|
||
„Hybrid“ bedeutet im aktuellen Code eine orchestrierte Kombination aus mehreren Retrieval-Schritten.
|
||
|
||
### Aktuelle Retrieval-Pipeline
|
||
|
||
1. Query Cleaning
|
||
2. Query Enrichment
|
||
3. Intent-Erkennung
|
||
4. Katalog-/Listenrouting
|
||
5. Tag-Routing auf Kandidatendokumente
|
||
6. globale Vektorsuche
|
||
7. optionale gescopte Vektorsuche auf Kandidatendokumente
|
||
8. Fusion der Treffer
|
||
9. Selektion der finalen Chunk-IDs
|
||
10. Laden der finalen Chunk-Texte aus NDJSON
|
||
|
||
### Verwendete Bausteine
|
||
|
||
- `QueryCleaner`
|
||
- `QueryEnricher`
|
||
- `IntentLite`
|
||
- `SalesIntentLite`
|
||
- `CatalogIntentLite`
|
||
- `IntentRouteResolver`
|
||
- `TagRoutingService`
|
||
- `VectorSearchClient`
|
||
- `NdjsonChunkLookup`
|
||
|
||
### Besondere Logiken
|
||
|
||
- Listenfragen werden gesondert erkannt.
|
||
- Kataloganfragen können direkt einen Katalogblock statt regulärer Chunks liefern.
|
||
- globale und gescopte Treffer werden gefused.
|
||
- Chunk-Selektion ist dokument- und abstandsbegrenzt.
|
||
- Exakte Auswahlfragen, Tabellen-/Indikatorfragen und Grenzwertfragen haben eigene Präzisionspfade.
|
||
|
||
---
|
||
|
||
## Vektor-Layer
|
||
|
||
### Komponenten
|
||
|
||
- `python/vector/vector_ingest.py`
|
||
- `python/vector/vector_search.py`
|
||
- `python/vector/vector_service.py`
|
||
|
||
### Betriebsmodus
|
||
|
||
Der produktive Zugriff erfolgt primär über den HTTP-basierten Vector-Service.
|
||
|
||
Service-URL im aktuellen Default:
|
||
|
||
- `http://127.0.0.1:8090`
|
||
|
||
### Aufgaben des Vector-Service
|
||
|
||
- Embedding-Modell laden
|
||
- FAISS-Hauptindex laden
|
||
- Tag-Index laden
|
||
- Suchanfragen für Chunks beantworten
|
||
- Suchanfragen für Tags beantworten
|
||
- Reloads auf neue Indexstände ermöglichen
|
||
|
||
Der Python-Service hält Modell und Indizes persistent im RAM, um wiederholte Suchanfragen deutlich schneller zu bedienen.
|
||
|
||
---
|
||
|
||
## Prompt-Aufbau
|
||
|
||
`PromptBuilder` setzt den finalen LLM-Prompt aus diesen Blöcken zusammen:
|
||
|
||
1. **SYSTEM**
|
||
Aktiver System-Prompt aus der Datenbank
|
||
|
||
2. **CONVERSATION CONTEXT (authoritative)**
|
||
Gesprächshistorie des Nutzers
|
||
|
||
3. **LIVE SHOP RESULTS (authoritative for products)**
|
||
Shopware-Treffer, falls Commerce aktiv ist
|
||
|
||
4. **RETRIEVED KNOWLEDGE (supporting)**
|
||
Wissens-Chunks aus dem Retriever
|
||
|
||
5. **CONTENT FROM URL (supporting)**
|
||
Optional extrahierter URL-Inhalt
|
||
|
||
6. **USER QUESTION**
|
||
Aktuelle Nutzerfrage
|
||
|
||
Für Produktfragen behandelt das System Shopdaten explizit als führende Produktquelle. Fachliche Eignungsaussagen bleiben dennoch an RAG-/Kontextbelege und Prompt-Guardrails gebunden.
|
||
|
||
---
|
||
|
||
## Commerce- und Shopware-Integration
|
||
|
||
RetrieX besitzt eine optionale Shopware-Store-API-Integration.
|
||
|
||
### Aktivierung
|
||
|
||
Die Shop-Suche wird nur genutzt, wenn `CommerceIntentLite` eine passende Anfrage erkennt.
|
||
|
||
Mögliche Zustände:
|
||
|
||
- `none`
|
||
- `product_search`
|
||
- `advisory_product_search`
|
||
|
||
### Aktueller Shop-Flow
|
||
|
||
1. Commerce-Intent erkennen.
|
||
2. LLM erzeugt zunächst eine kurze Shop-Suchphrase.
|
||
3. `CommerceQueryParser` normalisiert und bereinigt die Query.
|
||
4. Follow-up-/History-/RAG-Anker können die Query ergänzen.
|
||
5. `SearchRepairService` kann fehlende oder zu enge Shopqueries reparieren.
|
||
6. `ShopwareCriteriaBuilder` baut Suchkriterien.
|
||
7. `StoreApiClient` ruft `/store-api/search` auf.
|
||
8. Ergebnisse werden zu `ShopProductResult` gemappt.
|
||
9. Ergebnisidentität und Rollenlogik filtern zu breite Treffer.
|
||
10. Ergebnisse fließen in Prompt, Statuskarten und Folgeaktionen ein.
|
||
|
||
### Wichtige Präzisionsregeln in v1.6.0
|
||
|
||
- Exakte Artikelnummern und Produktnummern werden bevorzugt.
|
||
- Exakte Zubehörcodes bleiben exakt.
|
||
- Produktlisten-Follow-ups werden in Einzelqueries aufgeteilt.
|
||
- Produktidentität wird über Name, URL, Artikelnummer und sichtbare Antwortprodukte abgesichert.
|
||
- Schwache Shop-Meta-Fragen dürfen auf konkrete History-Anker zurückfallen.
|
||
- Shop-only Antworten bleiben vorsichtig, wenn keine belastbare technische Eignung belegt ist.
|
||
|
||
---
|
||
|
||
## Antwort-Streaming
|
||
|
||
Die Browserausgabe erfolgt per Server-Sent Events.
|
||
|
||
### Eigenschaften des aktuellen SSE-Flows
|
||
|
||
- Job-basierter Stream über `/ask-jobs` und `/ask-sse/{jobId}`
|
||
- direkter Legacy-Stream über `POST /ask-sse`
|
||
- Reconnect-/Replay-Unterstützung über Event-IDs
|
||
- Stale-Job-Erkennung
|
||
- Output Buffer werden aktiv geleert
|
||
- Cookies werden vor Streamstart weitergereicht
|
||
- Chunks werden direkt als SSE `data:`-Zeilen übertragen
|
||
- Zeilenumbrüche bleiben erhalten
|
||
- am Ende wird ein `done`-Event gesendet
|
||
|
||
---
|
||
|
||
## Projektstruktur
|
||
|
||
Die zentralen Verzeichnisse im aktuellen Stand sind:
|
||
|
||
- `src/`
|
||
- `config/`
|
||
- `templates/`
|
||
- `migrations/`
|
||
- `python/`
|
||
- `public/`
|
||
- `var/`
|
||
- `bin/`
|
||
|
||
### Wichtige Bereiche in `src/`
|
||
|
||
- `Agent/`
|
||
- `Commerce/`
|
||
- `Config/`
|
||
- `Context/`
|
||
- `Controller/Chat/`
|
||
- `Controller/Admin/`
|
||
- `Index/`
|
||
- `Ingest/`
|
||
- `Intent/`
|
||
- `Knowledge/`
|
||
- `Routing/`
|
||
- `Security/`
|
||
- `Shopware/`
|
||
- `Tag/`
|
||
- `Vector/`
|
||
|
||
---
|
||
|
||
## Wichtige Commands
|
||
|
||
Verifizierte relevante Commands im aktuellen Stand:
|
||
|
||
- `mto:agent:chat`
|
||
- `mto:agent:ingest:run`
|
||
- `mto:agent:ingest:version`
|
||
- `mto:agent:vector:control`
|
||
- `mto:agent:vector:rebuild`
|
||
- `mto:agent:vector:health`
|
||
- `mto:agent:tags:export`
|
||
- `mto:agent:tags:rebuild`
|
||
- `mto:agent:tags:job:run`
|
||
- `mto:agent:tag:health`
|
||
- `mto:agent:system:rebuild`
|
||
- `mto:agent:config:validate`
|
||
- `mto:agent:config:audit-source`
|
||
- `mto:agent:config:audit-patterns`
|
||
- `mto:agent:config:dump-effective`
|
||
- `mto:agent:regression:test`
|
||
- `mto:agent:test:shop-search`
|
||
- `mto:agent:test-vector`
|
||
- `mto:agent:user:create`
|
||
|
||
### Vector-Service steuern
|
||
|
||
```bash
|
||
bin/console mto:agent:vector:control --status
|
||
bin/console mto:agent:vector:control --install --start --reload
|
||
```
|
||
|
||
### Empfohlene Standardchecks nach Patches
|
||
|
||
```bash
|
||
php bin/console cache:clear
|
||
php bin/console lint:yaml config/packages/security.yaml config/retriex
|
||
php bin/console lint:twig templates
|
||
php bin/console mto:agent:config:validate
|
||
php bin/console mto:agent:regression:test
|
||
php bin/console mto:agent:config:audit-source --details
|
||
php bin/console mto:agent:config:audit-patterns --details
|
||
```
|
||
|
||
---
|
||
|
||
## Developer Policies / Governance
|
||
|
||
Die YAML-only-Migration gilt als abgeschlossen, solange diese Checks grün bleiben:
|
||
|
||
```bash
|
||
php bin/console mto:agent:config:validate
|
||
php bin/console mto:agent:config:audit-source --details
|
||
php bin/console mto:agent:config:audit-patterns --details
|
||
php bin/console mto:agent:regression:test
|
||
```
|
||
|
||
Entwickler müssen `DEVELOPER_POLICIES.md` beachten.
|
||
|
||
Kernregeln:
|
||
|
||
- YAML unter `config/retriex/` ist die Source of Truth für konfigurierbares Verhalten.
|
||
- Keine neuen PHP-only-semantischen Defaults, Tokenlisten, Prompttexte, Matching-Regeln oder Business-Fallbacks.
|
||
- Neues konfigurierbares Verhalten muss über YAML ergänzt und explizit verdrahtet werden.
|
||
- Regression-sensitive Flows aus den stabilen 1.4.x/1.5.x/1.6.0-Baselines müssen geschützt bleiben.
|
||
- Core-Pattern- und Source-Audits sollen Domainlisten im PHP-Core verhindern.
|