diff --git a/library/ProfileLoader.vue b/library/ProfileLoader.vue index 56a3364ad..9b38546ef 100644 --- a/library/ProfileLoader.vue +++ b/library/ProfileLoader.vue @@ -92,7 +92,7 @@ const profileName = computed(() => config.value?.profile || null) // prop is genuinely absent: profile-config arrives with keys profile/dataSource/instanceId/ // assetsBase and NO tk. This computed then produced '' and provided it to every child, so a map // nested INSIDE the composite got an empty accessToken and logged -// "No Mapbox access token provided" — the error the Driver saw at dashboard-plus-grid.js:605. +// "No Mapbox access token provided" — the error reported at dashboard-plus-grid.js:605. // // The generator's assumption was that a composite's nested maps each render in their OWN IFRAME // LEAF running its own token ladder. That is false for dashboard-plus-grid: it has zero iframes @@ -123,8 +123,8 @@ const mapboxToken = computed(() => { }) // SHARE WHAT THIS ELEMENT WAS GIVEN. An element handed a real `tk` publishes it page-wide, so a -// SIBLING or NESTED element that was handed none stops starting from nothing — the Driver's point -// that a token belongs to the page, not to whichever component happened to receive it. Publishing +// SIBLING or NESTED element that was handed none stops starting from nothing: a token belongs to +// the page, not to whichever component happened to receive it. Publishing // is idempotent and ignores empties, so this cannot clobber a good token with a blank one. watch(() => config.value?.tk, (tk) => { if (typeof tk === 'string' && tk) publishMapToken(tk) }, { immediate: true }) // A token-SERVICE URL in the profile-config (tokenUrl) is asked only when no token is at hand; its answer diff --git a/library/colors/wagf-region.js b/library/colors/wagf-region.js index b39468f46..989f34755 100644 --- a/library/colors/wagf-region.js +++ b/library/colors/wagf-region.js @@ -1,11 +1,10 @@ /** * WAGF region color strategy — colors pins by the region they belong to. * - * ★ THE VALUES ARE THE RESEARCH MAP'S, ON THE DRIVER'S INSTRUCTION (2026-09-24). He compared the - * two surfaces himself: "when i look on teh color ffor th regiosn tab of the simpel research map i - * don tsee the you using htes colors on the reigosn dashbarod hwen you shoudl". Two surfaces - * disagreeing about what Africa's colour means is a product defect whichever palette is prettier, - * and he chose which one wins. Source of truth: + * ★ THE VALUES ARE THE RESEARCH MAP'S (2026-09-24). The Simple Research map's Regions tab and the + * regions dashboard painted the same regions in different colours. Two surfaces disagreeing about + * what Africa's colour means is a product defect whichever palette is prettier, and the research + * map's palette was chosen to win. Source of truth: * library/colors/doxa-region.js (it lived at plugin-designs/doxa-research-map/src/colors/ until C1a), which the research dashboard and * three other consumers already paint from. * @@ -25,10 +24,10 @@ * seven regions as a TABLE with names and figures. Identity never rests on hue alone on either. * The LIGHTNESS FAIL is the part with no relief: three of these read faintly as PINS on a light * basemap. Darkening those three by ~10% L would enter the band while keeping the hue - * recognisable, and that is the Driver's call to make, not mine to make quietly — asked, not done. + * recognisable. That is provisional, pending a product decision — asked, not done quietly. * - * WHY THIS EXISTS. The regions element's no-selection state is a CHOOSER: the Driver's brief was - * "some type of map that would show the regions and countries and let you select one". For the + * WHY THIS EXISTS. The regions element's no-selection state is a CHOOSER: a map that shows the + * regions and countries and lets you select one. For the * seven regions to read AS regions the moment the map loads, the pins have to be colored by * region — which is a categorical encoding no existing strategy provides. (`_registry.js` and * `religion.js` both mention a `doxa-region.js`; it does not exist in this tree.) @@ -66,7 +65,7 @@ export const PROPERTY_KEY = 'region' // DX-life --color-brand-lighter: an unknown region reads as chrome, not as an eighth region. // ★ DELIBERATELY NOT THEIRS. doxa-region.js uses '#0098FF' for null/undefined and keys // 'No WAGF Region/Bloc' to '#1a1a2e'. Neither is a REGION colour — they are what an absent value -// looks like — and the Driver's instruction was about the seven regions. A bright blue for +// looks like — and the instruction was about the seven regions. A bright blue for // "unknown" would also read as a region on a map whose every other pin is a region. Every row in // this feed carries a wagf_region, so this value is almost never painted; it is chrome on purpose. const DEFAULT_COLOR = '#6d766e' diff --git a/library/components/charts/ShareCalendar.vue b/library/components/charts/ShareCalendar.vue index e38871e00..2b24ce93b 100644 --- a/library/components/charts/ShareCalendar.vue +++ b/library/components/charts/ShareCalendar.vue @@ -3,7 +3,7 @@ * ShareCalendar — the same 5,200-cell grid, shaded by a population-weighted share. * * ★ shareLabel IS REQUIRED AND HAS NO DEFAULT, on purpose. The shipped figure is the EVANGELICAL - * share (christian-share.json: pctEvangelical 0.6133), and the brief and the Driver both say + * share (christian-share.json: pctEvangelical 0.6133), and the brief says * "% Christian". IMB publishes no %-Christian column at all, so a true "% Christian" is not * computable from repo data (UPG100-RESEARCH-FINDINGS.md §3). This project has already retracted one * P0 that was two metrics wearing one name. A default here would let this component be the thing diff --git a/library/components/charts/packetCharts.js b/library/components/charts/packetCharts.js index ae9ff2fd6..4055059b2 100644 --- a/library/components/charts/packetCharts.js +++ b/library/components/charts/packetCharts.js @@ -246,7 +246,7 @@ export function scatterCells(total, n, seed = '') { * * `rows` is how many distinct grid rows the shaded cells touch. A contiguous block of 32 in a * 52-wide grid touches 1; a scatter of 32 over 5,200 touches close to 32. That single number is the - * difference between the page the Driver asked for and the one that shipped. + * difference between the page that was asked for and the one that shipped. */ export function scatterSpread(picked, columns) { const cols = Number(columns) || 1 diff --git a/library/components/dashboards/DashboardFacetRail.vue b/library/components/dashboards/DashboardFacetRail.vue index 658bb0193..3aa42073e 100644 --- a/library/components/dashboards/DashboardFacetRail.vue +++ b/library/components/dashboards/DashboardFacetRail.vue @@ -90,8 +90,8 @@ function rowsExcluding(exclude) { } // ── SECTION COLLAPSE STATE (BUG-DASHBOARD-BAND-GROWS-ENORMOUS-WITH-LIVE-DATA) ──────────────── -// Driver: "once the data fills all the sidebars, it causes the dashboard to become really tall... -// you have to like collapse all of the data." MEASURED live at 1440x900 in page-scroll mode +// Once live data filled the sidebars, the dashboard grew very tall and every section had to be +// collapsed by hand. MEASURED live at 1440x900 in page-scroll mode // (dashboard-plus-grid): all five sections open by default rendered 69 rows total (16 People / 7 // Place / 31 Language / 10 Religion / 5 Gospel Access), and the rail's OWN scroller never engaged // — frBody clientHeight === scrollHeight === 2117px — because a fully-open rail is simply that @@ -103,12 +103,9 @@ function rowsExcluding(exclude) { // header, same interaction as before. // ★ OPEN BY DEFAULT — and that is NOT a revert to the bug, it is the correct reading of it. // -// The previous pass set every section CLOSED, because the Driver said the rail "shouldn't be fully -// expanded". That was a literal reading of a symptom report. His correction, verbatim: "when I told -// you they shouldn't be fully expanded, I didn't mean collapse all the sidebars. I want people, -// place, language, religion EXPANDED. But when I say expanded I just mean OPEN — that doesn't mean -// fully expanded without a scroll bar. They should be open, but still have a scroll bar so they -// don't fully expand and cause the height of the dashboard to be super tall." +// The previous pass set every section CLOSED, a literal reading of "the rail should not be fully +// expanded". The intent was different: People, Place, Language and Religion stay OPEN, but open +// inside a bounded scroller, so they never grow the dashboard's height. // // So the defect was never "the sections are open". It was that opening them grew the PAGE instead of // filling a bounded scroller — 69 rows of content pushing the band to 2325px against a 900px @@ -170,7 +167,7 @@ function toRows(agg, facet, level) { } // ── THE ROWS THAT WENT TO ZERO (card BUG-TREE-LEGEND-BUTTONS-GO-DEAD-AFTER-TOGGLING) ──────── -// THE DRIVER'S REPORT: "after clicking around, the buttons started being unresponsive." The +// THE REPORT: after some clicking around, the buttons stopped responding. The // buttons did not break — THEY LEFT. aggregate() only ever returns keys that survive the current // filterSet, so a filtered-out sibling is simply ABSENT from the row list and is REMOVED FROM THE // DOM. Measured on the live composite (2026-09-22): selecting Place > Oceania took the rail from @@ -192,10 +189,10 @@ function toRows(agg, facet, level) { // unexpanded branch), which would ADD rows on filtering — the opposite surprise. The snapshot is // keyed per section id and only ever taken while the dashboard is unfiltered. // ── WHICH LIST OWNS THE ORDER (card BUG-TREE-EXPANDS-AT-THE-BOTTOM-NOT-UNDER-THE-SELECTED-NODE) ── -// THE DRIVER'S REPORT: "it expands the affinity block not underneath the selected affinity but -// underneath the very final affinity group at the very bottom of the semantic tree legend." He -// also isolated the trigger exactly: expanding with the caret ALONE is correct; SELECTING a row -// and THEN expanding it is broken. +// THE REPORT: the affinity block expanded not underneath the selected affinity but underneath +// the very last affinity group at the bottom of the semantic tree legend. The trigger was +// isolated exactly: expanding with the caret ALONE is correct; SELECTING a row and THEN expanding +// it is broken. // // ROOT CAUSE — this function used to let the BASELINE own the row order. It emitted every baseline // row first (survivor or zero), and only then appended whatever the live list had that the baseline @@ -301,8 +298,8 @@ function buildDrillRows(drill, topN) { } // ── TREE TRUNKS (card BUILD-TREE-LEGEND-SEMANTIC-INDENTED) ──────────────────────────────── -// Driver: "it is very hard for me to read the content because I cannot see that it is INDENTED -// like semantic trees. I want the semantic tree legend on the left just like on the research maps." +// The content was hard to read because nothing showed it is INDENTED like a tree; the rail uses the +// same nested legend as the research maps. // // Root cause: the rail conveyed depth with padding-left ALONE (.l0/.l1/.l2). Whitespace does not // read as hierarchy — nothing visually ties a child row to its parent, so People > bloc > cluster @@ -453,15 +450,15 @@ const scopeCount = computed(() => { // expand work above rewrites `value`; the People axis's label swap writes `label` only, and the // 'Other' bucket renders a null data-facet so it can never be filtered on. // ── AFFORDANCE (card BUG-SEMANTIC-TREE-SIDEBAR-NOT-INTEROPERABLE-WITH-GRID) ───────────────── -// DRIVER: "when I click on any of the people place language or religion semantic tree drop downs -// nothing happens." Measured, that report was TRUE-AS-EXPERIENCED and the wiring was FINE: the +// THE REPORT: clicking any of the people, place, language or religion semantic tree dropdowns +// did nothing. Measured, that report was TRUE-AS-EXPERIENCED and the wiring was FINE: the // rail split its hit targets so that the caret NAVIGATED and only the row body FILTERED. Clicking // a caret grew the row count 66 -> 73 and correctly did not filter. Correct by design — and // completely undiscoverable, because nothing on screen said the two halves of one row did two // different things. A user must never click something that silently does nothing. // // SO THE HIT TARGETS ARE NOW EXPLICIT, not positional: -// the WHOLE ROW filters — the Driver's mental model ("I clicked the row, select it") +// the WHOLE ROW filters — the reader's mental model: clicking a row selects it // an explicit CHEVRON BUTTON expands — a real