Commit Graph
12 Commits
Author SHA1 Message Date
liquidraver bbf54cfe1b fix(rx-coverage): open at the configured map default, with its own saved viewport (#2033)
The coverage page opened at a hardcoded [51.0, 4.8] zoom 8 regardless of deployment, ignoring /api/config/map (#2032). It now follows the same precedence as the main map (URL hash, then saved position, then /api/config/map, then [37.6, -122.1] zoom 9) and persists its own position across visits, syncing lat/lon/zoom into the hash so a view is shareable.

The saved position lives under its own key, rx-coverage-view, and the page never reads or writes the main map's map-view: sharing the configured default was the bug, sharing the session position was not. Both suites assert map-view stays untouched after a pan, so reintroducing a shared write fails instead of passing quietly.

Also fixed here: selectedRx is now percent-encoded into the hash, and a generation counter stops a late /api/config/map response or a stale 150ms layout timer from building a map for a page that was already left.

Reviewed twice. Verified by mutation rather than by reading: writing map-view too, ignoring the saved coverage position, and dropping the /api/config/map fetch each make the unit suite exit 1, so it covers the feature, the fix and the rejected alternative. The deploy.yml invocation was confirmed to land inside Run Playwright E2E tests (fail-fast) by parsing the workflow, and CI run 35261689694 is the E2E suite's first real execution: Go prints 'RX coverage viewport regressions OK' and Playwright prints 'RX coverage viewport browser regressions OK'.

Worth recording for the next reviewer: that E2E asserted localStorage.getItem('map-view'), so wiring it into deploy.yml without updating the assertion would have turned the job red on its first ever run. It was registered in scripts/non-unit-tests.json but invoked by nothing, the gap tracked as #2037.

Merged by the interim maintainer without a second human reviewer: CI and the mutation checks above are the independent checks.

Fixes #2032
2026-09-17 22:02:36 +02:00
Alex B 893773338e chore(tests): move root test-*.js into tests/unit and tests/e2e (#2036)
Moves 290 root test-*.js into tests/unit (177, listed in test-all.sh) and tests/e2e (113, classified in scripts/non-unit-tests.json), per #1981 and PR-D of #1385. Root goes from 348 entries to 48. test-all.sh and test-fixtures/ stay put. The inventory guard now fails if a test reappears in the root or sits in the wrong folder.

Verified independently of the diff: the invoked sets are unchanged (test-all.sh 177 before and after, deploy.yml 96 before and after, both identical as sets), and a full local run of test-all.sh on master and on the branch produced 4702 output lines each whose only differences are absolute paths, stack-trace line numbers shifted by the REPO_ROOT line, the inventory wording and two perf ratios. The guard was mutation-checked: a test back in the root, a unit suite in tests/e2e, and a suite dropped from test-all.sh each make it exit 1. CI run 35246304316 ran 97 suites from tests/e2e and is green.

Follow-up 9335c51d finished the instruction files: no bare root test command is left in AGENTS.md, the squad charters, .github or docs, and every tests/ path they name resolves.

Merged by the interim maintainer without a second human reviewer: CI and the local runs above are the independent checks.

Known and deliberately out of scope: 18 of the 113 files in tests/e2e are invoked by no runner at all, and one of them cannot run anywhere because it requires jsdom, which is not a declared dependency. Tracked separately.
2026-09-17 19:06:07 +02:00
735d9eb516 fix(#1715): dark-theme role swatches via per-theme CSS tokens (#1757)
## Summary

Dark-theme variants of the neighbor-graph role swatches (`#ngRoleChecks`
labels on `/analytics?tab=neighbor-graph`) still failed WCAG AA after
#1720's light-theme fix because the swatches used inline
`style="color:#..."` from `customize.js` `DEFAULTS.nodeColors`
(palette-700) — bypassing the theme tokens entirely.

Measured before:

| Role | Color | vs `#1a1a2e` (dark) |
|---|---|---|
| repeater | `#dc2626` | 3.53:1 ❌ |
| companion | `#2563eb` | 3.30:1 ❌ |
| observer | `#8b5cf6` | 4.02:1 ❌ |

## Fix

- Defines `--role-{repeater,companion,room,sensor,observer}` in `:root`
(palette-700, ≥4.5:1 on white) and overrides them in both dark blocks
(`[data-theme="dark"]` + the `@media (prefers-color-scheme: dark)`
mirror) with palette-400/500 shades that clear AA on `#1a1a2e`.
- Refactors the neighbor-graph swatch DOM in `public/analytics.js` from
inline `style="color:${hex}"` to class-based `<span class="role-swatch
role-swatch--{role}">`, with matching CSS rules that read the tokens.
- Removes all 5 `#1715` entries from `tests/a11y-allowlist.yaml` per the
issue's acceptance criteria.

After:

| Role | Light (vs `#fff`) | Dark (vs `#1a1a2e`) |
|---|---|---|
| repeater | `#dc2626` 4.83:1 | `#ef4444` 4.53:1 |
| companion | `#2563eb` 5.17:1 | `#3b82f6` 4.64:1 |
| room | `#15803d` 5.02:1 | `#16a34a` 5.18:1 |
| sensor | `#b45309` 5.02:1 | `#d97706` 5.35:1 |
| observer | `#7c3aed` 5.70:1 | `#a78bfa` 6.27:1 |

## Tests

- `test-a11y-1715-dark-role-swatches.js` — CSS-driven WCAG AA probes for
the 5 per-theme `--role-*` tokens plus markup invariants (no inline
color span; class names present in `#ngRoleChecks` block).
- Red commit: `a09ec21c` — fails on assertion with 12
below-threshold/markup probes.
- Green commit: `f87dcd64` — all probes PASS.
- `tests/a11y-allowlist.yaml` shed all 5 entries; the umbrella
`test-a11y-axe-1668.js` (CI) is now the live-browser net for those
cells.

## Preflight overrides

- `check-xss-sinks.sh` flags `public/analytics.js:2502` (label
"observer" appears in an `innerHTML=\`tpl\`` line). The flagged token is
a hardcoded literal string — no user-controlled data flows into that
template. No template content changed in this PR; the flag is
preexisting noise from the heuristic scan and the gate ultimately marks
✅ pass.

Fixes #1715

---------

Co-authored-by: clawbot <clawbot@kpa.local>
Co-authored-by: clawbot <bot@example.com>
2026-06-20 16:15:58 -07:00
0765c2cc69 fix(#1718): drop prefix-tool a11y allowlist entries — subsumed by #1720 (#1736)
## Summary

PR #1720 (merged 2026-06-13) consolidated active button states onto the
shared `.btn-active-accent` rule that paints
`background: var(--accent-strong)` (`#2563eb`) +
`color: var(--text-on-accent)` (`#f9fafb`) = **4.95:1**, WCAG AA pass in
both themes. That subsumes the `#ptCheckBtn` / `#ptGenBtn`
color-contrast violations issue #1718 tracked, so the allowlist entries
are stale.

## Change

Drop the two `issue: 1718` entries from `tests/a11y-allowlist.yaml`:

```yaml
- route: '/analytics?tab=prefix-tool'
  selector: '#ptCheckBtn'
  rule: color-contrast
  issue: 1718
  expires_at: 2026-09-11
- route: '/analytics?tab=prefix-tool'
  selector: '#ptGenBtn'
  rule: color-contrast
  issue: 1718
  expires_at: 2026-09-11
```

No other tabs touched. `#1715` dark-theme work and other
`expires_at: 2026-09-11` entries are out of scope — separate issues,
separate PRs. No production CSS/JS modified (PR #1720 did the
substantive fix).

## Verification

The CI a11y gate (`test-a11y-axe-1668.js`) is the authoritative check.
It re-renders `/analytics?tab=prefix-tool` in dark+light × desktop+
mobile and asserts zero net violations against the trimmed allowlist.
With this PR the entries are gone — if PR #1720's fix were ever
reverted, the gate fails immediately with no allowlist masking it.

Local repro not attempted: sandbox chromium lacks the
`@axe-core/playwright` module (matches the documented limitation in
PR #1730 / PR #1723). CI is the source of truth for this gate.

## TDD note

Config-change exemption per workspace AGENTS.md:
- No test files modified.
- No production code modified.
- Config-only allowlist trim; CI must stay green without test edits.
- The gate itself is the test — dropping the allowlist entries IS the
  red→green transition (entries gone → axe runs unfiltered → must
  remain pass because #1720 fixed the root cause).

Mirrors the exact pattern accepted in PR #1722 (clock-health),
PR #1723 (subpaths), PR #1730 (nodes), and PR #1731 (rf-health) —
same allowlist-drop shape, same upstream PR #1720 fix.

## Preflight

`bash ~/.openclaw/skills/pr-preflight/scripts/run-all.sh origin/master`
— config-only change; PII grep on diff clean.

Fixes #1718.

Refs PR #1720, PR #1722, PR #1723, PR #1730, PR #1731.

Co-authored-by: Kpa-clawbot <bot@openclaw.local>
Co-authored-by: efiten <erwin.fiten@gmail.com>
2026-06-19 11:37:22 -07:00
Kpa-clawbotandopenclaw-bot 1476b857d9 fix(#1716): drop rf-health a11y allowlist entry — subsumed by #1720 (#1731)
Fixes #1716.

PR #1720 (merged 2026-06-13) consolidated `.rf-range-btn.active` — along
with `.clock-filter-btn.active`, `.subpath-jump-nav a`,
`.node-filter-option.node-filter-active`, `.subpath-selected`, and
`.analytics-time-range button.active` — into the shared
`.btn-active-accent` rule that paints `background: var(--accent-strong)`
(`#2563eb`) + `color: var(--text-on-accent)` (`#f9fafb`) = **4.95:1**,
WCAG AA pass in both themes.

That makes the `#1716` axe allowlist entry obsolete: the underlying
violation no longer reproduces. This PR drops the entry and adds a
dedicated per-issue regression gate so a future refactor that only
breaks `.rf-range-btn.active` (without touching the other consolidated
selectors covered by `#1719`) trips with a clear `#1716` citation.

## Strict TDD red→green

### RED — `bce51a60` (test-only)
Adds `test-a11y-1716-rf-range-btn-active.js`, a pure-CSS probe with
three assertions:
- **A1** — `.rf-range-btn.active` is routed through a rule whose body
sets `background: var(--accent-strong)` + `color:
var(--text-on-accent)`.
- **A2** — the legacy `var(--accent)` + `#fff` pair (2.75:1) does NOT
  reappear on any block listing `.rf-range-btn.active`.
- **A3** — numeric contrast on the resolved tokens is ≥ 4.5:1 in both
  light and dark themes.

Locally verified the test FAILS when the consolidated active-button
block is reverted to `background: var(--accent); color: #fff`:

```
PASS A3[light]: 4.95:1 (fg=#f9fafb bg=#2563eb)
PASS A3[dark]: 4.95:1 (fg=#f9fafb bg=#2563eb)
FAIL A1: .rf-range-btn.active is NOT routed through the consolidated (--accent-strong / --text-on-accent) pair — PR #1720 regression
FAIL A2: legacy 2.75:1 pair re-emerged on .rf-range-btn.active (bg=var(--accent) fg=#fff)

FAIL: 2 assertion(s) tripped on .rf-range-btn.active (issue #1716)
```

Then restored CSS — test passes green on the consolidated state from
master.

### GREEN — `eea79791`
Removes from `tests/a11y-allowlist.yaml`:

```yaml
- route: '/analytics?tab=rf-health'
  selector: 'button[data-range="24h"]'
  rule: color-contrast
  issue: 1716
  expires_at: 2026-09-11
```

### CI wiring — `b300ce6d`
Hooks the new probe into the same `.github/workflows/deploy.yml` step
that already runs `test-a11y-axe-1668-selftest.js` and
`test-issue-1705-subpath-contrast.js`, so the gate runs on every PR.

## Gate output (after green)

```
$ node test-a11y-1716-rf-range-btn-active.js
  PASS A1: .rf-range-btn.active routes to var(--accent-strong) + var(--text-on-accent)
  PASS A2: no legacy var(--accent) + #fff pair on .rf-range-btn.active
  PASS A3[light]: 4.95:1 (fg=#f9fafb bg=#2563eb)
  PASS A3[dark]: 4.95:1 (fg=#f9fafb bg=#2563eb)

PASS: .rf-range-btn.active gated by consolidated --accent-strong / --text-on-accent pair (issue #1716)
```

The umbrella `#1719` probe also still passes (`PASS: all 4 root-cause
patterns ≥ 4.5:1 in both themes`).

## Scope

Only the `rf-health` / `.rf-range-btn.active` line. The sibling
allowlist entries for `#1714` (nodes), `#1715` (neighbor-graph), and
`#1718` (prefix-tool) are out of scope — separate issues, separate PRs.
No production CSS touched (PR #1720 did the substantive fix).

## Files changed

- `tests/a11y-allowlist.yaml` (−5 lines: drop `#1716` entry)
- `test-a11y-1716-rf-range-btn-active.js` (+177 lines: new regression
gate)
- `.github/workflows/deploy.yml` (+1 line: wire the new gate)

## Preflight

All hard gates clean (PII, branch scope, red commit, CSS-var defined,
CSS self-fallback, LIKE-on-JSON, sync migration, async migration, XSS
sinks). All warnings clean.

---------

Co-authored-by: openclaw-bot <bot@openclaw.local>
2026-06-15 13:49:41 -07:00
Kpa-clawbot b695aec4ec fix(#1714): drop nodes a11y allowlist entry — subsumed by #1720 (#1730)
## Summary

PR #1720 (commit `a344ae0a`, merged 2026-06-13) introduced
`--status-green-text=#15803d` (5.02:1 on white) and routed the
`/analytics?tab=nodes` stat-card text usage to the new token. The
remaining contrast violation that issue #1714 tracked is gone, so the
allowlist entry is stale.

## Change

Drop the single allowlist entry tagged `issue: 1714` from
`tests/a11y-allowlist.yaml`:

```yaml
- route: '/analytics?tab=nodes'
  selector: '.analytics-stat-card:nth-child(1) > div:nth-child(1)'
  rule: color-contrast
  issue: 1714
  expires_at: 2026-09-11
```

No other tabs touched (#1715/#1716/#1718 remain — separate issues,
separate PRs).

## Verification

The CI a11y gate (`test-a11y-axe-1668.js`) is the authoritative check.
It re-renders `/analytics?tab=nodes` in dark+light × desktop+mobile and
asserts zero net violations against the trimmed allowlist. With this
PR, the entry is gone — if PR #1720's fix were ever reverted, the gate
fails immediately (nothing left to mask it).

Local repro was not attempted: prior PR #1723 (same allowlist-drop
shape, same upstream PR #1720) documented sandbox chromium failures
(musl/glibc + Vulkan/EGL); CI is the source of truth for this gate.

Before (current `master`, with entry present): CI a11y gate green
(the allowlist masks the now-fixed selector).
After (this PR, entry removed): CI a11y gate must remain green
because the underlying contrast was actually fixed by PR #1720.

## TDD note

Config-change exemption per workspace AGENTS.md:
- No test files modified.
- No production code modified.
- Config-only allowlist trim; CI must stay green without test edits.
- The gate itself is the test — adding a duplicate assertion file would
  not catch anything CI does not already catch.

Mirrors the exact pattern accepted in PR #1723 (subpaths allowlist
drop, same upstream PR #1720 fix).

## Preflight

`bash ~/.openclaw/skills/pr-preflight/scripts/run-all.sh origin/master`
→ all hard gates pass, all warnings pass. ("Red commit" gate notes
this is a config-change with no test commits, justified above.)

Partial fix for #1714 (will switch to `Fixes #1714` once CI a11y gate
confirms zero net violations on `/analytics?tab=nodes`).

Refs PR #1720, PR #1723.
2026-06-15 13:49:36 -07:00
Kpa-clawbotandcorescope-bot 92e001c093 chore(a11y): drop subsumed subpaths allowlist entries (#1713) (#1723)
## Summary
PR #1720 merged (commit `a344ae0a`) and introduced the shared
`.btn-active-accent` color-contrast rule, which subsumes the per-link
allowlist entries for the subpaths tab pills on
`/analytics?tab=subpaths`.

This PR removes the 4 now-stale allowlist entries tagged `issue: 1713`:
- `a[href$="#sp-pairs"]`
- `a[href$="#sp-triples"]`
- `a[href$="#sp-quads"]`
- `a[href$="#sp-long"]`

All four were `rule: color-contrast` exemptions on
`/analytics?tab=subpaths`.

## Verification
CI a11y gate (`test-a11y-axe-1668.js`) is the authoritative check — it
re-renders the route in dark+light × desktop+mobile and asserts zero net
violations against the trimmed allowlist. Local repro was attempted but
blocked by sandbox chromium issues (musl/glibc relocations on bundled
playwright chromium; host chromium hits Vulkan/EGL init failures).
Relying on CI a11y job for the green signal.

## TDD note
Config exemption per workspace AGENTS.md:
- No test files modified.
- Config-only allowlist trim; CI must stay green without test edits.

Partial fix for #1713 (will switch to `Fixes #1713` once CI a11y gate
confirms zero net violations on `/analytics?tab=subpaths`).

Co-authored-by: corescope-bot <bot@corescope>
2026-06-13 20:48:29 -07:00
Kpa-clawbotandKpa-clawbot ae88d38b12 chore(a11y): drop subsumed clock-health allowlist entries (#1717) (#1722)
## Summary

Drops the two stale `issue: 1717` entries from
`tests/a11y-allowlist.yaml`. Both were subsumed by PR #1720 (merged at
a344ae0a), which fixed the underlying color-contrast root causes on
`/analytics?tab=clock-health`:

| Removed entry | PR #1720 fix |
|---|---|
| `button[data-filter="all"]` (clock-health active filter) | P1: shared
`.btn-active-accent` class → 4.95:1 |
| `.skew-badge--no_clock` (count_max: 300) | P2: new
`--skew-badge-no-clock-bg` token → 7.56:1 |

Leaving these entries in place would mask any regression on those
surfaces, defeating the purpose of the gate.

## Scope

Config-only. Single file touched: `tests/a11y-allowlist.yaml`.

## TDD discipline

Per workspace AGENTS.md TDD exemption for config changes:
- **no test files modified**
- **config-only allowlist trim, CI green without test edits**

The local axe harness (`test-a11y-axe-1668.js`) cannot run in this
sandbox (Playwright/chromium boot issue — same constraint cited in PR
#1720). CI runs the same gate against the staging fixture and is the
source of truth.

## Verification

CI a11y-axe gate on this PR must show zero NEW violations on
`/analytics?tab=clock-health` after the entries are removed.

Partial fix for #1717 (will switch to "Fixes #1717" once CI confirms
zero violations on the clock-health tab post-removal).

Co-authored-by: Kpa-clawbot <bot@openclaw.local>
2026-06-13 20:48:26 -07:00
69fba8032d test(a11y): expand axe CI gate to all 14 analytics tabs + prefix-tool (#1706) (#1711)
## Summary

Closes #1706.

Expands the axe-core a11y CI gate (`test-a11y-axe-1668.js`) to cover the
7 missing analytics tabs plus the `prefix-tool` utility surface. Before
this PR, only 7 of 14 analytics tabs were gated; the other 7 could
regress on contrast/aria without CI noticing.

## Changes

**`test-a11y-axe-1668.js`** — adds 8 hash-routes to `ROUTES`:

- `/analytics?tab=subpaths`
- `/analytics?tab=nodes`
- `/analytics?tab=distance`
- `/analytics?tab=neighbor-graph`
- `/analytics?tab=rf-health`
- `/analytics?tab=clock-health`
- `/analytics?tab=scopes`
- `/analytics?tab=prefix-tool`

The `prefix-tool` route was verified by greppping `public/analytics.js`:
the dispatch arm is `case 'prefix-tool':` (line 292), the nav button
uses `data-tab="prefix-tool"` (line 132), and existing UI cross-links
use `#/analytics?tab=prefix-tool` (lines 1467, 1469, 1795, 3064). It
lives in the analytics tab strip, not a separate `/tools/...` route.

`REGISTERED_ANALYTICS_TABS` already lists all 15 tabs (the selftest's
reciprocity check kept the constant honest), so no sibling slug-list at
line ~82 needed updating beyond the existing list.

**`test-a11y-axe-1668-selftest.js`** — adds a meta-assertion that loops
over `REGISTERED_ANALYTICS_TABS` and asserts each `tab` has a matching
`/analytics?tab=<tab>` entry in `ROUTES`. This locks the gate forever:
any new analytics tab added to `analytics.js` will fail the selftest
unless its route is also gated.

## TDD shape (red → green)

- **Red commit** `a1d9aa8e` — adds the meta-assertion to the selftest.
Selftest fails with `#1706: ROUTES missing analytics tab coverage for
"/analytics?tab=subpaths"` (asserted, not a build error).
- **Green commit** `501d9572` — adds the 8 missing entries to `ROUTES`.
Selftest passes: `routes=24 themes=2 allowlist=0`.

Cell count: 24 routes × 2 themes × 2 viewports = **96 cells** (was 64).

## Allowlist / tracking issues

None yet. The 7 new analytics tabs and `prefix-tool` have not yet been
exercised by the full axe browser run in CI — that happens when this PR
runs. Per the M5 policy embedded in the gate's header, if any of the new
routes fails axe on first run, a follow-up tracking issue + per-policy
allowlist entry will be filed (the violations will NOT be silenced in
this PR, and the routes will NOT be removed). I'll watch CI and report
back.

## Out of scope

Per the issue:

- No keyboard-nav / focus-visible coverage (separate gap).
- No modal / slideover open-state scans (separate gap).
- No tufte / density work.
- No source-code modifications to any analytics tab (contrast/aria fixes
happen in follow-up PRs, not here).

## Preflight

Ran `bash ~/.openclaw/skills/pr-preflight/scripts/run-all.sh
origin/master` — all hard gates pass, no warnings.

## Verification

```
$ node test-a11y-axe-1668-selftest.js
PASS: a11y-axe-1668 selftest — routes=24 themes=2 allowlist=0
```

---------

Co-authored-by: clawbot <bot@kpa-clawbot.local>
Co-authored-by: Kpa-clawbot <bot@openclaw.local>
Co-authored-by: openclaw-bot <bot@openclaw>
2026-06-13 10:54:24 -07:00
d954ea7444 feat(#1668): axe-core CI gate for WCAG AA color-contrast (M5) (#1696)
Partial fix for #1668 (M5 of 6).

After M1 (audit), M2 (color tokens, #1676), M3 (typography floor,
#1679), and M4 (per-route polish, #1681) cleared ~95% of
contrast/typography violations, M5 **locks in the wins** by adding an
axe-core CI gate that fails the build on any new WCAG AA color-contrast
regression.

## What's in the box

- `test-a11y-axe-1668.js` — Playwright + `@axe-core/playwright`. Runs
every major CoreScope route × `{dark, light}` at 1200×900 desktop,
injects axe, runs only the `color-contrast` rule, asserts net violations
=== 0.
- `test-a11y-axe-1668-selftest.js` — fast, deterministic, browser-free
unit test that exercises the YAML allowlist parser, the
`violationAllowed` matcher, and the route/theme metadata. Runs in the JS
unit block (no browser needed).
- `tests/a11y-allowlist.yaml` — operator-flagged false-positive
allowlist. **0 entries at M5 baseline.**

## Allowlist format

Each entry MUST cite a GH issue # and an `expires_at` date. Missing
fields = refused. Expired `expires_at` = refused (warning logged). This
**forces a periodic revisit** — no permanent suppressions.

```yaml
- route: /analytics?tab=channels
  selector: ".some-known-stale-element"
  rule: color-contrast
  issue: 1234
  expires_at: 2026-09-01
```

## Routes covered (19 × 2 themes = 38 cells)

`/`, `/packets`, `/nodes`, `/channels`, `/live`, `/map`, `/observers`,
`/compare`,
`/analytics?tab={overview,rf,topology,channels,hashsizes,collisions,roles,airtime}`,
`/audio-lab`, `/customize`, `/replay`.

## TDD red→green

- **RED** (`08adafdb`) — adds the gate + deliberately regresses
`--text-muted` from `palette-gray-700` (~10:1) to `#9ca3af` (~2.4:1).
axe-core fails on every light-theme cell.
- **GREEN** (`f62fb1e0`) — restores the M2 token. Net violations = 0
across all 38 cells.

## Scope discipline

- Only `color-contrast` (matches M2/M3/M4 scope). M6 owns `image-alt`,
`aria-required-attr`, `label`, mobile viewports, and letsmesh A/B.
- No new design tokens.
- M2-M4 tokens untouched.

## CI wiring

- `.github/workflows/deploy.yml:155` — selftest in JS unit block.
- `.github/workflows/deploy.yml:367` — real axe browser run in the
Playwright E2E block after the fixture server is up.

## Deps

`@axe-core/playwright@4.11.3` + `axe-core@4.12.1` added to
`devDependencies`. Pinned versions.

---------

Co-authored-by: openclaw-bot <bot@openclaw.local>
Co-authored-by: clawbot <clawbot@users.noreply.github.com>
2026-06-12 20:00:35 -07:00
Kpa-clawbotandmeshcore-bot e74e860725 fix(#1648): final emoji leaks — .obs-clock-naive-chip warning + analytics Channels encrypted group labels (#1665)
## What

Two Phosphor lint-gate breaches found by the v3.8.4 manual-test executor
— app-controlled UI labels still shipping raw emoji glyphs that the M6
final sweep (#1648) missed. One PR, two sprite swaps, same playbook as
#1657.

### Findings

| Test ID | Surface | Glyph | File:line | Fix |
|---|---|---|---|---|
| v384-1.2 | `/observers` `.obs-clock-naive-chip` | `⚠️` (U+26A0) ×14 |
`public/observers.js:30` | `ph-warning` sprite |
| v384-12.18 | `/analytics?tab=channels` encrypted row name cells | `🔒`
(U+1F512) ×158 | `public/analytics.js:978–979` | `ph-lock` sprite |

Finding 2 is a different surface from the M3/#1657 fix (which swapped
the section-header label, not the per-row `displayName`). The
unknown-encrypted row's `displayName` carried a raw `🔒 Encrypted (0xNN)`
text label that then flowed through `esc()` into the rendered name cell
as an escaped emoji glyph — exactly the same `innerText → innerHTML`
class of bug. Refactored to mirror the section-header pattern:
`displayNameHtml` carries the sprite-bearing raw HTML; `displayName`
stays plain text for sort/aria/tests.

## TDD

- **RED** `cde12370` — `test-issue-1648-followup-phosphor-leaks.js`
asserts ph-warning sprite + zero ⚠ in chip output, and ph-lock sprite +
zero 🔒 in analytics row labels. 6 assertions failed on master.
- **GREEN** `f1c64b17` — sprite swaps applied. All 9 assertions pass.
- **Anti-tautology proven both directions**: reverting only
`public/observers.js` → 2 chip-related assertions fail; reverting only
`public/analytics.js` → 4 analytics-related assertions fail.

## Verify

- ✅ `node test-issue-1648-followup-phosphor-leaks.js` — 9/9 pass
- ✅ `node test-issue-1648-m6-final-sweep.js` — 0 violations
- ✅ `node test-observer-naive-clock-1478.js` — 8/8 pass (existing chip
test accepts ph-warning sprite)
- ✅ `node test-analytics-channels-integration.js` — pre-existing
unrelated `Channel Analytics` failure only; encrypted-row assertions all
pass with new plain-text `displayName`
- ✅ pr-preflight all gates green (PII, branch-scope, red-commit,
CSS-var, LIKE-on-JSON, async-migration, XSS sinks)
- ✅ Browser-verified on staging: 11 chips render ph-warning sprite (0
emoji), 156 ph-lock sprites in row name cells (0 lock emoji on page)

Browser verified: http://analyzer-stg.00id.net/#/observers +
/#/analytics?tab=channels (hot-patched)
E2E assertion added: `test-issue-1648-followup-phosphor-leaks.js:67`
(chip), `test-issue-1648-followup-phosphor-leaks.js:147` (row cell)

---------

Co-authored-by: meshcore-bot <bot@meshcore.dev>
2026-06-11 18:29:30 -07:00
Kpa-clawbotandBot 89eade6e7b M6: emoji → Phosphor — final sweep, lint gate, carry-forwards (#1648) (#1654)
Red commit: fe7468d473 (CI run: will
appear in this PR's Checks tab — emoji lint test fails on the red
commit, passes on green)

**Fixes #1648.**

Closes the 6-milestone emoji→Phosphor migration started in #1649.

## Sweep results (real UI icons swapped this PR)

| File:line | Before | After |
|---|---|---|
| `public/index.html:140` | ⭐ | `ph-star-fill` |
| `public/mobile-page-actions.js:154` | ⭐ | `ph-star-fill` |
| `public/geofilter-builder.html:76` | ⬇ | `ph-download-simple` |
| `public/analytics.js:2103` | ⏱️ | `ph-clock` |
| `public/analytics.js:2288` | ⏰ | `ph-clock` |
| `public/analytics.js:4080` | ⏰ | `ph-clock` |
| `public/nodes.js:1066` | ⏰ | `ph-clock` |
| `public/observer-detail.js:284` | ⏰ | `ph-clock` |
| `public/channel-qr.js:133` | 📋 | `ph-clipboard-text` |
| `public/channel-qr.js:139` | ✓ | `ph-check` |
| `public/packets.js:1472` | ⏸ | `ph-pause` |

## Carry-forwards addressed

- **M5 CDP — live `.cust-emoji-preview` re-render** —
`public/customize-v2.js:2434` wires `renderConfigGlyph` to the `input`
event so previews update without Save+reload. (commit `9e698a04`)
- **M5 CDP — `.modal-close` 44×44 mobile** — `public/style.css` adds a
≤640px breakpoint bumping both `.modal-close` and `.ch-modal-close` to
WCAG-minimum hit targets. (commit `9e698a04`)
- **M4 CDP — route-hop fallback color** — `public/route-render.js` now
reads `var(--status-info)` (new token added to `:root` and dark-mode
blocks in `style.css`) instead of baked `#3b82f6`. (commit `9e698a04`)
- M2 carry-forward set (⭐ favStar / ▾ More / ⚠️ clock / 🌱⚡ welcome
cards) verified already addressed by re-running M3 emoji scan — all
green.

## Lint gate (M6 headline)

- Test: `test-issue-1648-m6-final-sweep.js` — full repo scan across
`public/**.{js,html,css}` and `cmd/(server|ingestor|decrypt)/*.go`.
- Self-test: `test-issue-1648-m6-lint-self.js` — exercises the lint
engine + anti-tautology probe.
- Allowlist: `tests/emoji-allowlist.txt`. Format: `path` (glob),
`path:line`, `path:line:U+XXXX`, or `/regex/`. Add intentional emojis
here with a `# why` comment.
- Wired into `test-all.sh` alongside M1/M2/M3 scans.

## routes.go smoke check

Server-side defaults in `cmd/server/routes.go:567-574` confirmed
`ph:bluetooth`/`ph:radio`/`ph:broadcast`/`ph:repeat` (M5 landed).
Operator-customized configs on staging/prod still carry their legacy
emoji overrides — per M5 design call those are preserved and NOT touched
by this PR.

## PR closing list

Fixes #1648. M1 #1649 ✅, M2 #1650 ✅, M3 #1651 ✅, M4 #1652 ✅, M5 #1653 ✅,
this PR ✅.

---------

Co-authored-by: Bot <bot@corescope>
2026-06-11 05:44:37 -07:00