Skip to content

fix(config): gate Traffic Management/StatusMessage support on firmware version#3457

Merged
Yeraze merged 1 commit into
mainfrom
fix/traffic-management-firmware-version-gate
Jun 14, 2026
Merged

fix(config): gate Traffic Management/StatusMessage support on firmware version#3457
Yeraze merged 1 commit into
mainfrom
fix/traffic-management-firmware-version-gate

Conversation

@Yeraze

@Yeraze Yeraze commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Summary

On firmware that fully supports Traffic Management (e.g. v2.7.24), the Device Configuration tab still showed it as "Unsupported by this device — requires Meshtastic firmware v2.7.22 or newer." The supportedModules flags were derived from the presence of the decoded ModuleConfig sub-message, but Proto3 omits a sub-message whose every field is default. A device that has never configured the module (the common case) sends no sub-message, so it was reported as unsupported regardless of firmware. This switches the gate to a firmware-version check — exactly what the UI message already promises.

Changes

  • Added private firmwareVersionAtLeast(major, minor, patch) helper (reuses existing parseFirmwareVersion).
  • Added supportsStatusMessage() (≥ 2.7.19) and supportsTrafficManagement() (≥ 2.7.22), mirroring the existing supportsFavorites() pattern.
  • getCurrentConfig().supportedModules now gates on these helpers instead of !!moduleConfig.statusmessage / !!moduleConfig.trafficManagement.
  • Thresholds taken from the existing UI "unsupported" strings (StatusMessage 2.7.19, Traffic Management 2.7.22) — gated independently.
  • New meshtasticManager.moduleSupport.test.ts regression suite.

Issues Resolved

None (reported directly: Traffic Management shown unsupported on firmware v2.7.24).

Documentation Updates

No documentation changes needed — this is backend support-detection logic; no feature docs describe the gating, and CHANGELOG is generated at release time.

Testing

  • Unit tests pass (full suite: 6984 tests, 0 failures)
  • TypeScript compiles cleanly (tsc --noEmit)
  • New regression suite (11 cases): version-threshold boundaries for both helpers; a 2.7.24 device with an empty actualModuleConfig reports both modules supported; old firmware reports them unsupported even with a stale config object present
  • Manual: on a v2.7.22+ device that has never configured Traffic Management, the Device Configuration tab shows the module as enabled/configurable (no "Unsupported" banner)

🤖 Generated with Claude Code

…e version

Device Configuration showed Traffic Management (and StatusMessage) as
"Unsupported by this device" on firmware that fully supports them
(e.g. v2.7.24). The supportedModules flags were derived from the presence
of the decoded ModuleConfig sub-message (!!moduleConfig.trafficManagement),
but Proto3 omits a sub-message whose every field is default. A device that
has never configured the module (the common case) therefore sends no
sub-message, so it was reported as unsupported regardless of firmware.

Gate on the firmware version instead — which is exactly what the UI message
already promises ("requires firmware v2.7.22 or newer"). Adds a private
firmwareVersionAtLeast() helper plus supportsStatusMessage() (>= 2.7.19)
and supportsTrafficManagement() (>= 2.7.22), mirroring the existing
supportsFavorites() pattern, and uses them in getCurrentConfig().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown

Claude finished @Yeraze's task —— View job


PR Review Complete ✅

This is an excellent fix that addresses a fundamental Proto3 serialization issue affecting module support detection. Here's my comprehensive review:

Code Quality & Best Practices

Excellent implementation with strong adherence to best practices:

  • Clear separation of concerns: The new helper methods (firmwareVersionAtLeast, supportsStatusMessage, supportsTrafficManagement) follow the existing pattern used by supportsFavorites()
  • Comprehensive documentation: Each method has clear JSDoc comments explaining the purpose and Proto3 gotcha
  • Consistent naming: Methods follow the existing supportsXxx() convention
  • Code reuse: Properly leverages the existing parseFirmwareVersion method rather than duplicating logic
  • Type safety: Return types are explicit (boolean) and the implementation is type-safe

Minor suggestion: Consider extracting the firmware version thresholds as constants:

private static readonly STATUS_MESSAGE_MIN_VERSION = { major: 2, minor: 7, patch: 19 };
private static readonly TRAFFIC_MANAGEMENT_MIN_VERSION = { major: 2, minor: 7, patch: 22 };

Bug Analysis

No bugs identified. The implementation correctly handles:

  • Missing firmware version (returns false safely)
  • Invalid firmware version strings (parsed version is null)
  • Version comparison logic is sound (tests verify boundary conditions)
  • The root cause is properly addressed: switching from config presence to firmware version detection

Performance Considerations

Excellent performance characteristics:

  • Minimal overhead: Version parsing and comparison are O(1) operations
  • No caching issues: Unlike supportsFavorites() which uses caching, these methods don't cache results, which is appropriate since they're called less frequently
  • No unnecessary work: Methods exit early on missing firmware version
  • Reuses existing logic: No duplicated parsing overhead

Security Assessment

No security concerns identified:

  • Input validation is handled by the existing parseFirmwareVersion method
  • No external inputs or user data processing
  • No privilege escalation or access control implications
  • Firmware version is already trusted data from the device

Test Coverage - Outstanding

Exemplary test suite with comprehensive coverage:

  • Boundary testing: Tests exact thresholds (2.7.19, 2.7.22)
  • Edge cases: Unknown firmware version, git commit suffixes
  • Integration testing: Verifies getCurrentConfig().supportedModules behavior
  • Regression prevention: Specifically tests the Proto3 omission scenario that caused the bug
  • Cross-version scenarios: Tests different firmware combinations (2.7.20 supporting StatusMessage but not Traffic Management)

The test file structure is excellent with clear mocking strategy and good test organization.

🎯 Problem Solution Quality

This fix addresses the exact root cause described in the PR:

  1. Correctly identifies the issue: Proto3 omits sub-messages with all default fields
  2. Implements the right solution: Gates on firmware version as the UI already promises
  3. Maintains backward compatibility: No breaking changes to existing APIs
  4. Future-proof: Pattern can be extended for other module support detection

📋 Minor Recommendations

  1. Consider constants for version thresholds (as mentioned above) for easier maintenance
  2. Return type could be explicit in method signature (though TypeScript infers it correctly)

🏆 Overall Assessment

This is high-quality production code that:

  • Solves a real user-facing bug
  • Implements a clean, maintainable solution
  • Includes comprehensive tests
  • Follows established patterns
  • Has excellent documentation
  • Introduces no performance or security issues

The implementation demonstrates deep understanding of both the Proto3 serialization behavior and the codebase patterns. The comprehensive test suite particularly stands out as exemplary.

Recommendation: Approve and merge - this is ready for production.

@Yeraze Yeraze merged commit 188a5f8 into main Jun 14, 2026
19 checks passed
Yeraze added a commit that referenced this pull request Jun 14, 2026
…mote-only) (#3460)

The getModuleConfigResponse handler in processAdminMessage was entirely
wrapped in `if (isRemoteNode)`, so explicit local module-config refreshes
(requestModuleConfig / requestAllModuleConfigs / refreshModuleConfigs) were
logged and then discarded — only the initial wantConfig download stream ever
populated the local node's actualModuleConfig. The Proto3-empty fallback that
records an all-default module under its key was also remote-only.

Add a local-node branch that merges the response into actualModuleConfig and,
for an empty (all-default, Proto3-omitted) response, records the module under
the pending request's key without clobbering an already-populated config.
requestModuleConfig now tracks that pending key (via LOCAL_MODULE_CONFIG_TYPE_KEYS,
keyed by the local node number) so the fallback can resolve it.

Discovered while fixing #3457 (Traffic Management shown unsupported on 2.7.24).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Yeraze Yeraze mentioned this pull request Jun 14, 2026
Yeraze added a commit that referenced this pull request Jun 14, 2026
Bump version to 4.10.3 across package.json, package-lock.json,
helm/meshmonitor/Chart.yaml, desktop/package.json, and
desktop/src-tauri/tauri.conf.json.

Finalize the CHANGELOG: promote [Unreleased] to [4.10.3] and add the
entries merged after the section was last written — MQTT NodeInfo
clobber fix (#3456), Traffic Management/StatusMessage firmware-version
gate (#3457), local-node module config storage (#3460), phantom channel
swap fix (#3453), and the TX power help-text clarification (#3459).

Add a release blog post highlighting the Traffic Management detection
fix and the bug-fix round.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Yeraze Yeraze deleted the fix/traffic-management-firmware-version-gate branch June 14, 2026 20:20
Yeraze added a commit that referenced this pull request Jun 15, 2026
…save (#3464) (#3465)

#3457 made the Status Message and Traffic Management module configs editable
(gated on firmware version), and the protobuf encoder's configFieldMap already
supported both. But the generic save route POST /api/config/module/:moduleType
validates against a separate hardcoded allow-list that was never updated, so
saving either one returned HTTP 400 "Invalid module type: statusmessage" /
"...: trafficmanagement" (#3464).

Extract the allow-list into an import-safe shared constant
(VALID_MODULE_CONFIG_TYPES + isValidModuleConfigType) that includes both new
types, and use it in the route. Add a unit test asserting the two types are
accepted and that telemetry/neighborinfo (dedicated routes) stay excluded — so
this allow-list / encoder drift can't silently recur.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant