fix(import): Stammbaum-/Eltern-/isResident-Tickets der Züchterin (18)
Import-Logik: - Externe Gründer (Zooladen/„von Privat"/„from …, <Land>") bekommen keine erfundenen Chart-Eltern mehr → Bill, Cooky, Zadar haben korrekt unbekannte Eltern (is_external_origin). [#5,#13,#28] - Hagrid: externe Zucht wird nicht mehr als Bestand markiert (isResident=false) + Leerhüllen-Dedup → ein Datensatz mit Eltern Snickers × Milka. [#17,#18,#20a] - Gender-Index: eindeutiges Geschlecht schlägt unbekanntes Duplikat → Rollen- Auflösung repariert (Vance→Mutter Enya, Zac→Vater Vance/Mutter Dorie). [#33,#35] - „Eltern: X + Y"-Wurfnotizen werden geparst (~46 Würfe); v.d.↔von-den-Namens- kanon (Theodore→BlackFire). [#9,#11,#30] Daten-Overrides (conflict-decisions.json, jetzt auch Gender + exakte Eltern): - Mozart→weiblich [#2], Yuki=Camaro×Izumi [#23], Gold-Mutter=Chelsea [#36], Arya=Vance×Sansa (Geschwisterverpaarung) [#16], Tony→Sammy [#12], Odelia [#15], Jamie→Danny [#31], Silver=Taro×Beatrice [#11]. Frontend: GerbilDetailPage blendet für isResident=false Würfe + Charakter aus (Hinweis nonResidentNote). [#17,#20b] Tests: test_extract/test_merge_resolve erweitert; vitest 135, playwright tiere 34 grün. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -417,6 +417,54 @@ if os.path.exists(kazuya_path):
|
||||
else:
|
||||
print("\nWarning: Kazuya stammbaum file not found, skipping photo-shift checks.")
|
||||
|
||||
# --- External-origin founders get NO fabricated chart-position parents -------
|
||||
# Tickets #5 (Bill von Privat), #13 (Cooky vom Zooladen), #28 (Zadar from … Croatia):
|
||||
# pet-shop / private / foreign-import animals have genuinely unknown ancestry, so
|
||||
# _reconstruct_parents must not invent parents for them from neighbouring blocks.
|
||||
check("is_external_origin: 'von Privat' name", e.is_external_origin("Bill von Privat"))
|
||||
check("is_external_origin: 'vom Zooladen (OBI)' name",
|
||||
e.is_external_origin("Cooky vom Zooladen (OBI)"))
|
||||
check("is_external_origin: foreign 'from …, Croatia'",
|
||||
e.is_external_origin("Zadar from Zeko i ptica, Croatia"))
|
||||
check("is_external_origin: clan animal is NOT external",
|
||||
not e.is_external_origin("Silver von den kleinen Chaoten", "Kleine Chaoten"))
|
||||
check("is_external_origin: ordinary cattery 'of Black Forest' is NOT external",
|
||||
not e.is_external_origin("Hagrid Rubeus of Black Forest", "Black Forest"))
|
||||
|
||||
# _reconstruct_parents must skip the external leaf but still parent the clan child.
|
||||
_ext_animals = [
|
||||
{"name": "Kind von den Kleinen Chaoten", "_gen": 0, "_row": 5, "dob": "01.01.2020",
|
||||
"zucht": "Kleine Chaoten", "breeder": "", "gender": None, "parentRefs": []},
|
||||
{"name": "Cooky vom Zooladen (OBI)", "_gen": 1, "_row": 4, "dob": "01.01.2018",
|
||||
"zucht": "", "breeder": "", "gender": "female", "parentRefs": []},
|
||||
{"name": "Papa von den Kleinen Chaoten", "_gen": 1, "_row": 6, "dob": "01.01.2017",
|
||||
"zucht": "Kleine Chaoten", "breeder": "", "gender": "male", "parentRefs": []},
|
||||
{"name": "OmaUnbekannt", "_gen": 2, "_row": 3, "dob": "", "zucht": "", "breeder": "",
|
||||
"gender": None, "parentRefs": []},
|
||||
]
|
||||
e._reconstruct_parents(_ext_animals)
|
||||
_cooky = next(a for a in _ext_animals if a["name"].startswith("Cooky"))
|
||||
check("_reconstruct_parents: external Cooky gets NO parentRefs",
|
||||
_cooky["parentRefs"] == [])
|
||||
_kind = next(a for a in _ext_animals if a["name"].startswith("Kind"))
|
||||
check("_reconstruct_parents: clan child still gets its chart-position parents",
|
||||
len(_kind["parentRefs"]) >= 1)
|
||||
|
||||
# --- gender override (conflict-decisions) — Mozart misread male, should be female ---
|
||||
_g_merged = [{"id": "moz", "name": "Mozart of Lennylengo", "dob": "12.03.2017",
|
||||
"gender": "male", "genotype": e.gt.parse(""), "parentRefs": [],
|
||||
"conflict": False}]
|
||||
_g_dec = os.path.join(tempfile.gettempdir(), "conflict-gender-test.json")
|
||||
import json as _json
|
||||
_json.dump({"resolutions": [
|
||||
{"name": "Mozart of Lennylengo", "dob": "12.03.2017", "gender": "female",
|
||||
"decision": "box colour misread"}
|
||||
]}, open(_g_dec, "w", encoding="utf-8"))
|
||||
e.apply_conflict_decisions(_g_merged, [], _g_dec)
|
||||
check("gender override: Mozart flipped male -> female", _g_merged[0]["gender"] == "female")
|
||||
try: os.remove(_g_dec)
|
||||
except OSError: pass
|
||||
|
||||
if failed:
|
||||
print(f"\n{failed} test(s) FAILED")
|
||||
sys.exit(1)
|
||||
|
||||
Reference in New Issue
Block a user