test(stammbaum): per-bloodline span regression replaces total-width (#724)

Total canvas width is the wrong metric: centring every ancestor makes a 24-root
forest wider overall (an accepted trade-off, pan/zoom handles navigation). The
actual fix is per-bloodline compactness. Assert every contiguous bloodline's
span stays far under the old full-canvas smear (4860px) — today the widest,
Albert de Gruyter's, is ~960px, down from being smeared across the whole canvas.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-04 13:51:03 +02:00
parent 0efe3a4ef6
commit e2ad1f2cf0

View File

@@ -581,4 +581,36 @@ describe('buildLayout — ancestor centring invariant (#724)', () => {
expect(intrudes, `foreign node ${id} interleaved into the R1 band`).toBe(false);
}
});
it('no bloodline is smeared across the canvas (per-bloodline span regression)', () => {
// Golden constant: measured 2026-06-04, the OLD per-generation block
// packer laid the canonical fixture out 4860px wide and smeared a single
// bloodline (Albert de Gruyter G0 … a far-right descendant) across that
// whole span — the bug. Total canvas width is NOT the right metric for the
// fix (centring every ancestor makes a 24-root forest wider overall, and
// pan/zoom from #692 handles navigation); per-bloodline compactness is.
// Each contiguous bloodline must occupy far less than the old full-canvas
// smear. Today the widest is Albert's at ~960px.
const OLD_FULL_CANVAS = 4860;
const layout = buildLayout(fixtureNodes, fixtureEdges);
const forest = buildFamilyForest(fixtureNodes, fixtureEdges);
const bloodlineSpan = (root: Unit): number => {
const ids: string[] = [];
const collect = (u: Unit) => {
ids.push(...u.members);
u.children.forEach(collect);
};
collect(root);
const xs = ids.map((id) => layout.positions.get(id)!.x);
return Math.max(...xs) + NODE_W - Math.min(...xs);
};
const spans = forest.roots.map(bloodlineSpan);
const widest = Math.max(...spans);
// Every bloodline is dramatically more compact than the old smear …
expect(widest).toBeLessThan(OLD_FULL_CANVAS);
// … and in fact comfortably under a quarter of it (no smear creeps back).
expect(widest).toBeLessThanOrEqual(OLD_FULL_CANVAS / 4);
});
});