docs: Dauerwissen aus dem Ticket-Lauf + Ergebnis/Folgeaufgaben
CLAUDE.md: C-Locus-Zygotie (Platin/Saphir/Platin-Hell, Paar-Token "x/y"), c[hm]-Alias, die neuen Resolution-Schlüssel goHomeDate/spottingType und die Präzedenz des genotype-Overrides, "pro Tier nur EINE Resolution" (inkl. der Falle, dass Wurfchronik-Jungtiere zur Override-Zeit kein DOB haben), der renameTo-Notiz-Sweep mit seinen Guards, der parse_date-Jahresguard und die sternlosen Geburtsdaten in Stammbaum-Charts. docs/ticket-triage.md: Ergebnis des Laufs (16/16 Resolved, 27/27 Prod-Checks) und die acht bewusst offen gelassenen Folgeaufgaben. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
37
CLAUDE.md
37
CLAUDE.md
@@ -216,6 +216,16 @@ python test_extract.py test_extract_docx.py test_genotype.py test_merge_resol
|
||||
`gerbil-manager-web/src/genetics`). Unbekanntes Allel = `-` (nicht `?`).
|
||||
E-Locus: `ee`=Fuchs, `eef`=Fuchsschimmel, `efef`=Schimmel. Rezessiver Fuchs ist
|
||||
zwingend homozygot → `e-` ist ungültig (wirft), `ee[-]`→`ee`.
|
||||
- **C-Locus-Zygotie (GEN-6, Tickets bde4ec70/f89e95ad — Regel der Züchterin):** Platin,
|
||||
Saphir und Platin-Hell unterscheiden sich **nur** in der C-Zygotie: `aa CC …pp` = **Platin**,
|
||||
`aa Cc[chm] …pp` = **Saphir**, `aa Cc[h] …pp` = **Platin-Hell**. Der Katalog-Match kann
|
||||
deshalb pro Locus ein **exaktes, ungeordnetes Allelpaar** verlangen — Token-Form `"x/y"`
|
||||
(z. B. `C: 'C/cchm'`), sonst reduziert `locusToken()` auf das dominante Allel und der erste
|
||||
Treffer (Platin) verschluckt die anderen. Gilt in **beiden** Mirrors (`catalog.ts` +
|
||||
`genotype.py`) und im Seed (`colorVarietySeed.*`, `ApplicationContext.SeedColorVarieties`,
|
||||
dort in Kompaktnotation `Ccchm`/`Cch` ohne Klammern).
|
||||
- **`c[hm]` ist ein Schreibfehler-Alias für `c[chm]`** (fehlendes c in einigen Stammbaum-Charts):
|
||||
beide Parser normalisieren ihn, sonst ist der Gencode unparsebar bzw. ergibt „…-Hell".
|
||||
- **Genetik-Engine = korrektheitskritisch: IMMER vollständig mit Tests absichern.**
|
||||
Jede Änderung an `src/genetics/**` (+ Backend-Mirror + `genotype.py`) braucht pro
|
||||
Use-Case/Ticket einen Regressionstest (`src/genetics/__tests__/genetics.test.ts`
|
||||
@@ -330,6 +340,33 @@ python test_extract.py test_extract_docx.py test_genotype.py test_merge_resol
|
||||
- **EMF/WMF sind keine Fotos**: Excel legt neben dem Foto teils ein Vektor-Metafile ab; Browser
|
||||
können es nicht darstellen (kaputte Bildkachel in der Akte) → `extract._attach_photos`
|
||||
überspringt `.emf`/`.wmf` (Regressionstest in `test_extract.py`).
|
||||
- **Resolution-Schlüssel in `conflict-decisions.json` (Stand 2026-08-19)**: neben
|
||||
`father/mother(+Dob)`, `isResident`, `notes`, `receiver`, `dateOfDeath`, `deceased`,
|
||||
`correctDob`, `renameTo`, `mergeExternalRefs`, `suppressExternalRefs`, `farbschlag` auch
|
||||
**`goHomeDate`** (autoritativ, überschreibt auch einen vorhandenen/kaputten Wert und zieht
|
||||
Status `GivenAway` nach, sofern nicht `Deceased`) und **`spottingType`** (Scheckungsart —
|
||||
der Importer leitet sie aus keiner Quelle ab; `IngestResolvedService` überträgt sie nur,
|
||||
wenn der Payload einen Wert hat, sonst bliebe eine von Hand erfasste Angabe nicht stehen).
|
||||
**`genotype`** gewinnt bei **präzisem** Match (externalRef ODER name+dob) auch gegen einen
|
||||
bereits gefüllten Wert — bei Wurfchronik-Tieren ist der meist nur der Kanon-Fill des
|
||||
Farbschlags; ein name-only-Match füllt weiterhin nur leere Felder (Namensvetter-Schutz).
|
||||
- **Pro Tier greift nur EINE Resolution** (first match: externalRef → endswith → name+dob →
|
||||
name-only). Nie einen zweiten Eintrag mit derselben externalRef/demselben (name,dob) anlegen,
|
||||
sondern den bestehenden **in place** erweitern — sonst gewinnt still der letzte und Felder
|
||||
gehen verloren. **Wurfchronik-Jungtiere haben zur Override-Zeit noch kein DOB** (das kommt
|
||||
später aus dem Wurfdatum) → dort ist `externalRef` der einzige zuverlässige Schlüssel.
|
||||
- **`renameTo` zieht durch Freitext-Notizen** (`apply_rename_note_sweep`, letzter Schritt vor
|
||||
dem Payload-Dump): der alte Name blieb sonst in Wurf-Notizen stehen („Blacky + Kruke v. …").
|
||||
Wortgenau, mit Guards — Quellname < 4 Zeichen oder > 2 Wörter wird ignoriert, kein Ersetzen,
|
||||
wenn der alte Name im neuen Rufnamen steckt, und Notizen, die die Umbenennung selbst
|
||||
dokumentieren („umbenannt"/„ursprünglich"), bleiben unberührt. Ohne diese Guards trifft der
|
||||
Sweep Abnehmer-Namen und Gewichtsnotizen (im Probelauf 16 von 22 Ersetzungen falsch).
|
||||
- **`parse_date` verwirft implausible Jahre** (< 1900 oder > aktuelles Jahr + 1) → `None`;
|
||||
Wurfchronik-Transkriptionen bauen Daten sonst falsch zusammen (JackJack: „1310-05-13").
|
||||
- **Sternloses Geburtsdatum in Stammbaum-Charts**: `extract.py` normalisiert Zellen wie
|
||||
`22.08.2019/+09.04.2024` (ohne `*`) zu `*…`, wenn Block-Kontext vorliegt (Genotyp ≤3 Zeilen
|
||||
darunter, Namenszelle ≤3 darüber). Ohne das erkennt die Blockheuristik das Tier nicht und
|
||||
`_reconstruct_parents` greift in den Nachbar-Ast (Ticket 65266679 Bijou).
|
||||
- **`renameTo` ist eltern-verknüpfungssicher**: umbenannte Tiere werden im Eltern-Namensindex
|
||||
zusätzlich unter ihrem **Quell-Namen** (`_pre_rename_name`) geführt, sonst verlieren Würfe, die
|
||||
den alten Namen referenzieren, ihren Eltern-Link (Ticket e0a0c304 Kruke→Kuke). `dateOfDeath`
|
||||
|
||||
Reference in New Issue
Block a user