v1.8.0 + v1.9.0 — estate tokens, kit distribution + the chart-engineering minor #17

Merged
A-Guevara merged 17 commits from feat/v1.8.0-tokens-typography into main 2026-08-12 20:44:40 +00:00
Owner

This branch carries TWO releases: the v1.8.0 slice (estate tokens, TuxStatusToast, theme hardening, kit distribution, tux-audit bin — frozen 2026-07-30) and today's v1.9.0 chart-engineering minor.


v1.9.0 (2026-08-12)

One audit-driven day, ten commits.

Payload — TuxChartGeographic per-kind async split: 348KB eager geo becomes 12–163KB per kind (geo data modules split byte-identical; build-geo.mjs emits the new layout).

Chart internals — shared scale/hover/tone modules (tuxChartScale, useTuxChartHover) + one palette file replace four drifted copies (two tick algorithms, a first-tick-dropping ceil, clamp-vs-wrap tones, four margin conventions) under 39 behavior-lock tests; ~135 pasted palette declarations collapse to tux-chart-palette.css, colors verified computed-identical per surface.

Interaction contract — treemap cells become real keyboard buttons (focus tooltip, Enter drill, Backspace up); donut + sunburst gain the full tooltip contract; scatter swaps 500 per-point tab stops for a roving cursor. components.md doctrine updated.

Testing — first mounted component tests in the repo: vitest.config.ts + @nuxt/test-utils nuxt environment; 66 tests total.

Deps (owner-decided) — @vueuse/* + @tanstack/vue-table dropped; tux-owned useTuxPersistedRef + useTuxClipboard; @tanstack/vue-virtual now backs TuxRichDataGrid's opt-in virtualized mode (17–25 rendered rows while scrolling 5,000, live-measured).

Focus rings — ten divergent recipes removed; the universal two-ring system owns focus, with the two sanctioned exceptions documented.

Fix wave — tux-audit a11y gate (jsdom, not puppeteer), Math.random() ids → useId(), radial-chart SSR float mismatches (2dp rounding), TuxExample formatter depth-leak/RangeError that was corrupting hydration on heavy pages.

Gates run locally: lint · typecheck · 66/66 tests · token audit · axe (targeted, 0 violations) · contrast AAA (all pairs pass).

Tags after merge: v1.8.0 → its bump commit (c48c44c), v1.9.0 → the merge; v1.7.1 backfilled (34b29f2). Consumers pin tags.

This branch carries TWO releases: the v1.8.0 slice (estate tokens, TuxStatusToast, theme hardening, kit distribution, tux-audit bin — frozen 2026-07-30) and today's v1.9.0 chart-engineering minor. --- ## v1.9.0 (2026-08-12) One audit-driven day, ten commits. **Payload** — TuxChartGeographic per-kind async split: 348KB eager geo becomes 12–163KB per kind (geo data modules split byte-identical; build-geo.mjs emits the new layout). **Chart internals** — shared scale/hover/tone modules (tuxChartScale, useTuxChartHover) + one palette file replace four drifted copies (two tick algorithms, a first-tick-dropping ceil, clamp-vs-wrap tones, four margin conventions) under 39 behavior-lock tests; ~135 pasted palette declarations collapse to tux-chart-palette.css, colors verified computed-identical per surface. **Interaction contract** — treemap cells become real keyboard buttons (focus tooltip, Enter drill, Backspace up); donut + sunburst gain the full tooltip contract; scatter swaps 500 per-point tab stops for a roving cursor. components.md doctrine updated. **Testing** — first mounted component tests in the repo: vitest.config.ts + @nuxt/test-utils nuxt environment; 66 tests total. **Deps (owner-decided)** — @vueuse/* + @tanstack/vue-table dropped; tux-owned useTuxPersistedRef + useTuxClipboard; @tanstack/vue-virtual now backs TuxRichDataGrid's opt-in virtualized mode (17–25 rendered rows while scrolling 5,000, live-measured). **Focus rings** — ten divergent recipes removed; the universal two-ring system owns focus, with the two sanctioned exceptions documented. **Fix wave** — tux-audit a11y gate (jsdom, not puppeteer), Math.random() ids → useId(), radial-chart SSR float mismatches (2dp rounding), TuxExample formatter depth-leak/RangeError that was corrupting hydration on heavy pages. Gates run locally: lint · typecheck · 66/66 tests · token audit · axe (targeted, 0 violations) · contrast AAA (all pairs pass). Tags after merge: v1.8.0 → its bump commit (c48c44c), v1.9.0 → the merge; v1.7.1 backfilled (34b29f2). Consumers pin tags.
feat(doctrine): unification-plan.md + compositions §Suite chrome + tuxCatalog single source + catalog invariant tests (v1.7.1)
All checks were successful
scan / trivy-fs (push) Successful in 44s
baseline-security / baseline (push) Successful in 55s
baseline-security / baseline (pull_request) Successful in 48s
scan / trivy-fs (pull_request) Successful in 29s
ai-review / review (pull_request) Successful in 2m24s
0b2b762c9d
- design/unification-plan.md: the portal-unification v4 plan reconstructed
  as permanent public-safe doctrine (two-shape identity rule, one-chrome-
  many-voices, registry law, distribution artifacts, execution log, open-
  decision ledger incl. the four decisions ratified 2026-07-30).
- compositions.md gains the §Suite chrome section TuxUserMenu/
  TuxUtilityCluster have cited since v1.7.0.
- app/utils/tuxCatalog.ts replaces four drifting hand-maintained registries
  (navTree, /components grid, components.md tables, homepage count); backfills
  ~30 missing index entries, 9 sidebar entries, 3 doctrine rows; fixes 10
  deprecated Lucide alias icons the test immediately caught.
- tests/tux-catalog.test.ts: catalog ↔ filesystem ↔ routes ↔ components.md
  invariants; npm test now gates CI (quality job).
- Doc truth pass: README v1.4.2 staleness + counts + rename artifact,
  homepage computed count + v1.7.0 update entry, getting-started counts,
  design-doc title maps completed.
- design/tokens.json → regenerated tokens.css + kit artifacts: text.on-brand
  (theme-invariant, adopted by CTA/Footer/PageHeader/AnnouncementBanner
  replacing 10 hardcoded #fff; contrast-audit now measures the real pair),
  surface.border-subtle (3 themes), spacing scale 2..64.
- Nuxt UI warning alias → TTI gold ramp (owner-ratified); amber stand-in and
  its self-doc note retired.
- Typography doctrine enforced: body + eyebrow/subhead → --font-body (Open
  Sans); .heading--display → --font-display (Oswald via style-variant
  rebinds), italic dropped; --font-sans deprecated; dead @nuxt/fonts dep
  removed; stale font-loading comments fixed (globals.css, tux.md).
- audit:tokens failure message teaches the canonical-rename migration path;
  kit/README gains the invented-name migration table + on-brand recipe.
- $production nitro prerender config fenced behind is-root-project so layer
  consumers stop inheriting docs-site build behavior.

Verified: lint ✓ typecheck ✓ 18/18 tests ✓ audit:tokens (262 defined) ✓
build:tokens deterministic ✓ live checks: body=Open Sans, warning
border=#DDAC37, .heading--display=Oswald 700.
- TuxStatusToast host + useTuxToast bus: polite live region, alert-role
  sticky errors, reduced-motion aware, Tauri OS-notification escalation per
  tauri-bindings contract; docs shell dogfoods the host; live showcase page.
- TuxAvatar extracted from TuxUserMenu (now consumes it); TuxPageContainer
  over new --layout-* width tokens.
- Batch K (hybrid doctrine, owner-ratified): controls ride --font-bold;
  Nuxt UI --ui-radius bound to --radius-md; four family fonts exposed as
  Tailwind utilities; TuxButton re-scoped editorial in components.md.
- TuxBadge tone=custom with --tux-badge-* token hooks.
- Consumer debts: TuxMegaMenu viewport cap; TuxSiteNav/TuxAppFrame publish
  measured --tux-nav-height; layer demo-route stripping for consumers
  (TTI_UX_DEMOS opt-in); dark-bridge *-dark tolerance + kill-switch; svg
  icon-mode guidance for reverse proxies.

Verified: lint ✓ typecheck ✓ 18/18 tests ✓ audit:tokens (269 defined) ✓
live: toast region role=status/alert semantics + sticky error verified in
browser; avatar/page-container showcase pages render.
feat(kit): brand.env + Power BI themes + tux-audit bin — distribution & guardrails for non-Vue consumers (v1.8.0 slice 3)
All checks were successful
scan / trivy-fs (push) Successful in 38s
baseline-security / baseline (push) Successful in 1m3s
1181cee8e0
- package files array finally ships kit/ + scripts/; bin: tux-audit.
- scripts/extract-brand.mjs → kit/env/brand.env (71 resolved keys, atomic
  write); scripts/build-powerbi-theme.mjs → kit/powerbi/*.json (10-series
  dataColors via new chart-9/10 tokens, theme-invariant brand block).
- audit-tokens.mjs generalized (target dirs, layer+consumer defs, extra
  prefixes); tux-audit dispatcher with honest delegation for contrast/a11y.
- kit/README artifact matrix; README consumer guardrails snippet.

Verified: lint ✓ typecheck ✓ 18/18 ✓ audit:tokens (271) ✓ build:kit
deterministic ✓; consumer validation: landscape/frontend PASSES,
tti-ai-studio FAILS with migration guidance (the intended catch).
chore(release): v1.7.1 — version bump + changelog section
All checks were successful
baseline-security / baseline (push) Successful in 58s
scan / trivy-fs (push) Successful in 51s
ai-review / review (pull_request) Successful in 25s
scan / trivy-fs (pull_request) Successful in 40s
baseline-security / baseline (pull_request) Successful in 1m0s
34b29f25ca
Merge v1.7.1 release into v1.8.0 branch + chore(release): v1.8.0 version bump + changelog section
All checks were successful
scan / trivy-fs (push) Successful in 40s
baseline-security / baseline (push) Successful in 1m2s
baseline-security / baseline (pull_request) Successful in 49s
scan / trivy-fs (pull_request) Successful in 32s
ai-review / review (pull_request) Successful in 2m23s
c48c44ced9
Member

AI review · advisory

Verdict: 7 things worth fixing (4 high · 1 medium · 2 low).

app/components/TuxSiteNav.vue:108 · HIGH — Missing import for onBeforeUnmount
The component uses onBeforeUnmount without importing it, causing a runtime error when the component tries to clean up resources.

Fix: Add import { onBeforeUnmount } from "vue"; at the top of the script.

app/composables/useTuxToast.ts:39 · HIGH — Missing imports for Nuxt composables and platform helper
The file uses useState and useTuxPlatform without importing them, leading to undefined errors when the composable runs.

Fix: Add import { useState } from "#app"; and import { useTuxPlatform } from "../utils/useTuxPlatform"; at the top.

app/components/TuxAvatar.vue:31 · HIGH — Missing Vue composition API imports
The component uses computed, ref, and watch without importing them, resulting in a runtime error.

Fix: Add import { computed, ref, watch } from "vue"; at the top of the script.

app/components/TuxStatusToast.vue:23 · HIGH — Missing import for useTuxToast composable
The component calls useTuxToast() without importing it, causing an undefined function error.

Fix: Add import { useTuxToast } from "../composables/useTuxToast"; (adjust the path if needed) at the top of the script.

app/composables/useTuxToast.ts:60 · MEDIUM — Potential memory leak with window.setTimeout
The show function creates timeouts to dismiss toasts but does not clear them if the component unmounts or clear() is called, risking memory leaks or errors.

Fix: Store timeout IDs in a Map keyed by toast ID and call clearTimeout() in dismiss() and clear().

app/components/TuxAvatar.vue:56 · LOW — Unsafe array access in initials derivation
The code uses p[0]! which will throw an error if a name contains an empty string or whitespace that bypasses the filter.

Fix: Replace p[0]! with p?.[0] ?? '' to safely handle unexpected empty strings.

app/composables/useTuxToast.ts:1 · LOW — Missing type safety for Tauri notification
The Tauri notification escalation lacks type safety, which could lead to runtime errors if the imported module does not match expected types.

Fix: Add type annotations or interfaces to ensure the Tauri notification module conforms to expected types.

⚑ panel: GPT-OSS 120B · Gemma 4 31B · Devstral 2 123B — 12 raised, 7 confirmed, 3 refuted · web: not used · context: 3 files · 6 codebase · 4 standards chunks

Panel debate — how this review was reached

Grounding — context: 3 files · 6 codebase · 4 standards chunks

Round 1 — independent reviews

  • GPT-OSS 120B (5 findings, confidence 0.96): The diff introduces several new components but misses critical imports, which will cause runtime errors.
  • Gemma 4 31B (2 findings, confidence 0.95): The PR is a large, high-quality unification release that correctly implements the 'four-family' typography rule and introduces robust distribution artifacts. The most significant risk is a minor memor
  • Devstral 2 123B (5 findings, confidence 0.8): The PR introduces several new features and improvements, but there are some issues that need to be addressed.

Round 2 — cross-examination

  • GPT-OSS 120B#1 Missing import for onBeforeUnmount · confirmed: Gemma 4 31B, Devstral 2 123B · refuted: —
  • GPT-OSS 120B#2 Missing imports for Nuxt composables and platform helper · confirmed: Devstral 2 123B · refuted: Gemma 4 31B
  • GPT-OSS 120B#3 Missing Vue composition API imports · confirmed: Devstral 2 123B · refuted: Gemma 4 31B
  • GPT-OSS 120B#4 Missing import for useTuxToast composable · confirmed: Devstral 2 123B · refuted: Gemma 4 31B
  • GPT-OSS 120B#5 Missing import for withDefaults macro (optional but recommended) · confirmed: — · refuted: Gemma 4 31B, Devstral 2 123B
  • Gemma 4 31B#1 Potential Memory Leak with window.setTimeout · confirmed: Devstral 2 123B · refuted: —
  • Gemma 4 31B#2 Unsafe Array Access in Initials Derivation · confirmed: Devstral 2 123B · refuted: GPT-OSS 120B
  • Devstral 2 123B#1 Missing unit test gate in CI · confirmed: — · refuted: GPT-OSS 120B, Gemma 4 31B
  • Devstral 2 123B#2 Inconsistent comment style · confirmed: — · refuted: Gemma 4 31B
  • Devstral 2 123B#3 Missing accessibility attributes · confirmed: — · refuted: GPT-OSS 120B, Gemma 4 31B
  • Devstral 2 123B#4 Missing error handling for Tauri notification · confirmed: — · refuted: Gemma 4 31B
  • Devstral 2 123B#5 Missing type safety for Tauri notification · confirmed: GPT-OSS 120B · refuted: Gemma 4 31B

Raised but refuted (left out of the review above)

  • GPT-OSS 120B#5 Missing import for withDefaults macro (optional but recommended) — withDefaults and defineProps are compiler macros in Vue <script setup> and specifically should not be imported.
  • Devstral 2 123B#1 Missing unit test gate in CI — The workflow runs npm test as a step without continue-on-error. If the tests fail, the step (and thus the job) fails, already acting as a gate in
  • Devstral 2 123B#3 Missing accessibility attributes — TuxAvatar already sets aria-hidden, role, and aria-label (when not decorative). These are the core accessibility attributes required for the e

Synthesis — Devstral 2 123B wrote the final review from 7 confirmed findings (+2 unconfirmed).

Transcript rv-20260730202040-66d858 — full round outputs, web results, and model reasoning are viewable by anyone with access to this repository via the AI gateway.

Full transcript: http://host.containers.internal:3939/-/ai/v1/review/rv-20260730202040-66d858

Three superPOD models reviewed this independently and cross-examined each other; only what survived is shown. Advisory — never a merge gate.

### AI review · advisory **Verdict: 7 things worth fixing** (4 high · 1 medium · 2 low). **`app/components/TuxSiteNav.vue:108`** · HIGH — Missing import for onBeforeUnmount The component uses `onBeforeUnmount` without importing it, causing a runtime error when the component tries to clean up resources. > **Fix:** Add `import { onBeforeUnmount } from "vue";` at the top of the script. **`app/composables/useTuxToast.ts:39`** · HIGH — Missing imports for Nuxt composables and platform helper The file uses `useState` and `useTuxPlatform` without importing them, leading to undefined errors when the composable runs. > **Fix:** Add `import { useState } from "#app";` and `import { useTuxPlatform } from "../utils/useTuxPlatform";` at the top. **`app/components/TuxAvatar.vue:31`** · HIGH — Missing Vue composition API imports The component uses `computed`, `ref`, and `watch` without importing them, resulting in a runtime error. > **Fix:** Add `import { computed, ref, watch } from "vue";` at the top of the script. **`app/components/TuxStatusToast.vue:23`** · HIGH — Missing import for useTuxToast composable The component calls `useTuxToast()` without importing it, causing an undefined function error. > **Fix:** Add `import { useTuxToast } from "../composables/useTuxToast";` (adjust the path if needed) at the top of the script. **`app/composables/useTuxToast.ts:60`** · MEDIUM — Potential memory leak with window.setTimeout The `show` function creates timeouts to dismiss toasts but does not clear them if the component unmounts or `clear()` is called, risking memory leaks or errors. > **Fix:** Store timeout IDs in a `Map` keyed by toast ID and call `clearTimeout()` in `dismiss()` and `clear()`. **`app/components/TuxAvatar.vue:56`** · LOW — Unsafe array access in initials derivation The code uses `p[0]!` which will throw an error if a name contains an empty string or whitespace that bypasses the filter. > **Fix:** Replace `p[0]!` with `p?.[0] ?? ''` to safely handle unexpected empty strings. **`app/composables/useTuxToast.ts:1`** · LOW — Missing type safety for Tauri notification The Tauri notification escalation lacks type safety, which could lead to runtime errors if the imported module does not match expected types. > **Fix:** Add type annotations or interfaces to ensure the Tauri notification module conforms to expected types. <sub>⚑ panel: GPT-OSS 120B · Gemma 4 31B · Devstral 2 123B — 12 raised, 7 confirmed, 3 refuted · web: not used · context: 3 files · 6 codebase · 4 standards chunks</sub> <details> <summary>Panel debate — how this review was reached</summary> **Grounding** — context: 3 files · 6 codebase · 4 standards chunks **Round 1 — independent reviews** - **GPT-OSS 120B** (5 findings, confidence 0.96): The diff introduces several new components but misses critical imports, which will cause runtime errors. - **Gemma 4 31B** (2 findings, confidence 0.95): The PR is a large, high-quality unification release that correctly implements the 'four-family' typography rule and introduces robust distribution artifacts. The most significant risk is a minor memor - **Devstral 2 123B** (5 findings, confidence 0.8): The PR introduces several new features and improvements, but there are some issues that need to be addressed. **Round 2 — cross-examination** - `GPT-OSS 120B#1` Missing import for onBeforeUnmount · confirmed: Gemma 4 31B, Devstral 2 123B · refuted: — - `GPT-OSS 120B#2` Missing imports for Nuxt composables and platform helper · confirmed: Devstral 2 123B · refuted: Gemma 4 31B - `GPT-OSS 120B#3` Missing Vue composition API imports · confirmed: Devstral 2 123B · refuted: Gemma 4 31B - `GPT-OSS 120B#4` Missing import for useTuxToast composable · confirmed: Devstral 2 123B · refuted: Gemma 4 31B - `GPT-OSS 120B#5` Missing import for withDefaults macro (optional but recommended) · confirmed: — · refuted: Gemma 4 31B, Devstral 2 123B - `Gemma 4 31B#1` Potential Memory Leak with window.setTimeout · confirmed: Devstral 2 123B · refuted: — - `Gemma 4 31B#2` Unsafe Array Access in Initials Derivation · confirmed: Devstral 2 123B · refuted: GPT-OSS 120B - `Devstral 2 123B#1` Missing unit test gate in CI · confirmed: — · refuted: GPT-OSS 120B, Gemma 4 31B - `Devstral 2 123B#2` Inconsistent comment style · confirmed: — · refuted: Gemma 4 31B - `Devstral 2 123B#3` Missing accessibility attributes · confirmed: — · refuted: GPT-OSS 120B, Gemma 4 31B - `Devstral 2 123B#4` Missing error handling for Tauri notification · confirmed: — · refuted: Gemma 4 31B - `Devstral 2 123B#5` Missing type safety for Tauri notification · confirmed: GPT-OSS 120B · refuted: Gemma 4 31B **Raised but refuted** (left out of the review above) - `GPT-OSS 120B#5` Missing import for withDefaults macro (optional but recommended) — `withDefaults` and `defineProps` are compiler macros in Vue `<script setup>` and specifically should not be imported. - `Devstral 2 123B#1` Missing unit test gate in CI — The workflow runs `npm test` as a step without `continue-on-error`. If the tests fail, the step (and thus the job) fails, already acting as a gate in - `Devstral 2 123B#3` Missing accessibility attributes — `TuxAvatar` already sets `aria-hidden`, `role`, and `aria-label` (when not decorative). These are the core accessibility attributes required for the e **Synthesis** — Devstral 2 123B wrote the final review from 7 confirmed findings (+2 unconfirmed). <sub>Transcript `rv-20260730202040-66d858` — full round outputs, web results, and model reasoning are viewable by anyone with access to this repository via the AI gateway.</sub> </details> <sub>Full transcript: http://host.containers.internal:3939/-/ai/v1/review/rv-20260730202040-66d858</sub> <sub>Three superPOD models reviewed this independently and cross-examined each other; only what survived is shown. Advisory — never a merge gate.</sub>
The a11y dispatcher gated on puppeteer while audit-a11y.mjs actually
imports jsdom + axe-core — blocking consumers that had the right deps
and admitting ones that crashed on import. Help text + README now state
the honest per-command split.

TuxFocusView's aria-labelledby id was a Math.random() computed (SSR
hydration mismatch when rendered open); TuxRuleBuilderGroup's rule ids
now derive from a per-instance useId() seed + counter.
The five kinds now render through async child components that each
statically import only their own geo data module. texas.ts splits into
texas-outline / texas-outline-polygon / txdot-districts / tx-metros
(data byte-identical to the previous generated output; texas.ts stays
as a compat re-export barrel) and build-geo.mjs emits that layout so a
regen can't reassemble the monolith. Public API, rendered SVG, and
SSR/prerender output unchanged; per-kind client payload drops from
~348KB to ~12KB (flow) / 21KB (dot-density) / 63KB (county) / 119KB
(districts) / 163KB (us-context) with a 2KB dispatcher.
tuxChartScale.ts (canonical nice-ticks, loop-safe extents, domain
padding, clamped series tones, DOM-free pointer projection, standard
margins) + useTuxChartHover() (the roving-cursor pointer/keyboard
contract) replace per-component copies that had drifted: two tick
algorithms (Scatter's dropped its first tick via a stray ceil),
clamp-vs-wrap tone rules, four margin conventions, and two arrow-key
seeds. Deliberate unifications are listed in the CHANGELOG entry.

tux-chart-palette.css collapses ~135 duplicated var(--chart-N, #hex)
declarations across six components into eight shared tone classes
setting --tux-chart-tone; rendered colors verified computed-identical
to the chart tokens on every showcase surface. Components keep their
…__series--cN classes as consumer styling hooks.

tests/tux-chart-scale.test.ts locks the canonical behavior (written
before the migration); net -400 lines across the family.
Closes the gap between the components.md chart-tooltip doctrine and the
code — six of thirteen charts had zero interactivity:

- TuxTreemap: cells were focusable with NO key handlers (focus ring,
  no readout, no drill). Cells are now role=button with accessible
  names; focus anchors the tooltip to the cell, arrows walk leaves,
  Enter/Space drills in, Backspace drills up, Escape dismisses. The
  canvas svg is role=group (not img) so the cell buttons aren't
  nested-interactive violations.
- TuxChartDonut + TuxChartSunburst: full tooltip contract — per-arc
  hover, branded card (value + % of total; sunburst names the parent
  group), sibling-dim highlight, native <title> fallbacks, hover emit,
  tooltip prop, single-tab-stop arrow-key access via useTuxChartHover.
- TuxChartScatter: roving cursor replaces per-point tab stops (a
  500-point scatter injected 500 tab stops, no Escape); svg is the one
  focusable surface, arrows walk points in x order, active dot ringed.
  Also restores the tooltip swatch color lost in the palette pass.
- Radial hydration fix: sunburst/donut/gauge serialized raw trig
  floats into arc attributes; server/client V8 differ in the last ulp
  on transcendentals → data-dependent hydration mismatches. Geometry
  now rounds to 2dp, verified byte-identical server-vs-client.

components.md contract text updated to match (one tab stop per chart;
treemap's per-cell buttons are the documented exception).

Verified: axe clean across the five changed showcase pages; keyboard,
hover, Escape, drill, and tooltip behavior exercised live per chart.
vitest.config.ts (never existed; npm test ran bare) with a two-tier
layout: pure tests keep the node environment, mounted tests opt into
the nuxt environment per file via docblock (@nuxt/test-utils 4 +
@vue/test-utils, jsdom DOM) so auto-imports resolve exactly as in the
app; mount with mountSuspended.

First mounted coverage in the repo — 18 tests locking the hand-rolled
behaviors nothing exercised before:
- TuxChartDonut: arrow cycling from mid-seed, Escape, sibling dim,
  per-slice hover, <title> fallbacks, tooltip=false gate, hover emits
- TuxChartScatter: roving cursor (one tab stop, arrows in x order,
  pointer/keyboard index sync, Escape)
- TuxTreemap: role=button cells with names, focus tooltip, Enter
  drill-in, Backspace drill-up, role=group canvas
- TuxFocusView: Escape emits + aria-labelledby resolves to the title
  (locks the useId fix), dismissOnEscape=false
- TuxAnnouncementBanner: localStorage dismissal memory (the nuxt
  jsdom env exposes no localStorage — suite installs an in-memory
  Storage, documented in-file)

components.md pre-push guards now include npm test.
All three were declared with zero call sites (VueUse even registered
as a Nuxt module) — dead weight in every consumer's graph. The
patterns they'd cover are now ~70 lines of tux-owned composables,
modeled on the semantics but without the dependency:

- useTuxPersistedRef: SSR-safe storage-backed ref (reads onMounted so
  SSR renders the default — no hydration mismatch), storage picker,
  serializer option so migrations keep their exact wire format (the
  banner has been writing "1" flags to real browsers since it
  shipped).
- useTuxClipboard: copy + Copied-flash with keyed variant; clears its
  reset timer on unmount (the three hand-rolled copies leaked theirs).

Migrated: TuxAnnouncementBanner, TuxCodeBlock, TuxExample,
TuxCitationExport (remaining storage sites tracked as follow-up).
@tanstack/vue-virtual stays — it backs the upcoming TuxRichDataGrid
virtualized mode (owner-requested). 57/57 tests green, including the
banner persistence suite exercising the migrated path.
Opt-in `virtualized` prop (+ `virtualRowHeight`, default 44):
table-compatible windowing — the virtualizer tracks scroll inside the
grid's own scroll container and only the visible slice of rows
renders, bracketed by spacer rows that preserve the scroll extent. No
absolute positioning, so table layout, the sticky header, sorting,
and key-based selection survive unchanged. Measured live: 17–25
rendered <tr>s while scrolling 5,000 rows (spacers 219,252px total,
splitting symmetrically mid-scroll).

Spacers are mounted-gated: the virtualizer's total size differs
between server and hydrating client, so SSR and first client render
agree on "no spacers, no rows" and the window streams in after
mount. (The /components/rich-data-grid page's 4 hydration warnings
are PRE-EXISTING — reproduced with this work stashed — and tracked
separately alongside a TuxExample formatter RangeError.)

Row expansion is disabled while virtualized (expansionOff) —
variable-height windows need per-row measurement; build when a
consumer needs it. Showcase demo with 5,000 generated rows; mounted
tests cover windowing, the expansion constraint, and non-virtualized
behavior preservation. 60/60 tests, axe clean.
The inline pretty-printer treated Vue's hydration comment markers
(<!--[--> / <!--]-->) as open tags: every marker leaked one indent
level forever (a rich-data-grid preview leaked +190, inflating 26KB
of DOM to 165KB of output), and <col>-class void elements leaked too.
On large, churning previews the quadratic runaway exceeded V8's max
string length (RangeError: Invalid string length) — and because that
threw during the hydration mount tick, Vue's reconciliation corrupted
and logged four 'Hydration completed but contains mismatches' errors
on /components/rich-data-grid. One root cause, both symptoms.

Formatter extracted to app/utils/tuxFormatHtml.ts with 6 unit tests:
comments tokenize as single units (so '<!-- a > b -->' can't corrupt
the stream) and are dropped as framework plumbing; the void-element
list is complete; input is hard-capped at 150k chars with a visible
truncation notice so no preview subtree can ever OOM the tab.

Verified live: fresh-tab loads of rich-data-grid and treemap show
zero console errors; the HTML tab renders comment-free at true DOM
depth (max indent 18, was 190+). 66/66 tests, axe clean.
The layer's *:focus-visible rule (globals.css) has always applied the
themed two-ring --shadow-focus, but ten components had grown their own
rings — four competing recipes including references to a non-existent
--focus-ring token (masked by fallbacks) and a brand-accent ring on
TuxTreemap — that either double-drew on the universal shadow or
suppressed it with outline: none.

All component-level rings removed (Accordion, Identity, RailNav,
CommentThread, ResultCount, RuleBuilderGroup, Donut, Scatter,
Sunburst); form-control :focus border tints kept (input affordances,
not rings). TuxTreemap keeps an outline by necessity — box-shadow
cannot render on SVG child elements — recolored from brand-accent to
the themed --focus-ring-outer (black in HC).

Doctrine added to components.md §'Focus rings': the universal rule
owns rings; the only sanctioned exceptions are SVG children (themed
token) and forced-colors blocks (system colors). Scope decisions
recorded: reduced-motion blocks stay colocated by design; small-type
utilities deferred pending the token question.
# Conflicts:
#	package-lock.json
#	package.json
chore(release): v1.9.0 — version bump + changelog section
All checks were successful
baseline-security / baseline (push) Successful in 1m31s
baseline-security / baseline (pull_request) Successful in 1m29s
scan / trivy-fs (push) Successful in 47s
scan / trivy-fs (pull_request) Successful in 49s
ai-review / review (pull_request) Successful in 8m44s
2040ead358
The chart-engineering minor. See CHANGELOG [1.9.0] for the full
inventory; unification-plan execution log updated (TuxKanban promotion
moves to an unnumbered later slice).
A-Guevara changed title from feat(v1.8.0): estate tokens + TuxStatusToast + theme hardening + kit distribution + tux-audit to v1.8.0 + v1.9.0 — estate tokens, kit distribution + the chart-engineering minor 2026-08-12 20:23:58 +00:00
ai-review-bot left a comment

AI review · advisory

Verdict: 5 things worth fixing (2 medium · 3 low).

Findings that didn't map to a diff line:

app/assets/css/globals.css:68 · LOW — Potential missing newline in .nuxtrc may cause parser warnings
The newly added .nuxtrc file ends without a newline character, which can trigger warnings in strict parsers or CI tools.

Fix: Add a trailing newline to .nuxtrc.

⚑ panel: GPT-OSS 120B · Gemma 4 31B · Devstral 2 123B · Laguna S 2.1 — 5 distinct, 5 confirmed, 0 refuted · web: not used · context: 9 files · 90 codebase · 14 standards chunks (best-grounded: Laguna S 2.1; smaller windows saw less)

Panel debate — how this review was reached

Grounding — context: 9 files · 90 codebase · 14 standards chunks (best-grounded: Laguna S 2.1; smaller windows saw less)

Round 1 — independent reviews

  • GPT-OSS 120B (4 findings, confidence 0.85): The changes introduce several documentation mismatches (version pins, stale comments) and a minor file formatting issue; otherwise the code modifications appear consistent.
  • Gemma 4 31B (1 finding, confidence 0.95): The PR is largely a comprehensive update for v1.8.0 and v1.9.0, introducing significant architectural improvements (geographic code splitting, shared chart math, and a new distribution kit). The only
  • Devstral 2 123B (0 findings):
  • Laguna S 2.1 (0 findings):

Round 2 — cross-examination

  • GPT-OSS 120B#1 Outdated version pin instructions · confirmed: Devstral 2 123B · refuted: —
  • Gemma 4 31B#1 Overly broad typography selector may cause regressions in third-party components · confirmed: GPT-OSS 120B · refuted: —
  • GPT-OSS 120B#3 Comment does not reflect updated heading style · confirmed: Devstral 2 123B · refuted: —
  • GPT-OSS 120B#2 Stale comment about warning colour · confirmed: Devstral 2 123B · refuted: —
  • GPT-OSS 120B#4 Potential missing newline in .nuxtrc may cause parser warnings · confirmed: Devstral 2 123B · refuted: —

Synthesis — Devstral 2 123B wrote the final review from 5 confirmed findings.

Transcript rv-20260812203837-6b47fb — full round outputs, web results, and model reasoning are viewable by anyone with access to this repository via the AI gateway.

Advisory — never a merge gate. Disagree with a finding? Reply on it, or use the finding board under this review. Transcript rv-20260812203837-6b47fb.

### AI review · advisory <!-- tti-rv:rv-20260812203837-6b47fb: --> **Verdict: 5 things worth fixing** (2 medium · 3 low). Findings that didn't map to a diff line: **`app/assets/css/globals.css:68`** · LOW — Potential missing newline in .nuxtrc may cause parser warnings The newly added .nuxtrc file ends without a newline character, which can trigger warnings in strict parsers or CI tools. > **Fix:** Add a trailing newline to .nuxtrc. <sub>⚑ panel: GPT-OSS 120B · Gemma 4 31B · Devstral 2 123B · Laguna S 2.1 — 5 distinct, 5 confirmed, 0 refuted · web: not used · context: 9 files · 90 codebase · 14 standards chunks (best-grounded: Laguna S 2.1; smaller windows saw less)</sub> <details> <summary>Panel debate — how this review was reached</summary> **Grounding** — context: 9 files · 90 codebase · 14 standards chunks (best-grounded: Laguna S 2.1; smaller windows saw less) **Round 1 — independent reviews** - **GPT-OSS 120B** (4 findings, confidence 0.85): The changes introduce several documentation mismatches (version pins, stale comments) and a minor file formatting issue; otherwise the code modifications appear consistent. - **Gemma 4 31B** (1 finding, confidence 0.95): The PR is largely a comprehensive update for v1.8.0 and v1.9.0, introducing significant architectural improvements (geographic code splitting, shared chart math, and a new distribution kit). The only - **Devstral 2 123B** (0 findings): - **Laguna S 2.1** (0 findings): **Round 2 — cross-examination** - `GPT-OSS 120B#1` Outdated version pin instructions · confirmed: Devstral 2 123B · refuted: — - `Gemma 4 31B#1` Overly broad typography selector may cause regressions in third-party components · confirmed: GPT-OSS 120B · refuted: — - `GPT-OSS 120B#3` Comment does not reflect updated heading style · confirmed: Devstral 2 123B · refuted: — - `GPT-OSS 120B#2` Stale comment about warning colour · confirmed: Devstral 2 123B · refuted: — - `GPT-OSS 120B#4` Potential missing newline in .nuxtrc may cause parser warnings · confirmed: Devstral 2 123B · refuted: — **Synthesis** — Devstral 2 123B wrote the final review from 5 confirmed findings. <sub>Transcript `rv-20260812203837-6b47fb` — full round outputs, web results, and model reasoning are viewable by anyone with access to this repository via the AI gateway.</sub> </details> <sub>Advisory — never a merge gate. Disagree with a finding? Reply on it, or use the finding board under this review. Transcript `rv-20260812203837-6b47fb`.</sub>
@ -16,2 +16,3 @@
**Current release:** v1.4.2 · WCAG 2.2 AA conformance · color contrast
**Current release:** see [`CHANGELOG.md`](CHANGELOG.md) — consumers pin a
git tag (never a branch) · WCAG 2.2 AA conformance · color contrast
verified at AAA across all three themes (light, dark, high-contrast) ·
Member

README.md:18 · MEDIUM — Outdated version pin instructions
The README instructs users to pin the package to v1.4.2, but the current release is v1.7.0. This can lead to confusion or outdated dependencies.

Fix: Update the version pins to v1.7.0 and adjust any surrounding text to match.

panel tally 2/4 · reply here or use the finding board to agree/disagree

**`README.md:18`** · MEDIUM — Outdated version pin instructions The README instructs users to pin the package to v1.4.2, but the current release is v1.7.0. This can lead to confusion or outdated dependencies. > **Fix:** Update the version pins to v1.7.0 and adjust any surrounding text to match. <sub>panel tally 2/4 · reply here or use the finding board to agree/disagree</sub> <!-- tti-rv:rv-20260812203837-6b47fb:GPT-OSS 120B#1 -->
@ -10,0 +9,4 @@
* green. `warning` is backed by the TTI gold ramp (#DDAC37 anchor,
* --color-gold-*) — owner-ratified 2026-07-30, replacing the amber
* stand-in. Landscape's local warning→gold override becomes redundant at
* its next pin-bump.
Member

app/app.config.ts:12 · LOW — Stale comment about warning colour
The comment states that warning uses the amber palette, but the code now maps it to the gold palette.

Fix: Update the comment to reflect that warning now uses the gold palette.

Proposed replacement (one-click ⚡ Apply on the findings board at the top of this PR):

// `warning` now uses the TTI gold palette (gold) rather than amber.

panel tally 2/4 · reply here or use the finding board to agree/disagree

**`app/app.config.ts:12`** · LOW — Stale comment about warning colour The comment states that `warning` uses the amber palette, but the code now maps it to the gold palette. > **Fix:** Update the comment to reflect that `warning` now uses the gold palette. **Proposed replacement** (one-click ⚡ Apply on the findings board at the top of this PR): ``` // `warning` now uses the TTI gold palette (gold) rather than amber. ``` <sub>panel tally 2/4 · reply here or use the finding board to agree/disagree</sub> <!-- tti-rv:rv-20260812203837-6b47fb:GPT-OSS 120B#2 -->
@ -30,3 +32,4 @@
font-weight: 700;
text-transform: uppercase;
letter-spacing: -0.01em;
line-height: 1.1;
Member

app/assets/css/tux.css:35 · LOW — Comment does not reflect updated heading style
The comment describes .heading--display as "italic," but the implementation no longer uses italic styling.

Fix: Update the comment to remove the mention of italic and reflect the current style (uppercase, extrabold, gold bar, display font).

Proposed replacement (one-click ⚡ Apply on the findings board at the top of this PR):

/* heading--display is the editorial-maximalist variant (uppercase + extrabold + gold bar) using the design display font. */

panel tally 2/4 · reply here or use the finding board to agree/disagree

**`app/assets/css/tux.css:35`** · LOW — Comment does not reflect updated heading style The comment describes `.heading--display` as "italic," but the implementation no longer uses italic styling. > **Fix:** Update the comment to remove the mention of italic and reflect the current style (uppercase, extrabold, gold bar, display font). **Proposed replacement** (one-click ⚡ Apply on the findings board at the top of this PR): ``` /* heading--display is the editorial-maximalist variant (uppercase + extrabold + gold bar) using the design display font. */ ``` <sub>panel tally 2/4 · reply here or use the finding board to agree/disagree</sub> <!-- tti-rv:rv-20260812203837-6b47fb:GPT-OSS 120B#3 -->
@ -655,3 +674,32 @@
color-mix(in srgb, var(--brand-primary) 6%, transparent) 12px
Member

app/assets/css/tux.css:674 · MEDIUM — Overly broad typography selector may cause regressions in third-party components
Applying font-family: var(--font-bold) to all buttons, inputs, and form elements globally can override intended styles in third-party components or accessibility-focused UI elements.

Fix: Scope the rule to components within the TUX namespace (e.g., .tux-control or .tux-component button).

Proposed replacement (one-click ⚡ Apply on the findings board at the top of this PR):

.tux-control,
.tux-component button,
.tux-component input,
.tux-component select,
.tux-component textarea,
.tux-component [role="button"] {
  font-family: var(--font-bold);
}

panel tally 2/4 · reply here or use the finding board to agree/disagree

**`app/assets/css/tux.css:674`** · MEDIUM — Overly broad typography selector may cause regressions in third-party components Applying `font-family: var(--font-bold)` to all buttons, inputs, and form elements globally can override intended styles in third-party components or accessibility-focused UI elements. > **Fix:** Scope the rule to components within the TUX namespace (e.g., `.tux-control` or `.tux-component button`). **Proposed replacement** (one-click ⚡ Apply on the findings board at the top of this PR): ``` .tux-control, .tux-component button, .tux-component input, .tux-component select, .tux-component textarea, .tux-component [role="button"] { font-family: var(--font-bold); } ``` <sub>panel tally 2/4 · reply here or use the finding board to agree/disagree</sub> <!-- tti-rv:rv-20260812203837-6b47fb:Gemma 4 31B#1 -->
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
tti/tti-ux!17
No description provided.