Importer consumes conflict-decisions.json to un-quarantine (HUMANQUESTION D)
god maintains tools/import/conflict-decisions.json as Julian/his wife answer the D-conflicts. extract.py now consumes it (apply_conflict_decisions): for an animal matching normalize(name)+dob, it clears the conflict, marks resolvedByDecision, and — when the decision carries a `genotype` (breeder notation, parsed via genotype.py) and/or `farbschlag` — treats those as AUTHORITATIVE. Tolerates a missing/empty/garbled file. Genuinely-unresolved conflicts stay quarantined. Loader (ImportService): SourceAnimal.ResolvedByDecision flows through; the report surfaces Animals.ConflictsResolvedByDecision + a German note. Result on real data: the 2 current decisions (Firefly D-/PP, WildFire PP) un-quarantine → Konflikte 21 → 19. As god appends entries the count grows; nothing else needed from me. Tests: python test_extract (decision clears conflict + genotype authoritative + removes from conflicts list + tolerates missing file) and a C# loader test (a resolved animal loads and is counted). Folded into the EXTRACT-BANDS branch so the next re-extract applies band-aware Farbschlag + these decisions in one pass. No schema change (JSON DTO fields). python + dotnet 121/121 green; has-pending clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -71,6 +71,29 @@ gen = e.gen_of
|
||||
check("gen_of: early bands < 2 (E,H)", gen(5) < 2 and gen(8) < 2)
|
||||
check("gen_of: deep bands >= 2 (K,N,Q)", gen(11) >= 2 and gen(14) >= 2)
|
||||
|
||||
# --- conflict-decisions consumption (HUMANQUESTION D / C6) ---
|
||||
dec_path = os.path.join(tempfile.gettempdir(), "conflict-decisions-test.json")
|
||||
import json as _json
|
||||
_json.dump({"resolutions": [
|
||||
{"name": "Firefly von den Kleinen Chaoten", "dob": "18.12.2019",
|
||||
"decision": "D-locus = D-", "genotype": "Aa c[chm]c[chm] D- Ee Gg PP Spsp",
|
||||
"source": "test"},
|
||||
]}, open(dec_path, "w", encoding="utf-8"))
|
||||
merged = [{"id": "x1", "name": "Firefly von den Kleinen Chaoten", "dob": "18.12.2019",
|
||||
"conflict": True, "farbschlag": "",
|
||||
"genotype": {"mapped8locus": {"D": ["D", "D"]}, "rawGenotype": "DD", "unmappedTokens": []}}]
|
||||
conflicts = [{"id": "x1", "name": "Firefly von den Kleinen Chaoten", "dob": "18.12.2019"}]
|
||||
n = e.apply_conflict_decisions(merged, conflicts, dec_path)
|
||||
check("decision un-quarantines (conflict cleared)", merged[0]["conflict"] is False)
|
||||
check("decision marks resolvedByDecision", merged[0].get("resolvedByDecision") is True)
|
||||
check("decision genotype is authoritative (D- not DD)", merged[0]["genotype"]["mapped8locus"]["D"] == ["D", "?"])
|
||||
check("decision removes entry from conflicts list", conflicts == [])
|
||||
check("apply_conflict_decisions returns resolved count", n == 1)
|
||||
check("missing decisions file tolerated (returns 0)",
|
||||
e.apply_conflict_decisions([], [], os.path.join(tempfile.gettempdir(), "does-not-exist.json")) == 0)
|
||||
try: os.remove(dec_path)
|
||||
except OSError: pass
|
||||
|
||||
# --- name-bleed guard (a parent name is not a Farbschlag) ---
|
||||
check("v.d. name rejected", e.looks_like_animal_name("Tennessee von den Kleinen Chaoten"))
|
||||
check("gen.+v.d. name rejected", e.looks_like_animal_name("Victoria Welby gen. Welby v.d. Kleinen Chaoten"))
|
||||
|
||||
Reference in New Issue
Block a user