Commit Graph

689 Commits

Author SHA1 Message Date
you
6324879d24 docs: list all 6 test files in AGENTS.md, not just 2 2026-03-23 23:59:49 +00:00
you
058fb5b0d0 docs: firmware source is THE source of truth for protocol behavior
Cloned meshcore-dev/MeshCore to firmware/ (gitignored).
AGENTS.md now mandates reading firmware source before implementing
anything protocol-related. Lists key files to check.
2026-03-23 23:58:58 +00:00
you
8bd9ce0431 docs: add rule — never check in private info (public repo) 2026-03-23 23:53:44 +00:00
you
ac3577d719 docs: add AGENTS.md — AI agent guide based on 685 commits of lessons
Derived from git history analysis: 4.3x fix ratio, 12 reverts, 7 cache
buster regressions, 21 commits for hash size, 6 for QR overlay.

Rules: test before push, bump cache busters, verify API shape, plan
before implementing, one commit per change, understand before fixing.
2026-03-23 23:48:10 +00:00
you
a779c39fe1 test: check in unit tests — 62 filter + 29 aging = 91 tests
test-packet-filter.js: all operators, fields, aliases, logic, edge cases
test-aging.js: getNodeStatus, getStatusInfo, getStatusTooltip, thresholds

Run: node test-packet-filter.js && node test-aging.js
2026-03-23 23:35:22 +00:00
you
3016493089 fix: use last_heard||last_seen for status in nodes table and map
renderRows() in nodes.js and three places in map.js were using only
n.last_seen to compute active/stale status, ignoring the more recent
n.last_heard from in-memory packets. This caused nodes that were recently
heard but had an old DB last_seen to incorrectly show as stale.

Also adds 29 unit tests for the aging system (getNodeStatus,
getStatusInfo, getStatusTooltip, threshold values).
2026-03-23 23:32:01 +00:00
you
685d48c62c fix: remove duplicate map link from hex breakdown longitude row
Keep the 📍map link in the Location metadata row (goes to app map).
Remove the redundant 📍 Map pill in the hex breakdown (went to Google Maps).
One link, one style.
2026-03-23 23:27:08 +00:00
you
656c8b8a07 fix: remove all /resolve-hops server API calls from packets page
Was making N API calls per observer for ambiguous hops on every page load,
plus another per packet detail view. All hop resolution now uses the
client-side HopResolver which already handles ambiguous prefixes.
Eliminates the main perf regression.
2026-03-23 23:23:08 +00:00
you
4677bff52e fix: remove 200 packet cap from WebSocket live update handler
Was slicing to 200 packets after every live update, truncating the
initial 32K+ packet list. Now keeps all packets.
2026-03-23 23:11:47 +00:00
you
aa181ce8d4 fix: ast.field not node.field in alias resolver, 37 tests passing
ReferenceError: node is not defined — was using wrong variable name.
Verified with 37 tests covering: firmware type names, aliases, route,
numeric ops, string ops, payload dot notation, hops, size, observations,
AND/OR/NOT, parentheses, and error handling.
2026-03-23 23:08:22 +00:00
you
7f948d3d63 fix: packet filter uses firmware type names (GRP_TXT, TXT_MSG, REQ, etc.)
Was using display names like 'Channel Msg' which aren't standard.
Now resolves to firmware names: GRP_TXT, TXT_MSG, REQ, ADVERT, etc.
Also accepts aliases: 'channel', 'dm', 'Channel Msg' all map to the
correct firmware name for convenience.
2026-03-23 23:02:37 +00:00
you
6d451a5c3e fix: grouped packets include route_type, snr, rssi — needed for packet filter
queryGrouped was missing route_type, snr, rssi fields. The packet filter
language couldn't filter by route/snr/rssi since grouped packets didn't
have those fields.
2026-03-23 22:56:35 +00:00
you
1254aa904a M3: Add tooltips to status labels explaining active/stale thresholds
- Add getStatusTooltip() helper with role-aware explanations
- Tooltips on status labels in: node badges, status explanation, detail table
- Tooltips on map legend active/stale counts per role
- Native title attributes (long-press on mobile)
- Bump cache busters
2026-03-23 22:51:11 +00:00
you
3094b96e07 feat: Packet Filter Language M1 — Wireshark-style filter engine + UI
Add a filter language for the packets page. Users can type expressions like:
  type == Advert && snr > 5
  payload.name contains "Gilroy"
  hops > 2 || route == FLOOD

Architecture: Lexer → Parser → AST → Evaluator(packet) → boolean

- packet-filter.js: standalone IIFE exposing window.PacketFilter
  - Supports: ==, !=, >, <, >=, <=, contains, starts_with, ends_with
  - Logic: &&, ||, !, parentheses
  - Fields: type, route, hash, snr, rssi, hops, observer, size, payload.*
  - Case-insensitive string comparisons, null-safe
  - Self-tests included (node packet-filter.js)
- packets.js: filter input with 300ms debounce, error display, match count
- style.css: filter input states (focus, error, active)
- index.html: script tag added before packets.js
2026-03-23 22:48:59 +00:00
you
418e1a761a Node Aging M2: status filters + localStorage persistence
- Nodes page: Add Active/Stale/All pill button filter
- Nodes page: Expand Last Heard dropdown (Any,1h,2h,6h,12h,24h,48h,3d,7d,14d,30d)
- Map page: Add Active/Stale/All status filter (hides markers, not just fades)
- Map legend: Show active/stale counts per role (e.g. '420 active, 42 stale')
- localStorage persistence for all filters:
  - meshcore-nodes-status-filter
  - meshcore-nodes-last-heard
  - meshcore-map-status-filter
- Bump cache busters
2026-03-23 22:37:52 +00:00
you
bb409a2e00 fix: nodes list shows actual last heard time, not just last advert
Server now computes last_heard from in-memory packet store (all traffic
types) and includes it in /api/nodes response. Client prefers last_heard
over DB last_seen for display, sort, filter, and status calculation.

Fixes inconsistency where list showed '5d ago' but side pane showed
'26m ago' for the same node.
2026-03-23 20:32:56 +00:00
you
5b64541985 refactor: extract shared node status/badge helpers, add status explanation to side pane
- Create getStatusInfo(), renderNodeBadges(), renderStatusExplanation(),
  renderHashInconsistencyWarning() shared helpers
- Side pane (renderDetail) now uses shared helpers and shows status explanation
  (was previously missing)
- Full page (loadFullNode) uses same shared helpers
- Both views now render identical status info
- Bump cache buster for nodes.js
2026-03-23 20:23:02 +00:00
you
091355c427 fix: fetch all nodes (up to 5000), filter client-side
Was fetching only 200 nodes with server-side filtering — missed nodes.
Now fetches full list once, caches it, filters by role/search/lastHeard
in the browser. Region change invalidates cache.
2026-03-23 20:13:44 +00:00
you
a9f0739392 fix: stale markers 70% opacity, 90% grayscale + dimmed
35% was too faint. Now subtle but obvious — visible but clearly
desaturated compared to active nodes.
2026-03-23 20:11:31 +00:00
you
06126bb571 fix: bump cache buster — roles.js was stale, getNodeStatus not defined
Browser cached old roles.js (without getNodeStatus) but loaded new
nodes.js (which calls it). Bumped all cache busters to force reload.
2026-03-23 19:57:36 +00:00
you
5c487204e7 feat: node aging M1 — visual aging on map + list
Two-state node freshness: Active vs Stale

- roles.js: add getNodeStatus(role, lastSeenMs) helper returning 'active'/'stale'
  - Repeaters/Rooms: stale after 72h
  - Companions/Sensors: stale after 24h
  - Backward compat: getHealthThresholds() with degradedMs/silentMs still works

- map.js: stale markers get .marker-stale CSS class (opacity 0.35, grayscale 70%)
  - Applied to both SVG shape markers and hash label markers
  - makeMarkerIcon() and makeRepeaterLabelIcon() accept isStale parameter

- nodes.js: visual aging in table, side pane, and full detail
  - Table: Last Seen column colored green (active) or muted (stale)
  - Side pane: status shows 🟢 Active or  Stale (was 🟢/🟡/🔴)
  - Full detail: Status row with role-appropriate explanation
    - Stale repeaters: 'not heard for Xd — repeaters typically advertise every 12-24h'
    - Stale companions: 'companions only advertise when user initiates'
  - Fixed lastHeard fallback to n.last_seen when health API has no stats

- style.css: .marker-stale, .last-seen-active, .last-seen-stale classes
2026-03-23 19:56:22 +00:00
you
ca951fc260 feat: make all nodes table columns sortable with click headers
- All 5 columns (Name, Public Key, Role, Last Seen, Adverts) are now
  sortable by clicking the column header
- Click toggles between ascending/descending sort
- Visual indicator (▲/▼) shows current sort column and direction
- Sort preference persisted to localStorage (meshcore-nodes-sort)
- Removed old Sort dropdown since headers replace it
- Client-side sorting on already-fetched data
- Default: Last Seen descending (most recent first)
2026-03-23 19:52:39 +00:00
you
7d62103129 Fix App Flags display to show type enum + add map link to location rows
- App Flags now shows human-readable type (Companion/Repeater/Room Server/Sensor)
  instead of confusing individual flag names like 'chat, repeater'
- Boolean flags (location, name) shown separately after type: 'Room Server + location, name'
- Added Google Maps link on longitude row using existing detail-map-link style
2026-03-23 19:48:13 +00:00
you
ebcdb994ef fix: map markers use role color always, not gray when hash_size is missing
Nodes without hash_size (older instances, no adverts seen) were showing
as gray #888 instead of their role color. Now always uses ROLE_STYLE color.
2026-03-23 19:21:30 +00:00
you
49e6d6d0b7 fix: advert flags are a 4-bit enum type, not individual bit flags
ADV_TYPE_ROOM=3 (0b0011) was misread as chat+repeater because decoder
treated lower nibble as individual bits. Now correctly: type & 0x0F as
enum (0=none, 1=chat, 2=repeater, 3=room, 4=sensor).

Includes startup backfill: scans all adverts and fixes any node roles
in the DB that were incorrectly set to 'repeater' when they should be
'room'. Logs count of fixed nodes on startup.
2026-03-23 19:20:13 +00:00
you
c524efc74d fix: section links are real deep-linkable URLs, not javascript:void
TOC: #/analytics?tab=collisions&section=inconsistentHashSection etc.
Back-to-top: #/analytics?tab=collisions (scrolls to top of tab)
All copyable, shareable, bookmarkable.
2026-03-23 18:51:02 +00:00
you
01688093af feat: Hash Issues page — section nav links at top, back-to-top on each section
TOC at top: Inconsistent Sizes | Hash Matrix | Collision Risk
Each section header has '↑ top' link on the right.
Smooth scroll navigation.
2026-03-23 18:48:05 +00:00
you
ef1e7751ea feat: deep-linkable sections within analytics tabs
Sections: inconsistentHashSection, hashMatrixSection, collisionRiskSection
Use ?tab=collisions&section=inconsistentHashSection to jump directly.
Scrolls after tab render completes (400ms delay for async content).
2026-03-23 18:47:18 +00:00
you
cd6f5dda86 feat: deep-linkable analytics tabs — #/analytics?tab=collisions
Parses ?tab= from hash URL and activates that tab on load.
e.g. #/analytics?tab=collisions → Hash Issues tab
2026-03-23 18:44:45 +00:00
you
2e54e51ec5 feat: deep-linkable sections on node detail page
Added ids: node-stats, node-observers, fullPathsSection, node-packets.
Use ?section=<id> to scroll to any section on load.
e.g. #/nodes/<pubkey>?section=node-packets
Variable hash size badge and analytics links updated to use ?section=.
2026-03-23 17:00:10 +00:00
you
790e96331d fix: recent packets always sorted newest-first
Server was returning oldest-first despite .reverse() — sort client-side
to guarantee descending time order on both detail page and side pane.
2026-03-23 16:58:09 +00:00
you
d97f35534f fix: smarter hash inconsistency detection — only flag flip-flopping, not upgrades
A node going 1B→2B and staying 2B is a firmware upgrade, not a bug.
Only flag as inconsistent when hash sizes flip-flop (2+ transitions in
the chronological advert sequence). Single transition = clean upgrade.
2026-03-23 16:55:16 +00:00
you
cc9a98bc69 fix: inconsistent hash table — proper contrast, row stripes, colored size badges
- Removed yellow text and redundant Status column
- Sizes Seen now uses colored badges (orange 1B, pale green 2B, bright green 3B)
- Row striping, card border/radius, accent-colored node links
- Current hash in mono with muted byte count
2026-03-23 16:52:59 +00:00
you
508520980c fix: hash size badge colors — 1B orange, 2B pale green, 3B bright green
1-byte is worst (most collisions), 3-byte is best (least collisions).
Colors now reflect quality: orange → pale green → bright green.
2026-03-23 16:50:12 +00:00
you
e7cdff9669 fix: link to actual firmware bug commit and release
- Bug: github.com/meshcore-dev/MeshCore/commit/fcfdc5f
  'automatic adverts not using configured multibyte path setting'
- Fix: github.com/meshcore-dev/MeshCore/releases/tag/repeater-v1.14.1
- Both links on node detail page banner and analytics Hash Issues tab
2026-03-23 16:49:33 +00:00
you
47734f0b02 feat: Hash Issues tab — shows inconsistent hash size nodes above collisions
- Renamed 'Hash Collisions' tab to 'Hash Issues'
- New section at top: 'Inconsistent Hash Sizes' table listing all nodes
  that have sent adverts with varying hash sizes
- Each node links to its detail page with ?highlight=hashsize for
  per-advert hash size breakdown
- Shows current hash prefix, all sizes seen, and affected count
- Green checkmark when no inconsistencies detected
- Existing collision grid and risk table unchanged below
2026-03-23 16:48:09 +00:00
you
09dcae274f feat: variable hash size badge links to detail page, shows per-advert hash sizes
- Badge is now a link to the detail page with ?highlight=hashsize
- Detail page auto-scrolls to Recent Packets section
- Each advert shows its hash size badge (yellow if different from current)
- Detail page shows always-visible explanation banner (not hidden)
- Side pane badge links to detail page too
2026-03-23 16:46:24 +00:00
you
80ae87380d fix: rename 'hash mismatch' to 'variable hash size' 2026-03-23 16:44:07 +00:00
you
0dae1ba3b7 fix: hash mismatch badge is clickable — expands explanation inline
Badge shows cursor:help and clicking toggles a yellow-bordered info box
explaining the issue and suggesting firmware update. Stats row just shows
'⚠️ varies' with tooltip. Much less jarring than a dead yellow badge.
2026-03-23 16:43:42 +00:00
you
211eb37fb2 fix: QR overlay sizing — override node-qr class margin/width, 56px square
node-map-qr-overlay also has node-qr class which was adding margin-top
and setting max-width to 100px. Override with !important and reset margins.
2026-03-23 16:41:59 +00:00
you
c706a39bbd fix: QR overlay — white 50% backing, transparent white spots, black modules
White semi-transparent square behind QR so black modules pop.
White rects in SVG already set to transparent by JS.
Same white backing in dark mode too (QR needs light bg to scan).
2026-03-23 16:39:50 +00:00
you
f7a4ad2b73 feat: detect and flag inconsistent hash sizes across adverts
Tracks all hash_size values seen per node. If a node has sent adverts
with different hash sizes, flags it as hash_size_inconsistent with a
yellow ⚠️ badge on both side pane and detail page. Tooltip mentions
likely firmware bug (pre-1.14.1). Stats row shows all sizes seen.
2026-03-23 16:39:02 +00:00
you
7bc8524404 revert: hash_size back to newest-first, not max
Repeaters can switch hash sizes (e.g. buggy 1.14 firmware emitting 0x00
path bytes). Latest advert is the correct current state.
2026-03-23 16:37:07 +00:00
you
9584dc3ca6 fix: QR overlay visible — semi-transparent white backing instead of invisible
50% opacity on transparent bg = invisible on dark maps.
Now uses white 60% bg (light) / black 50% bg (dark) with full opacity SVG.
2026-03-23 16:36:16 +00:00
you
57484d9fa6 fix: QR overlay opacity 50% 2026-03-23 16:34:31 +00:00
you
f33f7bc5a8 fix: hash_size uses max across all adverts, not just newest
Some nodes emit adverts with varying path byte values (e.g. 0x00 and 0x40).
Taking the first/newest was unreliable. Now takes the maximum hash_size
seen across all adverts for each node.
2026-03-23 16:33:39 +00:00
you
40c7a97590 fix: remove 'Scan with MeshCore app' text from all QR codes 2026-03-23 16:32:06 +00:00
you
3e8011472d fix: QR overlay actually transparent — JS strips white fills, 70% opacity
CSS fill-opacity selectors weren't matching the QR library's output.
Now JS directly sets white rects to transparent after SVG generation.
Overlay at 70% opacity so it doesn't fight the map for attention.
Removed 'Scan with MeshCore app' label from overlay version.
2026-03-23 16:31:18 +00:00
you
bb387c3958 fix: QR overlay on map — transparent background, 10% opacity white modules
Map shows through the QR code. Dark modules stay solid, white modules
at 10% opacity. No border/shadow/padding on the overlay container.
2026-03-23 16:28:24 +00:00
you
aab3e57e9f fix: QR code smaller, side pane reorganized
- QR globally reduced (140px → 100px, overlay 64px)
- Side pane: name/badges first, then map with QR overlaid in bottom-right corner
- Removed standalone QR section from side pane — saves vertical space
- Public key shown inline below map instead of separate section
- No-location nodes still get standalone centered QR
- Full detail page QR wrap narrower (max 160px)
2026-03-23 16:27:49 +00:00