From 89bb0b5d65e12d0813826404392006f3f1488306 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 28 May 2026 20:55:23 +0200 Subject: [PATCH] test(stammbaum): assert no node sits between AC2 spouses on same y (#361) Cycle-2 follow-up from Sara. The existing assertion `Math.abs(posA2.x - posB2.x) === NODE_W + COL_GAP` proves adjacency in the current integer-slot packer but would silently pass if a future refactor moved to fractional offsets with a third node squatting at a non-slot x between the spouses. The added loop closes that contract. Co-Authored-By: Claude Opus 4.7 --- .../lib/person/genealogy/layout/buildLayout.test.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/frontend/src/lib/person/genealogy/layout/buildLayout.test.ts b/frontend/src/lib/person/genealogy/layout/buildLayout.test.ts index 8c0c2d4c..4920884b 100644 --- a/frontend/src/lib/person/genealogy/layout/buildLayout.test.ts +++ b/frontend/src/lib/person/genealogy/layout/buildLayout.test.ts @@ -266,6 +266,19 @@ describe('buildLayout — multi-spouse ordering (#361)', () => { const posB2 = layout.positions.get(B2)!; expect(posA2.y).toBe(posB2.y); expect(Math.abs(posA2.x - posB2.x)).toBe(NODE_W + COL_GAP); + + // Tighter contract (Sara's cycle-2 follow-up): no third node may sit + // at an x strictly between the two spouses on the same y. The integer- + // slot adjacency check above (==NODE_W+COL_GAP) is correct today but + // would silently pass if a future layout change introduced fractional + // offsets and placed a node at a non-slot x between the spouses. + const minX = Math.min(posA2.x, posB2.x); + const maxX = Math.max(posA2.x, posB2.x); + for (const [id, p] of layout.positions) { + if (id === A2 || id === B2) continue; + if (p.y !== posA2.y) continue; + expect(p.x <= minX || p.x >= maxX).toBe(true); + } }); it('canonical_fixture_multi_spouse_falls_through_to_displayName_when_no_fromYear', () => {