Skip to content

feat(ui): warn on 1-byte path hash in channels, packet detail and node badge (#353) - #356

Merged
dborup merged 11 commits into
masterfrom
codex/issue-353-path-hash-1byte-warn
Oct 8, 2026
Merged

dborup merged 11 commits into
masterfrom
codex/issue-353-path-hash-1byte-warn

Conversation

@dborup-agent

@dborup-agent dborup-agent commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Relates to #353

Summary

A 1-byte path hash reads as an amber recommendation (not a red error) in all three places it appears. 2- and 3-byte hashes stay neutral, and missing or invalid sizes still render nothing. This reflects the operator decision on #353 (2026-10-07): 1-byte is the firmware default and the MeshCore FAQ still recommends it for companions, so it is surfaced as "use a 2- or 3-byte path hash", not an error.

Place After (1-byte)
Channel message "Sent with" badge (public/channels.js) .ch-path-hash-badge--warn, warning icon, factual Sent with: 1-byte + sr-only — recommended: 2- or 3-byte path hash, recommendation tooltip
Packet detail Hash Size row (public/packets.js) .detail-hash-size--warn, warning icon, factual 1 byte + the same sr-only recommendation
Node detail badge (renderNodeBadges, public/nodes.js) .node-path-hash-badge--warn, warning icon, visible label Recommended: 2- or 3-byte path hash

Design

  • One shared helper (DRY): public/app.js has isPathHashSizeWarn(size) for the decision (1 = recommend), pathHashSizeValue(size) to cast at the boundary (only a number or numeric string 1–3 counts), and renderPathHashSize(size, text, { block, cls, title, recInLabel }) for the markup. All three call sites use it.
  • Recommendation, not error (tone):
    • Palette: --path-hash-warn defaults to var(--warning) (amber) instead of var(--danger) (red), in the light semantic :root. The dark blocks redefine --warning, so the variable follows both themes. Mapped in the customizer as pathHashWarn (Advanced row, label, hint). No hardcoded colours.
    • Icon: a Phosphor ph-warning glyph (a warning/advisory glyph, not an error glyph), aria-hidden="true", so the cue never relies on colour alone.
    • Wording: the tooltip leads with "Recommended: use a 2- or 3-byte path hash. …"; the node badge shows "Recommended: 2- or 3-byte path hash" as its visible label; the inline channel/packet sites keep their factual value and carry the recommendation in an sr-only clause (no "Warning:" prefix).
  • Tooltip comes from the firmware docs: companion app Settings → Experimental Settings (firmware/docs/faq.md §3.9.3); repeater adverts set path.hash.mode 1|2 (§3.9.4, cli_commands.md); repeaters older than 1.14 drop 2/3-byte packets, so switch once most of the mesh runs 1.14+ (§3.9.1 / §3.9.6).
  • No empty row: hashSizeDetailHtml is gated on the shared helper's output, so a size the helper rejects renders no row instead of an empty <dd></dd> (round-2 review, finding 2).

WCAG AA contrast (round-2 review, finding 1)

--danger on the light packet-detail background was 4.43:1 (< AA). The amber --warning passes AA (≥ 4.5:1) on every surface it renders on, in both themes — measured in-browser:

Site Light (fg #b45309) Dark (fg #fcd34d)
Channel badge (on #ffffff / #232340) 5.02:1 10.51:1
Node badge (on #ffffff / #232340) 5.02:1 10.51:1
Packet-detail row (on #f4f5f7 / #0f0f23) 4.60:1 13.09:1

Tests

  • test-issue-353-path-hash-warn.js: helper decision; warn class, icon, recommendation sr clause vs recInLabel label; --path-hash-warn defaults to var(--warning) (not --danger); neutral 2/3; empty output for invalid sizes; escaping.
  • test-channels-observed-path-hash-size.js, test-packets.js, test-frontend-helpers.js, test-customizer-v2.js: the three call sites and the customizer mapping/hint, incl. the no-empty-row guard.
  • test-issue-353-path-hash-warn-e2e.js (in deploy.yml): channels, packet detail (stubbed 1- and 2-byte) and node detail (fixture nodes with hash_size 1 and 2), in light desktop, dark desktop, light 375×812, dark 375×812, and manual dark toggle on a light OS. Each checks the warn class, a visible aria-hidden icon, the recommendation sr/label, the recommendation tooltip, that the computed colour equals --path-hash-warn = --warning (and ≠ --danger), no horizontal overflow, and a WCAG AA color-contrast check (real @axe-core/playwright, with a direct-luminance fallback when axe's overlap heuristic leaves a narrow-viewport badge "incomplete").

Results and CI per job follow in a report comment.

🤖 Generated with Claude Code

dborup and others added 3 commits October 7, 2026 17:03
Unit tests for the shared isPathHashSizeWarn/renderPathHashSize helper,
the channel "Sent with" badge, the packet-detail Hash Size row, the node
badge and the customizer mapping, plus a browser regression in light and
dark theme and at 375x812. All fail until the warning is implemented.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e badge (#353)

One shared helper in app.js decides (size 1 = warning) and renders the
markup for all three places: the channel "Sent with" badge, the
packet-detail Hash Size row and a new node-detail badge. The warning has
a Phosphor warning icon (aria-hidden), sr-only text and a tooltip naming
the firmware settings (companion app Experimental Settings, repeater
path.hash.mode; firmware/docs/faq.md 3.9.x). Colour comes from the new
--path-hash-warn (default var(--danger)), mapped in the customizer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
renderPathHashSize and isPathHashSizeWarn live in app.js and are used
from channels.js, packets.js and nodes.js; the no-undef gate needs them
listed like senderPathHashSize.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dborup-agent

Copy link
Copy Markdown
Collaborator Author

Rapport — CS-pve-agent2 PR#356 #353 — head 7be5b5a

Status: Implemented and green. All three places warn on a 1-byte path hash through one shared helper. CI passes on head 7be5b5a1. Still a draft for review.

Evidence tags: [T] test run (local or CI), [A] analysis or code reading, [K] known or caveat.

Requirements

# Requirement Test (red before → green after) Mutant (killed by)
1 Channel "Sent with" badge warns on 1-byte; 2/3-byte neutral; invalid → no badge test-channels-observed-path-hash-size.js (3 new cases): before, the file aborts because app.js declares no helper; after, 13/13 pass [T]. E2E test-issue-353-path-hash-warn-e2e.js, channel step ×4 variants: before 0 warn badges, after pass [T] badge bypasses helper → unit and E2E red [T]; warn on 2-byte → red [T]
2 Packet detail Hash Size row warns on 1-byte test-packets.js (4 new): 4 ❌ before → 158/158 after [T]. E2E packet steps (stubbed 1-byte and 2-byte frames): red before → pass after [T] row rendered plain → unit and E2E red [T]
3 Node detail badge on a 1-byte node, not on 2/3 (Multibyte kept), not on null/0/4 test-frontend-helpers.js (3 new): 1 ❌ before → 712/712 after [T]. E2E node step on real fixture nodes with hash_size 1 and 2: red before → pass after [T] badge dropped → unit and E2E red [T]; badge on every size → red [T]
4 One shared helper for decision and markup (DRY) test-issue-353-path-hash-warn.js (new) tests isPathHashSizeWarn, pathHashSizeValue, renderPathHashSize from app.js as shipped (no copies): before, aborts (no helper); after, 14/14 [T]. All 3 call sites use it [A] warning icon dropped → 4 suites red [T]
5 --path-hash-warn (default var(--danger)), mapped in the customizer same file: :root default and no hardcoded colour in the rules [T]. test-customizer-v2.js (3 new): mapping, applyCSS override, label/hint/Advanced row: 3 ❌ before → 63/63 after [T]. E2E: computed colour = --path-hash-warn = --danger in light and dark [T]. Browser: Advanced row override sets the var [T] colour hardcoded in CSS → red [T]; key unmapped → red [T]; colour rule removed → E2E red [T]
6 Icon (not colour alone) and tooltip; setting name from the firmware Unit and E2E: ph-warning icon is visible and aria-hidden; sr-only Warning: text [T]. The tooltip names the companion setting Settings → Experimental Settings (firmware/docs/faq.md §3.9.3) and the repeater command path.hash.mode 1/2 (§3.9.4, cli_commands.md), and gives the pre-1.14 caveat (§3.9.1, §3.9.6) [A][T] covered by the icon-dropped mutant [T]
7 Browser check: light, dark, 375×812 The E2E runs channels, packet detail and node detail in light desktop, dark desktop, light 375×812 and dark 375×812: 20/20, with no horizontal overflow and the warning on-screen [T]. Screenshots checked by eye [T] n/a

Mutant totals: 8 unit mutants and 4 E2E mutants, all killed [T].

Invariants

  • cmd/server read-only: the diff touches no Go files (git diff origin/master -- cmd/ internal/ is empty) [T]
  • No new map[string]interface{}: 0 in the diff [T]
  • No hardcoded colours: the new CSS uses only var(--path-hash-warn) and existing tokens, checked by a unit test [T]
  • scripts/check-xss-sinks.sh --diff origin/master: clean, exit 0 [T]. Labels and titles go through escapeHtml and the tooltip is a constant [A]
  • Fork guards unchanged: deploy.yml 9, release-fast-path.yml 1 [T]
  • Perf: constant-time string building per badge or row, no new loops or fetches [A]

Local runs (prepared like CI: freshened e2e-fixture.db, inline seed, migrate, seeds 2073/199/245)

  • sh test-all.sh: 233 files passed, 0 failed [T]
  • node test-frontend-helpers.js: 712 passed, 0 failed [T]
  • cmd/server go test -timeout 20m ./...: ok [T]
  • cmd/ingestor go test ./...: ok with -timeout 60m [T]. The local 10m and 20m runs hit the timeout with 0 --- FAIL, at a different test each time. This host is slower than CI, and this PR changes no Go code [K]
  • Related E2Es on a local server: test-channels-observed-path-hash-size-e2e.js 8/8, test-packet-detail-sender-hash-size-obs-e2e.js 3/3, test-customize-theme-e2e.js 8/8, test-a11y-axe-1668.js 0 violations in 120 cells, the new Warn on 1-byte path hash: channel 'Sent with' badge, packet detail and node badge (recommend 2/3-byte) #353 E2E 20/20 [T]
  • eslint@8 public/*.js: 0 errors [T]

CI per job (head 7be5b5a1, run 37663726415)

Job Result
Go Build & Test pass [T]
Playwright E2E Tests pass. The new #353 E2E ran: 20 passed, 0 failed [T]
Build & Publish Docker Image pass [T]
Release Artifacts / Publish Badges & Summary / Deploy Staging skipping (fork-guarded) [T]

The first head, 963a81c6, failed Go Build & Test at the eslint no-undef step. The new helpers were not yet declared as globals in .eslintrc.json. This was a real failure, not the known-flaky #271. Commit 7be5b5a1 fixed it and lint passes [T]. No reruns were needed.

Leftovers

  • The customizer Advanced row "1-byte Path Hash" shows an empty (black) swatch until an override is set, because the server theme defaults do not carry this key. "Nav Active Pill" behaves the same way today. I left it this way so the default keeps following --danger [K]
  • The "1 = warning" threshold is hardcoded. A customizer option for the recommended minimum is a later milestone (AGENTS.md rule 8) [K]
  • The badge reflects the advert/frame width CoreScope observed (hash_size / header). It is not a guaranteed permanent sender setting [A]

@dborup-agent

Copy link
Copy Markdown
Collaborator Author

Review — CS-pve-agent3 PR#356 — head 7be5b5a

Dom: REQUEST CHANGES

This is an independent, read-only review. The design is sound: one shared helper drives all three sites, the token and the customizer are wired up, the tests are real and kill mutants, and the tooltip matches the firmware docs. There is one blocker. In the light theme, the new packet-detail warning fails WCAG AA colour contrast, and axe confirms it. CI did not catch it only because no axe route opens a 1-byte packet detail. The fix is small.

Evidence tags: [T] I ran it, [A] code or doc reading, [K] known, caveat or not verified.

Trees tested:

  • head 7be5b5a1.
  • merged = git merge-tree --write-tree origin/master 7be5b5a1… on origin/master 650218d4. The merge is clean and adds no Go diff [T].
  • git ls-remote showed 7be5b5a1 both before and after the review [T].

Findings

# Sev Where Finding Evidence
1 Medium (blocking) public/style.css .path-hash-warn / packet detail page In the light theme, the packet-detail Hash Size warning is #dc2626 (--danger) text on the page background #f4f5f7. That is 4.42:1, below the 4.5:1 AA minimum for 13px / weight 600, which is not "large" text. axe color-contrast flags it at 1400 px and at 375 px. Dark theme passes (6.82:1). The channel badge and both node badges sit on a white surface in light and on --surface-2 in dark, and pass (4.83:1 light, 5.48:1 dark). The repo's axe gate has a zero-violation policy. It passed in CI only because none of its 30 routes renders a 1-byte packet detail. [T] own Playwright + @axe-core/playwright run on the merged tree: "insufficient color contrast of 4.42 (foreground #dc2626, background #f4f5f7, 9.8pt)"
2 Low (nit) public/packets.js hashSizeDetailHtml The function returns early only on !hashSize and leaves range validation to renderPathHashSize. An out-of-range value such as 4 would emit <dt>Hash Size</dt><dd></dd>, an empty row where master printed "4 bytes". This is unreachable today, because senderPathHashSize returns only 1–3 or null. Gating the row on the helper's output would make it robust. [A]
3 Info public/nodes.js / product 59 of 204 fixture nodes (about 29%) get the new badge. A live mesh is likely to see far more, because 1-byte is the firmware default, and faq.md §3.9.3 still recommends 1-byte for companions until most repeaters run 1.14 or later. The tooltip states that caveat, and the scope is the operator's decision in #353. Flagged here so the operator sees how often the badge will appear. [T] fixture count, [A]
4 Info node detail The "Hash Prefix: 98 (1-byte)" row in node detail gets no warning. #353 asks only for a badge, so this is out of scope. [T] screenshot

Suggested fix for #1. Either option stays within #353:

  • (a) Give the packet-detail warning a surface pill, e.g. .detail-hash-size--warn { background: var(--surface-1); border: 1px solid var(--path-hash-warn); border-radius: …; padding: 0 4px; }. That mirrors the channel badge and gives 4.83:1.
  • (b) Default the light value to var(--palette-red-700) (#b91c1c, about 5.9:1 on #f4f5f7) and keep var(--danger) for dark. This departs from the letter of Warn on 1-byte path hash: channel 'Sent with' badge, packet detail and node badge (recommend 2/3-byte) #353 ("default var(--danger)"), so the operator would need to agree.

Whichever option is chosen, add an axe color-contrast assertion on the three warn elements to test-issue-353-path-hash-warn-e2e.js, so the gate covers these states. The current E2E checks that the colour equals --path-hash-warn, which cannot catch contrast.

Answers to the review points

  1. DRY. Yes [A][T].
    • isPathHashSizeWarn and pathHashSizeValue are the single decision. renderPathHashSize is the single markup.
    • All three sites call the helper: channels.js:74, packets.js:3618 and nodes.js:338-339. There is no per-page copy.
    • Of my mutants, M2 and M4 replaced the helper with an inline decision at a call site, and both were killed.
  2. Theming. Yes [A][T].
    • --path-hash-warn: var(--danger) is set in the light semantic :root. The dark blocks redefine --danger, and the computed colour follows it in both themes.
    • The token is mapped as pathHashWarn in THEME_CSS_MAP, with a label, a hint and an Advanced row. applyCSS writes it.
    • The diff adds no hardcoded colours. The only #… matches are #353 in comments.
    • The black swatch the author mentions is real but cosmetic, the same as navActiveBg today [K].
  3. Accessibility. Partly; see Foreign Traffic analytics + Scopes tab redesign #1.
    • The warning does not rely on colour alone: it has a Phosphor ph-warning icon with aria-hidden="true", and the visible text is preceded by sr-only Warning: [T].
    • Contrast fails in the light-theme packet detail [T].
    • The tooltip is in title only, the existing pattern in this codebase. Screen-reader users get the "Warning:" text but not the explanation [A].
    • The tooltip text matches the firmware docs, which I checked myself in firmware/ [A]:
      • The companion setting is "Settings (gear icon) → Experimental Settings" (faq.md §3.9.3).
      • The repeater command is set path.hash.mode {0|1|2}, where 1 means 2-byte and 2 means 3-byte (faq.md §3.9.4, cli_commands.md).
      • Repeaters older than 1.14 drop 2- and 3-byte packets (faq.md §3.9.1 / §3.9.6).
    • The node-badge remedy is also correct [A]:
      • Companion flood adverts use the same _prefs.path_hash_mode + 1 as messages (examples/companion_radio/MyMesh.cpp, sendFloodScoped).
      • Zero-hop 0x00 adverts are skipped by the server's computeNodeHashSizeInfo, so a zero-hop advert cannot cause a false 1-byte badge.
  4. Tests. Yes [T].
    • In all three places, 1-byte warns and 2- and 3-byte stay neutral.
    • Invalid sizes render nothing: undefined, null, 0, 4 and 'abc' for the channel badge, and null, undefined, 0 and 4 for the node badge.
    • Red before, green after: I ran the head's five unit files against origin/master code, and all five fail. The Warn on 1-byte path hash: channel 'Sent with' badge, packet detail and node badge (recommend 2/3-byte) #353 E2E against a master-frontend server gives 4 passed and 16 failed; the 4 that pass are just the "theme applied" sanity steps. On the merged tree, all pass.
  5. Browser. Yes, apart from Foreign Traffic analytics + Scopes tab redesign #1 [T].
    • The PR's E2E passed 20/20 against my local server, covering channels, packet detail and node detail in light and dark, on desktop and at 375×812, with no horizontal overflow. I checked the screenshots by eye.
    • My own script also covers the node side pane (row click in the nodes list), which the PR's E2E does not drive. The badge renders there too, with contrast 4.83 light and 5.48 dark, and no overflow at 375 px.
    • XSS gate: scripts/check-xss-sinks.sh --diff origin/master exits 0 on both head and the merged tree [T].

Invariants.

  • The diff touches no files under cmd/ or internal/, so cmd/server stays read-only [T].
  • 0 added map[string]interface{} [T].
  • Fork guards: deploy.yml 9 and release-fast-path.yml 1, both unchanged [T].
  • The PR body says "Relates to Warn on 1-byte path hash: channel 'Sent with' badge, packet detail and node badge (recommend 2/3-byte) #353". No closing keywords in the body or the commits [T].
  • All 3 commits are authored and committed by dborup, with the expected address [T].
  • No behaviour change beyond the purpose. Neutral 2- and 3-byte channel badges keep their text and title, which the E2E asserts. The packet row is now wrapped in a span. Multibyte is unchanged [A][T].

Tests and mutants (merged tree, local server prepared like CI)

The fixture was prepared as in CI: freshen, inline seed SQL, corescope-migrate, then seeds 2073, 199 and 245 [T].

Suite Result
sh test-all.sh 234 files passed, 0 failed [T]
node test-frontend-helpers.js 712 passed, 0 failed [T]
test-issue-353-path-hash-warn.js / test-channels-observed-path-hash-size.js / test-packets.js / test-customizer-v2.js 14/14, 13/13, 158/158, 63/63 [T]
cmd/server go test ./... rerun ok (849 s) [T]. The first run, made while test-all and E2E were loading the host, failed 3 TestHandleNodePaths_* tests with 503 {"error":"index loading"}. In isolation they passed 3/3. The merged tree has no Go diff against master, so this is load-timing flakiness, not something this PR causes [T][K]
cmd/ingestor not run. The PR has no Go diff, and CI "Go Build & Test" passed [K]
E2E: test-issue-353-path-hash-warn-e2e.js 20/20 [T]
E2E: test-channels-observed-path-hash-size-e2e.js / test-packet-detail-sender-hash-size-obs-e2e.js / test-customize-theme-e2e.js 8/8, 3/3, 8/8 [T]
E2E: test-a11y-axe-1668.js 0 violations in 120 cells [T]. The gate does not reach the 1-byte packet detail (#1)

My mutants, each applied alone to the merged tree and reverted afterwards [T]:

Mutant Killed by
M1: drop aria-hidden on the warning icon test-issue-353-path-hash-warn.js, test-channels-observed-path-hash-size.js
M2: node badge decision becomes Number(n.hash_size) <= 1 (bypasses the helper; fires on null/0) test-frontend-helpers.js
M3: --path-hash-warn defaults to var(--warning) test-issue-353-path-hash-warn.js
M4: packet row never warns (hashSize === 1 ? 2 : hashSize) test-packets.js
M5: pathHashSizeValue accepts 4 test-issue-353-path-hash-warn.js, test-channels-observed-path-hash-size.js
M6 (E2E): CSS .path-hash-warn .ph-icon { display: none }, which no unit test can see test-issue-353-path-hash-warn-e2e.js, 12/12 warn cells red ("warning icon missing, visible=false")

CI per job (run 37663726415, head 7be5b5a1) [T]:

Job Result
Go Build & Test success, including the eslint no-undef step
Playwright E2E Tests success. The log shows the #353 E2E ran: "20 passed, 0 failed"
Build & Publish Docker Image success
Release Artifacts / Deploy Staging / Publish Badges & Summary skipped (fork guards)

No known flaky failures (#256, #267) occurred.

Not verified

  • cmd/ingestor Go suite: not run locally, because there is no Go diff [K].
  • eslint: not run locally, because eslint@8 is not installed here. I relied on CI's lint step [K].
  • Customizer UI: the override was not exercised by hand in a browser. applyCSS is covered by unit tests, and test-customize-theme-e2e.js passes [K].
  • Screen readers: no real screen reader was used. I checked the DOM only (aria-hidden and sr-only text) [K].
  • Browsers: Chromium only. Firefox and WebKit were not checked [K].

dborup and others added 2 commits October 7, 2026 19:29
PR #356 review, round 2:

- F1: --path-hash-warn defaults to --danger (#dc2626), which is 4.43:1
  on the light packet page (--content-bg #f4f5f7), below WCAG AA 4.5:1.
  The unit test resolves the token from style.css in the light and both
  dark blocks and checks it against every surface the warning renders
  on. The E2E runs axe color-contrast on the three warning elements and
  requires axe to have measured them.
- F2: hashSizeDetailHtml(4) emits <dt>Hash Size</dt><dd></dd>. A width
  outside 1-3 must render no row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dborup

dborup commented Oct 7, 2026

Copy link
Copy Markdown
Owner

Scope note for the next round: per the operator decision on #353, the 1-byte flag becomes an amber recommendation (not a red error). Contrast must still meet WCAG AA in both themes.

dborup and others added 5 commits October 7, 2026 19:33
Mid-animation, axe samples a blended, lighter foreground (e.g. #e25b5c
on the light node page at 375px) and reports a contrast the settled page
never has. Wait until no running animation targets the warning element
or an ancestor before running color-contrast.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…353)

PR #356 review, round 2:

- F1: --path-hash-warn defaults to --palette-red-700 (#b91c1c) in the
  light theme: 5.93:1 on the packet page (#f4f5f7) and 6.47:1 on the
  white badge surfaces, where --danger (#dc2626) was 4.43:1 on the page.
  Both dark blocks set it back to --danger (#f87171): 6.82:1 on
  surface-0 and 5.48:1 on surface-2. The variable and the shared helper
  are unchanged, so the operator can still retune the tone.
- F2: hashSizeDetailHtml renders the Hash Size row only when
  renderPathHashSize returns markup, so a width outside 1-3 gives no row
  instead of an empty <dd>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…353)

The dark variants also set prefers-color-scheme: dark, so the media
block masked a missing --path-hash-warn override in the
[data-theme="dark"] block (#b91c1c on #0f0f23 is 2.92:1). A light-OS
context with the dark toggle exercises that block alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… error (#353)

Operator decision on #353 (round 3): a 1-byte path hash is a recommendation,
not an error. It is the firmware default and the FAQ still recommends it for
companions until most repeaters run 1.14+.

- --path-hash-warn now defaults to var(--warning) (amber) instead of
  var(--danger) (red), following the warning palette in both themes; still
  mapped in the customizer (pathHashWarn). This also clears the round-2
  blocker: red on the light packet-detail background was 4.43:1 (< AA);
  amber is 4.60:1. WCAG AA (>= 4.5:1) on every surface, both themes:
  channel/node 5.02:1 light / 10.51:1 dark, packet row 4.60:1 light /
  13.09:1 dark (measured in-browser).
- Wording reads as a recommendation, not a problem: the tooltip leads with
  "Recommended: use a 2- or 3-byte path hash", the node badge shows
  "Recommended: 2- or 3-byte path hash" as its visible label, and the inline
  channel/packet sites keep their factual value with an sr-only
  "— recommended: 2- or 3-byte path hash" clause (no "Warning:" prefix).
- Icon stays the warning glyph (ph-warning), not an error glyph, so the cue
  survives without colour.
- hashSizeDetailHtml now gates the row on the helper output, so an
  out-of-range width renders no row instead of an empty <dd></dd>
  (#356 review round 2, finding 2).

Tests updated (red before, green after); E2E gains an in-page WCAG AA
contrast assertion on all three sites in light and dark.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dborup-agent

Copy link
Copy Markdown
Collaborator Author

Rapport — CS-pve-agent3 PR#356 runde-2 — head 1c46e95

Review feedback addressed (commit 90c2e18e; head 1c46e95e)

Evidence tags: [T] I ran it (locally or in CI), [A] analysis or code reading, [K] known, caveat or not verified.

  1. F1 (blocking): contrast. In the light theme, --path-hash-warn now defaults to var(--palette-red-700, #b91c1c). Both dark blocks (prefers-color-scheme and [data-theme="dark"]) set it to var(--danger) (#f87171). This is the option (b) shape the review proposed, as this round's brief asked. The variable, the customizer key pathHashWarn and the shared helper are unchanged, so the operator can still retune the tone. I did not change the tone or which nodes get the warning: that policy waits for the operator.
    Contrast below is axe in Chromium on the merged tree, and matches my own WCAG calculation [T]. Before the fix, light packet detail was #dc2626 on #f4f5f7 = 4.43:1, a fail [T].

    Place Light Dark
    Channel "Sent with" badge (--surface-2) #b91c1c on #ffffff = 6.47:1 #f87171 on #232340 = 5.48:1
    Packet-detail Hash Size (page --content-bg) #b91c1c on #f4f5f7 = 5.93:1 #f87171 on #0f0f23 = 6.82:1
    Node badge (--surface-2) #b91c1c on #ffffff = 6.47:1 #f87171 on #232340 = 5.48:1

    In the packet side pane (--detail-bg) and on cards (--card-bg), the values are the same as on --surface-2: white in light, #232340 in dark. The unit test covers these surfaces; the E2E does not drive them [A][T].

  2. F2: empty row. hashSizeDetailHtml now renders the row only when renderPathHashSize returns markup. A width outside 1–3 (4, 5, -1, 255, NaN, 'x') gives no row instead of <dt>Hash Size</dt><dd></dd>. Null, undefined and 0 still give no row [T].

  3. F3 (info): badge frequency. No change. Which nodes get the warning is the operator's decision in Warn on 1-byte path hash: channel 'Sent with' badge, packet detail and node badge (recommend 2/3-byte) #353 [K].

  4. F4 (info): "Hash Prefix (1-byte)" row. No change. It is outside the scope of Warn on 1-byte path hash: channel 'Sent with' badge, packet detail and node badge (recommend 2/3-byte) #353 [A].

The PR body's Theming and Tests bullets said --path-hash-warn defaults to var(--danger), which is no longer true. I updated them to match. The PR is still a draft.

Commits (all by dborup <kontakt@meshview.dk>; no rebase, amend or force-push)

Commit What
628c5545 test: red tests for F1 (unit contrast plus E2E axe) and F2
f13eb735 merge origin/master 2dc04642, clean, no conflicts
25c4dd34 test: the E2E axe check waits for fade-ins. Mid-animation, axe sampled a blended #e25b5c (3.48:1) on the light node page at 375 px, which the settled page never shows
90c2e18e fix: F1 and F2
1c46e95e test: a new E2E variant, dark toggle on a light OS (see M2)

Tests (red before, green after)

Finding Test Before fix After fix
F1 test-issue-353-path-hash-warn.js: resolves --path-hash-warn from style.css (light :root and each dark block) and checks it is at least 4.5:1 on --content-bg, --detail-bg, --surface-2 and --card-bg. Also checks that both dark blocks set the token, to the same value 2 ❌ ("#dc2626 on --content-bg #f4f5f7 is 4.43:1", "a dark block lacks --path-hash-warn") [T] 17/17 [T]
F1 test-issue-353-path-hash-warn-e2e.js: axe color-contrast on each of the three warning elements. It requires 0 violations and that axe actually measured the element (a pass, not "incomplete"). The colour check is now color = --path-hash-warn; the old "= --danger" check is dropped 2 ✗: light desktop and light 375 packet detail, "insufficient color contrast of 4.42 (#dc2626 on #f4f5f7)" [T] 25/25, run twice locally [T]
F2 test-packets.js: "an out-of-range width renders no Hash Size row, never an empty one" 1 ❌ ("for 4") [T] 166/166 [T]

Mutants (each applied alone on top of the fix, then reverted)

Mutant Killed by
M1 (F1): light --path-hash-warn back to var(--danger) unit: light contrast ❌ 4.43:1. E2E: 2 ✗, axe on light packet detail [T]
M2 (F1): [data-theme="dark"] block loses its --path-hash-warn override unit: 2 ❌ (out of sync; #b91c1c on #0f0f23 = 2.92:1) [T]. The first E2E run did not catch it (20/20), because its dark variants also set the OS to dark, so the media block masked the missing override. The new variant (1c46e95e) runs the dark toggle on a light OS, and the E2E now kills M2 with 3 ✗ (axe on channel, packet and node) [T]
M3 (F2): row no longer gated on the helper output (old if (!hashSize) shape) test-packets.js ❌ "for 4" [T]

Local runs (merged tree; fixture prepared like CI: copied e2e-fixture.db, freshen, inline seed SQL, corescope-migrate, seeds 2073/199/245; local Go server -public public)

  • sh test-all.sh: 234 files passed, 0 failed [T]
  • node test-frontend-helpers.js: 712 passed, 0 failed [T]
  • test-issue-353-path-hash-warn.js 17/17, test-packets.js 166/166, test-channels-observed-path-hash-size.js 13/13, test-customizer-v2.js 63/63 [T]
  • cmd/server go test ./...: ok (899 s) [T]
  • cmd/ingestor go test ./...: ok (1018 s) [T]
  • E2E: test-issue-353-path-hash-warn-e2e.js 25/25 [T]
  • E2E: test-channels-observed-path-hash-size-e2e.js 8/8, test-packet-detail-sender-hash-size-obs-e2e.js 3/3, test-customize-theme-e2e.js 8/8 [T]
  • E2E: test-a11y-axe-1668.js 0 violations in 120 cells [T]
  • eslint@8 public/*.js: 0 errors (89 existing no-unused-vars warnings) [T]
  • scripts/check-xss-sinks.sh --diff origin/master: exit 0 [T]
  • Screenshots checked by eye: light packet detail at 375 px and light node detail on desktop. The warning reads as dark red with its icon, with no overflow [T]

Invariants

  • No Go diff against master (git diff origin/master...HEAD -- cmd internal is empty) [T].
  • 0 added map[string]interface{} [T].
  • No hardcoded colours outside :root. The #b91c1c fallback sits in the light :root next to the existing palette fallbacks [A].
  • Fork-guard counts (github.repository) are the same as master: deploy.yml 12/12, release-fast-path.yml 2/2 [T].

CI per job (run 37687784276, head 1c46e95e)

Job Result
Go Build & Test success [T]
Playwright E2E Tests success. The log shows the #353 E2E ran with "25 passed, 0 failed", and the axe gate reported "zero violations across 120 cells" [T]
Build & Publish Docker Image success [T]
Release Artifacts / Deploy Staging / Publish Badges & Summary skipped (fork guards) [T]

The known flaky tests #271 and #301 did not occur, and no reruns were needed [T].

Not verified

  • The node side pane is not driven by the E2E. It uses the same .node-path-hash-badge on --surface-2, so the values in the table apply [A][K].
  • Chromium only. No real screen reader [K].

…tion decision (#353)

# Conflicts:
#	public/packets.js
#	public/style.css
#	test-issue-353-path-hash-warn-e2e.js
#	test-issue-353-path-hash-warn.js
#	test-packets.js
@dborup-agent

Copy link
Copy Markdown
Collaborator Author

Rapport — CS-MacBook PR#356 runde-3 — head 1249b94

Review feedback addressed (commit 1249b94b). Round 3 implements the operator decision on #353: a 1-byte path hash is an amber recommendation, not a red error.

Evidence tags: [T] executed, [A] analysis/reading, [K] known/caveat.

  1. Operator decision — recommendation, not error (tone). --path-hash-warn now defaults to var(--warning) (amber) instead of var(--danger) (red), in the light semantic :root; the dark blocks redefine --warning, so the token follows both themes. Still mapped in the customizer as pathHashWarn (Advanced row, label, hint reworded to "Amber accent recommending a 2/3-byte over a 1-byte path hash"). The wording reads as a recommendation: the tooltip leads with "Recommended: use a 2- or 3-byte path hash …", the node badge's visible label is "Recommended: 2- or 3-byte path hash", and the inline channel/packet sites keep their factual value with an sr-only "— recommended: 2- or 3-byte path hash" clause (the "Warning:" prefix is gone). The icon stays ph-warning (a warning/advisory glyph, not an error glyph), aria-hidden, so the cue survives without colour. [A][T]

  2. Blocking (round-2 review F1) — WCAG AA contrast. --danger on the light packet-detail background was 4.43:1 (< AA). The amber --warning passes AA (≥ 4.5:1) on every surface, both themes — computed and measured in-browser, and confirmed by a real axe color-contrast check added to the E2E:

    Site (bg light / dark) Light fg #b45309 Dark fg #fcd34d
    Channel badge (#ffffff / #232340) 5.02:1 10.51:1
    Node badge (#ffffff / #232340) 5.02:1 10.51:1
    Packet-detail row (#f4f5f7 / #0f0f23) 4.60:1 13.09:1

    Worst case is 4.60:1 on the light packet detail — still above 4.5. [T]

  3. Nit (round-2 review F2) — no empty row. hashSizeDetailHtml is gated on the shared helper's output, so a width the helper rejects (null/0 or an out-of-range value) renders no row at all instead of an empty <dt>Hash Size</dt><dd></dd>. [T]

Tests (red before, green after)

  • sh test-all.sh: 234 files passed, 0 failed [T]
  • node test-frontend-helpers.js: 712 passed, 0 failed [T]
  • test-issue-353-path-hash-warn.js 15/15, test-channels-observed-path-hash-size.js 13/13, test-packets.js 166/166, test-customizer-v2.js 63/63 [T]
  • E2E test-issue-353-path-hash-warn-e2e.js on a local Go server (CI-prepared e2e-fixture.db): 25/25 — 5 variants (light/dark desktop, light/dark 375×812, and manual dark toggle on a light OS) × 5 steps, each asserting the warn class, a visible aria-hidden icon, the recommendation sr/label, the recommendation tooltip, colour = --path-hash-warn = --warning (≠ --danger), no horizontal overflow, and a WCAG AA color-contrast check [T]
  • Related E2Es: test-channels-observed-path-hash-size-e2e.js 8/8, test-packet-detail-sender-hash-size-obs-e2e.js 3/3, test-customize-theme-e2e.js 8/8 [T]
  • eslint public/*.js: 0 errors (pre-existing warnings only) [T]

Mutants (one per finding, applied alone, each killed, then reverted)

  • Tone (1): revert the sr clause to the error-style <span class="sr-only">Warning: </span> prefix → test-issue-353-path-hash-warn.js + test-channels-observed-path-hash-size.js red [T]
  • Contrast/token (2): --path-hash-warn back to var(--danger) → test-issue-353-path-hash-warn.js default assertion red, and the E2E fails on the light packet detail with contrast 4.43:1 < AA 4.5 (and colour ≠ --warning) [T]
  • No-empty-row (3): ungate hashSizeDetailHtml (if (!hashSize) return '') → test-packets.js "an out-of-range width renders no empty Hash Size row" red [T]

Branch state

This branch had received an independent round-3 push from another agent (628c5545…1c46e95e) that fixed the contrast blocker with a darker red (--palette-red-700) and kept the "Warning:" wording — i.e. it did not implement the operator's amber-recommendation decision. I merged that work (merge commit 1249b94b, non-force; their commits are preserved in history), resolved the design to the operator's amber decision, and kept their two useful test additions: the real @axe-core/playwright color-contrast check and the manual-dark-toggle variant. A direct-luminance fallback was added for the one case where axe leaves a narrow-viewport inline badge "incomplete" (an overlap heuristic, not a contrast failure); it still asserts ≥ 4.5:1. No rebase, amend or force-push. origin/master (2dc04642) is merged in. [A][T]

CI per job (run 37729327591, head 1249b94b)

Job Result
Go Build & Test success [T]
Playwright E2E Tests success — the #353 E2E ran 25/25 [T]
Build & Publish Docker Image success [T]
Release Artifacts / Deploy Staging / Publish Badges & Summary skipped (fork-guarded) [T]

No known-flaky (#271/#301) failures occurred; no reruns were needed. PR stays draft.

@adminopenclaw8-sketch

Copy link
Copy Markdown
Collaborator

Review — CS-Macmini PR#356 — head 1249b94

Dom: APPROVE med nits

Independent, read-only re-review of round 3. The operator decision is implemented as asked: a 1-byte path hash now reads as an amber recommendation in all three places, the wording carries the recommendation in text (no error phrasing, in the visible label or the screen-reader clause), the colour comes only from --path-hash-warn → --warning, and WCAG AA holds on every surface in both themes — I re-measured it in a browser rather than taking the table on trust. The parallel red round-3 push is fully absorbed: its CSS is gone with no residue or duplicate rules, its two useful test additions are kept, and the history is intact with no force-push. Everything left is cosmetic.

Evidence tags: [T] I ran it, [A] code or doc reading, [K] known, caveat or not verified.

Trees tested:

  • head 1249b94b (git ls-remote showed it before and after the review [T]).
  • merged = git merge-tree --write-tree origin/master 1249b94b… on origin/master ff9a501c. Clean merge, no Go diff [T].

Findings

# Sev Where Finding Evidence
1 Nit public/style.css:1990 The node badge's warn-only styling sits on the base class — .node-path-hash-badge { background: var(--surface-2); border: 1px solid var(--path-hash-warn); … } — not on the --warn modifier, unlike .ch-path-hash-badge--warn, which puts only border-color on the modifier. Harmless today, because nodes.js:342 is the one call site and it always passes 1. It does mean a future neutral use of the block would silently inherit the amber border, and it makes the three sites inconsistent about where the variant lives. [A]
2 Nit customizer With no override stored, the "1-byte Path Hash" colour input shows #000000 instead of the amber it will actually paint, because the token's declared value is var(--warning) rather than a literal. Pre-existing pattern, not introduced here: 3 of 39 colour inputs do this, including master's "Nav Active Pill". The override path itself works end to end — seeding pathHashWarn: #0000ff moved the root token and the packet-detail badge to rgb(0, 0, 255). [T]
3 Info test-issue-353-path-hash-warn.js The merge dropped round 2's unit-level numeric contrast harness (resolve the token chain out of style.css, compute WCAG against --content-bg / --detail-bg / --surface-2 / --card-bg in three theme states). Round 3 asserts only the chain --path-hash-warn: var(--warning). I checked whether that leaves AA unguarded and it does not: see mutant MM3 below — retuning the underlying --warning keeps every unit test green but the E2E axe check kills it at all three sites. The E2E gate is the stronger of the two, so this is a note, not a gap. [T]
4 Info public/nodes.js / product 59 of 204 fixture nodes (29%) get the badge. .badge uppercases it, so it reads "RECOMMENDED: 2- OR 3-BYTE PATH HASH" at 10px — a wide badge. In the nodes side pane it takes the full pane width and pushes the Details / Analytics / Reach buttons onto a second row. No clipping and no horizontal overflow at any viewport I measured, including 375×812. Scope is the operator's decision on #353; flagged so the visual weight is a conscious choice. [T]
5 Info public/packets.js hashSizeDetailHtml Deliberate behaviour change for an out-of-range width: master printed "4 bytes", head renders no row. That is exactly what round 2's finding 2 asked for, and it is unreachable today because senderPathHashSize returns only 1–3 or null. Noted so it is on the record as intended, not incidental. [T][A]

Answers to the review points

1. Operator decision (c): amber recommendation, not a red error. Yes, in all three places [T][A].

  • Channel badge (channels.js:71): ch-path-hash-badge ch-path-hash-badge--warn path-hash-warn, text Sent with: 1-byte + sr-only " — recommended: 2- or 3-byte path hash".
  • Packet-detail row (packets.js:3648): detail-hash-size detail-hash-size--warn path-hash-warn, text 1 byte + the same sr-only clause.
  • Node badge (nodes.js:342): badge node-path-hash-badge node-path-hash-badge--warn path-hash-warn, visible label Recommended: 2- or 3-byte path hash, no sr clause (correct — the recommendation is the label).
  • Tone. No "Warning:" prefix survives anywhere in the rendered output or the tests; the tooltip leads with "Recommended: use a 2- or 3-byte path hash." I grepped the diff and the DOM for error wording and found none [T]. The icon is ph-warning with aria-hidden="true" and a 16px box in every variant, so the cue does not depend on colour [T].
  • Colour. One declaration only: --path-hash-warn: var(--warning) in the light semantic :root. Both dark paths redefine --warning (#fcd34d at the prefers-color-scheme block and at [data-theme="dark"]), so the token follows the theme with no per-theme override needed. .path-hash-warn, .ch-path-hash-badge--warn and .node-path-hash-badge all reference the variable; no literal colour anywhere in the diff [A][T].
  • Customizer. Mapped as pathHashWarn → --path-hash-warn, label "1-byte Path Hash", hint "Amber accent recommending a 2/3-byte over a 1-byte path hash …", and it really is in the Advanced section — the panel renders it under "Advanced (16 options)" [T]. See nit 2 for the default swatch.
  • Tooltip vs. firmware docs, checked against firmware/ myself, not against the report [A]:
    • "MeshCore app Settings → Experimental Settings (message path hash size)" matches faq.md §3.9.3 word for word.
    • "set path.hash.mode 1 (2-byte) or 2 (3-byte)" matches §3.9.4 and cli_commands.md (0 = 1 byte, 1 = 2 byte, 2 = 3 byte, default 0).
    • "repeaters older than 1.14 drop 2/3-byte packets, so switch once most of your mesh runs 1.14+" matches §3.9.3 and the Temporary Note in cli_commands.md.

2. WCAG AA — measured, not only calculated. Confirmed, and my numbers reproduce the report's table exactly [T].

Measured in Chromium against a local Go server with the CI-prepared fixture: computed color of the element, and the first opaque ancestor background, with the ratio computed from sRGB luminance.

Site Light #b45309 Dark #fcd34d
Channel badge (on #ffffff / #232340) 5.02:1 10.51:1
Node detail badge (on #ffffff / #232340) 5.02:1 10.51:1
Packet-detail row (on #f4f5f7 / #0f0f23) 4.60:1 13.09:1
Node side pane badge — not driven by the PR's E2E (on #ffffff / #232340) 5.02:1 10.51:1
  • Worst case is 4.60:1, as claimed. The packet-detail row genuinely sits on the page background #f4f5f7, not on --detail-bg, so 4.60 is the number that matters [T].
  • Run in five variants: light desktop, dark OS desktop, manual dark toggle on a light OS, light 375×812, dark 375×812. The manual-toggle variant gives the same dark values, i.e. --warning really is redefined in the [data-theme="dark"] block and not only in the media query [T].
  • No horizontal page overflow and no element past the viewport in any of the 5 × 4 cells [T].
  • Independent WCAG arithmetic on the token values agrees to the second decimal [T].
  • I also checked the other surfaces the token can land on: light --card-bg/--surface-1 = #ffffff → 5.02:1; dark --surface-1 #1a1a2e → 11.83:1. Nothing below 4.5 [A][T].

3. Integration of the parallel red round-3 push. Clean [T][A].

  • git diff 1c46e95e 1249b94b -- public/style.css shows the red variant removed in full: the light default var(--palette-red-700, #b91c1c) replaced by var(--warning), and both dark-block overrides --path-hash-warn: var(--danger) deleted. No leftovers.
  • grep -n 'path-hash-warn' public/style.css returns exactly 4 lines — one declaration and three rules. No duplicate or dead rule [T].
  • No palette-red-700, #b91c1c or #dc2626 anywhere in the PR's code or tests; the remaining repo hits are all pre-existing and unrelated [T].
  • The red branch's assertions are gone with it, so no test contradicts the amber design; the two additions the author said they kept really are kept — the real @axe-core/playwright color-contrast check and the manual-dark-toggle variant are both in test-issue-353-path-hash-warn-e2e.js [A].
  • History intact: 1c46e95e is still an ancestor of 1249b94b (git merge-base --is-ancestor succeeds), the merge commit has both parents, and all 10 commits in origin/master..head are present — no rebase, amend or force-push [T].

4. Nit F2 — no empty Hash Size row. Fixed [T]. I called hashSizeDetailHtml directly over its whole input range:

  • 1 → warn row; 2, 3, '2' → neutral row;
  • 0, 4, 5, -1, 255, NaN, null, undefined, 'x' → '', i.e. no row at all, never an empty <dd></dd>.

5. Invariants.

  • cmd/server read-only: the diff touches nothing under cmd/ or internal/ [T].
  • 0 added map[string]interface{} (there is no Go diff) [T].
  • No hardcoded colours in the diff [T].
  • scripts/check-xss-sinks.sh --diff origin/master: exit 0, and it did scan the changed public/** files rather than reporting nothing to scan [T].
  • Fork guards: deploy.yml 9, release-fast-path.yml 1 — identical to master [T].
  • No closing keywords in the PR body ("Relates to Warn on 1-byte path hash: channel 'Sent with' badge, packet detail and node badge (recommend 2/3-byte) #353") or in any of the 10 commits [T].
  • All 10 commits authored and committed by dborup <kontakt@meshview.dk> [T].
  • PR is still a draft [T].
  • No behaviour change beyond the purpose: the neutral 2/3-byte channel badge keeps byte-identical text and title (the shared helper reproduces master's markup when cls is unset), the packet row is now wrapped in a span, Multibyte is untouched. The one intentional difference is finding 5 [A][T].

Acceptance criteria → tests, red before and green after

I ran head's five test files against master's public/ and every one of them fails [T]:

#353 acceptance Test Against master On the merged tree
1-byte gets the warn class, icon and tooltip test-issue-353-path-hash-warn.js crashes — helper absent 15/15
2- and 3-byte get no warn class same + test-channels-observed-path-hash-size.js crashes — helper absent 13/13
invalid or missing sizes render no badge test-issue-353-path-hash-warn.js crashes 15/15
same for the packet-detail row test-packets.js ❌ 5 (hashSizeDetailHtml is not a function, plus "renderDetail must use the shared row helper") 166/166
same for the node badge test-frontend-helpers.js ❌ 1 (missing node-path-hash-badge--warn) 712/712
customizer mapping test-customizer-v2.js ❌ 3 (mapping, applyCSS, label/hint/Advanced) 63/63
browser, light + dark + mobile; XSS gate test-issue-353-path-hash-warn-e2e.js; check-xss-sinks.sh — 25/25; exit 0

Tests I ran (merged tree, fixture prepared like CI)

Fixture: fresh copy, tools/freshen-fixture.sh, the workflow's inline seed SQL, corescope-migrate, then seeds 2073, 199 and 245. Local Go server on a free high port, -public public, stopped afterwards by its listening pid.

Suite Result
sh test-all.sh 234 files passed, 0 failed [T]
node test-frontend-helpers.js 712 passed, 0 failed [T]
test-issue-353-path-hash-warn.js / test-channels-observed-path-hash-size.js / test-packets.js / test-customizer-v2.js 15/15, 13/13, 166/166, 63/63 [T]
cmd/server go test ./... ok, 38.8 s [T]
cmd/ingestor go test ./... ok, 105.1 s [T]
E2E test-issue-353-path-hash-warn-e2e.js 25/25 [T]
E2E test-channels-observed-path-hash-size-e2e.js / test-packet-detail-sender-hash-size-obs-e2e.js / test-customize-theme-e2e.js 8/8, 3/3, 8/8 [T]
eslint@8 public/*.js 0 errors, 89 pre-existing warnings [T]
My own contrast + tone probe (5 variants × 4 surfaces, incl. the side pane) all cells ≥ 4.60:1 [T]

Screenshots checked by eye: channels light and dark, packet detail light, node detail at 375×812, nodes side pane light and dark. The recommendation reads amber and advisory, clearly distinct from the red REPEATER role badge beside it, with the icon visible and nothing clipped [T].

Mutants

My own, each applied alone to the merged tree and reverted afterwards [T]:

Mutant Result
MM1 — isPathHashSizeWarn warns on 2-byte too (pathHashSizeValue(size) <= 2), i.e. the mutant #353 names explicitly Killed by all four suites: test-issue-353-path-hash-warn.js (5 ❌), test-channels-observed-path-hash-size.js, test-packets.js, test-frontend-helpers.js
MM2 — drop the sr-only recommendation clause (const rec = ''), i.e. the amber colour becomes the only cue at the inline sites Killed by test-issue-353-path-hash-warn.js, test-channels-observed-path-hash-size.js and test-packets.js. test-frontend-helpers.js survives, correctly — the node badge uses recInLabel and has no sr clause to lose
MM3 — retune the underlying light --warning from #b45309 to #d97706 (2.92:1 on the packet page), leaving --path-hash-warn: var(--warning) intact Unit tests survive (they assert the chain, not the number), but the E2E kills it: 6 ✗, real axe color-contrast on channel, packet detail and node detail in both light variants. This is the check behind finding 3

Author's mutant re-verified [T]: --path-hash-warn back to var(--danger) → test-issue-353-path-hash-warn.js red on the default assertion, and the E2E red with 15 ✗ across all five variants.

CI per job (run 37729327591, head 1249b94b)

Job Result
Go Build & Test success [T]
Playwright E2E Tests success — the log shows the #353 E2E ran with "25 passed, 0 failed" [T]
Build & Publish Docker Image success [T]
Release Artifacts / Deploy Staging / Publish Badges & Summary skipped (fork guards) [T]

I read the E2E job log myself; there are no failing assertions in it, and neither known flaky test (#256 Hash Stats sort, #267 backfill write-hold) appears — the only matches for those names are branch names printed during checkout [T].

Not verified

  • No real screen reader. I checked the DOM only: aria-hidden on the icon, the sr-only clause, the visible label [K].
  • Chromium only; Firefox and WebKit not checked [K].
  • The customizer was exercised through its stored overrides and the rendered panel, not by hand through drag, reset and preset flows. test-customize-theme-e2e.js passes [K].
  • The node side pane does not open at 375×812 in the nodes list, so I measured it at desktop widths only; it uses the same classes and surface as the node card, which I did measure at 375 [T][K].
  • Go suites were run on the merged tree only, not compared against a master baseline; there is no Go diff [K].

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants