Compare commits

...

2 Commits

Author SHA1 Message Date
efce79b3fa GEN-3g: CP colourpoint het-naming rule — '-Hell' == cchm/ch (breeder C9 answer)
- colourpointName(): A- cchm/ch now yields 'CP-<base>-Hell' (was 'CP-<base>');
  A- cchm/cchm unchanged. Non-agouti branch (Marder/Siam/Zobel/Zobel-Hell)
  unchanged — already used the het token.
- Added 5 new catalog entries: CP-Agouti-Hell, CP-Silberagouti-Hell,
  CP-Algierfuchs-Hell, CP-Polarfuchs-Hell, CP-Orangeschimmel-Hell.
  CP-Fuchs-Hell was already present. Catalog 61 -> 66.
- Regenerated colorVarietySeed.generated.json (66 rows for Pam DATA-2 re-seed).
- Tests: 82 -> 82 (reworded het case) + 1 new GEN-3g describe block. All pass.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 15:14:23 +02:00
13eb17b453 docs(HUMANQUESTION): C6-Status praezisiert - 27 von 32 Konflikten geklaert, nur D6 (5 Tiere) offen; review-report nach IMPORT-POLISH-Re-Extract (Konflikte 5)
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 51s
CI / Frontend Tests (Node/Vite) (push) Successful in 9m32s
CI / Docker Build & Push (push) Failing after 9s
2026-06-06 15:06:20 +02:00
5 changed files with 105 additions and 34 deletions

View File

@@ -49,7 +49,7 @@ gelisteten Konflikt-Tiere + Tiere mit Sonder-Kürzeln warten in Quarantäne —
| ~~C3~~ | ✅ **BEANTWORTET** (2026-06-06): Ja, automatisch zusammenführen — **aber nur wenn auch der Zuchtname gleich ist** (Name + Geburtsdatum + Zuchtname = dasselbe Tier). Wird in die Dedup-Regel eingebaut. (Hinweis: der Extraktor fand bisher 0 Fälle mit gleichem Name+Datum aber verschiedenem Zuchtnamen, also ändert sich an den bestehenden Zusammenführungen nichts — die Regel ist die Absicherung.) | — erledigt |
| ~~C4~~ | ✅ **BEANTWORTET** (2026-06-06): Ja, **Wurfchronik Teil 2 existiert** — wird gerade überarbeitet, kommt später. Der Importer ist pro Datei wiederholbar (idempotent), also einfach die Datei schicken, sobald fertig → Michael importiert sie nach (keine Doppelungen). | ⏳ Datei folgt, wenn überarbeitet |
| ~~C5~~ | ✅ **BEANTWORTET** (2026-06-06): **Es gibt KEIN „Schwarzschimmel"** — das war ein Fehler in unserem Katalog. Die korrekten Schimmelarten: `efef`**Orangeschimmel** · `efef pp`**Rotaugenschimmel** · `efef gg`**Silberschimmel** · Kombis z. B. `c[chm]c[chm] efef`**CP-Orangeschimmel**. Michael korrigiert den Katalog (Schwarzschimmel raus, efef = Orangeschimmel). | — erledigt |
| C6 | **Die 32 Konflikt-Tiere prüfen** → siehe Abschnitt **D**. | diese 32 Tiere werden erst danach geladen |
| C6 | **FAST ERLEDIGT** (Stand 06.06. nachmittags): von den ursprünglich 32 Konflikt-Tieren sind **27 geklärt + geladen** (deine D1D5-Antworten + Beibehalten-Regel + „genauer gewinnt"-Regel). **Offen sind nur noch die 5 Tiere in D6**: Hanami (Sterbedatum), Big Ben (PP↔Pp), Vance Jr. (Spsp↔spsp), Kazu (3 Loci), Skarlett (Sterbedatum). | nur diese 5 warten noch auf den Import |
| C7 | *(optional)* Was hat dir bei **Renner Pro** gefehlt? Lieblings-Auswertungen? | mögliche neue Funktionen |
| ~~C8~~ | ✅ **BEANTWORTET** (2026-06-06): **Himalaya gibt es** — Himalaya = **`A- c[h]c[h]`** (agouti), Hermelin = **`aa c[h]c[h]`** (nicht-agouti). Beide bleiben im Katalog; die Engine unterscheidet bereits korrekt nach A-/aa. — erledigt |
| ~~C9~~ | ✅ **BEANTWORTET** (2026-06-06): **„CP-Fuchs" ist ein Sammelbegriff** — bei diesen Tieren ist unklar, ob es CP-Polarfuchs, CP-Algierfuchs, CP-Kohlfuchs oder CP-Blaufuchs ist (Tiere sind schneeweiß mit schwarzen Augen; Verpaarungen haben die Gene nicht verraten). Bekannt ist nur: **„CP-Fuchs" = `c[chm]c[chm]`**, **„CP-Fuchs hell" = `c[chm]c[h]`**. **Generelle Regel: das Wort „hell" im Farbschlag-Namen bedeutet immer, dass ein `c[h]` im Gencode steckt** (also `c[chm]c[h]`); ohne „hell" = `c[chm]c[chm]`. Die „-Hell"-Vermutung war richtig ✓; Engine-Update beauftragt (GEN-3g): bei unbekannten Unterscheidungs-Loci bleibt der Sammelbegriff „CP-Fuchs" korrekt. — erledigt |

View File

@@ -179,10 +179,11 @@ describe('Farbschlag catalog', () => {
expect(match.name).toBe('Unbekannter Farbschlag')
})
it('has the expected catalogue coverage (GEN-3f: 61 after cchm CP reconciliation)', () => {
// GEN-3f collapsed the 24 portal cchm colourpoint rows to 12 breeder-named
// varieties (Marder/Siam/Zobel/Zobel-Hell + CP-<base>), so 73 -> 61.
expect(CATALOG_SIZE).toBe(61)
it('has the expected catalogue coverage (GEN-3g: 66 after adding CP-*-Hell het variants)', () => {
// GEN-3f: 73 -> 61 (cchm CP reconciliation).
// GEN-3g: +5 het variants (CP-Agouti/Silberagouti/Algierfuchs/Polarfuchs/Orangeschimmel -Hell),
// giving 61 + 5 = 66. CP-Fuchs-Hell was already counted.
expect(CATALOG_SIZE).toBe(66)
})
it('frozen contract names round-trip to themselves (DB-key guard)', () => {
@@ -414,8 +415,12 @@ describe('GEN-3e: C-locus colourpoint naming', () => {
expect(name('AA cchmcchm DD EE GG PP spsp rere')).toBe('CP-Agouti')
})
it('A- + cchm/ch -> CP-<base colour>', () => {
expect(name('AA cchmch DD EE GG PP spsp rere')).toBe('CP-Agouti')
it('A- + cchm/ch -> CP-<base colour>-Hell (GEN-3g: het gets -Hell suffix)', () => {
expect(name('AA cchmch DD EE GG PP spsp rere')).toBe('CP-Agouti-Hell')
expect(name('AA cchmch DD EE gg PP spsp rere')).toBe('CP-Silberagouti-Hell')
expect(name('AA cchmch DD ee GG PP spsp rere')).toBe('CP-Algierfuchs-Hell')
expect(name('AA cchmch DD ee gg PP spsp rere')).toBe('CP-Polarfuchs-Hell')
expect(name('AA cchmch dd ee GG PP spsp rere')).toBe('CP-Fuchs-Hell')
})
it('aa fixed colourpoint names (Marder/Siam/Zobel/Zobel-Hell)', () => {
@@ -471,10 +476,50 @@ describe('GEN-3f: CP catalog reconciled to the breeder CP- naming (matches her l
expect(name('AA cchmcchm DD efef GG PP spsp rere')).toBe('CP-Orangeschimmel')
})
it('het cchm/ch colourpoints (Siam, Zobel-Hell) resolve to their own names', () => {
it('het cchm/ch colourpoints (Siam, Zobel-Hell, CP-*-Hell) resolve to their own names', () => {
const siam = BASE_COLORS.find((e) => e.name === 'Siam')!
const zh = BASE_COLORS.find((e) => e.name === 'Zobel-Hell')!
const cpah = BASE_COLORS.find((e) => e.name === 'CP-Agouti-Hell')!
const cpfh = BASE_COLORS.find((e) => e.name === 'CP-Fuchs-Hell')!
expect(genotypeToFarbschlag(representativeGenotype(siam))).toBe('Siam')
expect(genotypeToFarbschlag(representativeGenotype(zh))).toBe('Zobel-Hell')
expect(genotypeToFarbschlag(representativeGenotype(cpah))).toBe('CP-Agouti-Hell')
expect(genotypeToFarbschlag(representativeGenotype(cpfh))).toBe('CP-Fuchs-Hell')
})
})
describe('GEN-3g: "-Hell" in variety name == cchm/ch het; hom == cchm/cchm', () => {
const name = (s: string) => genotypeToFarbschlag(fromDisplayString(s))
const has = (n: string) => BASE_COLORS.some((e) => e.name === n)
it('all new -Hell het entries exist in catalog', () => {
for (const n of [
'CP-Agouti-Hell', 'CP-Silberagouti-Hell', 'CP-Algierfuchs-Hell',
'CP-Polarfuchs-Hell', 'CP-Orangeschimmel-Hell',
]) {
expect(has(n)).toBe(true)
}
})
it('engine correctly maps het (cchm/ch) to -Hell suffix for all A- bases', () => {
expect(name('AA cchmch DD EE GG PP spsp rere')).toBe('CP-Agouti-Hell')
expect(name('AA cchmch DD EE gg PP spsp rere')).toBe('CP-Silberagouti-Hell')
expect(name('AA cchmch DD ee GG PP spsp rere')).toBe('CP-Algierfuchs-Hell')
expect(name('AA cchmch DD ee gg PP spsp rere')).toBe('CP-Polarfuchs-Hell')
expect(name('AA cchmch dd ee GG PP spsp rere')).toBe('CP-Fuchs-Hell')
expect(name('AA cchmch DD efef GG PP spsp rere')).toBe('CP-Orangeschimmel-Hell')
})
it('hom (cchm/cchm) still maps without -Hell suffix', () => {
expect(name('AA cchmcchm DD EE GG PP spsp rere')).toBe('CP-Agouti')
expect(name('AA cchmcchm DD EE gg PP spsp rere')).toBe('CP-Silberagouti')
expect(name('AA cchmcchm DD efef GG PP spsp rere')).toBe('CP-Orangeschimmel')
})
it('aa non-agouti branch is unchanged (Marder/Siam/Zobel/Zobel-Hell)', () => {
expect(name('aa cchmcchm DD EE GG PP spsp rere')).toBe('Marder')
expect(name('aa cchmch DD EE GG PP spsp rere')).toBe('Siam')
expect(name('aa cchmcchm DD EE gg PP spsp rere')).toBe('Zobel')
expect(name('aa cchmch DD EE gg PP spsp rere')).toBe('Zobel-Hell')
})
})

View File

@@ -107,27 +107,29 @@ export const BASE_COLORS: readonly FarbschlagEntry[] = [
{ name: 'Topas dd', tokens: { A: 'A', C: 'C', D: 'd', E: 'E', G: 'G', P: 'p' }, image: 'topas-dd.jpg' },
{ name: 'Blaufuchs dd', tokens: { A: 'a', C: 'C', D: 'd', E: 'e', G: 'g', P: 'p' }, image: 'blaufuchs-dd.jpg' },
// ── GEN-3f: c^chm colourpoint varieties, reconciled to the breeder's CP- naming ──
// The merged GEN-3e colourpointName() rule is authoritative: aa points are the
// marten/sable group (Marder/Siam, +gg Zobel/Zobel-Hell — E and D irrelevant);
// A- points take the 'CP-<base colour>' prefix and the '-Hell' shade variants
// collapse (other loci irrelevant for the CP prefix). These names == the strings
// in her live data (god: extract animals.json) so the re-import name-matches and
// the Farbschlag mismatch hint stops. The het cchm/ch points (Siam, Zobel-Hell,
// CP-Fuchs-Hell) use the 'cchm/ch' pair token. The agouti fox/dilute points
// (CP-Fuchs/CP-Blaufuchs) resolve through the engine's E-family fallback to
// 'CP-Fuchs'; their distinct dropdown names remain for hand-pick + import match.
// ── GEN-3f/3g: c^chm colourpoint varieties ──
// GEN-3f: aa points = marten/sable group (Marder/Siam, +gg Zobel/Zobel-Hell).
// GEN-3g (breeder rule): '-Hell' == cchm/ch het; no '-Hell' == cchm/cchm hom.
// A- points: hom -> 'CP-<base>', het -> 'CP-<base>-Hell' (colourpointName()).
// CP-Fuchs is a Sammelbegriff (unknown loci); its -Hell het = CP-Fuchs-Hell.
// CP-Blaufuchs (D:d, G:g) still resolves engine-side to 'CP-Fuchs' (dd/gg
// fox CP has no dedicated base entry); kept for import name-match + hand-pick.
{ name: 'Marder', tokens: { A: 'a', C: 'cchm', D: 'D', E: 'E', G: 'G', P: 'P' }, image: 'marder.JPG' },
{ name: 'Siam', tokens: { A: 'a', C: 'cchm/ch', D: 'D', E: 'E', G: 'G', P: 'P' }, image: 'siam-marder-hell.JPG' },
{ name: 'Zobel-Hell', tokens: { A: 'a', C: 'cchm/ch', D: 'D', E: 'E', G: 'g', P: 'P' }, image: 'zobel-hell.jpg' },
{ name: 'CP-Agouti', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'E', G: 'G', P: 'P' }, image: 'agouti-cp.jpg' },
{ name: 'CP-Agouti-Hell', tokens: { A: 'A', C: 'cchm/ch', D: 'D', E: 'E', G: 'G', P: 'P' } },
{ name: 'CP-Silberagouti', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'E', G: 'g', P: 'P' }, image: 'silberagouti-cp.JPG' },
{ name: 'CP-Silberagouti-Hell', tokens: { A: 'A', C: 'cchm/ch', D: 'D', E: 'E', G: 'g', P: 'P' } },
{ name: 'CP-Algierfuchs', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'e', G: 'G', P: 'P' }, image: 'algierfuchs-cp.jpg' },
{ name: 'CP-Algierfuchs-Hell', tokens: { A: 'A', C: 'cchm/ch', D: 'D', E: 'e', G: 'G', P: 'P' } },
{ name: 'CP-Polarfuchs', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'e', G: 'g', P: 'P' }, image: 'polarfuchs-cp.jpg' },
{ name: 'CP-Polarfuchs-Hell', tokens: { A: 'A', C: 'cchm/ch', D: 'D', E: 'e', G: 'g', P: 'P' } },
{ name: 'CP-Fuchs', tokens: { A: 'A', C: 'cchm', D: 'd', E: 'e', G: 'G', P: 'P' } },
{ name: 'CP-Fuchs-Hell', tokens: { A: 'A', C: 'cchm/ch', D: 'd', E: 'e', G: 'G', P: 'P' } },
{ name: 'CP-Blaufuchs', tokens: { A: 'A', C: 'cchm', D: 'd', E: 'e', G: 'g', P: 'P' } },
{ name: 'CP-Orangeschimmel', tokens: { C: 'cchm', D: 'D', E: 'ef', G: 'G', P: 'P' } },
{ name: 'CP-Orangeschimmel-Hell', tokens: { C: 'cchm/ch', D: 'D', E: 'ef', G: 'G', P: 'P' } },
]
export const UNKNOWN_FARBSCHLAG = 'Unbekannter Farbschlag'
@@ -207,12 +209,14 @@ function baseColourFor(g: Genotype): string | null {
}
/**
* GEN-3e: the C-locus colourpoint NAMING transform (breeder-authoritative).
* GEN-3e/3g: the C-locus colourpoint NAMING transform (breeder-authoritative).
* Returns the colourpoint name, or null when it doesn't apply (full C present,
* or chch — which the base matcher names Hermelin/Himalaya, preserving both).
* aa cchm/cchm -> Marder | aa cchm/ch -> Siam
* aa cchm/cchm gg -> Zobel | aa cchm/ch gg -> Zobel-Hell
* A- cchm/cchm | cchm/ch -> CP-<base colour> (base computed as if C were full)
* A- cchm/cchm -> CP-<base> | A- cchm/ch -> CP-<base>-Hell
* GEN-3g (breeder rule): "-Hell" in variety name == c[h]-Allel (cchm/ch het);
* no "-Hell" == cchm/cchm hom. CP-Fuchs is a Sammelbegriff (unknown loci).
*/
function colourpointName(g: Genotype): string | null {
const c = resolvedPair(g, 'C')
@@ -227,9 +231,9 @@ function colourpointName(g: Genotype): string | null {
if (grey) return bothCchm ? 'Zobel' : 'Zobel-Hell'
return bothCchm ? 'Marder' : 'Siam'
}
// A- colourpoint -> CP-<base colour>, base as if C were full.
// A- colourpoint: base as if C were full; het (cchm/ch) -> '-Hell' suffix.
const base = baseColourFor(makeGenotype({ ...g, C: ['C', 'C'] }))
return base ? `CP-${base}` : null
return base ? `CP-${base}${bothCchm ? '' : '-Hell'}` : null
}
export function farbschlagFor(g: Genotype): FarbschlagMatch {

View File

@@ -340,42 +340,67 @@
"sortOrder": 53,
"image": "agouti-cp.jpg"
},
{
"name": "CP-Agouti-Hell",
"canonicalGenotype": "AA cchmch DD EE GG PP spsp rere",
"sortOrder": 54
},
{
"name": "CP-Silberagouti",
"canonicalGenotype": "AA cchmcchm DD EE gg PP spsp rere",
"sortOrder": 54,
"sortOrder": 55,
"image": "silberagouti-cp.JPG"
},
{
"name": "CP-Silberagouti-Hell",
"canonicalGenotype": "AA cchmch DD EE gg PP spsp rere",
"sortOrder": 56
},
{
"name": "CP-Algierfuchs",
"canonicalGenotype": "AA cchmcchm DD ee GG PP spsp rere",
"sortOrder": 55,
"sortOrder": 57,
"image": "algierfuchs-cp.jpg"
},
{
"name": "CP-Algierfuchs-Hell",
"canonicalGenotype": "AA cchmch DD ee GG PP spsp rere",
"sortOrder": 58
},
{
"name": "CP-Polarfuchs",
"canonicalGenotype": "AA cchmcchm DD ee gg PP spsp rere",
"sortOrder": 56,
"sortOrder": 59,
"image": "polarfuchs-cp.jpg"
},
{
"name": "CP-Polarfuchs-Hell",
"canonicalGenotype": "AA cchmch DD ee gg PP spsp rere",
"sortOrder": 60
},
{
"name": "CP-Fuchs",
"canonicalGenotype": "AA cchmcchm dd ee GG PP spsp rere",
"sortOrder": 57
"sortOrder": 61
},
{
"name": "CP-Fuchs-Hell",
"canonicalGenotype": "AA cchmch dd ee GG PP spsp rere",
"sortOrder": 58
"sortOrder": 62
},
{
"name": "CP-Blaufuchs",
"canonicalGenotype": "AA cchmcchm dd ee gg PP spsp rere",
"sortOrder": 59
"sortOrder": 63
},
{
"name": "CP-Orangeschimmel",
"canonicalGenotype": "AA cchmcchm DD efef GG PP spsp rere",
"sortOrder": 60
"sortOrder": 64
},
{
"name": "CP-Orangeschimmel-Hell",
"canonicalGenotype": "AA cchmch DD efef GG PP spsp rere",
"sortOrder": 65
}
]

View File

@@ -8,7 +8,7 @@ _Automatisch erzeugt von `tools/import/extract.py` — **noch nichts in die Date
- Nach Zusammenführung (eindeutige Tiere): **621**
- davon mit Geburtsdatum: 326
- in mehreren Dateien gefunden (Dubletten zusammengeführt): 158
- Konflikte zur Klärung: **8**
- Konflikte zur Klärung: **5**
- Mehrdeutige / unvollständige Einträge (ohne Name+Datum): **310**
- Fotos zugeordnet: **137**
- Würfe aus der Wurfchronik: **752**
@@ -25,12 +25,9 @@ Gleiches Tier (Name+Datum), aber widersprüchliche Angaben in verschiedenen Date
| Tier | Geburtsdatum | abweichende Genotypen | abweichende Farbschläge | Sterbedaten | Dateien |
|---|---|---|---|---|---|
| Ella | 10.06.2019 | Aa C D- ee[f] GG P- spsp // Aa Cc[chm] D- ee[f] UwUw P- spsp | Algierfuchsschimmel, hell | 03.02.2023 | Stammbaum von Akio Kids, Stammbaum von CP-Fuchs, CP-Sa Sp von Unity, Stammbaum von Valentino Firehearts Kids |
| Kazu von den Kleinen Chaoten | 23.04.2013 | Aa Cc[chm] DD e[f]e[f] Gg P Spsp // Aa Cc[chm] DD ee[f] UwUw PP Spsp | — | 03.09.2017 | Stammbaum von Akio Kids, Stammbaum von Vance |
| Enya von den Kleinen Chaoten | 01.11.2017 | Aa c[chm]c[chm] D- ee[-] G- P- spsp // Aa c[chm]c[chm] D- ee[-] Uwuw[d] P- spsp | — | — | Stammbaum von Alberto Kids, Stammbaum von Fire Kids, Stammbaum von Kohlief, Goldfuchsef Sp von Chrissi, Stammbaum von Stella Kids |
| Little Runner's Big Ben | 03.02.2020 | Aa Cc[chm] DD Ee Gg PP Spsp // Aa Cc[chm] DD Ee Gg Pp Spsp | — | 14.10.2023 | Stammbaum von CP-Fuchs, CP-Sa Sp von Unity, Stammbaum von Fire Kids, Stammbaum von Goldfuchs Sp (Pikachu) Kids, Stammbaum von Kohlief, Goldfuchsef Sp von Chrissi, Stammbaum von Valentino Firehearts Kids, Stammbaum von Watarus Kids |
| Vance Jr. von den Kleinen Chaoten | 10.04.2022 | aa Cc[hm] Dd Ee gg P- Spsp // aa Cc[hm] Dd Ee gg P- spsp | Kohlfuchs, hell | — | Stammbaum von Fire Kids, Stammbaum von Stella Kids |
| Zac gen. Action von den Kleinen Chaoten | 25.12.2020 | aa C- D- Ee G- Pp Spsp [DP] // aa CC D- Ee G- Pp Spsp [DP] | — | 31.01.2025 | Stammbaum von Goldfuchs Sp (Pikachu) Kids, Stammbaum von Kohlief, Goldfuchsef Sp von Chrissi, Stammbaum von Watarus Kids |
| Hanami von den Kleinen Chaoten | 10.09.2015 | aa Cc[chm] D- Ee gg P- spsp | — | 12.12.2019 // 14.01.2020 | Stammbaum von Kentucky, Stammbaum von Stella Kids |
| Skarlett v.d. Kleinen Chaoten | 14.07.2013 | / +2018, Aa Cc[chm] DD ee uw[d]uw[d] PP spsp // Aa Cc[chm] DD ee uw[d]uw[d] PP spsp | — | 17.04.2016 // 2018 | Stammbaum von Vance |
@@ -129,7 +126,7 @@ Diese Tokens stehen weiter in `rawGenotype`/`unmappedTokens` — Entscheidung (M
| Token | Vorkommen | Bedeutung (Vermutung) |
|---|---|---|
| `/+` | 7 | ? |
| `/+` | 6 | ? |
| `-g` | 2 | ? |
| `C(C)` | 2 | Schreibweise (C trägt c) |
| `Cc[]` | 1 | ? |