fix(tickets): 16 Tickets der Züchterin — Genetik, Importer, Daten, Akte
All checks were successful
CI / Frontend Tests (Node/Vite) (push) Successful in 9m38s
CI / Backend Tests (.NET) (push) Successful in 1m14s
CI / Docker Build & Push (push) Successful in 1m33s
CI / Deploy auf TrueNAS (Custom App) (push) Successful in 8s

Genetik-Engine (bde4ec70, f89e95ad, 2322c2a8):
- Saphir/Platin/Platin-Hell unterscheiden sich NUR in der C-Zygotie und waren im
  Katalog identisch (locusToken reduziert auf das dominante Allel) → Saphir war
  unerreichbar. Token darf jetzt ein exaktes, ungeordnetes Allelpaar "x/y"
  verlangen: Platin C/C, Saphir C/cchm, Platin-Hell C/ch. TS- und Python-Mirror
  identisch, Seeds regeneriert, Migration ReseedColorVarietiesGen6Saphir.
- c[hm] wird als Alias auf c[chm] normalisiert (Tippfehler in zwei Charts) —
  vorher war Jays Gencode unparsebar und ergab "Zobel-Hell".
- 6 Tiere wechseln den errechneten Farbschlag (5x Platin→Saphir, Jay→Zobel).

Importer-Logik:
- renameTo-Notiz-Sweep: der alte Name blieb in Wurf-Notizen stehen ("Blacky +
  Kruke") — jetzt wortgenau ersetzt, mit vier Guards gegen Kollateralschaden.
- Neuer Resolution-Schlüssel goHomeDate (autoritativ, zieht GivenAway nach) und
  spottingType; Gencode-Overrides gewinnen jetzt bei präzisem Match (vorher
  wurden Entscheidungen stumm verschluckt, z. B. Eliza und Chris).
- parse_date verwirft implausible Jahre (JackJack hatte 1310-05-13).
- extract.py erkennt Stammbaum-Blöcke auch ohne Stern vor dem Geburtsdatum
  (Bijou bekam dadurch den Nachbar-Ast als Mutter).
- Backend-Ingest überträgt SpottingType (nur bei Payload-Wert).

Daten (conflict-decisions.json, re-ingest-stabil): Kuke-Merge + Zuchtname,
Jamie- und Sakura-Dubletten, Phantom-Tier "Unbekannt", Eltern von Kathlin,
Fast Boy/Ziwa und dem Q4-/TS-Wurf, Eliza-Gencode, Merle-Abgabe, JackJack.

Frontend (24522f5f): Abgabedatum steht in der Tier-Akte jetzt direkt unter dem
Abnehmer und hängt nicht mehr am Status.

Tests: +25 Checks test_merge_resolve, +7 test_genotype, +8 genetics.test.ts,
neuer Extract- und Ingest-Test, e2e GOHOME-ROW. Alles grün.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-19 23:31:48 +02:00
parent bf074696b4
commit 5a6d1c2541
22 changed files with 2832 additions and 182 deletions

View File

@@ -179,7 +179,15 @@ export function seedDb(): MockDb {
// Statistik: Verstorbene + Abgegebene für Verluste/Bestandskurve
{ ...gerbil('willi', 'Willi', 'male', '2019-09-09', null, 'cv-schwarz'), status: 'Deceased', dateOfDeath: '2022-04-04' },
{ ...gerbil('pauli', 'Pauli', 'male', '2023-05-01', null, 'cv-himalaya'), status: 'GivenAway', goHomeDate: '2023-07-15', receiverContactId: 'con-huber' },
{ ...gerbil('rosa', 'Rosa', 'female', '2020-02-02', null, 'cv-gold'), status: 'Deceased', dateOfDeath: '2023-08-15' },
// Ticket 24522f5f (JackJack): abgegeben UND später beim Abnehmer verstorben —
// Status Deceased, aber Abnehmer + Abgabedatum gesetzt. Die Akte muss beides zeigen.
{
...gerbil('rosa', 'Rosa', 'female', '2020-02-02', null, 'cv-gold'),
status: 'Deceased',
dateOfDeath: '2023-08-15',
receiverContactId: 'con-huber',
goHomeDate: '2022-01-15',
},
{ ...gerbil('pauli-breeder', 'Pauli Breeder', 'male', '2023-05-01', null, 'cv-himalaya'), status: 'GivenAway', goHomeDate: '2023-07-15', receiverContactId: 'con-meier' },
{ ...gerbil('pauli-neither', 'Pauli Neither', 'male', '2023-05-01', null, 'cv-himalaya'), status: 'GivenAway', goHomeDate: '2023-07-15', receiverContactId: 'con-neither' },
// ABGABE: zwei Tiere zur Abgabe im Quarantänebecken (enc-leer ist leer, kein Konflikt

View File

@@ -221,6 +221,26 @@ test('Detailseite: Zuchtpartner-Liste trennt mit Komma HINTEN am Namen (KV-COMMA
expect(text).toBe('Greta, Frieda')
})
test('Detailseite: Abgabedatum steht direkt unter dem Abnehmer, auch bei Verstorbenen (GOHOME-ROW)', async ({
page,
}) => {
skipUnlessMock()
// Ticket 24522f5f (JackJack): Rosa wurde abgegeben und starb später beim Abnehmer
// (Status „Verstorben", aber Abnehmer + Abgabedatum gesetzt). Früher hing die
// Abgabedatum-Zeile am Status „Abgegeben" → sie fehlte genau in diesem Fall.
await page.goto('/rennmaeuse/rosa')
const receiverRow = page.locator('.ak-kv', {
has: page.locator('.ak-kv-label', { hasText: t.fields.receiver }),
})
await expect(receiverRow).toBeVisible()
await expect(receiverRow.locator('.ak-kv-value')).toContainText('Familie Huber')
// Abgabedatum ist die direkt folgende Zeile (Geschwister-Selektor).
const goHomeRow = receiverRow.locator('xpath=following-sibling::*[1]')
await expect(goHomeRow.locator('.ak-kv-label')).toHaveText(t.fields.goHomeDate)
await expect(goHomeRow.locator('.ak-kv-value')).toHaveText('15.01.2022')
})
/** QOL-ELTERN: Vater/Mutter im Abstammungs-Block des Tier-Formulars setzen. */
async function pickParent(page: Page, legend: string, name: string) {
const group = page.getByRole('group', { name: legend })