feat: support multibyte path hashes for MeshCore firmware v1.14+

Update path hash handling to accept variable-length hex-encoded hashes
(e.g. "4a" for single-byte, "b3fa" for multibyte) instead of requiring
exactly 2-character hashes. Bump meshcore dependency to >=2.3.0.

- Update normalizer to accept even-length hex strings >= 2 chars
- Update schemas and model docstrings for variable-length hashes
- Add tests for multibyte and mixed-length path hash round-trips
- Fix web test flakiness from local .env datetime locale leaking
This commit is contained in:
Louis King
2026-03-17 22:59:29 +00:00
parent 889aa32e3a
commit 29b5820ed1
21 changed files with 1076 additions and 17 deletions

View File

@@ -0,0 +1,81 @@
## TASK-001: Verify meshcore_py v2.3.0+ backwards compatibility
**Status:** completed
### Files Created
_(none)_
### Files Modified
_(none)_
### Notes
Research-only task. meshcore_py v2.3.0 handles multibyte path hashes transparently at the protocol level. Path hash size is self-describing in the wire format (upper 2 bits of path length byte encode hash size). The interface receiver, sender, and device wrapper pass event payloads through without manipulation, so no code changes are needed. pyproject.toml dependency confirmed at meshcore>=2.3.0.
---
## TASK-002: Update _normalize_hash_list to accept variable-length hex strings
**Status:** completed
### Files Created
_(none)_
### Files Modified
- `src/meshcore_hub/collector/letsmesh_normalizer.py`
### Notes
Changed length validation from `if len(token) != 2` to `if len(token) < 2 or len(token) % 2 != 0`. Updated docstring to describe variable-length hex hash support. Existing hex validation and uppercase normalization unchanged. All 98 collector tests pass.
---
## TASK-003: Update Pydantic schema descriptions for path_hashes fields
**Status:** completed
### Files Created
_(none)_
### Files Modified
- `src/meshcore_hub/common/schemas/events.py`
- `src/meshcore_hub/common/schemas/messages.py`
- `src/meshcore_hub/common/models/trace_path.py`
### Notes
Updated TraceDataEvent.path_hashes, TracePathRead.path_hashes, and TracePath model docstring to reflect variable-length hex strings. No Pydantic validators needed changes - both schemas use Optional[list[str]] with no per-element length constraints.
---
## TASK-004: Update SCHEMAS.md documentation for multibyte path hashes
**Status:** completed
### Files Created
_(none)_
### Files Modified
- `SCHEMAS.md`
### Notes
Updated path_hashes field description from "2-character" to variable-length hex. Updated example to include mixed-length hashes ["4a", "b3fa", "02"]. Added firmware v1.14 compatibility note.
---
## TASK-008: Verify web dashboard trace path display handles variable-length hashes
**Status:** completed
### Files Created
_(none)_
### Files Modified
_(none)_
### Notes
Verification-only task. The web dashboard SPA has no trace path page and no JavaScript/CSS code referencing path_hash or pathHash. Trace path data is only served by the REST API which returns path_hashes as list[str] with no length constraints. No changes needed.
---
## TASK-005: Write tests for multibyte path hash normalizer
**Status:** completed
### Files Created
- `tests/test_collector/test_letsmesh_normalizer.py`
### Files Modified
- `tests/test_collector/test_subscriber.py`
### Notes
Created 12 unit tests for _normalize_hash_list covering all 7 required scenarios plus edge cases. Added 2 integration tests to test_subscriber.py verifying multibyte path hashes flow through the full collector pipeline. All 35 collector tests pass.
---
## TASK-006: Write tests for database round-trip of multibyte path hashes
**Status:** completed
### Files Created
_(none)_
### Files Modified
- `tests/test_common/test_models.py`
### Notes
Added 2 new test methods to TestTracePathModel: test_multibyte_path_hashes_round_trip and test_mixed_length_path_hashes_round_trip. Verified JSON column handles variable-length strings natively. All 10 model tests pass. No Alembic migration needed.
---
## TASK-007: Write tests for API trace path responses with multibyte hashes
**Status:** completed
### Files Created
_(none)_
### Files Modified
- `tests/test_api/test_trace_paths.py`
### Notes
Added TestMultibytePathHashes class with 2 tests: list endpoint with multibyte hashes and detail endpoint with mixed-length hashes. All 9 API trace path tests pass.
---

View File

@@ -0,0 +1,146 @@
# Product Requirements Document
> Source: `.plans/2026/03/17/01-multibyte-support/prompt.md`
## Project Overview
MeshCore Hub must be updated to support multibyte path hashes introduced in MeshCore firmware v1.14 and the meshcore_py v2.3.0 Python bindings. Path hashes — node identifiers embedded in trace and route data — were previously fixed at 1 byte (2 hex characters) per hop but can now be multiple bytes, allowing longer repeater IDs at the cost of reduced maximum hops. The update must maintain backwards compatibility with nodes running older single-byte firmware.
## Goals
- Support variable-length (multibyte) path hashes throughout the data pipeline: interface → MQTT → collector → database → API → web dashboard.
- Maintain backwards compatibility so single-byte path hashes from older firmware nodes continue to work without modification.
- Update documentation and schemas to accurately describe the new variable-length path hash format.
## Functional Requirements
### REQ-001: Accept Variable-Length Path Hashes in Collector
**Description:** The collector's event handlers and normalizer must accept path hash strings of any even length (not just 2-character strings). Path hashes arriving from both the meshcore_py interface and LetsMesh-compatible ingest must be processed correctly regardless of byte length.
**Acceptance Criteria:**
- [ ] Path hashes with 2-character values (legacy single-byte) are accepted and stored correctly
- [ ] Path hashes with 4+ character values (multibyte) are accepted and stored correctly
- [ ] Mixed-length path hash arrays (e.g. `["4a", "b3fa", "02"]`) are accepted when the mesh contains nodes with different firmware versions
- [ ] The LetsMesh normalizer handles multibyte `pathHashes` values from decoded payloads
### REQ-002: Update Pydantic Schema Validation for Path Hashes
**Description:** The `path_hashes` field in event and message Pydantic schemas currently describes values as "2-character node hash identifiers". The schema description and any validation constraints must be updated to permit variable-length hex strings.
**Acceptance Criteria:**
- [ ] `TraceDataEvent.path_hashes` field description reflects variable-length hex strings
- [ ] `MessageEventBase.path_hashes` field description reflects variable-length hex strings (if applicable)
- [ ] No schema validation rejects path hash strings longer than 2 characters
### REQ-003: Verify Database Storage Compatibility
**Description:** The `path_hashes` column on the `trace_paths` table uses a JSON column type. Confirm that variable-length path hash strings are stored and retrieved correctly without requiring a schema migration.
**Acceptance Criteria:**
- [ ] Multibyte path hash arrays are round-tripped correctly through SQLAlchemy JSON column (store and retrieve)
- [ ] No Alembic migration is required (JSON column already supports arbitrary string lengths)
### REQ-004: Update API Responses for Variable-Length Path Hashes
**Description:** The trace paths API must return multibyte path hashes faithfully. API response schemas and any serialization logic must not truncate or assume a fixed length.
**Acceptance Criteria:**
- [ ] `GET /trace-paths` returns multibyte path hash arrays as-is from the database
- [ ] `GET /trace-paths/{id}` returns multibyte path hash arrays as-is from the database
- [ ] API response examples in documentation reflect variable-length path hashes
### REQ-005: Update Web Dashboard Trace/Path Display
**Description:** If the web dashboard displays path hashes (e.g. in trace path views), the rendering must handle variable-length strings without layout breakage or truncation.
**Acceptance Criteria:**
- [ ] Trace path views display multibyte path hashes correctly
- [ ] No fixed-width formatting assumes 2-character hash strings
### REQ-006: Verify meshcore_py Library Compatibility
**Description:** Confirm that the meshcore_py v2.3.0+ library handles backwards compatibility with single-byte firmware nodes transparently, so that MeshCore Hub does not need to implement compatibility logic itself.
**Acceptance Criteria:**
- [ ] meshcore_py v2.3.0+ is confirmed to handle mixed single-byte and multibyte path hashes at the protocol level
- [ ] The interface receiver and sender components work with the updated library without code changes beyond the dependency version bump (or with minimal changes if the library API changed)
## Non-Functional Requirements
### REQ-007: Backwards Compatibility
**Category:** Reliability
**Description:** The system must continue to operate correctly when receiving events from nodes running older (single-byte) firmware. No data loss or processing errors may occur for legacy path hash formats.
**Acceptance Criteria:**
- [ ] Existing test cases with 2-character path hashes continue to pass without modification
- [ ] New test cases with multibyte path hashes pass alongside legacy test cases
- [ ] No database migration is required that would break rollback to the previous version
### REQ-008: Documentation Accuracy
**Category:** Maintainability
**Description:** All documentation referencing path hash format must be updated to reflect the variable-length nature of multibyte path hashes.
**Acceptance Criteria:**
- [ ] `SCHEMAS.md` path hash descriptions updated from "2-character" to "variable-length hex string"
- [ ] Code docstrings and field descriptions in models/schemas updated
- [ ] Example payloads in documentation include at least one multibyte path hash example
## Technical Constraints and Assumptions
### Constraints
- Python 3.13+ (specified by project)
- meshcore_py >= 2.3.0 (already set in `pyproject.toml`)
- SQLite with JSON column for path hash storage (existing schema)
- No breaking changes to the REST API response format
### Assumptions
- The meshcore_py library handles protocol-level backwards compatibility for multibyte path hashes, so MeshCore Hub only needs to ensure its data pipeline accepts variable-length strings
- Path hashes are always valid hex strings (even number of characters)
- The JSON column type in SQLite/SQLAlchemy does not impose length restrictions on individual array element strings
- The `pyproject.toml` dependency has already been bumped to `meshcore>=2.3.0`
## Scope
### In Scope
- Updating Pydantic schema descriptions and validation for variable-length path hashes
- Updating collector handlers and normalizer for multibyte path hashes
- Verifying database storage compatibility (no migration expected)
- Verifying API response compatibility
- Updating web dashboard path hash display if applicable
- Updating `SCHEMAS.md` and code documentation
- Adding/updating tests for multibyte path hashes
- Confirming meshcore_py library handles backwards compatibility
### Out of Scope
- MeshCore firmware changes or device-side configuration
- Adding UI controls for selecting single-byte vs. multibyte mode
- Performance optimization of path hash processing
- Changes to MQTT topic structure or message format
- LetsMesh ingest protocol changes (beyond accepting multibyte values that LetsMesh already provides)
## Suggested Tech Stack
| Layer | Technology | Rationale |
|-------|-----------|-----------|
| MeshCore bindings | meshcore_py >= 2.3.0 | Specified by prompt; provides multibyte path hash support |
| Validation | Pydantic v2 | Existing stack — schema descriptions updated |
| Database | SQLAlchemy 2.0 + SQLite JSON | Existing stack — no migration needed |
| API | FastAPI | Existing stack — no changes to framework |
| Testing | pytest + pytest-asyncio | Existing stack — new test cases for multibyte |

View File

@@ -0,0 +1,17 @@
# Phase: 01-multibyte-support
## Overview
The latest MeshCore firmware (v1.14) has introduced multibyte support for multi-byte path hashes. The latest version of the MeshCore Python bindings (meshcore_py) has been updated to use this. This allows longer repeater IDs per hop, but reduces the maximum allowed hops. Nodes running older firmware only support 1-byte path hashes and will not receive messages if other nodes use multibyte path hashes.
## Goals
* Update Receiver/Sender component to use latest version of MeshCore Python bindings that support multibyte path hash handling.
## Requirements
* Must remain backwards compatible with previous version. Confirm whether this is handled by the Python library.
## References
* https://github.com/meshcore-dev/meshcore_py/releases/tag/v2.3.0

View File

@@ -0,0 +1,19 @@
# Code review round 001
# Phase: .plans/2026/03/17/01-multibyte-support
# Scope: full
# Generated by: /jp-codereview
issues: []
summary:
total_issues: 0
critical: 0
major: 0
minor: 0
by_category:
integration: 0
architecture: 0
security: 0
duplication: 0
error-handling: 0
style: 0

View File

@@ -0,0 +1,57 @@
# PRD Review
> Phase: `.plans/2026/03/17/01-multibyte-support`
> PRD: `.plans/2026/03/17/01-multibyte-support/prd.md`
> Prompt: `.plans/2026/03/17/01-multibyte-support/prompt.md`
## Verdict: PASS
The PRD comprehensively addresses the narrow scope of the original prompt. All prompt items are covered by specific requirements with testable acceptance criteria. The PRD appropriately expands the prompt's Receiver/Sender focus to cover the full data pipeline (collector, schemas, database, API, web), which is necessary for end-to-end multibyte support. No contradictions, feasibility concerns, or scope inconsistencies were found.
## Coverage Assessment
| Prompt Item | PRD Section | Covered? | Notes |
|---|---|---|---|
| Update Receiver/Sender to use latest meshcore_py with multibyte support | REQ-006 | Yes | Covered by library compatibility verification; receiver/sender work with updated bindings |
| Must remain backwards compatible with previous version | REQ-007 | Yes | Explicit non-functional requirement with 3 testable acceptance criteria |
| Confirm whether backwards compat is handled by the Python library | REQ-006 | Yes | First AC specifically calls for confirming library-level protocol compatibility |
| Reference to meshcore_py v2.3.0 release | Constraints, Tech Stack | Yes | Noted in constraints and suggested tech stack table |
**Coverage summary:** 4 of 4 prompt items fully covered, 0 partially covered, 0 not covered.
## Requirement Evaluation
All requirements passed evaluation. Minor observations:
### REQ-006: Verify meshcore_py Library Compatibility
- **Implementability:** Pass
- **Testability:** Pass -- though the first AC ("confirmed to handle...at the protocol level") is a verification/research task rather than an automated test, this is appropriate given the prompt explicitly asks to confirm library behavior
- **Completeness:** Pass
- **Consistency:** Pass
## Structural Issues
### Contradictions
None found.
### Ambiguities
None found. The PRD is appropriately specific for the scope of work.
### Missing Edge Cases
None significant. The PRD covers the key edge case of mixed-length path hash arrays from heterogeneous firmware networks (REQ-001 AC3).
### Feasibility Concerns
None. The changes are primarily documentation/description updates and verification tasks. The JSON column type inherently supports variable-length strings, and the meshcore_py dependency is already bumped.
### Scope Inconsistencies
None. The PRD's scope appropriately extends beyond the prompt's Receiver/Sender focus to cover downstream components (collector, API, web) that also handle path hashes. This is a necessary expansion, not scope creep.
## Action Items
No action items -- verdict is PASS.

View File

@@ -0,0 +1,89 @@
# Task Review
> Phase: `.plans/2026/03/17/01-multibyte-support`
> Tasks: `.plans/2026/03/17/01-multibyte-support/tasks.yaml`
> PRD: `.plans/2026/03/17/01-multibyte-support/prd.md`
## Verdict: PASS
The task list is structurally sound, correctly ordered, and fully covers all 8 PRD requirements. The dependency graph is a valid DAG with no cycles or invalid references. No ordering issues were found — no task references files that should be produced by a task outside its dependency chain. All tasks have valid roles, complexity values, and complete fields. The task breakdown is appropriate for the narrow scope of this phase.
## Dependency Validation
### Reference Validity
All dependency references are valid. Every task ID in every `dependencies` list corresponds to an existing task in the inventory.
### DAG Validation
The dependency graph is a valid DAG with no cycles. Maximum dependency depth is 1 (two test tasks depend on one implementation task each).
### Orphan Tasks
The following tasks are never referenced as dependencies by other tasks:
- **TASK-001** (Verify meshcore_py compatibility) — terminal verification task, expected
- **TASK-004** (Update SCHEMAS.md) — terminal documentation task, expected
- **TASK-005** (Tests for normalizer) — terminal test task, expected
- **TASK-006** (Tests for DB round-trip) — terminal test task, expected
- **TASK-007** (Tests for API responses) — terminal test task, expected
- **TASK-008** (Verify web dashboard) — terminal verification task, expected
All orphan tasks are leaf nodes (tests, docs, or verification tasks). No missing integration points.
## Ordering Check
No ordering issues detected. No task modifies a file that is also modified by another task outside its dependency chain. The `files_affected` sets across all tasks are disjoint except where proper dependency relationships exist.
## Coverage Check
### Uncovered Requirements
All PRD requirements are covered.
### Phantom References
No phantom references detected. Every requirement ID referenced in tasks exists in the PRD.
**Coverage summary:** 8 of 8 PRD requirements covered by tasks.
| Requirement | Covered By |
|---|---|
| REQ-001 | TASK-002, TASK-005 |
| REQ-002 | TASK-003 |
| REQ-003 | TASK-006 |
| REQ-004 | TASK-007 |
| REQ-005 | TASK-008 |
| REQ-006 | TASK-001 |
| REQ-007 | TASK-005, TASK-006, TASK-007 |
| REQ-008 | TASK-004 |
## Scope Check
### Tasks Too Large
No tasks flagged as too large. All tasks are `small` complexity except TASK-005 (`medium`), which is appropriately scoped for a test suite covering 7 unit test scenarios plus an integration test.
### Tasks Too Vague
No tasks flagged as too vague. All tasks have detailed descriptions (well over 50 characters), multiple testable acceptance criteria, and specific file paths.
### Missing Test Tasks
- **TASK-001** (Verify meshcore_py compatibility) — no associated test task. This is a research/verification task that does not produce source code, so a test task is not applicable. (Warning only)
- **TASK-004** (Update SCHEMAS.md) — no associated test task. This is a documentation-only task. (Warning only)
- **TASK-008** (Verify web dashboard) — no associated test task. This is a verification task that may result in no code changes. (Warning only)
All implementation tasks that modify source code (TASK-002, TASK-003) have corresponding test tasks (TASK-005, TASK-006, TASK-007).
### Field Validation
All tasks have valid fields:
- All `suggested_role` values are valid (`python`, `docs`, `frontend`)
- All `estimated_complexity` values are valid (`small`, `medium`)
- All tasks have at least one entry in `requirements`, `acceptance_criteria`, and `files_affected`
- All task IDs follow the `TASK-NNN` format with sequential numbering
## Action Items
No action items — verdict is PASS.

View File

@@ -0,0 +1,18 @@
status: completed
phase_path: .plans/2026/03/17/01-multibyte-support
branch: feature/multibyte-support
current_phase: completed
current_task: null
fix_round: 0
last_review_round: 1
review_loop_exit_reason: success
quality_gate: pass
tasks:
TASK-001: completed
TASK-002: completed
TASK-003: completed
TASK-004: completed
TASK-005: completed
TASK-006: completed
TASK-007: completed
TASK-008: completed

View File

@@ -0,0 +1,102 @@
# Phase Summary
> Phase: `.plans/2026/03/17/01-multibyte-support`
> Generated by: `/jp-summary`
## Project Overview
MeshCore Hub was updated to support multibyte path hashes introduced in MeshCore firmware v1.14 and meshcore_py v2.3.0. Path hashes — node identifiers embedded in trace and route data — were previously fixed at 1 byte (2 hex characters) per hop but can now be multiple bytes. The update maintains backwards compatibility with nodes running older single-byte firmware.
### Goals
- Support variable-length (multibyte) path hashes throughout the data pipeline: interface → MQTT → collector → database → API → web dashboard.
- Maintain backwards compatibility so single-byte path hashes from older firmware nodes continue to work without modification.
- Update documentation and schemas to accurately describe the new variable-length path hash format.
## Task Execution
### Overview
| Metric | Value |
|---|---|
| Total tasks | 8 |
| Completed | 8 |
| Failed | 0 |
| Blocked | 0 |
| Skipped | 0 |
### Task Details
| ID | Title | Role | Complexity | Status |
|---|---|---|---|---|
| TASK-001 | Verify meshcore_py v2.3.0+ backwards compatibility | python | small | completed |
| TASK-002 | Update _normalize_hash_list to accept variable-length hex strings | python | small | completed |
| TASK-003 | Update Pydantic schema descriptions for path_hashes fields | python | small | completed |
| TASK-004 | Update SCHEMAS.md documentation for multibyte path hashes | docs | small | completed |
| TASK-005 | Write tests for multibyte path hash normalizer | python | medium | completed |
| TASK-006 | Write tests for database round-trip of multibyte path hashes | python | small | completed |
| TASK-007 | Write tests for API trace path responses with multibyte hashes | python | small | completed |
| TASK-008 | Verify web dashboard trace path display handles variable-length hashes | frontend | small | completed |
### Requirement Coverage
| Metric | Value |
|---|---|
| Total PRD requirements | 8 |
| Requirements covered by completed tasks | 8 |
| Requirements with incomplete coverage | 0 |
## Files Created and Modified
### Created
- `tests/test_collector/test_letsmesh_normalizer.py`
### Modified
- `pyproject.toml`
- `SCHEMAS.md`
- `src/meshcore_hub/collector/letsmesh_normalizer.py`
- `src/meshcore_hub/common/schemas/events.py`
- `src/meshcore_hub/common/schemas/messages.py`
- `src/meshcore_hub/common/models/trace_path.py`
- `tests/test_collector/test_subscriber.py`
- `tests/test_common/test_models.py`
- `tests/test_api/test_trace_paths.py`
## Review Rounds
### Overview
| Metric | Value |
|---|---|
| Total review rounds | 1 |
| Total issues found | 0 |
| Issues fixed | 0 |
| Issues deferred | 0 |
| Issues remaining | 0 |
| Regressions introduced | 0 |
### Round Details
#### Round 1 (scope: full)
- **Issues found:** 0 (0 CRITICAL, 0 MAJOR, 0 MINOR)
- **Exit reason:** success (clean review, no fix rounds needed)
## Known Issues and Deferred Items
No known issues.
## Decisions
- **meshcore_py handles backwards compatibility transparently** -- Research (TASK-001) confirmed that meshcore_py v2.3.0 handles multibyte path hashes at the protocol level via self-describing wire format. No compatibility logic needed in MeshCore Hub's interface layer.
- **No database migration required** -- The existing JSON column type on `trace_paths.path_hashes` stores variable-length string arrays natively. Round-trip tests confirmed no data loss.
- **No web dashboard changes needed** -- The SPA has no trace path rendering page. Path hashes are only served via the REST API which uses `list[str]` with no length constraints.
- **Normalizer validation approach** -- Changed from exact length check (`len == 2`) to even-length minimum-2 check (`len >= 2 and len % 2 == 0`), preserving existing hex validation and uppercase normalization.
## Suggested Next Steps
1. Push the branch and create a pull request for review.
2. Perform manual integration testing with a MeshCore device running firmware v1.14+ to verify multibyte path hashes flow end-to-end.
3. Verify that mixed-firmware networks (some nodes v1.14+, some older) produce correct mixed-length path hash arrays in the database.

View File

@@ -0,0 +1,274 @@
# Task list generated from PRD: .plans/2026/03/17/01-multibyte-support/prd.md
# Generated by: /jp-task-list
tasks:
- id: "TASK-001"
title: "Verify meshcore_py v2.3.0+ backwards compatibility"
description: |
Research and confirm that meshcore_py v2.3.0+ handles backwards compatibility
with single-byte firmware nodes at the protocol level. Check the meshcore_py
v2.3.0 release notes and source code to determine whether the library
transparently handles mixed single-byte and multibyte path hashes, or whether
MeshCore Hub needs to implement any compatibility logic.
The pyproject.toml dependency is already set to meshcore>=2.3.0. Verify the
interface receiver (src/meshcore_hub/interface/receiver.py) and sender
(src/meshcore_hub/interface/sender.py) components work with the updated library
without code changes, or document any API changes that require updates.
Document findings as a comment block at the top of the PR description or in
the phase changelog.
requirements:
- "REQ-006"
dependencies: []
suggested_role: "python"
acceptance_criteria:
- "meshcore_py v2.3.0+ backwards compatibility behaviour is documented"
- "Any required interface code changes are identified (or confirmed unnecessary)"
- "pyproject.toml dependency version is confirmed correct at >=2.3.0"
estimated_complexity: "small"
files_affected:
- "pyproject.toml"
- id: "TASK-002"
title: "Update _normalize_hash_list to accept variable-length hex strings"
description: |
The LetsMesh normalizer method `_normalize_hash_list` in
src/meshcore_hub/collector/letsmesh_normalizer.py (line ~724) currently rejects
any path hash string that is not exactly 2 characters long:
if len(token) != 2:
continue
Update this method to accept variable-length hex strings (any even-length hex
string of 2+ characters). The validation should:
- Accept strings of length 2, 4, 6, etc. (even-length, minimum 2)
- Reject odd-length strings and empty strings
- Continue to validate that all characters are valid hexadecimal (0-9, A-F)
- Continue to uppercase-normalize the hex strings
Also update the method's docstring from "Normalize a list of one-byte hash
strings" to reflect variable-length support.
requirements:
- "REQ-001"
dependencies: []
suggested_role: "python"
acceptance_criteria:
- "_normalize_hash_list accepts 2-character hex strings (legacy single-byte)"
- "_normalize_hash_list accepts 4+ character hex strings (multibyte)"
- "_normalize_hash_list rejects odd-length strings"
- "_normalize_hash_list rejects non-hex characters"
- "_normalize_hash_list uppercases all hex strings"
- "Method docstring updated to describe variable-length support"
estimated_complexity: "small"
files_affected:
- "src/meshcore_hub/collector/letsmesh_normalizer.py"
- id: "TASK-003"
done: true
title: "Update Pydantic schema descriptions for path_hashes fields"
description: |
Update the `path_hashes` field description in Pydantic schemas to reflect
variable-length hex strings instead of fixed 2-character strings.
Files and fields to update:
1. src/meshcore_hub/common/schemas/events.py - TraceDataEvent.path_hashes
(line ~134): Change description from "Array of 2-character node hash
identifiers" to "Array of hex-encoded node hash identifiers (variable
length, e.g. '4a' for single-byte or 'b3fa' for multibyte)"
2. src/meshcore_hub/common/schemas/messages.py - MessageEventBase.path_hashes
or TracePathRead.path_hashes (line ~157): Update description similarly
if it references fixed-length hashes.
3. src/meshcore_hub/common/models/trace_path.py - TracePath.path_hashes
docstring (line ~23): Change "JSON array of node hash identifiers" to
"JSON array of hex-encoded node hash identifiers (variable length)"
Ensure no Pydantic validators or Field constraints reject strings longer
than 2 characters. The current schemas use Optional[list[str]] with no
per-element length validation, so no validator changes should be needed.
requirements:
- "REQ-002"
dependencies: []
suggested_role: "python"
acceptance_criteria:
- "TraceDataEvent.path_hashes description reflects variable-length hex strings"
- "TracePathRead.path_hashes description reflects variable-length hex strings"
- "TracePath model docstring updated for variable-length path hashes"
- "No Pydantic validation rejects path hash strings longer than 2 characters"
estimated_complexity: "small"
files_affected:
- "src/meshcore_hub/common/schemas/events.py"
- "src/meshcore_hub/common/schemas/messages.py"
- "src/meshcore_hub/common/models/trace_path.py"
- id: "TASK-004"
title: "Update SCHEMAS.md documentation for multibyte path hashes"
description: |
Update SCHEMAS.md to reflect the new variable-length path hash format
introduced in MeshCore firmware v1.14.
Changes needed:
1. Line ~228: Change "Array of 2-character node hash identifiers (ordered
by hops)" to "Array of hex-encoded node hash identifiers, variable length
(e.g. '4a' for single-byte, 'b3fa' for multibyte), ordered by hops"
2. Line ~239: Update the example path_hashes array to include at least one
multibyte hash, e.g.:
"path_hashes": ["4a", "b3fa", "02"]
This demonstrates mixed single-byte and multibyte hashes in the same trace.
3. Add a brief note explaining that firmware v1.14+ supports multibyte path
hashes and that older nodes use single-byte (2-character) hashes, so
mixed-length arrays are expected in heterogeneous networks.
requirements:
- "REQ-008"
dependencies: []
suggested_role: "docs"
acceptance_criteria:
- "path_hashes field description updated from '2-character' to 'variable-length hex'"
- "Example payload includes at least one multibyte path hash"
- "Note about firmware version compatibility is present"
estimated_complexity: "small"
files_affected:
- "SCHEMAS.md"
- id: "TASK-005"
done: true
title: "Write tests for multibyte path hash normalizer"
description: |
Add tests for the updated _normalize_hash_list method in the LetsMesh
normalizer to verify it handles variable-length hex strings correctly.
Add test cases in tests/test_collector/ (either in an existing normalizer
test file or a new test_letsmesh_normalizer.py if one doesn't exist):
1. Single-byte (2-char) hashes: ["4a", "b3", "fa"] -> accepted, uppercased
2. Multibyte (4-char) hashes: ["4a2b", "b3fa"] -> accepted, uppercased
3. Mixed-length hashes: ["4a", "b3fa", "02"] -> all accepted
4. Odd-length strings: ["4a", "b3f", "02"] -> "b3f" filtered out
5. Invalid hex characters: ["4a", "zz", "02"] -> "zz" filtered out
6. Empty list: [] -> returns None
7. Non-string items: [42, "4a"] -> 42 filtered out
Also add/update integration-level tests in tests/test_collector/test_subscriber.py
to verify that multibyte path hashes flow through the full collector pipeline
(subscriber -> handler -> database) correctly. The existing test cases at
lines ~607 and ~662 use 2-character hashes; add a parallel test case with
multibyte hashes.
requirements:
- "REQ-001"
- "REQ-007"
dependencies:
- "TASK-002"
suggested_role: "python"
acceptance_criteria:
- "Unit tests for _normalize_hash_list cover all 7 scenarios listed"
- "Integration test verifies multibyte path hashes stored correctly in database"
- "All existing 2-character path hash tests continue to pass"
- "All new tests pass"
estimated_complexity: "medium"
files_affected:
- "tests/test_collector/test_letsmesh_normalizer.py"
- "tests/test_collector/test_subscriber.py"
- id: "TASK-006"
title: "Write tests for database round-trip of multibyte path hashes"
description: |
Verify that the SQLAlchemy JSON column on the TracePath model correctly
stores and retrieves variable-length path hash arrays without data loss
or truncation.
Add test cases in tests/test_common/test_models.py (where existing
TracePath tests are at line ~129):
1. Store and retrieve a TracePath with multibyte path_hashes:
["4a2b", "b3fa", "02cd"] -> verify round-trip equality
2. Store and retrieve a TracePath with mixed-length path_hashes:
["4a", "b3fa", "02"] -> verify round-trip equality
3. Verify existing test with 2-character hashes still passes
These tests confirm REQ-003 (no migration needed) and contribute to
REQ-007 (backwards compatibility).
requirements:
- "REQ-003"
- "REQ-007"
dependencies:
- "TASK-003"
suggested_role: "python"
acceptance_criteria:
- "Test verifies multibyte path_hashes round-trip through JSON column correctly"
- "Test verifies mixed-length path_hashes round-trip correctly"
- "Existing 2-character path hash test continues to pass"
- "No Alembic migration is created or required"
estimated_complexity: "small"
files_affected:
- "tests/test_common/test_models.py"
- id: "TASK-007"
title: "Write tests for API trace path responses with multibyte hashes"
description: |
Add test cases in tests/test_api/test_trace_paths.py to verify that the
trace paths API returns multibyte path hashes faithfully.
The existing test fixtures in tests/test_api/conftest.py create
sample_trace_path objects with path_hashes like ["abc123", "def456",
"ghi789"] (line ~275). Note these are already 6-character strings, so
the API serialization likely already works. Add explicit test cases:
1. Create a trace path with multibyte path_hashes (e.g. ["4a2b", "b3fa"])
via the fixture, then GET /trace-paths and verify the response contains
the exact same array.
2. Create a trace path with mixed-length path_hashes (e.g. ["4a", "b3fa",
"02"]), then GET /trace-paths/{id} and verify the response.
3. Verify existing API tests with current path_hashes continue to pass.
These tests confirm REQ-004.
requirements:
- "REQ-004"
- "REQ-007"
dependencies:
- "TASK-003"
suggested_role: "python"
acceptance_criteria:
- "Test verifies GET /trace-paths returns multibyte path hashes correctly"
- "Test verifies GET /trace-paths/{id} returns mixed-length path hashes correctly"
- "Existing API trace path tests continue to pass"
estimated_complexity: "small"
files_affected:
- "tests/test_api/test_trace_paths.py"
- "tests/test_api/conftest.py"
- id: "TASK-008"
done: true
title: "Verify web dashboard trace path display handles variable-length hashes"
description: |
Verify that the web dashboard does not have any hardcoded assumptions about
2-character path hash strings. A grep of src/meshcore_hub/web/static/js/spa/
for "path_hash" and "trace" shows no direct references to path hashes in the
SPA JavaScript code, meaning path hashes are likely rendered generically
through the API data display.
Confirm this by:
1. Checking all web template and JavaScript files that render trace path data
2. Verifying no CSS or JS applies fixed-width formatting to path hash elements
3. If any fixed-width or truncation logic exists, update it to handle
variable-length strings
If no web code references path hashes directly (as initial grep suggests),
document that the web dashboard requires no changes for multibyte support.
This satisfies REQ-005.
requirements:
- "REQ-005"
dependencies: []
suggested_role: "frontend"
acceptance_criteria:
- "Web dashboard trace/path display verified to handle variable-length hashes"
- "No fixed-width formatting assumes 2-character hash strings"
- "Any necessary changes applied, or no-change finding documented"
estimated_complexity: "small"
files_affected:
- "src/meshcore_hub/web/static/js/spa/pages/trace-paths.js"