---
name: ticket-triage
description: >-
  Fehlerberichte (Tickets) der Züchterin abarbeiten: neue Tickets per Subagent
  triagieren, Rückfragen an die Tickets hängen, beantwortete Tickets wieder
  aufgreifen, Fixes gebündelt umsetzen und beim Schließen dokumentieren, was
  gefixt wurde. Nutze diesen Skill, wenn der Nutzer „Tickets abarbeiten /
  triagieren", „Fehlerberichte bearbeiten" o. Ä. verlangt.
---

# Ticket-Triage & Abarbeitung

Tickets entstehen über das „Fehler melden"-Feature (`POST /feedback`) und werden
unter **Hilfe → Meine Tickets** (`/hilfe/tickets`) verwaltet. Dieser Skill
automatisiert das Triagieren, Rückfragen-Stellen, Umsetzen und Schließen.

## Status-Lebenszyklus (Feedback.Status)

| Status | Bedeutung | Wer ist dran |
|---|---|---|
| `Open` | Neues Ticket, noch nicht triagiert | **KI** (triagieren) |
| `NeedsInfo` | KI hat eine **Rückfrage** angehängt | Züchterin (antworten) |
| `Answered` | Züchterin hat geantwortet | **KI** (wieder aufgreifen, umsetzen) |
| `Resolved` | Erledigt — mit `fixNote` (Changelog) | — |

**Zu bearbeiten sind `Open` (neu) und `Answered` (KI wieder dran).** `NeedsInfo`
wartet auf die Züchterin, `Resolved` ist fertig — beide überspringen.

## Voraussetzungen

- App läuft (Aspire): `dotnet run --project GerbilManager.AppHost`; API auf
  http://localhost:5179. Siehe `CLAUDE.md` (Architektur, Import→DB-Workflow,
  Domänenwissen: 6-Jahre-Lebensspanne, Geschwisterverpaarung, Genotyp/E-Locus,
  `isResident`).
- Feedback überlebt den Import-Ingest (FK-freie Spalten) — Tickets bleiben
  erhalten, auch wenn die DB neu befüllt wird.

## Ablauf

### 1. Tickets holen & einteilen
`curl -s http://localhost:5179/feedback` (neueste zuerst). Encoding-Falle: über
eine Datei holen (`curl -o raw.json`) und mit `python … .decode('utf-8')` lesen,
nicht via Windows-stdin-Pipe (sonst Mojibake). Test-/Dummy-Tickets ausschließen.
Filtere auf `status in (Open, Answered)`. Bei `Answered` zusätzlich das Feld
`answer` (Antwort der Züchterin) mitnehmen — darauf basiert die Umsetzung.

### 2. Triage per Subagent (ein Agent pro Ticket)
Nutze die **Workflow-Orchestrierung** (`pipeline`) — einen Triage-Agenten pro
Ticket. args ASCII-sicher halten (nur id/context/gerbilId/litterId übergeben; die
deutschen Nachrichten holt der Agent selbst aus `GET /feedback`). Defensive im
Script: `const tickets = Array.isArray(args) ? args : JSON.parse(args)`.

Jeder Triage-Agent:
1. liest `CLAUDE.md` + `docs/ticket-triage.md` (falls vorhanden),
2. holt seinen Ticket-Text (+ `answer` bei `Answered`) aus `GET /feedback`,
3. untersucht die echten Daten über die API (`GET /gerbils/{id}`, `/litters/{id}`,
   Eltern verfolgen; `provenance` zeigt Import-Herkunft inkl. verworfener Werte),
4. liefert strukturiert (StructuredOutput-Schema): `ticketId, title, category,
   rootCause, recommendation, fixLayer (import-data|import-logic|backend|frontend|
   genetics-engine), affectedAreas[], overlapKey (Cluster-Slug), effort (S/M/L),
   confidence, needsUserInfo`,
5. **terminale Aktion am Ticket selbst** (jeder Triage-Agent schließt seinen
   Vorgang ab, lässt nichts offen liegen): braucht es Infos von der Züchterin →
   **Rückfrage ordentlich stellen** (siehe 3); ist die Ursache rein eine Daten-/
   Code-Korrektur ohne Rückfrage → an den passenden Umsetzungs-Cluster (4)
   übergeben (NICHT selbst querschnittlich Dateien ändern).

Sammle alle Ergebnisse in **eine Datei** `docs/ticket-triage.md` (Cluster-/
Überschneidungs-Matrix + offene Rückfragen) — token-schonend per Python aus dem
Workflow-Ergebnis generieren, nicht 70 KB in den Kontext laden.

### 3. Rückfragen ordentlich stellen (durch den Triage-Agenten)
Wenn ein Ticket Infos der Züchterin braucht, hängt der Triage-Agent die Rückfrage
**direkt selbst** ans Ticket:
`PUT /feedback/{id}` mit `{"question": "<Rückfrage>"}` → Status wird `NeedsInfo`.
Anforderungen an eine gute Rückfrage: **eine konkrete Frage** (kein Sammelsurium),
in **einfacher, freundlicher Sprache** für die Züchterin (keine Code-/Fachbegriffe),
mit dem nötigen Kontext (welches Tier/welcher Wurf, was unklar ist), und mit einer
klaren Handlungsaufforderung (z. B. „Wie heißt die Mutter von X?"). Die Züchterin
beantwortet es in der App; beim nächsten Lauf erscheint es als `Answered` und wird
wieder aufgegriffen.

### 4. Umsetzen — gebündelt nach Cluster (Überschneidungen vermeiden!)
Die Triage-Matrix zeigt, welche Tickets sich Dateien teilen. Bündele nach
**datei-disjunkten Workstreams**, damit parallele Subagenten nicht kollidieren:
- **Genetik-Engine** → `gerbil-manager-web/src/genetics/**`, `tools/import/genotype.py`.
- **Stammbaum-Import** (Eltern/Dedup/Gender/`isResident`) → `tools/import/extract.py`,
  `merge_and_resolve.py`, `conflict-decisions.json`.
- **Frontend-Anzeige** (z. B. Nicht-Bestandstiere ausblenden) → `GerbilDetailPage.tsx`,
  `de.ts`.
Gemeinsam genutzte Dateien (`de.ts`, `GerbilDetailPage.tsx`) gehören **genau einem**
Workstream — sonst sequenziell. Datenkorrekturen, die die Züchterin nennt, als
Override in `conflict-decisions.json` kodieren (data-driven, re-ingest-stabil).
Subagenten committen NICHT und re-ingesten NICHT — das koordiniert der Haupt-Loop.

### 5. Import neu einspielen (bei Daten-/Import-Änderungen)
`python tools/import/extract.py` → `extract_contracts.py` → `merge_and_resolve.py`,
dann `POST /import/ingest-resolved` (wischt + lädt neu). Danach betroffene Tickets
gegen die API verifizieren.

### 6. Ticket schließen — MIT Changelog (durch den bearbeitenden Subagenten)
Der Subagent/Cluster, der den Fix umgesetzt hat, schließt **seine** Tickets selbst
ab — aber erst **nachdem der Fix verifiziert und (bei Daten-/Import-Fixes) live
eingespielt ist** (Schritt 5), damit „erledigt" auch stimmt:
`PUT /feedback/{id}` mit `{"status": "Resolved", "fixNote": "<verständliche
Erklärung, was korrigiert wurde>"}`.
**Die `fixNote` ist ein Changelog AUSSCHLIESSLICH für die Züchterin (Laiin) —
kein technisches Geschwafel.** Harte Regel:
- Schreib, **was sich für SIE sichtbar geändert hat**, in Alltagssprache; 1–3 Sätze.
- KEINE Dateinamen, Funktionen, Feldnamen, IDs, Status-Codes, „Resolver/Migration/
  Genotyp-Parser/isResident/conflict-decisions" o. Ä. Nenne Tiere/Würfe bei ihrem
  **Namen**, nicht per ID.
- Sag ggf., was sie tun soll (z. B. „Seite neu laden").

Gut: „Die Mutter von **Yuki** war falsch — sie ist jetzt **Izumi** (vorher stand
da Benjiro). Bitte den Stammbaum neu laden."
Gut: „**Hagrid** wird nicht mehr als dein eigenes Tier geführt, sondern nur noch
als Vorfahre — seine Würfe und der Charakter-Bereich werden nicht mehr angezeigt."
Schlecht (NICHT so): „assign_parent_roles korrigiert, motherId via
conflict-decisions.json gesetzt, re-ingest." / „isResident=false gesetzt."

### Abschluss-Regel (wichtig)
**Kein bearbeitetes Ticket bleibt offen liegen.** Jedes `Open`/`Answered`-Ticket
endet nach einem Lauf in genau einem Endzustand:
- **`NeedsInfo`** — Rückfrage wurde ordentlich gestellt (Info fehlt), oder
- **`Resolved`** — Fix umgesetzt + verifiziert, mit `fixNote`-Changelog.
Kann ein Ticket weder gefixt noch sinnvoll erfragt werden, stelle trotzdem eine
klärende Rückfrage (NeedsInfo) statt es offen zu lassen.

## Mehrrundige Rückfragen & Kontext-Kontinuität

Der Dialog kann mehrere Runden haben: `Open → (Rückfrage) NeedsInfo → (Antwort)
Answered → (KI prüft) ggf. neue Rückfrage NeedsInfo → Answered → … → Resolved`.
Jede **weitere Antwort** der Züchterin bringt das Ticket wieder auf `Answered` und
damit erneut in die Bearbeitung (Schritt 1 filtert `Answered` immer mit ein).

**Kontext-Träger ist das Ticket, nicht der Subagent.** Subagenten sind
sitzungsgebunden — antwortet die Züchterin später (neue Session), existiert der
ursprüngliche Agent nicht mehr. Daher MUSS der gesamte Verlauf am Ticket hängen
(Frage/Antwort je Runde) + der Triage-Eintrag in `docs/ticket-triage.md`. Beim
Wiederaufgreifen eines `Answered`-Tickets lädt der Subagent diesen vollständigen
Verlauf + die frühere Triage und macht **mit demselben Kontext** weiter (statt bei
null neu zu untersuchen) — praktisch „derselbe Vorgang, fortgesetzt".

**Innerhalb derselben Session** kann man stattdessen denselben Subagenten direkt
fortsetzen (SendMessage an seine Agent-ID, Kontext bleibt erhalten) — nur dann ist
echte Agent-Kontinuität möglich.

Das Datenmodell unterstützt Mehrrunden über einen **Verlauf/Thread** am Ticket
(mehrere Frage/Antwort-Einträge mit Autor + Zeit), nicht nur ein einzelnes
Frage/Antwort-Paar — so geht bei weiteren Antworten nichts verloren.

### Internes Agenten-Kontextfeld (für die Züchterin unsichtbar)

Das Ticket hat ein **internes Kontextfeld** (`agentContext`, NICHT in der Züchterin-
UI sichtbar) — das **Arbeitsgedächtnis** des Agenten. Damit ersetzt das Ticket den
sitzungsgebundenen Subagenten-Kontext:
- **Schreiben:** Bei jeder Bearbeitung legt der Agent dort seinen Arbeitsstand ab
  (kompaktes JSON/Markdown): Befunde, vermutete Ursache, geprüfte Hypothesen,
  betroffene Dateien/Daten, der Plan, **worauf gewartet wird** (welche Info die
  Rückfrage klären soll) und schon erledigte Teilschritte.
- **Lesen:** Beim Wiederaufgreifen eines `Answered`-Tickets liest der Agent zuerst
  `agentContext` (+ Verlauf + Triage-Eintrag) und setzt **dort an, wo er aufgehört
  hat** — keine Neu-Untersuchung von null.
- **Trennung:** `agentContext` ist intern/technisch (darf IDs/Dateinamen/Hypothesen
  enthalten); die **sichtbaren** Felder bleiben laienverständlich (Frage, Antwort,
  `fixNote`). `agentContext` wird in der Tickets-Seite NICHT angezeigt.
- `PUT /feedback/{id}` mit `{"agentContext": "<arbeitsstand>"}` aktualisiert es,
  ohne den Status zu ändern.

## Verifikation vor „fertig"
- Code-Fixes: `npx tsc --noEmit`, `npx vitest run`, betroffene `npx playwright test`,
  `dotnet build`/`dotnet test`, Python-`test_*.py` — grün.
- Daten-Fixes: in `resolved_import.json` stichprobenartig prüfen, dann re-ingest +
  API-Check des konkreten Tiers/Wurfs.
- Jedes erledigte Ticket auf `Resolved` mit `fixNote` gesetzt.

## Hinweise
- Pro Ticket genau ein Triage-Agent; Umsetzung gebündelt nach Cluster.
- Encoding: deutsche Texte als UTF-8 (Datei, nicht stdin-Pipe).
- Nichts committen, bis der Haupt-Loop verifiziert hat; auf `main` arbeiten.
