feat(meshcore): per-message scope/region override (#3701)#3704
Conversation
Let operators send a single channel message under a one-off scope/region override without changing the channel's persistent scope. Builds on the scope infrastructure from #3667. Backend: thread an optional `scope?: string | null` override through `MeshCoreManager.sendMessage` / `performScopedSend`. When provided, the override is used INSTEAD of `resolveScopeForSend(...)` but STILL inside `runSerialized` and STILL via `applyFloodScope`, preserving the scope-assert -> send serialization invariant (the device flood scope is a single global stateful value). The override is normalized like elsewhere (strip leading '#', keep letters/digits/hyphens) and is one-off only -- never persisted to the channel row, so the next normal send re-asserts the channel/default scope. API: `POST .../messages/send` accepts an optional `scope` field (validated as a string <= 63 chars); absent = resolve channel/default as usual. Frontend: `useMeshCore.sendMessage` gains the optional override arg, and `MeshCoreChannelsView` adds an unobtrusive per-message scope control next to the channel compose box, defaulting/placeholdering to the channel's resolved scope and offering discovered-region suggestions via a datalist. The override resets on channel switch so it never leaks across channels. Tests: extend meshcoreManager.scope.test.ts to assert the override beats both channel and default scope, is normalized, supports explicit unscoped, is NOT persisted, and still issues set_flood_scope before send_message. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4
|
Claude finished @Yeraze's task —— View job PR Review: feat(meshcore): per-message scope/region override (#3701)
Overall this is a clean, well-considered implementation. The design is sound and the key invariant (scope-assert → send serialization) is preserved correctly. A few things worth discussing: Backend —
|
System Test ResultsMeshMonitor System Test ResultsTest Run: 2026-06-24 08:03:08 EDT ❌ Overall Result: FAILEDAborted on first failing test (fail-fast mode). Remaining tests skipped. Failed Test
|
…tract, tests Review fixes for the per-message scope/region override (#3701): 1. discoverRegions no longer fires on every reconnect. It emitted active radio traffic on each status?.connected transition, which flapping would turn into a discovery flood. Region discovery is now lazy (only after the operator opens the scope-override control, signalling intent) and runs at most once per mount via a ref guard. The cheap local getDefaultScope baseline read still refreshes on reconnect, so the suggestion list and placeholder stay populated. 2. Aligned/documented the normalization contract between the lenient per-send override (normalizeScopeOverride) and the strict persisted POST /config/default-scope (400). Kept lenient sanitising for the transient one-off override but added a warning log when characters are stripped, and documented the rationale in a code comment. 3. Clarified scope null vs '' vs absent semantics at both the send route and normalizeScopeOverride: undefined/null = no override (normal channel/default resolution); ''/whitespace/punctuation-only = explicit unscoped; non-empty string = one-off override. normalizeScopeOverride now collapses null to undefined to match what the route already does. 4. Added a concurrency test asserting the serializer atomically pairs an explicit override send with its own scope-assert→send and the normal send with the channel scope, with no interleaving. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4
|
Claude finished @Yeraze's task —— View job PR Review: feat(meshcore): per-message scope/region override (#3701)
This is a well-implemented PR. The previous review feedback (from the initial CI run) has been addressed thoughtfully. Here's my assessment of the current state: What was addressed from the first review
Concurrent override + non-override serialization test — Added. The new test at line 224-248 fires an override send and a normal send concurrently with a Remaining observations (minor)
<datalist id="mc-scope-region-suggestions">The id is not unique per-source. If two
const resolvedScope = (active.scope && active.scope.trim()) || defaultScope.trim() || '';
...(scope !== undefined ? { scope } : {}),When the caller passes No blockersThe core invariant (scope-assert → send serialized per source) is preserved, the override is correctly one-off, the concurrency test is thorough, and the radio-traffic concern from the first review has been cleanly resolved. The items above are all minor polish. The system test failure (Reverse Proxy Test) appears to be pre-existing infrastructure flakiness unrelated to this PR's changes. |
System Test ResultsMeshMonitor System Test ResultsTest Run: 2026-06-24 08:33:16 EDT ❌ Overall Result: FAILEDAborted on first failing test (fail-fast mode). Remaining tests skipped. Failed Test
|
Summary
Implements issue #3701: let operators send a single MeshCore channel message under a one-off scope/region override without changing the channel's persistent scope. Builds on the scope infrastructure from #3667.
Changes
Backend (
meshcoreManager.ts)sendMessage/performScopedSendaccept an optionalscopeOverride?: string | null.resolveScopeForSend(...)but STILL insiderunSerializedand STILL viaapplyFloodScope— the scope-assert -> send serialization is load-bearing because the device flood scope is a single global stateful value.#, keep letters/digits/hyphens). One-off only: never persisted to the channel row, so the next normal send re-asserts the channel/default scope.null); omitted = resolve channel/default as usual.API (
meshcoreRoutes.ts)POST .../messages/sendaccepts an optionalscopefield, validated as a string (<= 63 chars). Absent = no override.Frontend (
useMeshCore.ts,MeshCoreChannelsView.tsx,MeshCorePage.css)sendMessageaction gains the optional override arg.discoverRegions) via a<datalist>. The override resets on channel switch so it never leaks across channels.Tests (
meshcoreManager.scope.test.ts)set_flood_scopeis still issued beforesend_message.Testing
success: true, 7387 passed, 0 failed, 0 failed suites.tsc --noEmit: no errors in touched files.eslint: clean.Closes #3701
🤖 Generated with Claude Code