openvibers/openvibe.shared Commits

shipped.js: the update log's selected filter chip is --on-accent-strong on --accent-strong (4.5:1 in every theme) instead of white on --accent (3.67:1, axe color-contrast serious on every site's /updates, found by the browser harness); test/login-contrast.test.js checks it

OP OpenVibers committed 26 Sept 2026 · f4877e0d3b · 3 files, +9 −2


Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 1441004..ca015ef 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -8,6 +8,8 @@ A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
**`openvibe-shared/browser-harness`** (roadmap WS-Q task 3, WS-T tasks 3 and 4): Live's browser smoke suite, generalised for any site. It drives headless Chrome over the DevTools protocol with Node's own WebSocket (Node 22+, no dependency), one browser context per route. `run({ base, routes, widths, checks, navigation, … })` checks every route at 390, 768 and 1280 px: the HTTP status (a route can expect 404), console errors (exceptions, `console.error`, failed loads, CSP), horizontal overflow (naming the elements) and scripts requested twice. With JavaScript off it checks the visible text (200 characters), exactly one absolute canonical link, and that JSON-LD parses and its headline or name is in the visible text. axe-core runs at the widest width: serious and critical violations fail, moderate is reported. Once per site, A → B → A navigation runs five times, clicking a link when there is one so a single-page app navigates in place. After a forced GC it samples heap, DOM nodes, listeners and documents (`Performance.getMetrics`), plus live intervals, pending timeouts and open WebSockets (a probe installed before page scripts). A measure fails when it grows past its budget from lap 2 to the last lap and is still growing (`BUDGETS`). CPU, requests and bytes over 5 idle seconds are reported, not failed. `ignoreErrors` rules are counted per label, never dropped silently. `format()` gives text or Markdown, and `summarize()` gives per-check counts. axe-core is not vendored: an installed `axe-core` is used, else 4.13.0 comes from jsDelivr, checked against a pinned sha384 (the same bytes as the npm tarball) and cached. `test/browser-harness-chrome.test.js` runs it in real Chrome against a fixture and skips without Chrome. Additive.
++Fix: the selected filter chip of the shared update log (`shipped.js`, every site's `/updates`) was white on `--accent` (3.67:1). It now uses `--accent-strong` / `--on-accent-strong` (4.5:1 or better in every theme), like the navbar's Sign In button. The harness found it.
++
## 1.15.0 — 2026-09-26
**`openvibe-shared/perf-budget`** (roadmap WS-T task 1): size budgets for a page's first load, measured from the running server with no browser. `measure({ base, path })` fetches the page and every same-origin script and stylesheet it names. It reports the files and their raw and brotli KB; cross-origin assets are listed as `external` and not weighed. `check(m, budgets)` lists the budgets exceeded, and `format()` is the failure message.
ddiff --git a/shipped.js b/shipped.js
iindex 6056b70..cb41f8e 100644
---- a/shipped.js
++++ b/shipped.js
@@@ -56,7 +56,7 @@
'.ov-shipped-log{display:flex;flex-direction:column;gap:22px;min-width:0}',
'.ov-shipped-bar{display:flex;flex-wrap:wrap;gap:6px;align-items:center}',
`.ov-shipped-chip{font:inherit;font-size:.8rem;padding:4px 12px;border-radius:999px;border:1px solid ${BORDER};background:transparent;color:${MUTED};cursor:pointer;text-decoration:none}`,
-- `.ov-shipped-chip:hover{color:${TEXT};border-color:var(--accent,#3b82f6)}.ov-shipped-chip[aria-pressed="true"]{background:var(--accent,#3b82f6);border-color:var(--accent,#3b82f6);color:var(--on-accent,#fff)}`,
++ `.ov-shipped-chip:hover{color:${TEXT};border-color:var(--accent,#3b82f6)}.ov-shipped-chip[aria-pressed="true"]{background:var(--accent-strong,#1d4ed8);border-color:var(--accent-strong,#1d4ed8);color:var(--on-accent-strong,#fff)}`,
`.ov-shipped-day h3{font-size:.95rem;font-weight:600;color:${MUTED};padding-bottom:8px;border-bottom:1px solid ${BORDER};margin:0 0 4px}`,
'.ov-shipped-entries{display:flex;flex-direction:column;gap:2px}',
'.ov-shipped-entry{display:flex;align-items:baseline;gap:10px;padding:8px 12px;border-radius:6px;min-width:0}',
ddiff --git a/test/login-contrast.test.js b/test/login-contrast.test.js
iindex 4ae63fd..db31f94 100644
---- a/test/login-contrast.test.js
++++ b/test/login-contrast.test.js
@@@ -1,5 +1,6 @@
'use strict';
--// The navbar's Sign In button (navbar.js .openvibe-navbar-login) is --on-accent-strong on --accent-strong:
++// The navbar's Sign In button (navbar.js .openvibe-navbar-login) and the update log's pressed filter chip
++// (shipped.js) are --on-accent-strong on --accent-strong:
// that pair must read at 4.5:1 or better (WCAG AA, normal text) in every built-in theme. An axe survey
// found white on the accent (#3b82f6) at 3.67:1 on nine sites (roadmap WS-T task 3).
const assert = require('assert');
@@@ -17,6 +18,10 @@ const ratio = (a, b) => { const [x, y] = [lum(a), lum(b)].sort((p, q) => q - p);
const css = fs.readFileSync(path.join(__dirname, '..', 'navbar.js'), 'utf8');
assert.match(css, /\.openvibe-navbar-login \{[^}]*background: var\(--accent-strong, #1d4ed8\); color: var\(--on-accent-strong, #fff\)/, 'the button uses --accent-strong and --on-accent-strong');
++// The same pair on the selected filter chip of the shared update log (shipped.js), which the browser check
++// (openvibe-shared/browser-harness) found at 3.67:1 on every site's /updates page.
++const shipped = fs.readFileSync(path.join(__dirname, '..', 'shipped.js'), 'utf8');
++assert.match(shipped, /\.ov-shipped-chip\[aria-pressed="true"\]\{background:var\(--accent-strong,#1d4ed8\);border-color:var\(--accent-strong,#1d4ed8\);color:var\(--on-accent-strong,#fff\)\}/, 'the pressed chip uses the pair');
const low = [];
for (const t of BUILTIN_THEMES) {
const bg = t.variables['--accent-strong'], fg = t.variables['--on-accent-strong'];