Files
GerbilManager/.claude/skills/ticket-triage/SKILL.md
Gulum 2e7911074f
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 1m36s
CI / Frontend Tests (Node/Vite) (push) Successful in 9m35s
CI / Docker Build & Push (push) Successful in 1m28s
CI / Deploy auf TrueNAS (Custom App) (push) Failing after 3s
feat(triage): Ticket-Fixes (Daten + Code) + prod-fähige Triage
Daten-Fixes (conflict-decisions.json, re-ingest-stabil) für ~30 Tickets:
Merges (Jamie/Hiro/Mino/Jana/Blacky/Sakura/Malou/Socke→Marty), Eltern-Korrekturen
(Jacky/Idefix/Ichika/Roni/Ethan), Kruke→Kuke (+ Todesdatum), Targa-Wurf R14 + Druna,
Stacy/Merle/Domi/Eliza; Joghurt-Phantomwurf entfernt.

Code-Fixes:
- Gaida & alle Verstorbenen: Status wird aus Todesdatum/Abgabe abgeleitet
  (Program.cs Startup-Sweep heilt Altfälle; IngestResolved re-derived nach Freeze).
- CoCo: Scheckungsart wird bei jeder Schecke angezeigt (Platzhalter wenn leer).
- M-Wurf/Gale: über-gemergte Fremdtiere via neuem litterChildren-Override entfernt.
- renameTo eltern-verknüpfungssicher (Quell-Name im Index); dateOfDeath als Override.

Prod-fähige Triage (API):
- GET /feedback/{id} + GET /feedback?status= (kein 2-MB-Dump).
- POST /import/ingest-resolved/upload (multipart) → Ingest gegen Prod ohne SSH.

Tests: 280 Backend, 149 Frontend, alle Python, betroffene Playwright grün.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 00:41:43 +02:00

12 KiB
Raw Blame History

name, description
name description
ticket-triage 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.

Ziel-System: lokal ODER Prod (WICHTIG — zuerst klären)

Die Tickets liegen dort, wo die Züchterin sie meldet — im Regelfall Prod (TrueNAS Custom-App). Kläre zu Beginn, gegen welches System der Lauf geht, und setze die API-Base-URL entsprechend für ALLE feedback/gerbils/litters-Aufrufe:

System API-Base Bookmark der Züchterin
Prod (Regelfall) http://truenas:8090/api http://truenas:8090/
Lokal (Aspire) http://localhost:5179 — (App via dotnet run --project GerbilManager.AppHost)
  • Ticket-CRUD läuft immer gegen das Ziel-System (Prod: …/api/feedback). Einzelticket: GET /feedback/{id}; nur die offenen: GET /feedback?status=Open,Answered (spart den 2-MB-Volldump). Encoding: über Datei holen + Python-UTF-8 lesen.
  • Untersuchung bleibt lokal: die Quellen (Stammbaum-xlsx, _rpro3.db, Wurfchronik, output/*.json) liegen lokal. Datenfixes gehören re-ingest-stabil in conflict-decisions.json / rpro3-decisions.json — NICHT die Live-DB patchen.
  • Prod-Re-Ingest ohne SSH (bevorzugt): lokal resolved_import.json generieren (extract → extract_contracts → merge_and_resolve), dann per HTTP hochladen + ingesten:
    curl -X POST http://truenas:8090/api/import/ingest-resolved/upload \
      -F "resolved=@tools/import/output/resolved_import.json" \
      [-F "photos=@neue_fotos.zip"]   # photos optional, nur bei neuen Fotos
    
    Der Endpoint staget die Datei serverseitig und ruft denselben UPSERT-Ingest auf (manuell/verified/feedback überleben). DB-Copy vom lokalen Stand ist VERBOTEN, sobald Prod eigenständig kuratiert wurde — es überschreibt die Prod-Kuratierung; nur der Upsert-Ingest bewahrt sie. (Fallback ohne Endpoint: resolved_import.json per scp + docker cp nach ix-gerbilmanager-api-1:/tools/import/output/ und POST …/api/import/ingest-resolved.)
  • Vor jeder Prod-Mutation (Ingest, Ticket-Schließen im großen Stil) kurz beim Nutzer rückversichern.

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-Enginegerbil-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.pyextract_contracts.pymerge_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; 13 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.