doxa-maps/plugin-designs/doxa-research-map/scripts
Doxa Maps f79d8f48e2 D1: a filter may be several values, and one function decides what matches
SPEC-DASHBOARD-KIT D1. filterSet[key] may hold an array meaning "any of these";
keys still AND together. The array support is four lines. The reason this is a
landing rather than a patch is the other half.

`a(r) === filterSet[k]` WAS WRITTEN OUT SEVEN TIMES — the shell's filteredRows,
the facet rail twice, the map panel, the table, the charts rail and the CSV
exporter. Seven copies of a one-character rule are survivable while the rule
stays one character. The moment it grows an array case, six of the seven keep
comparing an array with ===, every one of them quietly matches NOTHING, and the
panels disagree with each other about what is on screen. That is not abstract:
the facet rail computes the COUNTS a reader acts on before clicking, so a rail
still using === would print counts for a scope the map and table no longer show.
So the predicate now lives in the bus and every panel calls it. The
de-duplication is what makes the four lines safe.

WHAT A CLICK DOES IS UNCHANGED, deliberately. A plain click still REPLACES. D1
gives the bus the capability; making a rail row additive on an unmodified click
would change what every existing click does to the flagship, which is a product
decision and not this one. The array path is reached programmatically today.

AND THAT PATH IS THE PAYOFF: "Arabic" now narrows the grid. The language tier
covers 22 ISO codes, so no single value expressed it, and the composite had to
send nothing and leave the axis unfiltered — honest, and visibly incomplete,
because the map narrowed and the grid did not. The whole code set now crosses and
the grid ORs it. Verified per tier on the committed fixture rather than on one
example: for all 805 tiers the joined set selects exactly the rows the map
selected.

★ THE SEPARATOR IS `|`, AND MY FIRST DRAFT GOT THAT WRONG IN A WAY WORTH
RECORDING. I joined on `,` and broke label matching outright: 120 of the 864 live
language labels are comma-inverted ("Arabic, Mesopotamian"), so a selection made
BY LABEL was chopped in half and matched nothing. A separator that can also occur
inside a value is not a separator — the rule the URL hash states one file over,
which I had just written and then violated. check:filter-multivalue caught it
before it left this machine, and it caught it because it asserts a behaviour I
was KEEPING (label matching) and not only the one I was adding. Asserting only
the new behaviour would have shipped it.

EMPTY IS NOT A FILTER. An empty array clears the key rather than matching
nothing — a UI deselecting its last chip produces exactly that array, and
treating it as "narrow to zero" is the silent-empty-screen failure the hierarchy
contract already exists to prevent. A one-element array collapses to the scalar
it means, so the hash, the chips and every adapter keep their existing shape
until somebody actually picks two.

THE SURFACES THAT CANNOT SHOW A LIST SAY SO HONESTLY. labelFor resolves each
value and joins them, at the one owner, so the chip bar, the research-filter
chips and the CSV provenance line cannot drift apart. A dropdown shows NO
selection when the key holds several: ticking the first of three would state
something false about the board, which is worse than stating nothing, and the
chip still names every value so the selection is never invisible. The URL hash
carries a list and drops the display slug for it — the slug is one human name for
one code, and there is no honest slug for twenty-two.

check:filter-multivalue runs the real bus, greps the panels for surviving copies
of the predicate, round-trips the hash including a value containing a comma, and
lifts the grid's valueMatches to prove both ends OR the same way. No browser.

Green: check:filter-multivalue, check:language-code-link, check:facet-cascade and
its self-test, check:kpi-unit, check:csv-shape, check:no-free-identifiers,
check:sfc-parse, check:mjs-parse, check:descriptions, check:no-orphan-gates,
check:doc-scripts, check:script-flags, check:quoted-scripts.

SOURCE ONLY. Stacked on kit landing 1, which moved the bus into library/.
STUDIO: needs a rebuild of research-dashboard, dashboard-plus-grid,
doxa-research-map, research-map-plus-grid and people-groups-grid. package.json is
main's copy plus two lines beside check:fits-screen.
2026-09-26 17:28:46 +00:00
..
fixtures "Arabic" emptied the grid, because no people group speaks "Arabic" 2026-09-26 13:35:57 +00:00
check-clustering-modes.mjs Point my two map gates at the tree that exists, and stop them reading the old picture 2026-09-25 21:35:57 +00:00
check-export-one-click.mjs Export gate reads the tree name from the build config 2026-09-25 21:32:35 +00:00
check-language-code-link.mjs D1: a filter may be several values, and one function decides what matches 2026-09-26 17:28:46 +00:00
check-pin-dim-slider.mjs Point my two map gates at the tree that exists, and stop them reading the old picture 2026-09-25 21:35:57 +00:00
check-reduced-motion-jumps.mjs Reduced motion jumps, and 31 more strings stop being typed in English 2026-09-26 04:00:41 +00:00