fix(#1151): drop orphan separators from side-panel Heard By rows (#1161)

Fixes #1151

## Problem

The side-panel "Heard By" row template in `public/nodes.js` (line 1337)
built its stats suffix with inline ternaries:

```js
${o.packetCount} pkts · ${o.avgSnr != null ? '...' : ''}${o.avgRssi != null ? ' · RSSI ...' : ''}
```

When `avgSnr` and/or `avgRssi` were `null` (very common in prod —
many CJS observers have both null), this produced orphan separators:

- both null → `"110 pkts · "` (trailing dot)
- snr null only → `"55 pkts ·  · RSSI -50"` (double dot)

## Fix

Build a filtered parts array, then `.join(' · ')`. Only present fields
contribute, so the separator can never appear next to nothing.

```js
const stats = [`${o.packetCount} pkts`];
if (o.avgSnr != null)  stats.push('SNR ' + Number(o.avgSnr).toFixed(1) + 'dB');
if (o.avgRssi != null) stats.push('RSSI ' + Number(o.avgRssi).toFixed(0));
// → stats.join(' · ')
```

Full-page table (line 1337's neighbor) was already null-safe (separate
`<td>` cells), so only the side-panel template needed the change.

## TDD

Red commit: `1c02ff9a7889aadd16f87f4e673287f9742d4ad0` — adds
`test-issue-1151-orphan-separators-e2e.js` to the deploy.yml E2E job.

The test stubs `/api/nodes/:pubkey/health` via Playwright `page.route()`
with four observer permutations (both null, snr-only-null,
rssi-only-null,
both set), opens the side panel, and asserts no `.observer-row` stat
suffix matches `· ·`, leading `·`, or trailing `·`.

E2E assertion added: `test-issue-1151-orphan-separators-e2e.js:96`

## Preflight

All hard gates pass — see preflight output in the implementation log.

---------

Co-authored-by: CoreScope Bot <bot@corescope>
This commit is contained in:
Kpa-clawbot
2026-05-07 08:29:22 -07:00
committed by GitHub
parent cfd1903c6b
commit d6256c4f94
3 changed files with 137 additions and 3 deletions
+1
View File
@@ -238,6 +238,7 @@ jobs:
BASE_URL=http://localhost:13581 node test-issue-1150-404-state-e2e.js 2>&1 | tee -a e2e-output.txt
BASE_URL=http://localhost:13581 node test-issue-1146-path-link-contrast-e2e.js 2>&1 | tee -a e2e-output.txt
BASE_URL=http://localhost:13581 node test-issue-1147-section-order-e2e.js 2>&1 | tee -a e2e-output.txt
BASE_URL=http://localhost:13581 node test-issue-1151-orphan-separators-e2e.js 2>&1 | tee -a e2e-output.txt
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-logo-rebrand-e2e.js 2>&1 | tee -a e2e-output.txt
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-logo-theme-e2e.js 2>&1 | tee -a e2e-output.txt
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-logo-default-sage-teal-e2e.js 2>&1 | tee -a e2e-output.txt