fix: COI direct-ancestor bug — correct Wright algorithm + frontend relation guard #45

Merged
jason merged 2 commits from fix/pairing-coi-and-direct-relation-guard into master 2026-03-10 14:57:16 -05:00
Owner

Problem

Direct parent × offspring pairings (e.g. River as sire of the selected dam) showed 0.00% COI because getAncestors() started traversal at generation 1 — the dog itself was never included in its own ancestor map, so it could never appear as a common ancestor.


Backend Fix — server/routes/pedigree.js

Root cause (old code)

// OLD — starts at parents (gen 1+). Dog itself never in map.
function getAncestors(dogId) {
  const parents = db.prepare('SELECT parent_id FROM parents WHERE dog_id = ?').all(dogId);
  parents.forEach(p => recurse(p.parent_id, 1));
}

Fix (new code)

// NEW — include self at gen 0, then recurse into parents
function getAncestorMap(db, dogId, maxGen = 6) {
  recurse(parseInt(dogId), 0); // dogId itself at generation 0
}

Wright formula

COI contribution per path = (0.5)^(sireGen + damGen + 1)

Example — River (sire) × dog2 (River's offspring):
  sireMap: River @ gen 0
  damMap:  River @ gen 1 (direct parent)
  => (0.5)^(0+1+1) = 0.25 => 25% COI ✅

Additional backend improvements

  • All path combinations through a common ancestor are summed (correct linebreeding)
  • processedPaths Set prevents double-counting
  • Generation depth: 5 → 6
  • New endpoint: GET /api/pedigree/relations/:sireId/:damId — returns { related, relationship } for use by frontend
  • directRelation field included in /trial-pairing response

Frontend Fix — client/src/pages/PairingSimulator.jsx

  • On every sire/dam selection change, calls the new /api/pedigree/relations endpoint
  • Displays a yellow warning banner before simulate if a direct relation is detected: "Direct Relation Detected — Sire is the parent of the selected dam"
  • Simulate button stays enabled so COI can still be calculated and displayed
  • Result panel shows a red alert confirming the direct relation alongside the correct COI value
  • Generation note updated: "within 5 generations" → "within 6 generations"

Closes

Supersedes PR #44 — this branch includes all fixes from that PR plus the frontend guard.

## Problem Direct parent × offspring pairings (e.g. River as sire of the selected dam) showed **0.00% COI** because `getAncestors()` started traversal at generation 1 — the dog itself was never included in its own ancestor map, so it could never appear as a common ancestor. --- ## Backend Fix — `server/routes/pedigree.js` ### Root cause (old code) ```js // OLD — starts at parents (gen 1+). Dog itself never in map. function getAncestors(dogId) { const parents = db.prepare('SELECT parent_id FROM parents WHERE dog_id = ?').all(dogId); parents.forEach(p => recurse(p.parent_id, 1)); } ``` ### Fix (new code) ```js // NEW — include self at gen 0, then recurse into parents function getAncestorMap(db, dogId, maxGen = 6) { recurse(parseInt(dogId), 0); // dogId itself at generation 0 } ``` ### Wright formula ``` COI contribution per path = (0.5)^(sireGen + damGen + 1) Example — River (sire) × dog2 (River's offspring): sireMap: River @ gen 0 damMap: River @ gen 1 (direct parent) => (0.5)^(0+1+1) = 0.25 => 25% COI ✅ ``` ### Additional backend improvements - All path combinations through a common ancestor are summed (correct linebreeding) - `processedPaths` Set prevents double-counting - Generation depth: 5 → 6 - New endpoint: `GET /api/pedigree/relations/:sireId/:damId` — returns `{ related, relationship }` for use by frontend - `directRelation` field included in `/trial-pairing` response --- ## Frontend Fix — `client/src/pages/PairingSimulator.jsx` - On every sire/dam selection change, calls the new `/api/pedigree/relations` endpoint - Displays a **yellow warning banner** before simulate if a direct relation is detected: _"Direct Relation Detected — Sire is the parent of the selected dam"_ - Simulate button stays enabled so COI can still be calculated and displayed - Result panel shows a **red alert** confirming the direct relation alongside the correct COI value - Generation note updated: "within 5 generations" → "within 6 generations" --- ## Closes Supersedes PR #44 — this branch includes all fixes from that PR plus the frontend guard.
jason added 2 commits 2026-03-10 14:56:37 -05:00
jason merged commit 6431164d3b into master 2026-03-10 14:57:16 -05:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jason/breedr#45