diff --git a/README.md b/README.md index 40b13ff..ee6d32e 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,9 @@ The [Linux deployment guide](docs/linux-deployment.md) covers systemd services, protected credentials, HTTPS and non-billable readiness checks. The [integration key manager](docs/integration-keys.md) lets signed-in users create, reveal and revoke project-scoped machine credentials. +The web tab **Benutzeranleitung** includes the [user guide](docs/user-guide.md) +and operator documentation, including project/source/database configuration. +After editing bundled documentation, run `python scripts/build_user_manual.py`. Requires Python 3.11 or newer. diff --git a/docs/intake-api.md b/docs/intake-api.md index 6b7a08d..8e1e5f4 100644 --- a/docs/intake-api.md +++ b/docs/intake-api.md @@ -4,7 +4,8 @@ Die API erstellt interne Case-Pakete und veröffentlicht sie atomar in der Inbox Externe Programme liefern Metadaten und Dateien; sie erzeugen und bearbeiten keine internen Manifeste. Die API führt keine Analyse und keine LLM-Aufrufe aus. Ein dauerhaft laufender [Analyseworker](analysis-worker.md) übernimmt anschließend die -Aufnahme und Verarbeitung. Die allgemeine Weboberfläche bleibt ein weiterer Ausbauschritt. +Aufnahme und Verarbeitung. Die [Weboberfläche](web-console.md) bietet Übersicht, +Auftragsübergabe, Testerantworten und Ergebnisdownloads. ## Lokaler Start @@ -17,7 +18,9 @@ $env:VBA_INTAKE_TOKEN = [Convert]::ToHexString([System.Security.Cryptography.Ran ``` Der API-Token ist ein eigener Zugangsschlüssel, kein Gemini-Key. Programme erhalten -je einen Client und einen Token aus einer serverseitigen Umgebungsvariable. Der +vorzugsweise einen Schlüssel aus der [Web-Schlüsselverwaltung](integration-keys.md). +Alternativ bleiben Clients mit Token aus einer serverseitigen Umgebungsvariable +unterstützt; der Beispielstart oben zeigt diese Variante. Der Token benötigt 32–256 Zeichen aus `A-Z a-z 0-9 _ -`. Auf älterem Windows PowerShell kann ein solcher Token über einen Passwortmanager erzeugt und als Variable gesetzt werden. Der Beispielstart bindet nur an `127.0.0.1:8080`. Für entfernte Nutzung sind diff --git a/docs/project-configuration.md b/docs/project-configuration.md new file mode 100644 index 0000000..044bae6 --- /dev/null +++ b/docs/project-configuration.md @@ -0,0 +1,114 @@ +# Projekt und Recherchezugriffe konfigurieren + +Die Projektkonfiguration wird über Dateien verwaltet, nicht über die Webseite. +Sie legt fest, welche Werkzeuge ein Auftrag verwenden darf. Ein aufrufendes +Programm kann weder Repository noch DB-Zugänge oder Budgets mit einem Auftrag +überschreiben. Aktuell ist das Profil `wow/vcore` mit dem Importadapter `vcore` +implementiert; andere Projekttypen erfordern entsprechende Adapter und Profile. + +## Zuordnung in api.toml + +Ein Projektelement ordnet eine feste Projekt-ID einem Profil und dessen +Konfigurationsdateien zu. Relative Pfade beziehen sich auf die API-Konfigurationsdatei. +Der Erfassungsworker muss genau dieselbe Projekt-/Profilzuordnung senden und +sein Integrationsschlüssel muss für das Projekt freigegeben sein. + +```toml +[[projects]] +id = "viano-core" +type = "wow" +profile = "vcore" +adapter = "vcore" +planning_mode = "joint" +[projects.settings] +project_config = "project.toml" +llm_config = "llm.toml" +investigation_config = "investigation.bounded.toml" +budget_config = "budget.human-tests.toml" +``` + +Die Linux-Vorlagen stehen unter `deploy/linux/`; der Installer legt die +Konfiguration unter `/etc/viano-bug-analysis` an. Er überschreibt bestehende +Dateien nicht. Die ausführliche Vcore-Projektvorlage steht unter +`config/project.example.toml`, die Relationsregeln unter +`config/project-relations.vcore.toml`. + +## Source und Datenbank in project.toml + +```toml +relations_file = "project-relations.vcore.toml" +[project] +type = "wow" +profile = "vcore" + +[source] +path = "/srv/viano-bug-analysis/viano-core" +url = "https://gitea.viano-software.de/Nico/Viano-Core" +commit = "VOLLSTAENDIGEN_40_STELLIGEN_COMMIT_EINTRAGEN" + +[database] +host = "127.0.0.1" +port = 3306 +database = "cata_world" +user = "viano_reader" +password_env = "VIANO_DB_PASSWORD" +snapshot_id = "KENNUNG_DER_TATSAECHLICHEN_DATENGRUNDLAGE" +tables = ["creature_template", "creature"] +``` + +Das Beispiel zeigt nur den Aufbau und enthält absichtlich ungültige Platzhalter. +Die beiden Tabellen sind keine vollständige Vcore-Freigabeliste. Für das echte +Profil die vollständige Vorlage einschließlich Limits, Enrichment und +Analysewerkzeugregeln verwenden und passend prüfen. + +Der Source-Checkout muss lokal vorhanden sein und den konfigurierten Commit +enthalten. Die URL allein klont oder aktualisiert kein Repository. Der Worker +liest Git-Objekte dieses festen Stands und benötigt keine Schreibrechte auf den +Checkout. Die Linux-Vorlage enthält eine gezielte Git-Vertrauenskonfiguration +für den root-eigenen Checkout. Neue Source-Stände bewusst bereitstellen und +deren vollständigen Commit konfigurieren. + +Der DB-Administrator legt einen Benutzer mit ausschließlich passenden SELECT- +Rechten an. Zusätzlich begrenzt `tables` die zugänglichen Tabellen. Diese +Freigabeliste ersetzt keine serverseitigen Rechte. Account- oder Charakterdaten +gehören nicht zur standardmäßigen World-Recherche. Für entfernte DBs einen +geschützten Netzwerkweg nutzen; der aktuelle Provider konfiguriert selbst kein TLS. + +Das Passwort steht entweder in der durch `password_env` benannten +Umgebungsvariable oder einer separaten geschützten Datei über `password_file`. +Nur eine dieser Varianten setzen. Unter Linux lädt der Worker beispielsweise +`VIANO_DB_PASSWORD` aus seiner root-geschützten `worker.env`. +Passwörter nicht in Fallakten, LLM-Prompts oder Versionsverwaltung ablegen. +Die LLM bekommt Werkzeugergebnisse statt Zugangsdaten. + +## Weitere Konfigurationen + +| Datei | Zuständigkeit | +| --- | --- | +| api.toml | HTTP-Bindung, Workspace, Projekte, Nutzerdatei und optionale env-basierte Maschinenclients | +| worker.toml | Verweis auf api.toml, Polling, Wiederholungsabstände, Speicherreserve und Telemetrie | +| llm.toml | Anbieter, Modell, Schlüssel-Environment, Timeouts, Ausgabe-/Denkeinstellungen und Cache | +| investigation.bounded.toml | Untersuchungsmodus und begrenztes Kontextfenster | +| budget.human-tests.toml | Fachliche Budgetregeln und menschliche Testanfragen | +| telemetry.toml | Heartbeats und lokale Betriebsbeobachtung | +| project-relations.vcore.toml | Projektspezifische Beziehungen für Recherchewerkzeuge | + +Die versionierte Modellvorlage `config/llm.gemini-cache.example.toml` verwendet +`GEMINI_API_KEY`. Das ist unabhängig vom Integrationsschlüssel für externe +Auftragsübergaben. Die API erhält `api.env`; der Analyseworker erhält +`worker.env` mit Cloud- und DB-Zugangsdaten. + +## Prüfen und ändern + +Der Befehl `python -m viano_bug_analysis.deployment check` prüft mit Rolle und +Konfigurationspfad die Betriebsbereitschaft ohne Modellanfrage. Die +[Linux-Anleitung](linux-deployment.md) zeigt die vollständigen Befehle unter der +tatsächlichen Dienstidentität. Die Prüfung umfasst Git-Objekte und freigegebene +DB-Schemata; die Gültigkeit des Cloud-Schlüssels wird nicht durch einen bezahlten +Modellaufruf getestet. `--offline` prüft keine Git-/DB-Verbindung. + +Vor Code- oder Profiländerungen den Worker kontrolliert anhalten und die +Auswirkungen auf laufende Akten prüfen. Der Worker bindet Fälle an ihren +Konfigurationsstand. Eine Änderung ist kein Weg zum Zurücksetzen von Budgets; +abweichende Bindungen können eine Betreiberprüfung erfordern. Bestehende Dateien +und Zugangsdaten vor Änderungen sichern. diff --git a/docs/test-results/user-manual-20261023.md b/docs/test-results/user-manual-20261023.md new file mode 100644 index 0000000..a2aa4c3 --- /dev/null +++ b/docs/test-results/user-manual-20261023.md @@ -0,0 +1,42 @@ +# Benutzeranleitung in der Weboberfläche – 2026-10-23 + +Ergebnis: eigener Reiter mit neun Dokumenten, Inhaltsverzeichnis, sicheren +Markdown-Darstellungen und Markdown-Download. Neue allgemeine Bedienungs- und +Funktionsbeschreibung sowie Projekt-/Source-/DB-/Modellkonfigurationsanleitung. +Vorhandene Einrichtungsanleitungen werden eingebunden, nicht als Serverpfade +verlinkt. Die Übergabe-API-Dokumentation wurde an den vorhandenen Webbetrieb +und die Web-Schlüsselverwaltung angepasst. + +Quellen: `docs/` und `deploy/capture-worker/README.md`, feste Auswahlliste in +`scripts/build_user_manual.py`. Die generierte Webressource wird mit dem Paket +ausgeliefert. Ein Drift-Test verhindert unbemerkte Abweichungen von den Quellen. +Keine tatsächlichen Konfigurationen oder Zugangsdaten im Bundle. + +Validierung: + +```text +python -m pytest tests/test_user_manual.py tests/test_dashboard.py tests/test_web_auth.py tests/test_human_web.py -q +28 passed, 1 dependency deprecation warning +node tests/dashboard-smoke.mjs +PASS, console_errors: [], overflow: false +python scripts/build_user_manual.py --check +PASS +node --check src/viano_bug_analysis/web/user-manual.js +PASS +pip wheel --no-deps --no-index --no-build-isolation . +PASS, manual JSON and renderer included in wheel +``` + +Nach Ergänzung des Pflegehinweises die manuelspezifischen Tests erneut bestanden. +Browser prüft Login, Dokumentauswahl, Inhaltsverzeichnis, Linux-Befehle, +Konfigurationstabellen, HTML-/URL-Abwehr im Renderer und Logout. Desktop- und +Mobilansicht visuell kontrolliert. Quellen bleiben als Markdown separat pflegbar. +Die Darstellung unterstützt die im Korpus verwendeten Überschriften, Listen, +Tabellen, Codeblöcke, Inline-Code, Hervorhebungen und bekannte Dokumentverweise; +beliebiges HTML wird als Text angezeigt. + +Vor lokalen Tests Trials 16.939.129.428 Bytes und Fehlerkorpus 2.471.041 Bytes; +kleine temporäre synthetische Testdaten und Paket-Builds halten das Gesamtbudget +weiter unter 20 GB. Temporäres Wheel nach Prüfung entfernt. Keine realen +Fallkopien, Modellanfragen, Cloudkosten, Dienststarts oder Serveränderungen. +`docs/architecture.md` unverändert. Kein Push. diff --git a/docs/user-guide.md b/docs/user-guide.md new file mode 100644 index 0000000..0e3068f --- /dev/null +++ b/docs/user-guide.md @@ -0,0 +1,153 @@ +# BugAnalysis verwenden + +BugAnalysis untersucht gemeldete Softwarefehler und übergibt das Ergebnis an die +nächste zuständige Stelle. Das Programm erstellt selbst keinen fertigen Patch +und spielt keine Änderungen auf einen Server ein. Der aktuelle Erfassungsadapter +ist für WoW/Vcore eingerichtet. + +## So arbeitet BugAnalysis + +1. Eine Person oder ein Erfassungsprogramm übergibt Bugbeschreibung und + Diagnosearchive. Die Übergabe-API erstellt daraus eine Fallakte. +2. Ein dauerhaft laufender Analyseworker übernimmt den Auftrag und lädt die + Konfiguration des angegebenen Projekts. +3. Der Casebuilder wertet Beobachtungen und Telemetrie aus. Er kann relevante + Identitäten mit den konfigurierten Recherchewerkzeugen auflösen. +4. Die LLM interpretiert den Fall und entwickelt Hypothesen. Im gemeinsamen + Planungsmodus geschieht beides in einem Aufruf. +5. Die Untersuchung prüft Hypothesen mit Source- und DB-Werkzeugen. Eine knappe + Untersuchungsschleife sammelt Ergebnisse; Prüfungen und Konsolidierungen + übernehmen diese in den strukturierten Arbeitsstand. Werkzeuge lesen Daten; + Zugangsdaten erhält die LLM nicht. +6. Die finale Diagnose bewertet die Befunde und kann einen Frühabschluss + annehmen oder weitere Untersuchung verlangen. Fachliche Budgets begrenzen + einzelne Untersuchungen. Ein bestimmter Erfolg ist nicht garantiert. +7. Das Ergebnis enthält Diagnose und Aufträge für Codingagent und menschlichen + Entwickler. Ein Auftrag darf ausdrücklich erklären, dass keine Arbeit für + den jeweiligen Empfänger vorliegt. Fehlende Daten zur Umsetzung können als + menschlicher Auftrag übergeben werden, ohne die erfolgreiche Analyse zu sperren. + +Ein Ergebnis bleibt eine begründete Analyse, keine Garantie für einen wirksamen +Fix. Nach Umsetzung und Tests können Rückmeldungen eine neue Analyserevision +derselben Akte auslösen. Behauptungen, Testerbeobachtungen und bestätigte Befunde +sollten bei der Bewertung auseinandergehalten werden. + +## Anmeldung und Start + +Die Webadresse im Browser öffnen und mit Benutzername und Passwort anmelden. +Benutzerkonten werden ausschließlich per privilegierter Konsole angelegt; +eine Selbstregistrierung gibt es nicht. Alle menschlichen Benutzer haben die +gleichen Rechte für alle Projekte. Externe Programme benutzen eigene +Integrationsschlüssel mit Projektfreigaben. + +API und Analyseworker sind getrennte Dienste. Das Öffnen der Webseite startet +keinen Worker und sendet keine Modellanfrage. Der laufende Worker verarbeitet +Aufträge selbstständig; die Webseite ist die Übersicht und alternative Bedienung. + +## Übersicht und laufende Fälle + +Die Übersicht zeigt erreichbare Worker, den bearbeiteten Fall und dessen +Fortschrittsbalken. Der Balken folgt abgeschlossenen Phasen, nicht vergangener +Zeit. Während einer längeren Untersuchung kann er daher unverändert bleiben. +Abgeschlossene Fälle verschwinden aus der aktiven Workeransicht. + +Die Diagramme zeigen gemessenen Tokenverbrauch. Korrektur- und Wiederholungsaufrufe +bilden eine eigene Kategorie. Denktokens sind bereits in den Ausgabetokens +enthalten und werden nicht doppelt addiert. Fehlende Messwerte werden als solche +ausgewiesen. Diese Zahlen sind keine verbindliche Cloud-Abrechnung und umfassen +nur die erhaltenen Akten im gewählten Messumfang. + +Über Fallnummern lässt sich die Detailansicht öffnen: Beobachtungen, Einordnung, +Hypothesen, Befunde, Diagnose und Aufträge. Frühere Revisionen bleiben über die +Revisionsauswahl einsehbar. Die vollständigen Daten stehen im herunterladbaren ZIP. + +## Neue Aufträge und Rückgaben + +Unter **Auftrag übergeben** Projekt, Bug-ID, Fallname und Beobachtungen eingeben. +Für einen neuen Vcore-Fall das wowdiag-Archiv und möglichst das dazugehörige +wowsrc-Archiv derselben Erfassung auswählen. Die Bug-ID muss mit den Archiven +übereinstimmen. Zusätzliche Dateien lassen sich als Anhänge hinzufügen. + +Nach dem Absenden bestätigt die API die Annahme. Das ist noch kein Analyseerfolg. +Bei einer unterbrochenen Übergabe verwendet das Formular bei unveränderten +Eingaben denselben Idempotenzschlüssel, damit kein doppelter Auftrag entsteht. + +Für eine Rückgabe den Auftragstyp **Abgeschlossene Akte zurückgeben** wählen, +die aktuelle abgeschlossene Case-ZIP hochladen und Ergebnis sowie neue +Beobachtungen eintragen. Beispielsweise kann ein getesteter Patch den Fehler +nicht behoben haben. BugAnalysis ergänzt die Akte und öffnet eine neue Revision. +Blockierte oder noch laufende Akten sind keine Abschlussrückgaben. + +Automatische Erfassung erfolgt über den wowdiag-Worker und dieselbe Übergabe-API. +Externe Programme erstellen keine internen Case-Manifeste selbst. + +## Testanfragen beantworten + +Die Seite **Testanfragen** listet offene menschliche Recherche- und Testfragen +mit Projekt. Nach Zeitpunkt oder Projekt sortieren, eine Anfrage auswählen und +zunächst **Bearbeiten** drücken. Erst dann wird das Antwortformular freigegeben. + +Die Anfrage ist während der Session exklusiv gebunden. Andere Personen können +sie nicht gleichzeitig bearbeiten. Beobachtungen und verlangte Angaben sachlich +eintragen und absenden. Bei Sessionablauf oder Abmeldung wird die Bearbeitung +wieder freigegeben. Nach gültiger Antwort setzt der Worker die Analyse mit dem +vorhandenen Stand fort; fachliche Budgets werden nicht erneuert. + +Eine Testanfrage während der Ursachenklärung ist etwas anderes als ein +Human-Dev-Auftrag im fertigen Ergebnis. Letzterer gehört zur weiteren Umsetzung. + +## Bearbeitete Fälle und Downloads + +Unter **Bearbeitete Fälle** stehen Ergebnisse, übergebene Fälle, blockierte Fälle +und gescheiterte Analysen in einer gemeinsamen Liste. Projekt, Kategorie und +Suchbegriff können kombiniert werden; die Sortierung ist separat wählbar. +Links lädt der Pfeilknopf die aktuelle vollständige Fallakte als ZIP herunter. +Ein Download ändert den Fallstatus nicht und bestätigt keine Übergabe. + +| Zustand | Bedeutung | +| --- | --- | +| Ergebnis bereit / OUTPUT_READY | Analyseergebnis für die weitere Bearbeitung; Routingziel Outbox | +| Übergeben / HANDED_OFF | Die Akte wurde intern als übergeben markiert | +| Blockiert / BLOCKED | Analyse wartet, beispielsweise auf Testerantwort oder technische Behebung | +| Analyse gescheitert / FAILED_TO_ANALYZE | Analyse konnte nicht erfolgreich abschließen; Routingziel Review | + +Blockiert bedeutet nicht abgeschlossen. Sperrgrund und Detailansicht erklären +die nächsten Schritte. Technische Fehler oder unzureichende Eingaben sind von +einem fachlichen Diagnoseergebnis zu unterscheiden. Die Ablagespalte zeigt das +Routingziel, keinen unabhängigen Verzeichnisbestand. + +## Betrieb steuern + +Die Betriebssteuerung in der Übersicht erlaubt das Pausieren neuer Fälle eines +Projekts. Bereits begonnene Fälle dürfen weiterlaufen. Geeignete technische +Fehlerfälle können über eine Fortsetzungsanforderung nach Behebung wieder +freigegeben werden. Diese Aktion ist kein beliebiger Neustart und setzt keine +Budgets zurück. Menschliche Testantworten werden auf ihrer eigenen Seite erfasst. + +## Programme anbinden + +Unter **API-Schlüssel** einen Programmnamen und die erlaubten Projekte auswählen. +Den erzeugten Schlüssel über **Anzeigen** oder **Kopieren** abrufen und im +aufrufenden Dienst geschützt hinterlegen. Schlüssel sind später erneut anzeigbar. +**Widerrufen** verhindert weitere authentifizierte Anfragen mit diesem Schlüssel. + +Die Schlüssel dienen zur Auftragsübergabe und zum lesenden Projektzugriff; +Maschinenprogramme können darüber keine anderen Schlüssel verwalten oder +menschliche Testerantworten ausfüllen. Ein Integrationsschlüssel ist kein +Gemini- oder anderer Modellanbieter-Schlüssel. + +## Einrichtung und Hilfe + +- [Linux-Installation und Betrieb](linux-deployment.md) +- [Projekt-, Source-, DB- und Modellkonfiguration](project-configuration.md) +- [Übergabe-API und Rückgaben](intake-api.md) +- [Analyseworker und Wiederanlauf](analysis-worker.md) +- [Benutzerkonten](user-accounts.md) +- [Integrationsschlüssel und deren Sicherung](integration-keys.md) +- [Weboberfläche im Detail](web-console.md) +- [Erfassungsworker v0.4](capture-worker.md) + +Vor dem ersten Feldbetrieb auf dem Zielserver Bereitschaftsprüfung, HTTPS, +Dienstneustart und Backups prüfen. Danach einen kontrollierten echten Auftrag +einschließlich Rückfrage und Ergebnisabholung durchführen. Die LLM-Zugriffe +erzeugen erst beim laufenden Analysebetrieb Kosten. diff --git a/docs/web-console.md b/docs/web-console.md index f49161b..eb757de 100644 --- a/docs/web-console.md +++ b/docs/web-console.md @@ -15,6 +15,25 @@ Für entfernte Zugriffe HTTPS verwenden. Der Analyseworker läuft unabhängig da [Analyseworker](analysis-worker.md) beschrieben. Das Öffnen der Übersicht löst keine Modellanfragen aus. +## Benutzeranleitung + +Der Reiter **Benutzeranleitung** enthält die allgemeine Bedienung und +Funktionsweise sowie Anleitungen für Linux, Projekt-/DB-/Sourcekonfiguration, +Übergabe-API, Analyseworker, Nutzerkonten, Integrationsschlüssel, Weboberfläche +und Erfassungsworker. Dokumentauswahl, Inhaltsverzeichnis und interne Verweise +erlauben Navigation ohne Server-Dateizugriff. Markdown-Downloads sind ebenfalls +möglich. Der Reiter benötigt eine angemeldete Sitzung; sein Aufruf startet keine +Analyse. Tabellen, Codebeispiele und Überschriften werden als sichere DOM-Elemente +dargestellt, eingebettetes HTML wird nicht ausgeführt. + +Für Dokumentationsänderungen die ursprünglichen Markdown-Dateien unter `docs/` +beziehungsweise `deploy/capture-worker/README.md` bearbeiten und danach +`python scripts/build_user_manual.py` ausführen. Die feste Auswahlliste steht im +Skript; tatsächliche lokale Konfigurationen oder Secrets werden nicht gebündelt. +`python scripts/build_user_manual.py --check` und die Tests erkennen veraltete +Webfassungen. Das erzeugte `web/user-manual.json` wird mit dem Python-Paket +ausgeliefert, sodass keine lokale Kopie des Dokumentationsordners nötig ist. + ## Worker und Fortschritt Die Startseite listet lebende Worker und darunter den jeweils bearbeiteten Fall diff --git a/pyproject.toml b/pyproject.toml index e0f5495..be87021 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ where = ["src"] [tool.setuptools.package-data] "viano_bug_analysis.schemas" = ["*.json"] "viano_bug_analysis.llm.prompts" = ["*.txt"] -"viano_bug_analysis.web" = ["*.html", "*.css", "*.js"] +"viano_bug_analysis.web" = ["*.html", "*.css", "*.js", "user-manual.json"] [tool.pytest.ini_options] testpaths = ["tests"] diff --git a/scripts/build_user_manual.py b/scripts/build_user_manual.py new file mode 100644 index 0000000..2d54804 --- /dev/null +++ b/scripts/build_user_manual.py @@ -0,0 +1,38 @@ +"""Bundle selected, non-secret operator docs for installed web applications. + +Edit the original Markdown files, then run this script. --check detects drift. +""" +import argparse +import json +from pathlib import Path + +ROOT=Path(__file__).resolve().parents[1] +DOCUMENTS=( + ('user-guide','Verwendung und Funktionsweise','docs/user-guide.md'), + ('linux-deployment','Linux-Installation und Betrieb','docs/linux-deployment.md'), + ('project-configuration','Projekt-, Source-, DB- und Modellkonfiguration','docs/project-configuration.md'), + ('intake-api','Übergabe-API und Rückgaben','docs/intake-api.md'), + ('analysis-worker','Analyseworker und Wiederanlauf','docs/analysis-worker.md'), + ('user-accounts','Benutzerkonten','docs/user-accounts.md'), + ('integration-keys','Integrationsschlüssel','docs/integration-keys.md'), + ('web-console','Weboberfläche im Detail','docs/web-console.md'), + ('capture-worker','Erfassungsworker v0.4','deploy/capture-worker/README.md'), +) +TARGET=ROOT/'src/viano_bug_analysis/web/user-manual.json' + + +def bundle(): + return {'format_version':1,'documents':[{'id':identifier,'title':title, + 'markdown':(ROOT/path).read_text(encoding='utf-8')} for identifier,title,path in DOCUMENTS]} + + +def main(): + parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--check',action='store_true');args=parser.parse_args() + content=json.dumps(bundle(),ensure_ascii=False,indent=2)+'\n' + if args.check: + if not TARGET.exists() or TARGET.read_text(encoding='utf-8')!=content: + parser.exit(1,'User manual is stale; run python scripts/build_user_manual.py\n') + else:TARGET.write_text(content,encoding='utf-8',newline='\n') + + +if __name__=='__main__':main() diff --git a/src/viano_bug_analysis/api/app.py b/src/viano_bug_analysis/api/app.py index b206810..99e0322 100644 --- a/src/viano_bug_analysis/api/app.py +++ b/src/viano_bug_analysis/api/app.py @@ -89,6 +89,11 @@ def create_app(config): async def health(request): return JSONResponse({'status': 'OK'}) + async def manual(request): + authenticate(request) + data=json.loads(files('viano_bug_analysis.web').joinpath('user-manual.json').read_text(encoding='utf-8')) + return JSONResponse(data,headers={'Cache-Control':'no-store'}) + async def integration_keys(request): # Machine credentials can never manage or reveal credentials. if request.headers.get('authorization'):raise APIError('AUTH_SESSION_REQUIRED',403) @@ -218,11 +223,11 @@ def create_app(config): async def web(request): from starlette.responses import Response name = request.path_params.get('asset', 'index.html') - if name not in {'index.html', 'dashboard.js', 'dashboard.css', 'case-detail.js','operations.js','test-requests.js','integration-keys.js'}: + if name not in {'index.html', 'dashboard.js', 'dashboard.css', 'case-detail.js','operations.js','test-requests.js','integration-keys.js','user-manual.js'}: raise APIError('API_NOT_FOUND', 404) data = files('viano_bug_analysis.web').joinpath(name).read_bytes() response = Response(data, media_type={'index.html': 'text/html', 'dashboard.js': 'text/javascript', - 'dashboard.css': 'text/css', 'case-detail.js':'text/javascript','operations.js':'text/javascript','test-requests.js':'text/javascript','integration-keys.js':'text/javascript'}[name]) + 'dashboard.css': 'text/css', 'case-detail.js':'text/javascript','operations.js':'text/javascript','test-requests.js':'text/javascript','integration-keys.js':'text/javascript','user-manual.js':'text/javascript'}[name]) response.headers.update({'Content-Security-Policy': "default-src 'self'; script-src 'self'; style-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'", 'X-Content-Type-Options': 'nosniff', 'Referrer-Policy': 'no-referrer', 'Cache-Control': 'no-store'}) return response @@ -296,6 +301,7 @@ def create_app(config): app = Starlette(routes=[Route('/', web), Route('/assets/{asset}', web), Route('/v1/auth/{action}',auth,methods=['GET','POST']), + Route('/v1/manual',manual), Route('/v1/integration-keys',integration_keys,methods=['GET','POST']), Route('/v1/integration-keys/{identifier}/{action}',integration_keys,methods=['POST']), Route('/v1/overview', overview), Route('/healthz', health), Route('/v1/profiles', profiles), diff --git a/src/viano_bug_analysis/web/case-detail.js b/src/viano_bug_analysis/web/case-detail.js index b127d83..63f0d0a 100644 --- a/src/viano_bug_analysis/web/case-detail.js +++ b/src/viano_bug_analysis/web/case-detail.js @@ -116,6 +116,10 @@ function syncDetail(){ if(!detailLoading&&(!selectedCase||detailHash!==location.hash||(!location.hash.includes('/revision/')&¤t?.package_generation!==selectedCase.package_generation)))loadDetail(location.hash); } function route(){ + if(typeof manualRoute==='function'&&manualRoute()){ + if(typeof clearKeys==='function')clearKeys();return; + } + if($('manual-page'))$('manual-page').hidden=true; if(typeof keysRoute==='function'&&keysRoute())return; if($('keys-page')){$('keys-page').hidden=true;clearKeys();} if(typeof testRoute==='function'&&testRoute())return; diff --git a/src/viano_bug_analysis/web/dashboard.css b/src/viano_bug_analysis/web/dashboard.css index 8b17853..d544344 100644 --- a/src/viano_bug_analysis/web/dashboard.css +++ b/src/viano_bug_analysis/web/dashboard.css @@ -5,3 +5,4 @@ .case-link{color:#4f61c7;font-weight:650;text-decoration:none}.case-link:hover{text-decoration:underline}.detail-panel>summary{font-size:18px;font-weight:650;cursor:pointer}.detail-body{margin-top:20px}.semantic-text{color:#45516a;white-space:pre-wrap;overflow-wrap:anywhere;margin:5px 0 12px}.semantic-fields{display:grid;grid-template-columns:minmax(130px,190px) minmax(0,1fr);gap:12px 22px;margin:0}.semantic-fields dt{font-size:12px;color:#7c8599;font-weight:600}.semantic-fields dd{margin:0;min-width:0}.semantic-fields .semantic-fields{grid-template-columns:130px minmax(0,1fr)}.semantic-list{display:grid;gap:10px}.semantic-item{border-left:2px solid #e6eaf6;padding-left:13px}.statement small{display:block;color:#9299a8}.reference-list{color:#7785ae;font-size:11px;overflow-wrap:anywhere}.hypothesis-card{border:1px solid #e6e9f1;border-radius:9px;padding:20px;margin-bottom:16px}.hypothesis-heading{display:flex;align-items:center;justify-content:space-between;gap:12px}.hypothesis-heading h3{font-size:16px;margin:0}.hypothesis-heading .badge{flex-shrink:0}.hypothesis-card .detail-panel{margin:16px 0 0;padding:14px;box-shadow:none}.hypothesis-card .detail-panel>summary{font-size:13px}.evidence-columns{display:grid;grid-template-columns:1fr 1fr;gap:26px;margin-top:18px}.evidence-columns h4{font-size:12px;color:#68758c}.evidence-columns>div{background:#f7f8fc;padding:16px;border-radius:7px;min-width:0}.detail-controls{display:flex;align-items:center;gap:16px}.detail-controls label{margin:0;min-width:170px}.detail-controls button{margin-top:20px}.history-note{background:#f1f3fd;color:#6472ae;padding:12px;border-radius:6px;font-size:12px}.assignment-status{font-weight:650;color:#34436a}.human-document{white-space:pre-wrap;overflow-wrap:anywhere;font:13px/1.7 system-ui}.next-actions p{color:#5f6d85}#case-detail .panel{scroll-margin-top:20px}@media(max-width:900px){.semantic-fields,.semantic-fields .semantic-fields{grid-template-columns:1fr;gap:4px}.semantic-fields dd{margin-bottom:12px}.detail-controls{flex-wrap:wrap}}@media(max-width:700px){.hypothesis-heading{align-items:flex-start;flex-direction:column}.evidence-columns{grid-template-columns:1fr}.detail-controls{width:100%}.detail-controls button{margin-top:0}.hypothesis-card{padding:14px}.rail{flex-wrap:wrap}.rail nav{flex-wrap:wrap}} #key-projects{border:1px solid var(--line);border-radius:8px;padding:12px;margin-bottom:14px}#key-projects label{display:flex;align-items:center;gap:10px;margin:8px 0}#key-projects input{width:auto;margin:0}#key-list button{margin:10px 8px 0 0}#key-list input{font-family:monospace} #result-rows .package-icon{width:34px;height:34px;padding:0;font-size:22px;line-height:1;border-radius:8px}#result-rows td small{display:block;max-width:320px;overflow-wrap:anywhere;color:var(--muted);font-size:11px} +.manual-selector{display:flex;align-items:end;gap:18px;flex-wrap:wrap}.manual-selector label{flex:1;min-width:230px;margin:0}.manual-selector button{margin:0}.manual-layout{display:grid;grid-template-columns:250px minmax(0,1fr);gap:24px;align-items:start}.manual-outline{position:sticky;top:20px;max-height:85vh;overflow:auto;padding:18px}.manual-outline h2{font-size:14px;margin-bottom:14px}#manual-toc{display:grid;gap:5px}#manual-toc button{background:transparent;color:var(--muted);text-align:left;font-size:12px;padding:7px;border-radius:5px}#manual-toc button:hover{background:#eef0fd;color:var(--accent)}#manual-toc .manual-top-heading{font-weight:700;color:var(--ink)}.manual-body{line-height:1.75;overflow-wrap:anywhere;min-width:0}.manual-body h2{font-size:26px;margin:0 0 20px}.manual-body h3{margin:30px 0 10px;font-size:19px}.manual-body h4{margin:24px 0 8px}.manual-body h2,.manual-body h3,.manual-body h4{scroll-margin-top:20px}.manual-body p,.manual-body li{color:#45516a}.manual-body li{margin-bottom:8px}.manual-body a{color:#4f61c7}.manual-body pre{background:#f3f5fa;border:1px solid var(--line);border-radius:8px;padding:16px;overflow:auto;max-width:100%;white-space:pre;font-size:12px}.manual-body code{font-family:ui-monospace,Consolas,monospace}.manual-body p code,.manual-body li code{background:#eef0f7;padding:2px 4px;border-radius:3px}.manual-body td,.manual-body th{white-space:normal;min-width:120px;vertical-align:top}.manual-body ul,.manual-body ol{padding-left:24px}@media(max-width:1000px){.manual-layout{grid-template-columns:1fr}.manual-outline{position:static;max-height:260px}}@media(max-width:700px){.manual-body{padding:20px}.manual-body h2{font-size:22px}} diff --git a/src/viano_bug_analysis/web/dashboard.js b/src/viano_bug_analysis/web/dashboard.js index 9ccaf72..4ea8bec 100644 --- a/src/viano_bug_analysis/web/dashboard.js +++ b/src/viano_bug_analysis/web/dashboard.js @@ -31,6 +31,7 @@ function logout(remote=true) { if(typeof clearOperations==='function')clearOperations(); if(typeof clearTests==='function')clearTests(); if(typeof clearKeys==='function')clearKeys(); + if(typeof clearManual==='function')clearManual(); ['active-count','token-count','correction-count','finished-count'].forEach(id=>$(id).textContent='—'); $('pie').getContext('2d').clearRect(0,0,360,360); } diff --git a/src/viano_bug_analysis/web/index.html b/src/viano_bug_analysis/web/index.html index 26944ca..26c24c2 100644 --- a/src/viano_bug_analysis/web/index.html +++ b/src/viano_bug_analysis/web/index.html @@ -2,11 +2,11 @@ BugAnalysis · Übersicht - +
BETRIEBSÜBERSICHT

Analyse im Blick.

Aktuelle Arbeit und messbarer Verbrauch.

Warte auf Verbindung
@@ -42,5 +42,6 @@

+
diff --git a/src/viano_bug_analysis/web/user-manual.js b/src/viano_bug_analysis/web/user-manual.js new file mode 100644 index 0000000..6f564fd --- /dev/null +++ b/src/viano_bug_analysis/web/user-manual.js @@ -0,0 +1,88 @@ +'use strict'; +let manualData=null,manualLoading=null,manualCurrent=null; +function clearManual(){manualData=null;manualLoading=null;manualCurrent=null;$('manual-document').replaceChildren();$('manual-content').replaceChildren();$('manual-toc').replaceChildren();$('manual-download').disabled=true;} +function manualLink(target){ + if(/^https?:\/\//i.test(target)){try{const url=new URL(target);if(!url.username&&!url.password)return {href:url.href,external:true};}catch{}return null;} + const match=target.match(/^(?:\.\.\/|\.\/|docs\/)*([a-z0-9-]+)\.md(?:#([a-z0-9-]+))?$/); + if(match&&manualData?.documents.some(d=>d.id===match[1]))return {href:`#manual/${match[1]}`}; + return null; +} +function manualInline(parent,value){ + // Render only supported Markdown with DOM nodes. Never interpret source HTML. + const pattern=/(`[^`]+`|\*\*[^*]+\*\*|\[[^\]]+\]\([^\s)]+\))/g;let cursor=0; + for(const match of value.matchAll(pattern)){ + parent.append(document.createTextNode(value.slice(cursor,match.index)));const part=match[0]; + if(part.startsWith('`'))parent.append(text('code',part.slice(1,-1))); + else if(part.startsWith('**'))parent.append(text('strong',part.slice(2,-2))); + else{const link=part.match(/^\[([^\]]+)\]\((.+)\)$/),destination=manualLink(link[2]); + if(destination){const anchor=text('a',link[1]);anchor.href=destination.href;if(destination.external){anchor.target='_blank';anchor.rel='noopener noreferrer';}parent.append(anchor);} + else parent.append(document.createTextNode(link[1])); + } + cursor=match.index+part.length; + } + parent.append(document.createTextNode(value.slice(cursor))); +} +function renderManualMarkdown(markdown){ + const fragment=document.createDocumentFragment(),lines=markdown.replace(/\r/g,'').split('\n'),headings=[]; + const cells=line=>line.trim().replace(/^\||\|$/g,'').split('|').map(s=>s.trim()); + let index=0; + while(index{const cell=document.createElement('th');manualInline(cell,value);row.append(cell);});head.append(row);table.append(head);index+=2; + const body=document.createElement('tbody');while(index{const cell=document.createElement('td');manualInline(cell,value);row.append(cell);});body.append(row); + }table.append(body);wrap.append(table);fragment.append(wrap);continue; + } + const item=line.match(/^\s*(?:[-*]|\d+\.)\s+(.+)$/); + if(item){const ordered=/^\s*\d+\./.test(line),list=document.createElement(ordered?'ol':'ul'); + while(indexd.id===identifier); + if(!manualCurrent){$('manual-content').replaceChildren(text('p','Diese Anleitung ist nicht vorhanden.'));$('manual-toc').replaceChildren();$('manual-download').disabled=true;return;} + $('manual-document').value=manualCurrent.id;const rendered=renderManualMarkdown(manualCurrent.markdown); + $('manual-content').replaceChildren(rendered.fragment);$('manual-toc').replaceChildren();$('manual-download').disabled=false; + if(previous&&previous!==identifier)window.scrollTo(0,0); + rendered.headings.forEach(heading=>{const button=text('button',heading.label);button.type='button';button.className=heading.level===1?'manual-top-heading':'';button.onclick=()=>document.getElementById(heading.id)?.scrollIntoView({behavior:'smooth',block:'start'});$('manual-toc').append(button);}); +} +function manualRoute(){ + if(!/^#manual(?:\/|$)/.test(location.hash))return false; + if($('manual-page').hidden)window.scrollTo(0,0); + ['overview-page','results','case-detail','submit','test-page','keys-page'].forEach(id=>$(id).hidden=true);$('manual-page').hidden=false; + document.querySelector('header h1').textContent='Benutzeranleitung.'; + document.querySelectorAll('nav a').forEach(a=>a.classList.toggle('selected',a.hash==='#manual')); + if(!token)return true; + const generation=session; + const selected=()=>location.hash.slice('#manual/'.length)||'user-guide'; + if(manualData){displayManual(location.hash==='#manual'?'user-guide':selected());return true;} + if(!manualLoading){$('manual-content').replaceChildren(text('p','Anleitungen werden geladen …')); + manualLoading=api('/v1/manual').then(data=>{ + if(generation!==session)return;manualData=data;$('manual-document').replaceChildren(...data.documents.map(d=>new Option(d.title,d.id))); + if(/^#manual(?:\/|$)/.test(location.hash))displayManual(location.hash==='#manual'?'user-guide':selected()); + }).catch(e=>{if(generation===session){error(`Anleitung nicht verfügbar: ${e.message}`);$('manual-content').replaceChildren(text('p','Die Anleitung konnte nicht geladen werden. Bitte erneut öffnen.'));}}).finally(()=>{if(generation===session)manualLoading=null;}); + } + return true; +} +$('manual-document').addEventListener('change',()=>{location.hash='#manual/'+$('manual-document').value;}); +$('manual-download').addEventListener('click',()=>{ + if(!manualCurrent)return;const url=URL.createObjectURL(new Blob([manualCurrent.markdown],{type:'text/markdown;charset=utf-8'})),link=document.createElement('a'); + link.href=url;link.download=manualCurrent.id+'.md';document.body.append(link);link.click();link.remove();setTimeout(()=>URL.revokeObjectURL(url),30000); +}); diff --git a/src/viano_bug_analysis/web/user-manual.json b/src/viano_bug_analysis/web/user-manual.json new file mode 100644 index 0000000..e4a5dd5 --- /dev/null +++ b/src/viano_bug_analysis/web/user-manual.json @@ -0,0 +1,50 @@ +{ + "format_version": 1, + "documents": [ + { + "id": "user-guide", + "title": "Verwendung und Funktionsweise", + "markdown": "# BugAnalysis verwenden\n\nBugAnalysis untersucht gemeldete Softwarefehler und übergibt das Ergebnis an die\nnächste zuständige Stelle. Das Programm erstellt selbst keinen fertigen Patch\nund spielt keine Änderungen auf einen Server ein. Der aktuelle Erfassungsadapter\nist für WoW/Vcore eingerichtet.\n\n## So arbeitet BugAnalysis\n\n1. Eine Person oder ein Erfassungsprogramm übergibt Bugbeschreibung und\n Diagnosearchive. Die Übergabe-API erstellt daraus eine Fallakte.\n2. Ein dauerhaft laufender Analyseworker übernimmt den Auftrag und lädt die\n Konfiguration des angegebenen Projekts.\n3. Der Casebuilder wertet Beobachtungen und Telemetrie aus. Er kann relevante\n Identitäten mit den konfigurierten Recherchewerkzeugen auflösen.\n4. Die LLM interpretiert den Fall und entwickelt Hypothesen. Im gemeinsamen\n Planungsmodus geschieht beides in einem Aufruf.\n5. Die Untersuchung prüft Hypothesen mit Source- und DB-Werkzeugen. Eine knappe\n Untersuchungsschleife sammelt Ergebnisse; Prüfungen und Konsolidierungen\n übernehmen diese in den strukturierten Arbeitsstand. Werkzeuge lesen Daten;\n Zugangsdaten erhält die LLM nicht.\n6. Die finale Diagnose bewertet die Befunde und kann einen Frühabschluss\n annehmen oder weitere Untersuchung verlangen. Fachliche Budgets begrenzen\n einzelne Untersuchungen. Ein bestimmter Erfolg ist nicht garantiert.\n7. Das Ergebnis enthält Diagnose und Aufträge für Codingagent und menschlichen\n Entwickler. Ein Auftrag darf ausdrücklich erklären, dass keine Arbeit für\n den jeweiligen Empfänger vorliegt. Fehlende Daten zur Umsetzung können als\n menschlicher Auftrag übergeben werden, ohne die erfolgreiche Analyse zu sperren.\n\nEin Ergebnis bleibt eine begründete Analyse, keine Garantie für einen wirksamen\nFix. Nach Umsetzung und Tests können Rückmeldungen eine neue Analyserevision\nderselben Akte auslösen. Behauptungen, Testerbeobachtungen und bestätigte Befunde\nsollten bei der Bewertung auseinandergehalten werden.\n\n## Anmeldung und Start\n\nDie Webadresse im Browser öffnen und mit Benutzername und Passwort anmelden.\nBenutzerkonten werden ausschließlich per privilegierter Konsole angelegt;\neine Selbstregistrierung gibt es nicht. Alle menschlichen Benutzer haben die\ngleichen Rechte für alle Projekte. Externe Programme benutzen eigene\nIntegrationsschlüssel mit Projektfreigaben.\n\nAPI und Analyseworker sind getrennte Dienste. Das Öffnen der Webseite startet\nkeinen Worker und sendet keine Modellanfrage. Der laufende Worker verarbeitet\nAufträge selbstständig; die Webseite ist die Übersicht und alternative Bedienung.\n\n## Übersicht und laufende Fälle\n\nDie Übersicht zeigt erreichbare Worker, den bearbeiteten Fall und dessen\nFortschrittsbalken. Der Balken folgt abgeschlossenen Phasen, nicht vergangener\nZeit. Während einer längeren Untersuchung kann er daher unverändert bleiben.\nAbgeschlossene Fälle verschwinden aus der aktiven Workeransicht.\n\nDie Diagramme zeigen gemessenen Tokenverbrauch. Korrektur- und Wiederholungsaufrufe\nbilden eine eigene Kategorie. Denktokens sind bereits in den Ausgabetokens\nenthalten und werden nicht doppelt addiert. Fehlende Messwerte werden als solche\nausgewiesen. Diese Zahlen sind keine verbindliche Cloud-Abrechnung und umfassen\nnur die erhaltenen Akten im gewählten Messumfang.\n\nÜber Fallnummern lässt sich die Detailansicht öffnen: Beobachtungen, Einordnung,\nHypothesen, Befunde, Diagnose und Aufträge. Frühere Revisionen bleiben über die\nRevisionsauswahl einsehbar. Die vollständigen Daten stehen im herunterladbaren ZIP.\n\n## Neue Aufträge und Rückgaben\n\nUnter **Auftrag übergeben** Projekt, Bug-ID, Fallname und Beobachtungen eingeben.\nFür einen neuen Vcore-Fall das wowdiag-Archiv und möglichst das dazugehörige\nwowsrc-Archiv derselben Erfassung auswählen. Die Bug-ID muss mit den Archiven\nübereinstimmen. Zusätzliche Dateien lassen sich als Anhänge hinzufügen.\n\nNach dem Absenden bestätigt die API die Annahme. Das ist noch kein Analyseerfolg.\nBei einer unterbrochenen Übergabe verwendet das Formular bei unveränderten\nEingaben denselben Idempotenzschlüssel, damit kein doppelter Auftrag entsteht.\n\nFür eine Rückgabe den Auftragstyp **Abgeschlossene Akte zurückgeben** wählen,\ndie aktuelle abgeschlossene Case-ZIP hochladen und Ergebnis sowie neue\nBeobachtungen eintragen. Beispielsweise kann ein getesteter Patch den Fehler\nnicht behoben haben. BugAnalysis ergänzt die Akte und öffnet eine neue Revision.\nBlockierte oder noch laufende Akten sind keine Abschlussrückgaben.\n\nAutomatische Erfassung erfolgt über den wowdiag-Worker und dieselbe Übergabe-API.\nExterne Programme erstellen keine internen Case-Manifeste selbst.\n\n## Testanfragen beantworten\n\nDie Seite **Testanfragen** listet offene menschliche Recherche- und Testfragen\nmit Projekt. Nach Zeitpunkt oder Projekt sortieren, eine Anfrage auswählen und\nzunächst **Bearbeiten** drücken. Erst dann wird das Antwortformular freigegeben.\n\nDie Anfrage ist während der Session exklusiv gebunden. Andere Personen können\nsie nicht gleichzeitig bearbeiten. Beobachtungen und verlangte Angaben sachlich\neintragen und absenden. Bei Sessionablauf oder Abmeldung wird die Bearbeitung\nwieder freigegeben. Nach gültiger Antwort setzt der Worker die Analyse mit dem\nvorhandenen Stand fort; fachliche Budgets werden nicht erneuert.\n\nEine Testanfrage während der Ursachenklärung ist etwas anderes als ein\nHuman-Dev-Auftrag im fertigen Ergebnis. Letzterer gehört zur weiteren Umsetzung.\n\n## Bearbeitete Fälle und Downloads\n\nUnter **Bearbeitete Fälle** stehen Ergebnisse, übergebene Fälle, blockierte Fälle\nund gescheiterte Analysen in einer gemeinsamen Liste. Projekt, Kategorie und\nSuchbegriff können kombiniert werden; die Sortierung ist separat wählbar.\nLinks lädt der Pfeilknopf die aktuelle vollständige Fallakte als ZIP herunter.\nEin Download ändert den Fallstatus nicht und bestätigt keine Übergabe.\n\n| Zustand | Bedeutung |\n| --- | --- |\n| Ergebnis bereit / OUTPUT_READY | Analyseergebnis für die weitere Bearbeitung; Routingziel Outbox |\n| Übergeben / HANDED_OFF | Die Akte wurde intern als übergeben markiert |\n| Blockiert / BLOCKED | Analyse wartet, beispielsweise auf Testerantwort oder technische Behebung |\n| Analyse gescheitert / FAILED_TO_ANALYZE | Analyse konnte nicht erfolgreich abschließen; Routingziel Review |\n\nBlockiert bedeutet nicht abgeschlossen. Sperrgrund und Detailansicht erklären\ndie nächsten Schritte. Technische Fehler oder unzureichende Eingaben sind von\neinem fachlichen Diagnoseergebnis zu unterscheiden. Die Ablagespalte zeigt das\nRoutingziel, keinen unabhängigen Verzeichnisbestand.\n\n## Betrieb steuern\n\nDie Betriebssteuerung in der Übersicht erlaubt das Pausieren neuer Fälle eines\nProjekts. Bereits begonnene Fälle dürfen weiterlaufen. Geeignete technische\nFehlerfälle können über eine Fortsetzungsanforderung nach Behebung wieder\nfreigegeben werden. Diese Aktion ist kein beliebiger Neustart und setzt keine\nBudgets zurück. Menschliche Testantworten werden auf ihrer eigenen Seite erfasst.\n\n## Programme anbinden\n\nUnter **API-Schlüssel** einen Programmnamen und die erlaubten Projekte auswählen.\nDen erzeugten Schlüssel über **Anzeigen** oder **Kopieren** abrufen und im\naufrufenden Dienst geschützt hinterlegen. Schlüssel sind später erneut anzeigbar.\n**Widerrufen** verhindert weitere authentifizierte Anfragen mit diesem Schlüssel.\n\nDie Schlüssel dienen zur Auftragsübergabe und zum lesenden Projektzugriff;\nMaschinenprogramme können darüber keine anderen Schlüssel verwalten oder\nmenschliche Testerantworten ausfüllen. Ein Integrationsschlüssel ist kein\nGemini- oder anderer Modellanbieter-Schlüssel.\n\n## Einrichtung und Hilfe\n\n- [Linux-Installation und Betrieb](linux-deployment.md)\n- [Projekt-, Source-, DB- und Modellkonfiguration](project-configuration.md)\n- [Übergabe-API und Rückgaben](intake-api.md)\n- [Analyseworker und Wiederanlauf](analysis-worker.md)\n- [Benutzerkonten](user-accounts.md)\n- [Integrationsschlüssel und deren Sicherung](integration-keys.md)\n- [Weboberfläche im Detail](web-console.md)\n- [Erfassungsworker v0.4](capture-worker.md)\n\nVor dem ersten Feldbetrieb auf dem Zielserver Bereitschaftsprüfung, HTTPS,\nDienstneustart und Backups prüfen. Danach einen kontrollierten echten Auftrag\neinschließlich Rückfrage und Ergebnisabholung durchführen. Die LLM-Zugriffe\nerzeugen erst beim laufenden Analysebetrieb Kosten.\n" + }, + { + "id": "linux-deployment", + "title": "Linux-Installation und Betrieb", + "markdown": "# Linux-Betrieb\n\nAPI und Analyseworker laufen als getrennte systemd-Dienste. Ein Auftragseingang\nweckt keinen neuen Prozess: Der dauerhaft laufende Worker übernimmt Inbox-Aufträge.\nDie Weboberfläche ist eine alternative Bedienung desselben Arbeitsablaufs.\nDie Installation startet keine Dienste und führt keine Modellanfrage aus.\n\n## Voraussetzungen und Verzeichnisse\n\nLinux mit systemd, Python 3.11 oder neuer inklusive venv/pip, Git und Nginx.\nDiese Programme über die Paketverwaltung des Servers installieren. Die aktuelle\nProjektvorlage ist für WoW/Vcore eingerichtet; sie ist kein allgemeiner Adapter.\n\n| Pfad | Zweck und Rechte |\n| --- | --- |\n| `/opt/viano-bug-analysis` | Root-eigener Checkout und virtuelle Python-Umgebung; Dienst darf nur lesen |\n| `/etc/viano-bug-analysis` | Root-eigene Konfiguration, Gruppe `buganalysis`, Verzeichnis 0750, Dateien 0640 |\n| `/etc/viano-bug-analysis/*.env` | Zugangsdaten, root:buganalysis 0600; systemd liest sie vor dem Benutzerwechsel |\n| `/etc/viano-bug-analysis/auth/users.sqlite3` | Root-verwaltete Nutzer, Gruppe `buganalysis` darf lesen |\n| `/var/lib/viano-bug-analysis` | Dienst-eigene Fallakten, Laufzeitdaten und Websessions |\n| `/srv/viano-bug-analysis/viano-core` | Root-eigener Source-Checkout, Dienst hat Leserechte |\n\nDie env-Dateien sind durch Betriebssystemrechte geschützte Klartextdateien, kein\nverschlüsselter Tresor. Sie gehören nicht ins Repository oder in Diagnosepakete.\nAPI und Worker erhalten unterschiedliche Dateien: Nur der Worker erhält Cloud-\nund DB-Zugangsdaten. Die Diensthärtung und EnvironmentFile-Nutzung folgen der\n[systemd-Dokumentation](https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html).\n\nDie [Webverwaltung für Integrationsschlüssel](integration-keys.md) ergänzt die\nenv-basierte Maschinenanmeldung. Ihre SQLite und separate Schlüsseldatei müssen\nebenfalls gesichert werden; beide liegen standardmäßig unter der Fallablage.\n\n## Installation\n\nDen vertrauenswürdigen BugAnalysis-Checkout als root unter\n`/opt/viano-bug-analysis` ablegen. Code und Unterverzeichnisse dürfen nicht für\nandere Benutzer schreibbar sein. Dann:\n\n```sh\ncd /opt/viano-bug-analysis\npython3 deploy/install.py --dry-run\nsudo python3 deploy/install.py\n```\n\nDer Installer legt den Dienstbenutzer `buganalysis`, Konfigurationen, venv und\nUnits an. Er installiert die Python-Abhängigkeiten und lädt systemd neu.\nBestehende Zielkonfigurationen und Units werden erhalten. Updates an bereits\ninstallierten Units daher bewusst mit den versionierten Vorlagen abgleichen.\nBei Installationsfehlern bleiben vorhandene Dateien erhalten; erneutes Ausführen\nsetzt die Einrichtung fort. Der Installer verändert keine bestehende Datenbank.\n\n## Einmalige Konfiguration\n\nMit `sudoedit` die Dateien unter `/etc/viano-bug-analysis` bearbeiten:\n\n1. `project.toml`: DB-Adresse/Port, Datenbank und nur lesenden Benutzer einstellen,\n tatsächliche Snapshotkennung und vollständigen Source-Commit eintragen.\n Die ausgelieferten Null-Commit- und `CONFIGURE_ME`-Werte sind Platzhalter.\n2. Den Vcore-Checkout als root unter `/srv/viano-bug-analysis/viano-core` anlegen;\n der konfigurierte Commit muss lokal vorhanden und für `buganalysis` lesbar sein.\n Der Dienst lädt keine Commits nach. `gitconfig` vertraut ausschließlich diesem\n konkreten Root-Checkout, nicht beliebigen Repositories.\n3. `worker.env`: `GEMINI_API_KEY=...` und `VIANO_DB_PASSWORD=...` eintragen.\n Keine `export`-Anweisungen verwenden. Für Sonderzeichen gelten die\n EnvironmentFile-Quotingregeln von systemd. Werte nicht als Shellargumente übergeben.\n4. `api.env`: `VBA_INTAKE_TOKEN=...` für den Erfassungsworker setzen\n (32–256 Zeichen aus Buchstaben, Ziffern, `_` und `-`). Dies ist ein separater\n Integrationsschlüssel, kein Gemini-Key. Wird keine externe API-Integration\n benötigt, den zugehörigen `[[clients]]`-Block aus `api.toml` entfernen.\n5. `llm.toml`: gewünschtes Modell, Anbieter und Cacheeinstellungen kontrollieren.\n Investigation-, Budget- und Telemetrie-Dateien sind separat konfigurierbar.\n\nDie DB-Verbindung benötigt einen Benutzer mit ausschließlich passenden\nSELECT-Rechten auf die freigegebenen World-Tabellen. Diese Rechte legt der\nDB-Administrator an; BugAnalysis vergibt keine Grants. Der Readiness-Test belegt\nLesbarkeit, nicht die Abwesenheit zusätzlicher Schreibrechte. Für entfernte DBs\neinen geschützten Netzwerkweg verwenden: Der aktuelle DB-Provider konfiguriert\nselbst kein TLS. Zugang zu Produktionsdaten ist für die lokale Entwicklung\nweiterhin nicht erforderlich.\n\nWebnutzer anlegen; das Passwort wird verdeckt abgefragt:\n\n```sh\nsudo /opt/viano-bug-analysis/.venv/bin/python -m viano_bug_analysis.api create_user NAME --config /etc/viano-bug-analysis/api.toml --service-group buganalysis\n```\n\nNutzerverwaltung bleibt root vorbehalten. Siehe [Nutzerverwaltung](user-accounts.md).\nKeine Nutzer werden automatisch angelegt. Nach der Installation besitzen die\nenv-Dateien Modus 0600; diese Rechte nach manuellen Änderungen erhalten.\n\n## Kostenfreie Bereitschaftsprüfung\n\nDie Prüfung unter der tatsächlichen Dienstidentität samt env-Datei ausführen:\n\n```sh\nsudo systemd-run --wait --pipe --collect --property=User=buganalysis --property=Group=buganalysis --property=EnvironmentFile=/etc/viano-bug-analysis/api.env /opt/viano-bug-analysis/.venv/bin/python -m viano_bug_analysis.deployment check --role api --config /etc/viano-bug-analysis/api.toml\nsudo systemd-run --wait --pipe --collect --property=User=buganalysis --property=Group=buganalysis --property=EnvironmentFile=/etc/viano-bug-analysis/worker.env --setenv=GIT_CONFIG_GLOBAL=/etc/viano-bug-analysis/gitconfig /opt/viano-bug-analysis/.venv/bin/python -m viano_bug_analysis.deployment check --role worker --config /etc/viano-bug-analysis/worker.toml\n```\n\nErwartet: `READY`, `model_requests: 0`. Geprüft werden Konfiguration,\nZugangsdaten-Präsenz, Speicherreserve, Schreibbarkeit der Laufzeitablage,\nWebnutzer/Sessions beziehungsweise Git-Objekte und die freigegebenen DB-Schemata.\nCloud-Key-Gültigkeit und Modellverfügbarkeit sind damit noch nicht getestet.\n`--offline` überspringt Git-/DB-Zugriffe und meldet nur `CONFIG_READY`.\nFehlerausgaben enthalten kontrollierte Fehlercodes statt Zugangsdaten.\n\n## HTTPS und Start\n\nDie API bleibt auf `127.0.0.1:8080`. `nginx.conf.example` enthält eine\nReverse-Proxy-Vorlage: Domain und Zertifikatpfade anpassen, gültiges Zertifikat\nbereitstellen und als Nginx-Site installieren. Die Vorlage übernimmt die\nForwarded-Header kontrolliert; die API vertraut ihnen ausschließlich vom\nLoopback-Proxy. So verwenden Anmeldung und Cookies das öffentliche HTTPS-Schema.\nDie Proxyparameter sind in der\n[Nginx-Dokumentation](https://nginx.org/en/docs/http/ngx_http_proxy_module.html) beschrieben.\n\nVor dem ersten Start auf dem Linux-Zielsystem prüfen:\n\n```sh\nsudo systemd-analyze verify /etc/systemd/system/viano-bug-analysis-api.service /etc/systemd/system/viano-bug-analysis-worker.service\nsudo nginx -t\nsudo systemctl reload nginx\nsudo systemctl enable --now viano-bug-analysis-api.service viano-bug-analysis-worker.service\nsudo systemctl status viano-bug-analysis-api.service viano-bug-analysis-worker.service\n```\n\nSobald der Worker aktiviert ist, kann er vorhandene Aufträge verarbeiten und\nkostenpflichtige Modellaufrufe senden. Erst mit leerem Eingang starten, dann einen\nkontrollierten Feldtest über die Übergabe-API oder Weboberfläche übergeben.\nAnmeldung, Auftragsannahme, Fortschritt, menschliche Testanfrage und Outbox dabei\ngemeinsam prüfen. Die automatisierte Einrichtung ersetzt diesen Feldtest nicht.\n\n## Laufender Betrieb\n\nDie Dienste starten beim Booten und nach unerwartetem Prozessende erneut.\nFehlende Startvoraussetzungen werden nach zehn Sekunden erneut geprüft.\nExterne DB und Sourcebereitstellung werden nicht von diesen Units installiert.\nAPI und Worker können unabhängig voneinander laufen.\n\n```sh\nsudo journalctl -u viano-bug-analysis-api -u viano-bug-analysis-worker -f\nsudo systemctl stop viano-bug-analysis-worker\n```\n\nDer Worker beendet beim Stoppen den aktuellen Dispatch kontrolliert; seine Unit\nsetzt dafür kein hartes Stop-Zeitlimit. Ein Stop kann daher während einer\nlanglaufenden Anfrage dauern. Für Code-/Profiländerungen den Worker zuerst\nanhalten. Profilbindungen laufender Fälle nicht beiläufig ändern: Unterschiede\nwerden als Aufmerksamkeit erfordernder Zustand behandelt, Budgets nicht erneuert.\nCodeänderungen danach in die root-eigene venv installieren und Dienste neu starten.\n\nBackups umfassen die Fallablage, Konfiguration einschließlich geschützter Secrets\nund Nutzer-SQLite. Für eine einfache konsistente Dateisicherung beide Dienste\nanhalten. Sessions sind keine dauerhaft nötigen Fachdaten. Produktive Fallaufbewahrung\nseparat festlegen; das 20-GB-Entwicklungslimit ist kein Produktionslimit.\n\nUnter Windows bleibt die vorhandene PowerShell-Umgebungsvariable für Entwicklung\nunterstützt. Dort installiert dieser Installer keine Dienste; `--dry-run` ist möglich.\n" + }, + { + "id": "project-configuration", + "title": "Projekt-, Source-, DB- und Modellkonfiguration", + "markdown": "# Projekt und Recherchezugriffe konfigurieren\n\nDie Projektkonfiguration wird über Dateien verwaltet, nicht über die Webseite.\nSie legt fest, welche Werkzeuge ein Auftrag verwenden darf. Ein aufrufendes\nProgramm kann weder Repository noch DB-Zugänge oder Budgets mit einem Auftrag\nüberschreiben. Aktuell ist das Profil `wow/vcore` mit dem Importadapter `vcore`\nimplementiert; andere Projekttypen erfordern entsprechende Adapter und Profile.\n\n## Zuordnung in api.toml\n\nEin Projektelement ordnet eine feste Projekt-ID einem Profil und dessen\nKonfigurationsdateien zu. Relative Pfade beziehen sich auf die API-Konfigurationsdatei.\nDer Erfassungsworker muss genau dieselbe Projekt-/Profilzuordnung senden und\nsein Integrationsschlüssel muss für das Projekt freigegeben sein.\n\n```toml\n[[projects]]\nid = \"viano-core\"\ntype = \"wow\"\nprofile = \"vcore\"\nadapter = \"vcore\"\nplanning_mode = \"joint\"\n[projects.settings]\nproject_config = \"project.toml\"\nllm_config = \"llm.toml\"\ninvestigation_config = \"investigation.bounded.toml\"\nbudget_config = \"budget.human-tests.toml\"\n```\n\nDie Linux-Vorlagen stehen unter `deploy/linux/`; der Installer legt die\nKonfiguration unter `/etc/viano-bug-analysis` an. Er überschreibt bestehende\nDateien nicht. Die ausführliche Vcore-Projektvorlage steht unter\n`config/project.example.toml`, die Relationsregeln unter\n`config/project-relations.vcore.toml`.\n\n## Source und Datenbank in project.toml\n\n```toml\nrelations_file = \"project-relations.vcore.toml\"\n[project]\ntype = \"wow\"\nprofile = \"vcore\"\n\n[source]\npath = \"/srv/viano-bug-analysis/viano-core\"\nurl = \"https://gitea.viano-software.de/Nico/Viano-Core\"\ncommit = \"VOLLSTAENDIGEN_40_STELLIGEN_COMMIT_EINTRAGEN\"\n\n[database]\nhost = \"127.0.0.1\"\nport = 3306\ndatabase = \"cata_world\"\nuser = \"viano_reader\"\npassword_env = \"VIANO_DB_PASSWORD\"\nsnapshot_id = \"KENNUNG_DER_TATSAECHLICHEN_DATENGRUNDLAGE\"\ntables = [\"creature_template\", \"creature\"]\n```\n\nDas Beispiel zeigt nur den Aufbau und enthält absichtlich ungültige Platzhalter.\nDie beiden Tabellen sind keine vollständige Vcore-Freigabeliste. Für das echte\nProfil die vollständige Vorlage einschließlich Limits, Enrichment und\nAnalysewerkzeugregeln verwenden und passend prüfen.\n\nDer Source-Checkout muss lokal vorhanden sein und den konfigurierten Commit\nenthalten. Die URL allein klont oder aktualisiert kein Repository. Der Worker\nliest Git-Objekte dieses festen Stands und benötigt keine Schreibrechte auf den\nCheckout. Die Linux-Vorlage enthält eine gezielte Git-Vertrauenskonfiguration\nfür den root-eigenen Checkout. Neue Source-Stände bewusst bereitstellen und\nderen vollständigen Commit konfigurieren.\n\nDer DB-Administrator legt einen Benutzer mit ausschließlich passenden SELECT-\nRechten an. Zusätzlich begrenzt `tables` die zugänglichen Tabellen. Diese\nFreigabeliste ersetzt keine serverseitigen Rechte. Account- oder Charakterdaten\ngehören nicht zur standardmäßigen World-Recherche. Für entfernte DBs einen\ngeschützten Netzwerkweg nutzen; der aktuelle Provider konfiguriert selbst kein TLS.\n\nDas Passwort steht entweder in der durch `password_env` benannten\nUmgebungsvariable oder einer separaten geschützten Datei über `password_file`.\nNur eine dieser Varianten setzen. Unter Linux lädt der Worker beispielsweise\n`VIANO_DB_PASSWORD` aus seiner root-geschützten `worker.env`.\nPasswörter nicht in Fallakten, LLM-Prompts oder Versionsverwaltung ablegen.\nDie LLM bekommt Werkzeugergebnisse statt Zugangsdaten.\n\n## Weitere Konfigurationen\n\n| Datei | Zuständigkeit |\n| --- | --- |\n| api.toml | HTTP-Bindung, Workspace, Projekte, Nutzerdatei und optionale env-basierte Maschinenclients |\n| worker.toml | Verweis auf api.toml, Polling, Wiederholungsabstände, Speicherreserve und Telemetrie |\n| llm.toml | Anbieter, Modell, Schlüssel-Environment, Timeouts, Ausgabe-/Denkeinstellungen und Cache |\n| investigation.bounded.toml | Untersuchungsmodus und begrenztes Kontextfenster |\n| budget.human-tests.toml | Fachliche Budgetregeln und menschliche Testanfragen |\n| telemetry.toml | Heartbeats und lokale Betriebsbeobachtung |\n| project-relations.vcore.toml | Projektspezifische Beziehungen für Recherchewerkzeuge |\n\nDie versionierte Modellvorlage `config/llm.gemini-cache.example.toml` verwendet\n`GEMINI_API_KEY`. Das ist unabhängig vom Integrationsschlüssel für externe\nAuftragsübergaben. Die API erhält `api.env`; der Analyseworker erhält\n`worker.env` mit Cloud- und DB-Zugangsdaten.\n\n## Prüfen und ändern\n\nDer Befehl `python -m viano_bug_analysis.deployment check` prüft mit Rolle und\nKonfigurationspfad die Betriebsbereitschaft ohne Modellanfrage. Die\n[Linux-Anleitung](linux-deployment.md) zeigt die vollständigen Befehle unter der\ntatsächlichen Dienstidentität. Die Prüfung umfasst Git-Objekte und freigegebene\nDB-Schemata; die Gültigkeit des Cloud-Schlüssels wird nicht durch einen bezahlten\nModellaufruf getestet. `--offline` prüft keine Git-/DB-Verbindung.\n\nVor Code- oder Profiländerungen den Worker kontrolliert anhalten und die\nAuswirkungen auf laufende Akten prüfen. Der Worker bindet Fälle an ihren\nKonfigurationsstand. Eine Änderung ist kein Weg zum Zurücksetzen von Budgets;\nabweichende Bindungen können eine Betreiberprüfung erfordern. Bestehende Dateien\nund Zugangsdaten vor Änderungen sichern.\n" + }, + { + "id": "intake-api", + "title": "Übergabe-API und Rückgaben", + "markdown": "# Übergabe-API v1\n\nDie API erstellt interne Case-Pakete und veröffentlicht sie atomar in der Inbox.\nExterne Programme liefern Metadaten und Dateien; sie erzeugen und bearbeiten keine\ninternen Manifeste. Die API führt keine Analyse und keine LLM-Aufrufe aus. Ein\ndauerhaft laufender [Analyseworker](analysis-worker.md) übernimmt anschließend die\nAufnahme und Verarbeitung. Die [Weboberfläche](web-console.md) bietet Übersicht,\nAuftragsübergabe, Testerantworten und Ergebnisdownloads.\n\n## Lokaler Start\n\n```powershell\n.\\.venv\\Scripts\\python.exe -m pip install -e '.[api]'\nCopy-Item config/api.example.toml config/api.local.toml\n$env:VBA_INTAKE_TOKEN = [Convert]::ToHexString([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32))\n.\\.venv\\Scripts\\python.exe -m viano_bug_analysis.api check --config config/api.local.toml\n.\\.venv\\Scripts\\python.exe -m viano_bug_analysis.api serve --config config/api.local.toml\n```\n\nDer API-Token ist ein eigener Zugangsschlüssel, kein Gemini-Key. Programme erhalten\nvorzugsweise einen Schlüssel aus der [Web-Schlüsselverwaltung](integration-keys.md).\nAlternativ bleiben Clients mit Token aus einer serverseitigen Umgebungsvariable\nunterstützt; der Beispielstart oben zeigt diese Variante. Der\nToken benötigt 32–256 Zeichen aus `A-Z a-z 0-9 _ -`. Auf älterem Windows PowerShell\nkann ein solcher Token über einen Passwortmanager erzeugt und als Variable gesetzt\nwerden. Der Beispielstart bindet nur an `127.0.0.1:8080`. Für entfernte Nutzung sind\nHTTPS und ein passend konfigurierter Reverseproxy erforderlich. Tokens nicht in\nURLs oder Git-Konfiguration ablegen. Zugriff auf das Workspace-Dateisystem bleibt\nauf den Dienst und vertrauenswürdige Betreiber beschränkt.\n\n`projects` ist die serverseitige Freigabeliste. Jeder Auftrag benennt `project_id`\nund `profile_id`. Er kann keine Repository-URLs, DB-Zugänge, Budgets oder\nKonfigurationspfade überschreiben. Optionale `projects.settings` halten die spätere\nWorker-Konfiguration bereit; die Eingangsschicht verwendet diese Dateien nicht für\nAnalysen. Aktuell ist der Importadapter `vcore` für `wow/vcore` implementiert.\nWeitere Projekte benötigen passende Adapter/Profile, keine separat gepflegten Forks.\n\n## Endpunkte\n\n| Methode/Pfad | Bedeutung |\n|---|---|\n| `GET /healthz` | Minimale öffentliche Erreichbarkeitsprüfung |\n| `GET /v1/profiles` | Für diesen Client freigegebene Projekte/Profile |\n| `GET /v1/schema` | Öffentliches JSON-Schema der Übergabemetadaten |\n| `GET /v1/overview` | Projektbezogene Worker-/Fallübersicht und Tokenstatistik |\n| `POST /v1/submissions` | Multipart-Upload, `201` bei neuer Einreihung, `200` bei Wiederholung |\n| `GET /v1/submissions/{id}` | Quittung und aktueller verwalteter Zustand |\n| `GET /v1/submissions/{id}/package` | Abgeschlossene Akte herunterladen; sonst `409` |\n\nAlle Endpunkte außer Health benötigen `Authorization: Bearer TOKEN`.\nPOST benötigt zusätzlich `Idempotency-Key: frei-gewaehlte-eindeutige-id` (1–128\nZeichen, Buchstaben/Ziffern sowie Punkt, Unterstrich, Bindestrich; erstes Zeichen\nalphanumerisch). Derselbe Client/Schlüssel mit denselben Metadaten und Dateiinhalten\nliefert dieselbe Quittung, auch nach einem Neustart. Abweichender Inhalt ergibt\n`409 API_IDEMPOTENCY_CONFLICT`. Dateinamen und Multipart-Grenzen zählen nicht als\nInhaltsänderung; Rollen und Reihenfolge der Dateien zählen. Ein zweiter neuer\nAuftrag für dasselbe Projekt und dieselbe Case-ID wird zurückgewiesen.\n\n## Neuer Auftrag\n\n`metadata` ist ein UTF-8-JSON-Textfeld, kein Datei-Upload. Dateien: genau einmal\n`wowdiag`, optional einmal `wowsrc`, optional mehrfach `attachments`. Für Vcore muss\ndie Case-ID dem Bug des Erfassungsarchivs entsprechen (`BUG-000020`). Beide\nErfassungsarchive müssen zueinander passen. Beispiel `submission.json`:\n\n```json\n{\n \"kind\": \"new_case\",\n \"project_id\": \"viano-core\",\n \"profile_id\": \"vcore\",\n \"case_id\": \"BUG-000020\",\n \"report\": {\n \"title\": \"Wolpertinger fehlen\",\n \"observations\": [\"Nach Questannahme waren im untersuchten Gebiet keine Tiere sichtbar.\"],\n \"expected_behavior\": [\"Fangbare Tiere sind im Gebiet vorhanden.\"]\n },\n \"versions\": {\n \"reported_server\": \"commit-des-gemeldeten-serverstands\",\n \"capture_server\": \"commit-des-erfassungsstands\"\n }\n}\n```\n\n```powershell\ncurl.exe --fail-with-body -H \"Authorization: Bearer $env:VBA_INTAKE_TOKEN\" -H \"Idempotency-Key: bug20-capture-001\" -F \"metadata=/auth/users.sqlite3`. Die API öffnet\ndiese Datei ausschließlich schreibgeschützt. Gesalzene scrypt-Hashes ersetzen\nKlartextpasswörter. Sitzungen, Anmeldebegrenzung und Bearbeitungssperren liegen\nseparat in `/runtime/web-sessions/sessions.sqlite3`; Sitzungstokens\nwerden dort nur als Hash gespeichert.\n\nProduktionskonfiguration, Pfade relativ zur Konfigurationsdatei oder absolut:\n\n```toml\n[auth]\nusers_database = \"/etc/viano-bug-analysis/users.sqlite3\"\nsession_seconds = 3600\n```\n\nDie Benutzerdatei und ihr Verzeichnis gehören unter Linux root; CLI-Befehle setzen\n0640 bzw. 0750. `--service-group buganalysis` erlaubt dem dedizierten Dienstkonto\ndas Lesen, nicht die Benutzerverwaltung. Verzeichnisvorfahren dürfen nicht durch\nunvertrauenswürdige Benutzer austauschbar sein. Der Dienst benötigt Schreibzugriff\nauf seinen Workspace und die Sitzungsdatei. Unter Windows entsprechend geschützte\nNTFS-Verzeichnisse/ACLs verwenden: Administratoren verwalten die Benutzerdatei,\ndas Dienstkonto liest sie. Die Konsolenbefehle prüfen auch dort die erhöhte\nAdministratorberechtigung. Wer Programmcode oder Authentifizierungsdateien selbst\nändern kann, liegt außerhalb der Web-Zugriffsgrenze; deshalb sind diese OS-Rechte\nBestandteil der Servereinrichtung.\n\nSQLite benötigt keinen MariaDB-Dienst. Für einen Umzug die Benutzerdatei und die\nProjekt-/Workspace-Daten sichern; die separate Sitzungsdatei kann bei gestoppter\nAPI bewusst verworfen werden, um alle Sitzungen und Sperren zu beenden.\n\n## Sitzungen und Bearbeiten\n\nDie Anmeldung erzeugt ein HttpOnly-/SameSite-Strict-Cookie; unter HTTPS zusätzlich\nSecure. Entfernte Zugriffe über HTTPS betreiben. Mutationen benötigen den an die\nSitzung gebundenen CSRF-Header. Die Oberfläche hält nur diesen CSRF-Wert im\nArbeitsspeicher; Passwörter und Sitzungstokens werden nicht im Local Storage\ngespeichert. Sitzungen gelten standardmäßig absolut eine Stunde, konfigurierbar\nvon 60 Sekunden bis 24 Stunden; regelmäßige Seitenaktualisierungen verlängern sie\nnicht endlos. Nach einem Neuladen kann eine gültige Sitzung weiterverwendet werden.\nAnmeldeversuche werden serverseitig zeitlich begrenzt.\n\nEine Testanfrage lässt sich zunächst nur ansehen. Erst **Bearbeiten** übernimmt\ndie Anfrage atomar für die aktuelle Sitzung. Eine zweite Sitzung erhält\n`API_TEST_CLAIMED` und eine verständliche Meldung. Erst dann erscheinen Eingabefelder.\nDie Serverprüfung verlangt dieselbe Sperre auch beim Absenden; das Ausblenden\nvon Feldern allein ist nicht die Zugriffskontrolle. Identische Wiederholungen\nbleiben idempotent, abweichende zweite Antworten werden zurückgewiesen.\n\n**Bearbeitung freigeben**, Abmeldung oder Sitzungsablauf machen die Anfrage für\nandere Sitzungen verfügbar. Der Ablauf wird bei erneuter Übernahme anhand der\nserverseitigen Zeit geprüft; es wird kein Hintergrundtimer benötigt. Zwei Tabs\nderselben Sitzung gehören derselben Bearbeitung; zwei getrennte Sitzungen auch\ndesselben Benutzers konkurrieren um die Sperre.\n\nHTTP: `POST /v1/auth/login`, `GET /v1/auth/session`, `POST /v1/auth/logout`.\nTestübernahme/-freigabe: `POST /v1/test-requests/{key}/claim` mit\n`{request_id,analysis_revision,action:\"edit\"|\"release\"}`. Feedback bestätigt wie\nbisher die konkrete Anfrage und führt dieselbe Analyse-Revision fort. Bearer-\nClients können keine menschliche Bearbeitungssperre oder Antwort übernehmen.\n" + }, + { + "id": "integration-keys", + "title": "Integrationsschlüssel", + "markdown": "# Integrationsschlüssel\n\nAngemeldete Webnutzer finden unter **API-Schlüssel** eine eigene Verwaltungsseite.\nProgrammname und mindestens ein Projekt auswählen, dann den Schlüssel erstellen.\n**Anzeigen** ruft ihn bei Bedarf erneut ab; **Verbergen** entfernt ihn aus dem\nEingabefeld. **Kopieren** verwendet die Zwischenablage (HTTPS oder localhost).\n**Widerrufen** sperrt ihn sofort für nachfolgende API-Anfragen. Bereits laufende\nAnfragen werden dadurch nicht abgebrochen. Ein widerrufener Schlüssel wird nicht\nmehr angezeigt; für einen Ersatz einen neuen Schlüssel erstellen.\n\nAlle angemeldeten menschlichen Nutzer haben dieselben Verwaltungsrechte.\nMaschinenzugänge können weder Schlüssel verwalten noch andere Schlüssel anzeigen.\nWebmutationen einschließlich Anzeigen benötigen die vorhandene CSRF-Absicherung.\n\nDas aufrufende Programm sendet `Authorization: Bearer ` an die\nÜbergabe-API. Neue Schlüssel erlauben Auftragsübergabe einschließlich Rückgaben\nund lesenden Zugriff auf die ausgewählten Projekte. Sie erlauben keine\nBetriebssteuerung oder Beantwortung menschlicher Testanfragen. Zugriff auf weitere\nProjekte erfordert einen neuen Schlüssel. Bestehende env-basierte Integrationen\nbleiben unverändert nutzbar und erscheinen nicht in der SQLite-Schlüsselliste.\n\n## Speicherung und Sicherung\n\n- SQLite unter `/runtime/integrations/keys.sqlite3` speichert Metadaten,\n SHA-256-Prüfwerte und mit Fernet authentifiziert verschlüsselte Schlüssel.\n- Der separate Serverschlüssel entsteht beim ersten Erstellen automatisch unter\n `/runtime/integration-secrets/master.key`, Dateimodus 0600.\n Nutzerkonten und ihre root-verwaltete SQLite-Datei werden nicht verändert.\n- Mit `VIANO_INTEGRATION_KEY_FILE` kann die API stattdessen eine separate\n Schlüsseldatei verwenden. Vorhandene Dateien müssen einen gültigen Fernet-Key\n enthalten und für den API-Dienst lesbar sein; fehlt die Datei beim ersten\n Erstellen, muss der Dienst sie im gewählten Verzeichnis anlegen dürfen.\n- SQLite und Serverschlüssel getrennt geschützt sichern. Das Laufzeitverzeichnis\n enthält damit dauerhaft notwendige Integrationsdaten und darf bei einer\n Bereinigung von Sessions nicht pauschal gelöscht werden. Unter Windows passende\n Dateisystem-ACLs verwenden; POSIX-Modusbits ersetzen dort keine ACLs.\n- Geht der Serverschlüssel verloren oder wird er unpassend ausgetauscht, können\n Schlüssel nicht mehr angezeigt werden. Das System ersetzt ihn bei bestehenden\n Einträgen nicht stillschweigend. Vorhandene Schlüssel können anhand ihrer\n Prüfwerte weiterhin authentifiziert und über die Weboberfläche widerrufen werden.\n Zur Wiederherstellung die richtige Schlüsseldatei aus der Sicherung zurückspielen.\n\nNach einem Update die API-Abhängigkeiten neu installieren (`.[api]` umfasst jetzt\n`cryptography`) und den API-Dienst neu starten. Eine Datenbankmigration per Hand\nist nicht nötig. Keine Änderung oder Neueingabe des Gemini-Schlüssels erforderlich.\n" + }, + { + "id": "web-console", + "title": "Weboberfläche im Detail", + "markdown": "# Webübersicht\n\nDie Betriebsübersicht wird durch die bestehende Übergabe-API ausgeliefert:\n\n```powershell\n.\\.venv\\Scripts\\python.exe -m viano_bug_analysis.api serve --config config/api.local.toml\n```\n\nAnschließend `http://127.0.0.1:8080/` öffnen und mit **Benutzername und Passwort**\nanmelden. Benutzer werden ausschließlich über privilegierte Konsolenbefehle\nangelegt, geändert und gelöscht, siehe [Benutzerverwaltung](user-accounts.md).\nAlle Webbenutzer haben dieselben Rechte für alle Projekte. Die unten beschriebenen\nClient-/Projektberechtigungen gelten weiterhin für externe API-Integrationen.\nFür entfernte Zugriffe HTTPS verwenden. Der Analyseworker läuft unabhängig davon wie unter\n[Analyseworker](analysis-worker.md) beschrieben. Das Öffnen der Übersicht löst\nkeine Modellanfragen aus.\n\n## Benutzeranleitung\n\nDer Reiter **Benutzeranleitung** enthält die allgemeine Bedienung und\nFunktionsweise sowie Anleitungen für Linux, Projekt-/DB-/Sourcekonfiguration,\nÜbergabe-API, Analyseworker, Nutzerkonten, Integrationsschlüssel, Weboberfläche\nund Erfassungsworker. Dokumentauswahl, Inhaltsverzeichnis und interne Verweise\nerlauben Navigation ohne Server-Dateizugriff. Markdown-Downloads sind ebenfalls\nmöglich. Der Reiter benötigt eine angemeldete Sitzung; sein Aufruf startet keine\nAnalyse. Tabellen, Codebeispiele und Überschriften werden als sichere DOM-Elemente\ndargestellt, eingebettetes HTML wird nicht ausgeführt.\n\nFür Dokumentationsänderungen die ursprünglichen Markdown-Dateien unter `docs/`\nbeziehungsweise `deploy/capture-worker/README.md` bearbeiten und danach\n`python scripts/build_user_manual.py` ausführen. Die feste Auswahlliste steht im\nSkript; tatsächliche lokale Konfigurationen oder Secrets werden nicht gebündelt.\n`python scripts/build_user_manual.py --check` und die Tests erkennen veraltete\nWebfassungen. Das erzeugte `web/user-manual.json` wird mit dem Python-Paket\nausgeliefert, sodass keine lokale Kopie des Dokumentationsordners nötig ist.\n\n## Worker und Fortschritt\n\nDie Startseite listet lebende Worker und darunter den jeweils bearbeiteten Fall\nmit seinem Namen und einem Ladebalken. Der bestehende Dienst erlaubt einen Worker\nje Workspace; die Darstellung ist bereits als Liste aufgebaut. Die Einführung\neines parallelen Worker-Pools ist damit nicht verbunden.\n\nDer Balken folgt abgeschlossenen Arbeitsschritten, nicht vergangener Zeit. Seine\nsieben Anteile entsprechen intern Aufnahme, Fallaufbau, Interpretation,\nHypothesenbildung, Untersuchung, Diagnose und Codingauftrag. Die Oberfläche führt\ndiese Stufen nicht einzeln auf. Der Codingauftrag ist die letzte Stufe, auch wenn\nsein Dokument fachlich erklärt, dass kein Codingauftrag benötigt wird. Bei\ngemeinsamer Interpretation/Hypothesengenerierung können zwei Anteile gleichzeitig\nfertig werden. Eine lang laufende Untersuchung füllt den Balken nicht künstlich.\n\nDer aktive Fall verschwindet bei `OUTPUT_READY`, `HANDED_OFF` oder\n`FAILED_TO_ANALYZE` aus der Workeransicht und der Tabelle laufender Fälle. Er bleibt\nin der Verbrauchsstatistik enthalten. Wartende Fälle bleiben in der Fallübersicht,\nbelegen aber keinen arbeitenden Worker. Ein alter Dienstsnapshot ohne lebenden\nTelemetrie-Heartbeat wird nicht als aktiver Worker dargestellt.\n\n## Verbrauch\n\n- Kreisdiagramm: bekannte Eingabe- und Ausgabetokens je Phase; zusätzliche\n Korrektur-/Reparatur-/Wiederholungsaufrufe haben ein eigenes orangefarbenes Segment.\n Die Legende zeigt Fallaufbau, Fallplanung, Hypothesen, Untersuchung, Diagnose und\n Codingauftrag auch bei null gemessenen Tokens. Nullwerte erzeugen keinen\n künstlichen Tortenanteil. Gemeinsame Planungsaufrufe bleiben einmal gezählt.\n- Balkendiagramm: Eingabe und Ausgabe einschließlich Denken je Kategorie.\n- Der erste reguläre Aufruf bleibt bei seiner Phase, auch wenn sein Ergebnis später\n zurückgewiesen wurde. Seine Korrektur wird ausschließlich dem Korrektursegment\n zugeordnet. Abgeleitete, deterministisch reparierte Antwortdokumente sind keine\n zusätzlichen Anbieteraufrufe und werden nicht erneut gezählt.\n- Denktokens sind bereits Bestandteil der Ausgabetokens. Sie werden weder zum\n Kreisdiagramm noch zum Gesamtverbrauch noch einmal hinzuaddiert.\n- Neue LLM-Runden speichern ihre Verbrauchszuordnung deterministisch aus der\n Operationskennung. Das verändert keine Prompts, Modellparameter oder Budgets.\n Bereits gespeicherte Aufrufe bleiben unverändert. Bei älteren Akten wird nur\n eindeutig erkennbare Korrekturinformation übernommen; sonst erscheint der Anteil\n als „Nicht zugeordnet“.\n- Fehlende Messwerte bleiben unbekannt. Die Diagramme summieren nur bekannte Werte\n und weisen unvollständige Aufrufe aus. Bei vollständig fehlender Tokennutzung\n lässt sich deren Größe nicht als Kreisanteil darstellen.\n\nDer Messumfang umfasst **alle erhaltenen, für den Client freigegebenen Akten und\nderen Revisionen** im konfigurierten Workspace. Er ist keine Google-Abrechnung und\nkeine lebenslange Statistik bereits gelöschter Akten. Dauerhafte Testbilanzen unter\n`docs/test-results/token-usage/` bleiben davon unabhängig. Ein Projektfilter wendet\nsich auf Fallliste, Worker und Diagramme gleichzeitig an. Gemeinsame Planungsaufrufe\nwerden einmal als Fallplanung gezählt, nicht zusätzlich als Hypothesengenerierung.\n\n## Übergabe\n\nDie Oberfläche bietet ein einfaches Formular für neue wowdiag-/wowsrc-Aufträge und\nfür abgeschlossene ZIP-Akten mit Testerfeedback. Es verwendet dieselbe Multipart-\nAPI und denselben Idempotenzmechanismus wie externe Programme. Bei unveränderten\nEingaben verwendet eine Wiederholung denselben Schlüssel. Anhänge und Fallakten\nwerden nicht clientseitig bearbeitet. Betreiberaktionen stehen separat berechtigten\nClients zur Verfügung.\n\n## Fallakte und Ergebnisse\n\nFallnamen verlinken auf eine lesbare Detailansicht mit Testerbeobachtungen,\nInterpretation, Hypothesen, Confidence, stützenden und widersprechenden Befunden,\nDiagnose sowie Coding- und Human-Dev-Auftrag. Befunde bleiben ausdrücklich\nKI-Bewertungen mit Belegreferenzen. Das Belegverzeichnis zeigt Herkunft und\nAbdeckungsinformationen; die vollständigen Recherchepayloads stehen im ZIP.\nEin expliziter Auftrag „Kein Auftrag“ wird von einem noch nicht erstellten Dokument\nunterschieden. Die gemeinsame Liste **Bearbeitete Fälle** enthält Ergebnisse\n(`OUTPUT_READY`, Ziel Outbox), bereits übergebene Fälle (`HANDED_OFF`), blockierte\nFälle (`BLOCKED`) und gescheiterte Analysen (`FAILED_TO_ANALYZE`, Ziel Review).\nBlockierte Fälle bleiben ausdrücklich unvollständig und können weiterhin auch\nin der Übersicht wartender Fälle erscheinen. Ein Sperrgrund wird angezeigt;\n`AWAITING_TEST_FEEDBACK` erscheint als „Wartet auf Testerantwort“.\n\nProjekt- und Kategoriefilter sowie Suche sind kombinierbar. Die Sortierung erlaubt\nneueste/älteste Aktualisierung, Kategorie oder Projekt. Links in jeder Zeile lädt\nein beschrifteter Iconknopf die vollständige aktuelle Fallakte herunter, auch für\nblockierte oder gescheiterte Analysen. Der Download ändert keinen Status und löst\nkeine Analyse aus. Die Ablagespalte zeigt das im Manifest gespeicherte Routingziel;\nes ist keine unabhängige Bestandsprüfung des Outbox-Dateiverzeichnisses. Der Download\nliest die verwaltete aktuelle Akte und funktioniert auch ohne separate Exportkopie.\nAngezeigt wird der aktuelle Stand je Fall/Paket. Nach Wiedereröffnung erscheinen\naktive Fälle wieder in der laufenden Übersicht; ältere Revisionen bleiben in der\nDetailansicht erhalten. Berechtigungen und Projektgrenzen gelten auch für Downloads.\n\nDie Revisionsauswahl liest akzeptierte Artefakte aus der Checkpointhistorie der\naktuellen vollständigen Akte. Ergebnisse neuerer Revisionen erscheinen nicht in\nälteren Ansichten. Über die Übergabe-API erfasste Patch-Rückmeldungen werden bis\nzur gewählten Revision dargestellt. Bei gesperrten Fällen erscheinen Sperrgrund\nund passende Betreiberhinweise. Für berechtigte Betreiber kann eine zulässige\nFortsetzung angefordert werden; Budgets werden dabei nicht zurückgesetzt.\n\n## Betriebssteuerung\n\nAlle angemeldeten Webbenutzer können die Betriebssteuerung verwenden. Externe\nAPI-Clients erhalten standardmäßig keine Betreiberrechte. Ein eigener Client mit\neigenem Token und `operator = true` in der API-Konfiguration erhält Aktionen für\nseine freigegebenen Projekte (Beispiel in `config/api.example.toml`). API nach einer\nRechteänderung neu starten. Der Gemini-Schlüssel ist dafür nicht geeignet.\n\n- **Neue Fälle pausieren / wieder zulassen:** gilt je Projekt und bleibt nach\n Neustart erhalten. HTTP-Aufträge werden weiterhin dauerhaft angenommen. Der\n Worker lässt sie im Eingang bzw. wartet bei noch nicht begonnenen Fällen.\n Begonnene Analysen laufen weiter. Eine Pause unterbricht keinen Modellaufruf.\n- **Fortsetzung nach Fehlerbehebung anfordern:** in der aktuellen Falldetailansicht\n bei passenden Schedulerfehlern bzw. `RESEARCH_UNAVAILABLE`. Die API bestätigt\n nur `QUEUED`, nicht bereits eine Freigabe. Der lebende Worker prüft den Auftrag\n zwischen Dispatches erneut; ein gestoppter Worker bearbeitet ihn nach Neustart.\n- Veraltete Paketgeneration, geänderte Konfigurationsbindung, noch nicht fällige\n Research-Sperre und unzulässige fachliche Sperren werden abgewiesen. Keine\n Zurücksetzung von Hypothesenbudgets, Versuchszählern oder LLM-Operationen.\n- Das Aktionsprotokoll dokumentiert Clientkennung, UTC-Zeit, Projekt, Aktion und\n Ergebnis. Fortsetzungen haben getrennte Eingangs- und Ausführungseinträge mit\n derselben Auftragskennung. Die Ansicht zeigt die letzten 100 berechtigten\n Einträge; das vollständige Protokoll bleibt unter `runtime/worker/control/`.\n Es enthält keine Tokens oder Konfigurationsinhalte. Erfolgreiche lokale\n CLI-Freigaben erscheinen als `local-cli`.\n- Workerdetails zeigen Erreichbarkeit, letzten Zustand, Aktivität und Fehlercode.\n Ein alter Snapshot gilt nicht als lebender Worker. Globale Workerdetails sind\n nur Betreibern mit Zugriff auf alle konfigurierten Projekte zugänglich.\n\n`GET /v1/operations` liefert Rechte, projektbezogenen Pausenzustand und für Betreiber\nProtokoll/Workerzustand. `POST /v1/operations` benötigt Betreiberrechte und JSON:\n`{\"action\":\"pause\",\"project_id\":\"viano-core\"}` bzw. `resume`, oder\n`{\"action\":\"retry\",\"key\":\"\",\"package_generation\":42}`.\nBei gleichzeitigem Zugriff kann `API_CONTROL_BUSY` auftreten; nach Aktualisierung\nerneut versuchen. Der Worker muss nach diesem Softwareupdate neu gestartet werden.\n\n## Menschliche Testanfragen\n\nDie eigene Seite **Testanfragen** listet offene menschliche Rückfragen mit\nEingangszeit, Projekt, Bug-ID, Falltitel und Frage. Projektfilter sowie Sortierung\n„Älteste zuerst“, „Neueste zuerst“ und „Projekt, dann älteste zuerst“ ermöglichen\nchronologisches oder projektweises Abarbeiten. Die Liste aktualisiert sich mit der\nÜbersicht; eine noch offene Eingabe wird dabei nicht überschrieben.\n\n„Ansehen / beantworten“ zeigt Umgebung, Voraussetzungen, Testschritte, benötigte\nBeobachtungen und angefragten Termin. Die Antwort erfasst die tatsächliche Umgebung,\nBeobachtungen und „Test durchgeführt“ oder „Nicht durchführbar“. Die ausdrückliche\nBestätigung ist erforderlich. Textdaten bleiben untrusted observations, keine\nauszuführenden Befehle. Diese erste Oberfläche nimmt Text, keine Dateianhänge an.\n\nMenschliche Antworten erfordern eine angemeldete Benutzersitzung und die exklusive\nÜbernahme über **Bearbeiten**, siehe [Benutzeranmeldung](user-accounts.md).\nEs gibt keine gesonderten Testerrollen für Webbenutzer. Menschliche Zugänge\nausschließlich mit `create_user` anlegen.\nDie bestätigende Identität und Zeit stammen vom Server, nicht aus frei editierbaren\nFormularfeldern. `GET /v1/test-requests` liefert ausschließlich freigegebene Projekte;\n`POST /v1/test-requests/{case-key}` bestätigt die konkrete Anfrage/Revision.\nKollisionen, veraltete Anfragen und widersprüchliche Wiederholungen werden abgewiesen.\nEine identische erneute Übermittlung derselben Sitzung bleibt ohne doppelte Wirkung.\n\nEine bestätigte Antwort setzt `AWAITING_TEST_FEEDBACK` über den vorhandenen\nCoordinator auf `INVESTIGATING_HYPOTHESES` zurück. Revision, Budget und ursprüngliche\nBelege bleiben erhalten. Der laufende Worker verarbeitet die Rückmeldung regulär;\neine besondere Betreiberfreigabe ist dafür nicht erforderlich. Der Termin führt\nauch nach Ablauf zu keiner automatischen Fortsetzung und verwirft die Anfrage nicht.\n\nDie Werkzeugfreigabe erfolgt über `budget_config = \"budget.human-tests.toml\"` in\nden vertrauenswürdigen Projekteinstellungen. Die lokale Dienstkonfiguration wurde\nentsprechend ergänzt. Diese Policy erlaubt `testing.request_human` für 40 fachliche\nEinheiten, automatisierte Tests bleiben ohne Eintrag gesperrt. Bei Trial-Läufen\ndie Datei ausdrücklich mit `--budget-config config/budget.human-tests.toml` angeben.\nBestehende Revisionen behalten ihre eingefrorene Policy; sie werden nicht migriert.\nNach Konfigurationsänderung API und Worker neu starten. Keine Modellanfrage wird\nallein durch Öffnen oder Beantworten der Seite gestartet; der Worker läuft separat.\n\n`GET /v1/cases/{key}?revision=N` liefert diese projektgebundene Ansicht.\n`GET /v1/cases/{key}/package` lädt die vollständige aktuelle Akte einschließlich\naller erhaltenen Revisionen herunter, auch als Zwischenstand eines laufenden Falls.\nBeide Endpunkte benötigen denselben Bearer-Token und verwenden `no-store`.\nDer Schlüssel stammt aus der Übersicht, nicht aus einem lokalen Dateipfad.\nGroße Anzeigeinhalte werden begrenzt und als gekürzt gekennzeichnet. Der Download\nbleibt vollständig; die Anzeige verändert keine Paketgeneration und löst keine\nLLM-Aufrufe aus.\n\n## Datenschutz und Betrieb\n\n`GET /v1/overview` benötigt eine Benutzersitzung oder einen Maschinen-Bearer-Token.\nWebbenutzer sehen alle Projekte; Maschinenclients nur ihre freigegebenen Projekte.\nPrompts, vollständige Modellantworten, lokale Pfade und Zugangsdaten werden nicht\nan den Browser übergeben. Fallnamen werden als Text dargestellt. Die Seite lädt\nkeine externen Fonts, Chartbibliotheken oder Analysedienste; Diagramme werden lokal\nmit Canvas/CSS gezeichnet. Eine Content Security Policy begrenzt Ressourcen auf\ndenselben Ursprung. Abmeldung entfernt dargestellte Daten und Formularinhalte;\nverzögert eintreffende Antworten aus einer vorherigen Anmeldung werden ignoriert.\n\nDie Ansicht aktualisiert sich alle vier Sekunden. Validierte Darstellungen werden\nfür unveränderte Paketgenerationen im API-Prozess zwischengespeichert; dies ist\neine Anzeigeoptimierung, kein fachlicher Zustand und kein Analysecache.\n\n## Lokale Prüfung\n\n```powershell\n.\\.venv\\Scripts\\python.exe -m pytest tests/test_dashboard.py -q\nnode tests/dashboard-smoke.mjs\n```\n\nDer Browser-Smoke-Test verwendet einen lokalen temporären API-Server, einen\nunsichtbaren Edge-Browser und ausdrücklich künstliche Fall-/Verbrauchsdaten. Er\nprüft Desktop, Mobilansicht, Projektfilter, Formularumschaltung, Abmeldung,\nTokenanzeige, Fortschritt, Ergebnisliste, Falldetails, Aufträge und Browserfehler.\nDie API-Tests prüfen zusätzlich Projektzugriff, ZIP-Download und Revisionsisolation.\nUnter Windows wird der installierte\nEdge erwartet; über `BROWSER_PATH` lässt sich ein anderes Chromium angeben.\nDie Testserver/-browser werden beendet, ihre erzeugten temporären Verzeichnisse\nnach Pfadprüfung entfernt. Screenshots als Prüfergebnis liegen unter\n`service-data/ui-preview/`. Es werden keine LLM- oder Datenbankanbieter aufgerufen.\n" + }, + { + "id": "capture-worker", + "title": "Erfassungsworker v0.4", + "markdown": "# wowdiag-worker v0.4 – BugAnalysis-Übergabe\n\nErweiterung des vorgelegten v0.3-Workers. Die ursprüngliche Queue-Claim-Logik und\nDB-Struktur bleiben erhalten. Keine Änderung der aktiven `config.toml`, kein\nDienststart und keine Datenbankmigration durch diese Dateien.\n\nNach erfolgreicher wowdiag-/wowsrc-Erzeugung wird ein Versandauftrag dauerhaft\nin einer separaten lokalen SQLite-Outbox gespeichert. `diagnostic_runs.completed`\nbedeutet weiterhin **Erfassung abgeschlossen**, nicht Analyse abgeschlossen oder\nAPI-Zustellung bestätigt. Die Versandquittung ist über `--handoff-status` sichtbar.\nDie API übernimmt den Fall anschließend in ihren eigenen Analyseworker.\n\n## Einrichtung\n\n1. Bestehende `wowdiag_worker.py` sichern und die v0.4-Datei sowie\n `buganalysis_handoff.py` nebeneinander installieren. Python 3.11 und PyMySQL\n bleiben die Voraussetzungen; der HTTP-Client benötigt keine neue Bibliothek.\n2. Den Abschnitt aus `buganalysis.config.example.toml` in die vorhandene\n Worker-Konfiguration übernehmen. Tatsächliche URL und Projektzuordnung setzen.\n Der URL muss die Serverwurzel sein; HTTPS ist für entfernte Server erforderlich.\n3. Einen Integrationsschlüssel in BugAnalysis für das Projekt erzeugen und im\n Dienst-Environment als `VBA_INTAKE_TOKEN` hinterlegen. Unter Linux eine geschützte\n systemd-EnvironmentFile verwenden; den Schlüssel nicht in Skriptargumente,\n Repository oder Worker-Logs schreiben. Bestehende Unit um EnvironmentFile\n ergänzen und anschließend kontrolliert neu starten.\n4. SQLite-Outbox und Diagnosearchive bis zur bestätigten Zustellung erhalten.\n Das Outbox-Verzeichnis muss für den Worker schreibbar sein und einen lokalen\n Datenträger mit SQLite-Dateisperren verwenden. Die Datei nicht zwischen\n unabhängigen Installationen teilen.\n\nOhne aktivierten `[buganalysis]`-Abschnitt bleibt der bisherige Ablauf erhalten.\nDas Flag bedeutet ausschließlich Erfassung plus Übergabe; der Worker löst keine\nModellanfrage selbst aus. Ein laufender BugAnalysis-Worker kann nach Annahme\nallerdings sofort eine kostenpflichtige Analyse beginnen.\n\n## Wiederholungen und Status\n\n```sh\npython3 wowdiag_worker.py --config config.toml --handoff-status\npython3 wowdiag_worker.py --config config.toml --retry-handoffs\n```\n\nDiese beiden Befehle führen keine Erfassung aus. Der normale Dauerdienst sendet\nfällige Aufträge vor dem nächsten Capture; `--once` versucht sie auch danach.\nNetzwerkfehler, Serverausfälle, temporäre Ablehnungen und fehlende/ungültige\nZugangsdaten bleiben `pending`. Nach Behebung werden dieselben Inhalte mit\ndemselben Idempotenzschlüssel versandt. Auch eine verlorene Erfolgsantwort legt\ndadurch keinen zweiten Fall an. Es werden keine HTTP-Redirects verfolgt.\n\nUnveränderliche Metadaten, Ziel-URL, Archivpfade und Inhaltsprüfwerte stehen in der\nOutbox; Zugangsdaten stehen dort nicht. Archivänderung oder endgültiger HTTP-\nKonflikt wird `attention` und benötigt Betreiberprüfung. Ein Lease verhindert\ngleichzeitigen regulären Versand durch mehrere Worker-Prozesse. Ein Prozessabbruch\nlässt den Auftrag nach Ablauf des Lease erneut versuchen. Es gibt keine automatische\nNeuerzeugung von Archiven oder ein Zurücksetzen der ursprünglichen Queue-Claims.\n\nBereits vor dem Update abgeschlossene Erfassungen werden nicht automatisch\nnachträglich eingesendet. Ein erneuter neuer Auftrag für dieselbe Bug-ID wird von\nBugAnalysis bewusst abgewiesen, wenn der Fall bereits existiert. Rückgaben nach\neinem Patch erfolgen über den separaten `case_return`-Vertrag und nicht durch\nautomatisches Umdeuten neuer Captures.\n\nDer Übergabeumschlag nennt die Bug-ID und den Erfassungs-Commit. Die wirklichen\nTesterbeobachtungen, Titel und Beziehungen liest der BugAnalysis-Importer direkt\naus den unveränderten Archiven. Der Worker erfindet keine Beobachtungen und gibt\nden Erfassungsstand nicht als Stand der ursprünglichen Fehlermeldung aus.\n\n## Lokale Prüfung im BugAnalysis-Checkout\n\n`python -m pytest tests/profiles/vcore/test_capture_handoff.py` prüft den Versand gegen die echte\nlokale Intake-API mit synthetischen Archiven. Kein echter Server, keine Cloud-\nAnfrage, keine Änderung der Diagnose-Queue. Ein Server-Feldtest mit einem neuen\nBug und Dienstneustart steht nach der Konfiguration noch aus.\n" + } + ] +} diff --git a/tests/dashboard-smoke.mjs b/tests/dashboard-smoke.mjs index aa7625f..6d86004 100644 --- a/tests/dashboard-smoke.mjs +++ b/tests/dashboard-smoke.mjs @@ -96,7 +96,21 @@ try { if(await evaluate("document.querySelector('#key-list input').value!==''"))throw new Error('Hidden key retained in input'); await evaluate("window.confirm=()=>true;Array.from(document.querySelectorAll('#key-list button')).find(b=>b.textContent==='Widerrufen').click()"); await until(()=>evaluate("document.getElementById('key-list').textContent.includes('Widerrufen')")); + await evaluate("location.hash='#manual'"); + await until(()=>evaluate("!document.getElementById('manual-page').hidden&&document.getElementById('manual-content').textContent.includes('So arbeitet BugAnalysis')")); + if(!await evaluate("document.getElementById('manual-document').options.length===9&&document.querySelectorAll('#manual-toc button').length>5"))throw new Error('Manual catalog or table of contents missing'); + const safe=await evaluate("(()=>{const rendered=renderManualMarkdown(' [bad](javascript:alert)');const root=document.createElement('div');root.append(rendered.fragment);return !root.querySelector('script,a')&&root.textContent.includes('