From 288bbf278ad497fd767657258dddea0d6f6fc14a Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Mon, 28 Sep 2026 16:04:08 +0000 Subject: [PATCH] Assert that no ring value makes a group vanish The bounded half already asserts that its total is conserved; the centered half did not. It pins the three states as separate, and separateness is not completeness: a group with a ring nobody anticipated could fall out of placed, centre and unplaced alike and simply not exist on the page. That is the failure that looks like a smaller dataset rather than an error. An empty chart gets noticed; a chart quietly missing eleven groups does not, and eleven is exactly how many carry ring -1 today. Checked with the awkward values rather than the tidy ones: out of range high and low, missing, fractional, and a numeric string. All seven are accounted for, the out-of-range pair land in unplaced rather than being clamped to ring 1 or 10, and a fractional ring is unplaced rather than rounded onto a neighbour it does not belong to. Falsified before trusting it: a filter that silently drops non-integer rings turns the arm red at 5 of 7. The negative control also pins that the count moves with the input, so it is not counting a constant. --- internal/check-gospel-set-charts.mjs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/internal/check-gospel-set-charts.mjs b/internal/check-gospel-set-charts.mjs index 6aba38f68..e9e8bd8fa 100644 --- a/internal/check-gospel-set-charts.mjs +++ b/internal/check-gospel-set-charts.mjs @@ -139,6 +139,31 @@ ok('centered: a placed group with no recorded neighbour yields NO arrow', noNb.placed.length === 1 && inwardArrow(noNb.placed[0], {}) === null) + +// ★ CENTERED CONSERVATION, which the bounded half already asserts and this half did not. +// The three states are pinned as SEPARATE above, but separateness is not completeness: a group with +// a ring nobody anticipated could fall out of all three and simply not exist on the page. That is +// the failure that looks like a smaller dataset rather than an error — an empty chart gets noticed, +// a chart quietly missing eleven groups does not. Checked with the awkward values on purpose: +// out-of-range high and low, missing, fractional, and a numeric STRING. +const odd = [ + { id: 'hi', ring: 99 }, { id: 'lo', ring: -5 }, { id: 'centre', ring: 0 }, + { id: 'norel', ring: -1 }, { id: 'none' }, { id: 'str', ring: '3' }, { id: 'frac', ring: 3.5 }, +] +const oddL = layoutCenteredSet(odd, {}) +const accounted = oddL.placed.length + oddL.centre.length + oddL.unplaced.length +ok('centered: total is conserved — no ring value makes a group vanish', + accounted === odd.length, `${accounted} of ${odd.length}`) +ok('centered: an out-of-range ring is UNPLACED, never clamped into ring 1 or 10', + oddL.unplaced.some((p) => p.id === 'hi') && oddL.unplaced.some((p) => p.id === 'lo') && + !oddL.placed.some((p) => p.id === 'hi' || p.id === 'lo')) +ok('centered: a fractional ring is unplaced rather than rounded onto a neighbour', + oddL.unplaced.some((p) => p.id === 'frac')) +// NEG CONTROL: the conservation arm can fail, so it is not counting a constant. +ok('NEG CONTROL: dropping one group from the input drops the accounted total', + (() => { const l = layoutCenteredSet(odd.slice(1), {}); return l.placed.length + l.centre.length + l.unplaced.length === odd.length - 1 })()) + + if (fail.length) { console.log(`\nGOSPEL-SET-CHARTS: FAIL — ${fail.length}: ${fail.join(', ')}`) process.exit(1)