GEN-4 REW erweitert: alle 3 C-Kombi + pp = REW (Julian bestätigt)

- cReduced(c) = cchm || ch; REW wenn cReduced(c0) && cReduced(c1) && pp
  (cchm/cchm, cchm/ch, ch/ch alle REW; mind. ein volles C = NICHT REW)
- Counterproof-Test: C/cchm + pp und C/ch + pp = nicht REW
- Frozen-Round-Trip-Test: PEW (ch/ch+pp) explizit ausgenommen (intentional
  shadow durch REW-Check per Julian-Regel; PEW bleibt Dropdown-Name)
Gate: build ✓  eslint ✓  vitest 95/95 ✓  e2e 148/148 ✓
This commit is contained in:
2026-06-06 21:32:20 +02:00
parent b12b5d720d
commit 5c327cd8d8
2 changed files with 24 additions and 8 deletions

View File

@@ -187,7 +187,13 @@ describe('Farbschlag catalog', () => {
it('frozen contract names round-trip to themselves (DB-key guard)', () => { it('frozen contract names round-trip to themselves (DB-key guard)', () => {
// The first 18 are the frozen ColorVariety keys — their representative // The first 18 are the frozen ColorVariety keys — their representative
// genotype MUST resolve back to their own name, never a later variety. // genotype MUST resolve back to their own name, never a later variety.
// GEN-4 exception: 'Pink Eyed White (PEW)' (ch/ch+pp) now computes 'REW'
// because the REW engine check (both C-alleles reduced + pp) fires first.
// PEW stays in the catalog as a user-pickable import name; its computed
// farbschlag is intentionally 'REW' per Julian's extended rule.
const REW_SHADOWED = new Set(['Pink Eyed White (PEW)'])
for (const entry of BASE_COLORS.slice(0, FROZEN_COUNT)) { for (const entry of BASE_COLORS.slice(0, FROZEN_COUNT)) {
if (REW_SHADOWED.has(entry.name)) continue
expect(genotypeToFarbschlag(representativeGenotype(entry))).toBe(entry.name) expect(genotypeToFarbschlag(representativeGenotype(entry))).toBe(entry.name)
} }
}) })
@@ -538,14 +544,21 @@ describe('GEN-4: Dilute prefix, REW, no-bare-Fuchs', () => {
expect(name('aa CC dd EE GG pp spsp rere')).toBe('Dilute Platin') expect(name('aa CC dd EE GG pp spsp rere')).toBe('Dilute Platin')
}) })
it('REW: cchm/cchm + pp = REW regardless of A/D/E/G', () => { it('REW: both C alleles reduced (no full C) + pp = REW — all three cases (Julian confirmed)', () => {
// hom cchm/cchm + pp
expect(name('AA cchmcchm DD EE GG pp spsp rere')).toBe('REW') // CP-Gold expect(name('AA cchmcchm DD EE GG pp spsp rere')).toBe('REW') // CP-Gold
expect(name('AA cchmcchm DD ee GG pp spsp rere')).toBe('REW') // CP-Goldfuchs expect(name('AA cchmcchm DD ee GG pp spsp rere')).toBe('REW') // CP-Goldfuchs
expect(name('AA cchmcchm DD EE gg pp spsp rere')).toBe('REW') // CP-Elfenbein expect(name('AA cchmcchm DD EE gg pp spsp rere')).toBe('REW') // CP-Elfenbein
expect(name('AA cchmcchm DD ee gg pp spsp rere')).toBe('REW') // CP-Apricot expect(name('AA cchmcchm DD ee gg pp spsp rere')).toBe('REW') // CP-Apricot
expect(name('AA cchmcchm dd EE GG pp spsp rere')).toBe('REW') // CP-dd Gold expect(name('AA cchmcchm dd EE GG pp spsp rere')).toBe('REW') // CP-dd Gold
// cchm/ch (het) + pp is NOT REW (only homozygous cchm/cchm qualifies) // het cchm/ch + pp (Julian: also REW)
expect(name('AA cchmch DD EE GG pp spsp rere')).not.toBe('REW') expect(name('AA cchmch DD EE GG pp spsp rere')).toBe('REW')
// ch/ch + pp (Julian: also REW — subsumes PEW)
expect(name('AA chch DD EE GG pp spsp rere')).toBe('REW')
expect(name('aa chch DD EE GG pp spsp rere')).toBe('REW')
// Counterproof: full C present → NOT REW (residual pigment)
expect(name('AA Ccchm DD EE GG pp spsp rere')).not.toBe('REW') // Cc[chm] + pp = Gold-like
expect(name('AA Cch DD EE GG pp spsp rere')).not.toBe('REW') // Cc[h] + pp
}) })
it('bare Fuchs never appears — dilute-fox combinations are named specifically', () => { it('bare Fuchs never appears — dilute-fox combinations are named specifically', () => {

View File

@@ -253,13 +253,16 @@ export function farbschlagFor(g: Genotype): FarbschlagMatch {
if (locusToken(g, 'Sp') === 'Sp') modifiers.push('Schecke') if (locusToken(g, 'Sp') === 'Sp') modifiers.push('Schecke')
if (locusToken(g, 'Re') === 'Re') modifiers.push('Rex') if (locusToken(g, 'Re') === 'Re') modifiers.push('Rex')
// GEN-4 REW check: homozygous colourpoint (cchm/cchm) + pink-eyed (pp) = REW. // GEN-4 REW check (Julian confirmed + extended): both C alleles reduced (no full 'C')
// This combination removes both fur pigment (C locus) and eye pigment (P locus) // AND pink-eyed (pp) = REW (Rotaugenweiß), A/D/E/G-independent.
// regardless of A/D/E/G. Examples: CP-Gold, CP-Goldfuchs, CP-Elfenbein, CP-Apricot. // cchm/cchm + pp → REW (CP varieties with pink-eye)
// Flagged to god for confirmation (condition: cchm×cchm + p×p). // cchm/ch + pp → REW (het colourpoint + pink-eye)
// ch/ch + pp → REW (this also subsumes the frozen 'Pink Eyed White (PEW)' entry)
// Counterproof: at least one full 'C' + pp → NOT REW (residual pigment remains).
const [c0, c1] = resolvedPair(g, 'C') const [c0, c1] = resolvedPair(g, 'C')
const [p0, p1] = resolvedPair(g, 'P') const [p0, p1] = resolvedPair(g, 'P')
if (c0 === 'cchm' && c1 === 'cchm' && p0 === 'p' && p1 === 'p') { const cReduced = (c: string) => c === 'cchm' || c === 'ch'
if (cReduced(c0) && cReduced(c1) && p0 === 'p' && p1 === 'p') {
const name = ['REW', ...modifiers].join(' ') const name = ['REW', ...modifiers].join(' ')
return { name, base: null, unknown: false } return { name, base: null, unknown: false }
} }