Files
VianoBugAnalysis/docs/project-research-v1.md

220 lines
13 KiB
Markdown

# Projekt-Recherche v1
`ProjectResearch` ist die gemeinsame lesende Schnittstelle für die deterministische
Case-Aufbereitung und die LLM-gesteuerte Hypothesenuntersuchung. Die erste LLM-Phase
bleibt der CaseInterpreter. Der CaseBuilder diagnostiziert nicht und führt keine
LLM-Abfragen aus. `docs/architecture.md` bleibt unverändert.
## Datenquellen und Grenzen
- Sourcecode: lokaler Git-Clone des vom Betreiber freigegebenen Repositories.
Abfragen lesen Git-Objekte eines vollständigen Commit-Hashes, nicht den veränderlichen
Arbeitsbaum. Ein Branchwechsel oder Git-Pull ändert keine bestehende Bindung.
- Source-Schemata: SQL-Dateien desselben Commits. Sie beweisen Tabellenstrukturen
dieses Codestands, keine tatsächlich vorhandenen Datenbankzeilen.
- Datenbank: parameterisierte SELECT-Abfragen gegen ausdrücklich freigegebene Tabellen
einer MySQL-/MariaDB-Datenbank. Zugangsdaten bleiben in Environment-Variablen oder
einer lokalen Passwortdatei. Sie werden nicht in Requests, Captures oder Logs kopiert.
- Externe Webrecherche: weiterhin separat für vorgesehenes Verhalten. Dieser Meilenstein
aktiviert keine Google-Suche und führt keine kostenpflichtigen LLM-Aufrufe aus.
Die LLM darf weder Serveradresse, URL, Branch, Dateisystemwurzel, Datenbank noch
Zugangsdaten bestimmen. Freies SQL, Shellzugriff, Joins mit frei vorgegebenen Ausdrücken,
Schreiboperationen, Builds und Labsteuerung stehen nicht zur Verfügung.
Zusammenhänge werden durch aufeinanderfolgende explizite Abfragen untersucht.
## Operationen
Die Investigation verwendet `next.kind = "tool"`, `operation = "project.query"`
und `arguments` gemäß `project-query-v1.schema.json`.
| `arguments.kind` | Funktion |
| --- | --- |
| `source.files` | Dateipfade durch literalen Teilstring finden |
| `source.search` | Literale Textsuche, optional auf Pfadpräfix begrenzt |
| `source.symbol` | Suche nach vollständigem Symbolwort |
| `source.registration` | Symbolvorkommen als Ausgangspunkt einer Registrierungsprüfung |
| `source.schema` | Literale Suche ausschließlich in SQL-Dateien |
| `source.read` | Begrenzten Zeilenbereich einer bekannten Datei lesen |
| `database.tables` | Namen in den konfigurierten Datenbanken und Tabellenfreigaben finden |
| `database.schema` | Tatsächliche Spalten, Typen, Nullbarkeit und Schlüssel lesen |
| `database.rows` | Spalten auswählen, explizite Filter und begrenzte Seite lesen |
| `database.count` | Vollständige Trefferzahl für dieselben Filter bestimmen |
DB-Filter unterstützen `eq`, `ne`, `lt`, `le`, `gt`, `ge`, `contains`, `in`.
Mehrere Filter werden mit AND verbunden. `contains` behandelt `%`, `_` und das
Escape-Zeichen als literale Eingabe. Werte werden ausschließlich als SQL-Parameter
übergeben. Tabellen und Spalten sind validierte Bezeichner; Tabellen müssen zusätzlich
in der Betreiber-Allowlist liegen. Ein Schema-Lookup prüft die tatsächlichen Spalten.
SQL-DECIMAL-Werte werden als exakte Zeichenfolgen übertragen, nicht gerundet.
Textsuche ist lexikalisch: ein Treffer beweist weder eine semantische Definition noch
eine Registrierung oder einen ausgeführten Aufruf. Auch historische SQL-Updates sind
kein Ersatz für die aktuelle Datenbank. Pfad-Traversal, absolute Pfade und Git-Metadaten
werden abgelehnt; Symlinks und Submodule werden nicht als lesbare Source-Dateien aufgenommen.
Abfragen haben konfigurierbare Zeilen-, Byte-, Datei- und Zeitlimits. Ergebnisse markieren
Pagination, ausgelassene Dateien und gekürzte Zeilen. `complete_filtered_rows` gilt nur
für das genau beschriebene Prädikat ohne Offset/weitere Seite. Eine vollständige Abfrage
mit null Treffern ist ein belastbarer Abwesenheitsbeleg **innerhalb dieses Snapshots und
Prädikats**. Eine partielle Suche rechtfertigt keinen globalen Abwesenheitsschluss.
## Persistenz und Budget
Captures besitzen Formatversion 1, Schema, Anfrage, Ursprung und Ergebnis. Git-Ursprünge
enthalten URL und Commit; Treffer zusätzlich Blob-ID, SHA-256 und Zeilennummer.
DB-Ursprünge enthalten Datenbank und die vom Betreiber vergebene Snapshot-Identität.
Diese Identität muss beim Wechsel/Neuimport eines Snapshots ebenfalls geändert werden;
sie ist keine automatisch berechnete Prüfsumme eines laufenden Servers.
Investigation-Ergebnisse werden unter `analysis/evidence/captures/<sha256>.json`
zusammen mit Requests, Rohantworten und Evidence Records append-only gespeichert.
Auch leere Antworten behalten Anfrage und Abdeckung. Historienprüfung und Wiedereinstieg
benötigen keinen laufenden Git-/DB-Provider. Die Fallakte enthält die tatsächlich gelesenen
Ausschnitte und Zeilen, nicht eine vollständige Kopie von Repository und World-DB.
Ein Tool schreibt selbst nicht in den Case. Der bestehende Controller reserviert das
positive Aktionsbudget für `project.query`, führt die Anfrage aus und übernimmt validierte
Captures atomar mit der Evidenz. Wiederholte identische Ergebnisse sind keine neue Evidenz.
Der In-Memory-Cache friert eine Antwort während Query/Validierung/Persistenz ein; bei einem
Neustart sind gespeicherte Evidenz und der bestätigte Plan autoritativ.
Ausfälle der Recherche führen zu `BLOCKED / RESEARCH_UNAVAILABLE`. Ein bestätigter Plan
bleibt wiederaufnehmbar, einschließlich seiner Reservation. Ungültige Modellantworten
führen nach dem konfigurierten Limit zu `BLOCKED / INVALID_LLM_RESPONSES`; eine technische
Ablehnung beendet keine Hypothese und verändert keine vorhandene Evidenzbewertung.
Nach Behebung ist eine explizite Operator-Wiederaufnahme über `CheckpointStore.advance`
in den im letzten Blockierungscheckpoint hinterlegten `resume_state` nötig. Der
Retry-Zeitpunkt und die bestehende Feedback-Sperre bleiben verbindlich.
## Case-Aufbereitung
`CaseBuilder(..., project_research=service)` sammelt vor Abschluss einer Revision
deterministisch konfigurierte Queries und Entity-Lookups. Namen und Questvoraussetzungen
werden mit Provenienz als technische Fakten sichtbar, bevor die erste LLM-Anfrage beginnt.
Das verhindert, dass eine numerische ID allein als Name oder betroffener NPC ausgelegt wird.
Abfragen und Resultate liegen unter `research/project/`; die Case-Inputs werden mit einem
neuen versionierten Index erweitert. Derselbe Enrichment-Checkpoint wird nicht wiederholt.
Eine abgeschlossene Revision wird nicht nachträglich mit neuen Rohinputs umgeschrieben.
Die Beispielkonfiguration löst Creature- und Quest-IDs generisch auf. Sie enthält keine
BUG-000020-spezifische Diagnose oder Wolpertinger-ID. Die LLM kann während der Untersuchung
weitere Tabellen und Source-Ausschnitte gezielt abfragen.
### Kontextorientierte Erweiterung
Die Quest-Aufbereitung übernimmt nun auch `LogDescription`, `QuestDescription` und
`StartItem`. Damit bleiben Handlung, Zweck des mitgegebenen Gegenstands und die
beschriebenen Voraussetzungen sichtbar. Questtexte beschreiben die im Template
formulierte Mechanik; sie beweisen keine tatsächlich ausgeführte Serveraktion.
`enrichment.texts` hebt solche Texte als eigene `project_description`-Fakten mit
Quellspalte, Rollenlabel und Herkunft hervor. Im numerischen Query-Fakt bleibt ein
Textverweis statt einer zweiten Kopie. Die vollständige unveränderte Antwort liegt
weiterhin im Capture; die Interpretation sieht den Text einmal in lesbarem Kontext.
`enrichment.relationships` verfolgt ausdrücklich konfigurierte Beziehungen aus
zurückgegebenen DB-Spalten. `from_table`, `from_column` und `from_id_column` bestimmen
den Ursprung. `table`, `column` und `columns` bestimmen die folgende DB-Abfrage.
`relation` benennt den Zusammenhang; `entity_type` ergänzt eine referenzierte Entität.
Die Herkunft jeder Beziehung zeigt mit Capture und JSON-Pointer auf den Originalwert.
Ein referenziertes Item wird nicht als beobachtetes Laufzeitobjekt oder Ursache markiert.
Die Vcore-Konfiguration verfolgt mitgegebene/geforderte Items, Queststarter,
SmartAI-Datensätze und ausdrücklich gebundene Creature-/Item-/Spell-Scriptnamen.
SmartAI-Abfragen berücksichtigen `source_type = 0`, damit numerisch gleiche IDs anderer
Entitätstypen nicht vermischt werden. Scriptnamen werden als Symbol gesucht, nicht als
beliebige Zahl über die gesamte Historie. Weitere Beziehungen bleiben konfigurierbar;
das generische Python-Modul enthält keine WoW-IDs oder Quest-Sonderfälle.
`when_column`/`when_value` begrenzen bedingte Beziehungen. Standardmäßig werden null,
leere Zeichenfolgen und numerische Null nicht verfolgt; `ignore_values` kann dies für
andere Profile anpassen. Identische Queries werden nur einmal gesammelt. Zyklen und
Verzweigungen sind durch konfigurierbare `max_queries`, `max_depth` und
`max_relationships` begrenzt. Ausgelassene Abfragen/Beziehungen werden als
`project_context_coverage` sichtbar statt als vollständige Ermittlung ausgegeben.
Leere Item-Script- oder Queststarter-Resultate sind nur Befunde innerhalb dieser
Tabellen. Sie beweisen weder ein fehlendes Item noch, dass eine Quest nicht durch einen
anderen Mechanismus vergeben werden kann. Client-/Hotfix-Itemdaten werden durch diesen
Meilenstein nicht importiert oder erfunden. Eine komplette Item→Spell→Creature-Kette
ist deshalb nicht in jedem Case automatisch auflösbar; fehlende Teile bleiben Recherchebedarf.
Mit aktivierter Projekt-Recherche wird `investigation_project_v1` verwendet. Der volle
Context bleibt unverändert archiviert. Der Prompt lässt Input-Inventar und doppelte
vorige Resultate weg; fremde Hypothesen behalten Evidenz-IDs/Provenienz, aber keine Payloads.
Die Auswahl ist deterministisch und gekennzeichnet. Bereits gespeicherte Legacy-Prompts
bleiben mit ihrer alten Version rekonstruierbar. Dies reduziert Kontextmenge, garantiert
aber keinen bestimmten Eurobetrag und ersetzt keine Messung des nächsten LLM-Tests.
## Lokale Testumgebung
Die eingerichtete Instanz benutzt MariaDB 10.11.14 aus dem offiziellen portablen ZIP
(SHA-256 `838b7d91b871a30c2e42e5ceff9c6859ddd061b57328fb7cb51154af9bd8ddf4`).
Es wird kein Windows-Dienst installiert. Daten und Logs liegen ausschließlich unter
`service-data/research/`, Git-Clone ebenfalls dort. Diese Dateien werden nicht committet.
Importiert wurde ausschließlich `cata_world` (206 Tabellen) aus dem bereitgestellten
Backup, SHA-256 `4964f277ef5cf7f7f98bf4378971dcb55180bac813d49bcda6d2f03ff6969662`.
Account-, Charakter- und weitere Datenbankabschnitte wurden ausgelassen.
Die Instanz bindet `127.0.0.1:33079`; `viano_reader` besitzt SELECT ohne GRANT OPTION.
`read_only` ist aktiviert, Abfragen verwenden zusätzlich eine Read-only-Transaktion.
Der administrative Restore ist ein separates Entwicklungswerkzeug, keine Runtime-Funktion
des Analyseprogramms und kein Modelltool.
Optionale Dependencies installieren:
```powershell
.\.venv\Scripts\python.exe -m pip install -e ".[research,test]"
```
`config/project.local.toml` wurde aus der Beispielkonfiguration vorbereitet. Das Programm
lädt relative Providerpfade relativ zu dieser Konfigurationsdatei. Ein zukünftiger
Server nutzt eigene lokale Zugangsdaten und dieselbe Schnittstelle mit SELECT-only-Rechten.
Die bereits initialisierte Instanz bei Bedarf starten/stoppen:
```powershell
.\.venv\Scripts\python.exe scripts/dev_world_db.py start --binary-dir service-data/research/runtime/portable/mariadb-10.11.14-winx64/bin --directory service-data/research/world-db
.\.venv\Scripts\python.exe scripts/dev_world_db.py stop --binary-dir service-data/research/runtime/portable/mariadb-10.11.14-winx64/bin --directory service-data/research/world-db
```
Ein neuer Rechner benötigt zunächst den portablen Server, eine initialisierte Datadir
(`mariadb-install-db.exe --datadir=<absoluter Pfad> --port=33079 --silent`) und einen
einmaligen `dev_world_db.py restore --dump <Backup>` gegen diese neue lokale Instanz.
Das Werkzeug verweigert Administration, wenn der Port zu einer anderen Datadir gehört.
Zugangsdaten bleiben unter `service-data/`; `reader.local.txt` enthält nur das Reader-Passwort.
Eine strukturierte Anfrage kann ohne LLM und ohne Paketänderung geprüft werden:
```json
{"kind":"database.rows","table":"creature_template","columns":["entry","name"],"filters":[{"column":"name","operator":"contains","value":"Wolpertinger"}],"offset":0,"limit":10}
```
Als `service-data/research/query.json` speichern und ausführen:
```powershell
.\.venv\Scripts\python.exe -m viano_bug_analysis.project_research --config config/project.local.toml --query service-data/research/query.json
```
Ein späterer, ausdrücklich gestarteter LLM-Trial erhält zusätzlich
`--project-config config/project.local.toml`. Für den Qualitäts-/Kostenvergleich einen
frischen Testcase verwenden: alte Hypothesen und frühere terminale Budgetstände werden
durch diesen Meilenstein nicht heimlich korrigiert oder zurückgesetzt.
Offline-Suite und optionale Integrationstests:
```powershell
.\.venv\Scripts\python.exe -m pytest -q
$env:VBA_TEST_PROJECT_CONFIG = "config/project.local.toml"
.\.venv\Scripts\python.exe -m pytest tests/test_project_database_integration.py -q
```
Die Integrationstests prüfen den bekannten Backupstand ausschließlich lesend. Der
CaseBuilder-Smoke-Test aus den echten wowdiag/wowsrc-Paketen liegt separat unter
`service-data/research/smoke`; die ursprüngliche gestoppte Fallakte bleibt erhalten.
Gemini unterstützt Google Search Grounding, wenn die API-Anwendung es aktiviert:
https://ai.google.dev/gemini-api/docs/google-search . Der aktuelle OpenAI-kompatible Adapter
setzt keine solchen Tools. Ein Gitea Runner ist für diesen Stand nicht nötig; er könnte
später Indizes aufbauen, während die Analyse weiterhin nur lesend auf diese zugreift.