220 lines
13 KiB
Markdown
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.
|