🧪 The Testening
This release transforms MeshCore Analyzer from a "push and pray" codebase into a properly tested, CI-gated project. 99 commits, 950+ tests, and every push must pass before reaching production.
Test Infrastructure
- 950+ automated tests across 12 test files — unit, integration, E2E, spec-driven, and golden fixtures
- CI/CD pipeline gates every deploy: backend tests → frontend E2E → coverage report → deploy (only if all pass)
- Playwright E2E tests run against a local server before deploy — broken frontend blocks production
- Code coverage tracking — backend (88%) and frontend (42%) measured and reported on every push
- Dynamic badges in README auto-update: test counts, backend coverage, frontend coverage, deploy status
- Istanbul-instrumented frontend — Playwright exercises code,
window.__coverage__extracted, merged with backend coverage - Golden fixture tests — 20 real production packets frozen as regression tests. If decoder output changes, tests break immediately.
- Spec-driven decoder tests — verified against MeshCore firmware C++ source (
Mesh.cpp,Packet.h,AdvertDataHelpers.h)
AGENTS.md — AI Agent Guide
New project-level AGENTS.md derived from analyzing all 685 commits:
- 4.3x fix ratio identified and documented — rules to prevent it
- Must read firmware source before implementing protocol features
- All tests must pass before push, every feature adds tests
- Cache busters in same commit, verify API shape before building UI
- Plan → human sign-off → implement (no more yolo)
Features
- Packet Filter Language — Wireshark-style filter engine (
type == GRP_TXT && snr > 5) - Node Aging System — 🟢 Active / ⚪ Stale with visual fading on map markers, configurable thresholds
- Hash Issues Detection — flags nodes with inconsistent hash sizes, links to firmware bug + fix
- Sortable Node Columns — click any header to sort, persisted to localStorage
- Deep-linkable Analytics —
#/analytics?tab=collisions§ion=inconsistentHashSection - 8 Preset Themes with WCAG AA contrast verification
Bug Fixes
- Decoder: encrypted payload field sizes matched to firmware source (dest 1B, src 1B, MAC 2B — was 6+6+4)
- Decoder: advert flags are a 4-bit enum type, not individual bit flags (room servers were misclassified)
- 4 missing payload types added: GRP_DATA, MULTIPART, CONTROL, RAW_CUSTOM
- Room server detection now works (52 room servers correctly identified)
- Node list shows actual last-heard time from all traffic, not just adverts
- 200 packet cap removed from WebSocket handler
- Resolve-hops API calls eliminated from packets page (client-side only)
- Map markers always use role color (not gray when hash_size missing)
Performance
- All nodes fetched once, filtered client-side (was 200 limit with server filtering)
- Hop resolution fully client-side — no per-packet API calls
- WebSocket live updates no longer cap at 200 packets
Coverage Breakdown
| Component | Statements | Tests |
|---|---|---|
| Backend overall | 88% | 895+ |
| decoder.js | 86% | 307 |
| packet-store.js | 67% | 34 |
| db.js | 88% | 68 |
| server routes | 85% | 200 |
| server-helpers.js | 95% | 70 |
| packet-filter.js | 100% | 62 |
| Frontend overall | 42% | 8 E2E |