#!/usr/bin/env node /** * check-list-selection — what the vertical legend emits, and the zones a region tree forgets. Headless. * * ★ WHY THIS IS IN internal/ AND NOT internal-tracker/. It began as a internal-tracker probe, which is GITIGNORED * in this repo (.gitignore:113) — so it ran green on my disk and would NOT have landed with the * component. studio caught that while staging: "the 13 assertions are not in either commit". I had * reported them as evidence for code that was about to ship untested, which is the same failure this * whole file guards against — a green result measured somewhere other than where it matters. * A probe proves something once. A registered check keeps proving it. */ // What the vertical legend emits, and the zones a region tree forgets. // // The second half is the one that matters most: four joinable UPG-100 zones are absent from // zone-regions.json today, one of them the consumer's largest at 100 groups. A region-grouped tree // drops them with no error and no empty state — just a shorter tree — so this asserts they survive. import { readFileSync } from 'node:fs' import { fileURLToPath } from 'node:url' import { dirname, join } from 'node:path' import { leavesOf, zoneIdsIn, withUnassigned, selectedId, UNASSIGNED_ID } from '../library/components/legends/listSelection.js' const DATA = join(dirname(fileURLToPath(import.meta.url)), '..', 'plugin-designs', 'my-upg-100-list', 'data') const readJson = (f) => JSON.parse(readFileSync(join(DATA, f), 'utf8')) let fails = 0 const ok = (c, m) => { console.log(` ${c ? 'ok ' : 'FAIL'} - ${m}`); if (!c) fails++ } const TREE = [{ id: 'asia', label: 'Asia', depth: 0, children: [ { id: 'z1', label: 'Zone 1', zoneKey: 'Z1' }, { id: 'sub', label: 'Sub', depth: 1, children: [{ id: 'z2' }, { id: 'z3' }] }, ], }] // The real gap, named as it appears in the data. const MISSING = [ 'asia-china-guizhou-province', 'asia-china-xinjiang-uyghur-autonomous-region', 'asia-india-bihar', 'asia-india-madhya-pradesh', ] ok(leavesOf(TREE[0]).map((l) => l.id).join(',') === 'z1,z2,z3', 'leavesOf walks NESTED children, not one level') ok([...zoneIdsIn(TREE)].sort().join(',') === 'z1,z2,z3', 'zoneIdsIn collects every leaf id in the tree') // ── the emit contract ─────────────────────────────────────────────────────────────────────────── ok(selectedId({ id: 'z1' }) === 'z1', 'a LEAF emits its zone id') ok(selectedId({ id: 'asia' }) === 'asia', 'a REGION row emits the region id — the consumer expands it, where the join lives') ok(selectedId(null) === null, 'and a CLEARED selection emits null, so a filter can be dropped') ok(typeof selectedId({ id: 'z1' }) === 'string', 'the value is a STRING, so it survives ?zone=, profile-config and a deep link') // ── never drop a zone ─────────────────────────────────────────────────────────────────────────── const all = ['z1', 'z2', 'z3', ...MISSING] const withBucket = withUnassigned(TREE, all, 'Unassigned') ok(withBucket.length === TREE.length + 1, 'zones absent from the tree get an explicit bucket') const bucket = withBucket[withBucket.length - 1] ok(bucket.id === UNASSIGNED_ID && bucket.children.length === 4, 'and all four missing zones are in it') ok(bucket.children.map((c) => c.id).includes('asia-china-xinjiang-uyghur-autonomous-region'), 'including xinjiang — the consumer\'s largest zone at 100 groups, which a region tree loses silently') ok(bucket.children.every((c) => c.id && c.zoneKey), 'each is a SELECTABLE leaf, not a lump — a reader wants xinjiang, not "the four nobody filed"') ok(withUnassigned(TREE, ['z1', 'z2', 'z3']).length === TREE.length, 'CONTROL: no bucket appears when nothing is missing') ok(withUnassigned(TREE, null).length === TREE.length && withUnassigned(TREE, []).length === TREE.length, 'CONTROL: omitting the zone set leaves the tree untouched, so this is additive') // NEG CONTROL: the drop this exists to prevent must be detectable. const naive = TREE // what a region-grouped tree gives you, unaugmented ok(!zoneIdsIn(naive).has('asia-china-xinjiang-uyghur-autonomous-region'), 'NEG CONTROL: the unaugmented tree really does omit xinjiang, so the bucket is not decoration') // ── a region sweep is NOT a zone sweep (gospel, END-GOS-VLG2) ─────────────────────────────────── // ★ The consequence of the bucket that neither of us should leave implicit: ticking every REGION // still does not select every ZONE, because the four unfiled zones have no region BY DEFINITION. // Nothing on screen would say so — the reader just gets a smaller total, which is the exact // silent-wrong-answer shape the bucket exists to end. So if a "select all" is ever added it must // sweep ZONES, not regions, or it inherits the bug. Pinned here so the wrong one cannot ship // quietly; gospel pins the mirror of it on the expansion side. const regionRows = withBucket.filter((n) => n.id !== UNASSIGNED_ID) const byRegionSweep = zoneIdsIn(regionRows) ok(byRegionSweep.size < all.length, 'selecting every REGION reaches fewer zones than exist — a region sweep is not a zone sweep') ok(!byRegionSweep.has('asia-china-xinjiang-uyghur-autonomous-region'), 'and the 100 groups it misses are xinjiang\'s, so a "select all" over regions must be over zones') ok(zoneIdsIn(withBucket).size === all.length, 'sweeping the WHOLE tree, bucket included, does reach all of them — what the bucket buys') // ── a zone with no members stays SELECTABLE (gospel: 16 of 33 resolve today) ──────────────────── // Of the 33 zones, members resolve for 16; 5 await a wagf field and 9 have no selector anywhere. // Those zones must render as EMPTY, not vanish — same reason as the bucket. A tree that hides what // it cannot resolve tells the reader the zone does not exist, when the truth is that we cannot // currently join it. Nothing here filters on member count, and this fails if anything starts to. const EMPTYZONE = [{ id: 'asia', label: 'Asia', depth: 0, children: [{ id: 'z9', label: 'Zone 9', zoneKey: 'Z9', members: [] }] }] ok(leavesOf(EMPTYZONE[0]).map((l) => l.id).join(',') === 'z9', 'a zero-member zone is still a LEAF, so a reader can select it and see an empty result') ok(selectedId(leavesOf(EMPTYZONE[0])[0]) === 'z9', 'and it still emits its own id') ok(withUnassigned(EMPTYZONE, ['z9']).length === EMPTYZONE.length, 'presence is by ID, not by member count, so an unresolvable zone is not ALSO dumped in the bucket') // ── the gap is REAL TODAY, not just real in my fixture (gospel, END-GOS-VLG3) ─────────────────── // ★ EVERY ASSERTION ABOVE RUNS AGAINST A FIXTURE. That proves the MODULE behaves, and it proves the // fixture models a gap — it does not prove the gap still exists in the data we ship. So the negative // control above could stay green forever while the bucket quietly became dead code, or while a FIFTH // zone went missing and nobody heard. That is the same failure in a new costume: evidence that lives // somewhere other than where the thing it describes lives. gospel named it — find out where your // evidence lives — after catching the identical shape in their own work. // // This does NOT resolve the three disagreeing lists (33 in zone-regions, 12 reachable via // admin-to-list, 14 in groupings, disagreeing in BOTH directions). That is a data-ownership ruling // for upg100 and the agent, and picking a winner here would be exactly the silent join we have both // refused. It only compares the region tree's own source against the joinable set and RECORDS the // difference, so the disagreement cannot drift without someone being told. const regionOf = readJson('zone-regions.json') // the region tree's source: zone id -> region const adminToList = readJson('admin-to-list.json') // admin name -> zone id; its VALUES are joinable const filed = new Set(Object.keys(regionOf)) const joinable = new Set(Object.values(adminToList).map(String)) const realGap = [...joinable].filter((id) => !filed.has(id)).sort() ok(realGap.length > 0, realGap.length > 0 ? `the region tree really does omit ${realGap.length} joinable zone(s) TODAY — the bucket is load-bearing in the shipped data, not only in the fixture` : 'INERT ARM: every joinable zone is now filed under a region, so this check no longer measures anything. That is not a pass. Re-derive the bucket against the current data or DELETE it and its component — do not leave a green arm guarding nothing.') ok(realGap.join(',') === MISSING.join(','), realGap.join(',') === MISSING.join(',') ? 'and it is exactly the four this check names, so the fixture above models the shipped data rather than a story about it' : `THE GAP MOVED — re-derive. shipped now: [${realGap.join(', ')}] but this check asserts: [${MISSING.join(', ')}]. A zone ADDED here is groups that just became unreachable; a zone REMOVED got filed and the fixture is stale. Either way the numbers in the commit body are no longer true.`) ok(joinable.has('asia-china-xinjiang-uyghur-autonomous-region') && !filed.has('asia-china-xinjiang-uyghur-autonomous-region'), 'xinjiang specifically: joinable in admin-to-list, absent from zone-regions — its 100 groups are reachable ONLY through the bucket') console.log(fails ? `\nLIST-SELECTION: ${fails} FAIL(s)` : '\nLIST-SELECTION: serialisable ids out, and no joinable zone can be dropped') process.exit(fails ? 1 : 0)