fix(traceroute): route over the default-keyed channel + add channel dropdowns for Traceroute & Node Info (#3696)#3723
Conversation
…slot 0 (#3696) Channel index 0 is only the PRIMARY slot; its PSK can be a private custom key. Hardcoding slot 0 reproduced the original #3696 bug for anyone who gave channel 0 a private key. Resolve the lowest channel whose PSK is the well-known default key (mesh-readable) instead. Also accept an explicit channel override on the traceroute and nodeinfo routes for the UI dropdown. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJPe6J5vKrcbwzt6vCdtrt
…nfo (#3696) Mirror the existing Exchange Position split-button: a ▾ dropdown (shown when >1 channel exists) lets the user pick the channel for a traceroute or node-info exchange. Backend routes already accept an explicit channel override; this wires the UI through handleTraceroute/handleExchangeNodeInfo. Also add backend tests proving traceroute resolves the default-keyed channel by PSK (not hardcoded slot 0) and honors the dropdown override. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJPe6J5vKrcbwzt6vCdtrt
|
Claude finished @Yeraze's task —— View job PR Review: fix(traceroute): route over the default-keyed channel + channel dropdowns
|
…ssumption, add edge tests (#3696) - /traceroute now resolves channel directly (valid explicit override wins, else resolveBroadcastChannel) instead of the double-call through resolveDestinationChannel — clearer and one fewer DB read. - Export isValidChannelIndex; document that NULL is the stored unencrypted PSK form ('' handled defensively); include channel count in the warning. - Add traceroute route tests for explicit channel 0 (falsy-trap guard) and out-of-range explicit channel falling back to the default-keyed channel. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJPe6J5vKrcbwzt6vCdtrt
|
Claude finished @Yeraze's task —— View job PR Review: fix(traceroute): route over the default-keyed channel + channel dropdownsTasks:
SummaryThis PR correctly fixes the core issue: traceroute traversability depends on the PSK value (default key), not the slot number. The implementation is clean and the previous review's substantive concerns were all addressed in Backend
The logic in Traceroute route handler — Cleaner than before // meshRequestRoutes.ts:31–33
const channel = isValidChannelIndex(req.body.channel)
? req.body.channel
: await resolveBroadcastChannel(traceManager, databaseService);This is a clear improvement over the original Minor: Extra parentheses (pre-existing, out of scope) Lines like
FrontendDropdown state is not reset when
Actions menu traceroute/nodeinfo don't show channel selection The compact actions menu (lines 1118–1171) calls Test CoverageStrongly improved from the previous version:
One remaining gap: The VerdictThe logic is correct, well-tested, and the core issue is properly solved. The debounce gap in |
|
Thanks for the thorough review — addressed the substantive items in Addressed
Declined (with reasoning)
Full suite green (7463 passed), CI was green on the prior commit; re-running now. |
* chore(release): bump version to 4.12.0 Finalize 4.12.0 (from 4.12.0-rc2): package.json, package-lock.json, desktop/package.json, desktop/src-tauri/tauri.conf.json, helm/Chart.yaml. Promote CHANGELOG [Unreleased] → [4.12.0]. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4 * docs(4.12.0): document Automation Engine, MeshCore regions/scopes & UI additions Release-audit of every PR since v4.11.5 surfaced documentation gaps. Brings the docs site current with the 4.12.0 feature set: - New page docs/features/automation-engine.md (+ sidebar nav) for the node/ builder-based Automation Engine (#3653 et al). v-pre-wrapped so the {{ }} token syntax renders literally without breaking the VitePress build. - meshcore.md: new Regions/Scopes section (#3667 et al), channel unread indicators, heard-repeaters badge, per-message route line, byte counter, on-demand telemetry polling, Define Path editor, repeater DM-hidden behavior. - automation.md: corrected stale auto-favorite eligibility table (#3786/#3774). - maps.md: traceroute default-keyed channel routing + channel dropdowns (#3723). - map-analysis.md: rich multi-source node popups (#3692). - device.md: unmessagable-node DM-hidden behavior (#3760). Verified: vitepress build passes; tokens render literally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4 * fix(migration): make migration 104 PostgreSQL channel_database rebuild atomic Release-audit (PR #3753) flagged the tombstone-exhaustion rebuild path as a data-availability risk: it DROPs the live channel_database and RENAMEs a fresh copy into place, but the migration runner wraps each migration's statements in no transaction, so each DDL auto-commits. A crash/connection drop in the DROP→RENAME window would leave the database with no channel_database — and the migration's own idempotency check (`'channel_database'::regclass`) would then throw "relation does not exist" on the next startup, blocking recovery. Wrap the rebuild in BEGIN/COMMIT with ROLLBACK on error. PostgreSQL DDL is transactional, so any failure now rolls back to the original table intact. (Channel keys/PSKs were already copied before the drop, so this hardens the narrow availability window rather than fixing data loss. The path only fires at ≥1500 attnum tombstones — 1500+ restarts on the old migration 021 bug — so it's rare, but the blast radius warranted the fix.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4 --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Summary
Follow-up to #3699 (the original #3696 fix). That PR made traceroutes always use channel index 0, on the premise that "channel 0 is the only channel readable by all nodes." That premise is wrong: channel 0 is merely the PRIMARY slot — its PSK can be a private custom key. Anyone who reconfigured channel 0 with a private key would hit the exact same #3696 symptom (opaque payload → "Unknown" hops), just on slot 0 instead of a secondary slot.
What actually makes a traceroute traversable is the PSK, not the slot number: every intermediate node must be able to decrypt the packet to append itself to the route. The channel the whole mesh shares is the one using the well-known default key (
AQ==), which is what LongFast uses by default.Changes
Backend
resolveBroadcastChannel(manager, db)— resolves the lowest-numbered channel whose PSK is the well-known default key (AQ==) or is unencrypted, i.e. one every node can decrypt. Falls back to channel 0 (with a warning) when no channel is mesh-readable./traceroutenow resolves viaresolveBroadcastChannelinstead of hardcoding0, and accepts an explicitchanneloverride./nodeinfo/requestnow accepts an explicitchanneloverride (default behavior unchanged — still the node's stored channel, so key-repair routes over the shared PSK per project convention).Frontend
▾channel-selection dropdown (shown when more than one channel exists), mirroring the existing Exchange Position control.handleTraceroute/handleExchangeNodeInfotake an optionalchanneland forward it to the backend.Tests
resolveBroadcastChannel: picks the default-keyed channel even when it is not slot 0; treats unencrypted channels as readable; prefers the lowest index; ignores out-of-range indices; falls back to 0 when every channel is private./traceroute: resolves by PSK (not slot 0), honors the dropdown override, falls back to 0 when nothing is mesh-readable./nodeinfo/request: honors the dropdown override.Full suite: 7463 passed, 0 failed.
Closes #3696
🤖 Generated with Claude Code