"Claude PR Assistant workflow"#1
Merged
Merged
Conversation
Contributor
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Merged
Yeraze
added a commit
that referenced
this pull request
Oct 12, 2025
5 tasks
Yeraze
added a commit
that referenced
this pull request
Nov 9, 2025
This commit includes three critical fixes for the auto-upgrade system: **Bug Fix #1: Network name interpreted as image name** - Location: scripts/upgrade-watchdog.sh:126-136 - Problem: Shell variable expansion ${network:+--network "$network"} caused word-splitting where network name was interpreted as the image name - Solution: Rewrote using positional parameters (set --) with hardcoded image name to prevent word-splitting issues **Bug Fix #2: Empty environment variable causing trailing -e flag** - Location: scripts/upgrade-watchdog.sh:109-117 - Problem: Docker inspect returned empty environment variable creating a trailing -e flag with no value, consuming the hardcoded image name - Solution: Added grep -v '^$' to filter empty lines before converting to -e flags **Feature: Auto-reload frontend on version change** - Location: src/App.tsx:1650-1672 - Feature: Frontend now polls /api/health to detect backend version changes - Behavior: Automatically reloads page when backend version changes (e.g., after auto-upgrade) - Benefits: Works even when user is logged out, uses existing health endpoint Tested with upgrade from v2.16.0-1 → v2.16.1 (official release). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This was referenced Nov 9, 2025
Closed
Yeraze
pushed a commit
that referenced
this pull request
Nov 11, 2025
Add intelligent permission checking to the container entrypoint script that automatically detects and resolves permission issues, eliminating the most common unRAID deployment problem. Entrypoint Changes (docker/docker-entrypoint.sh): - Add permission check before any file operations - Test if /data is writable by node user (UID 1000) - Automatically run chown if permissions are incorrect - Provide clear success/failure messages - Display actionable error instructions if auto-fix fails - Exit gracefully with exit code 1 if unable to fix Template Updates (unraid-template.xml): - Update Overview to mention automatic permission fixing - Simplify permission notes (auto-fix handles most cases) Documentation Updates (UNRAID_DEPLOYMENT.md): - Update Quick Tips to highlight auto-fix feature - Rewrite Permission Errors section to focus on auto-fix - Document the three possible outcomes and log messages - Provide manual fix instructions only as fallback Benefits: - Eliminates #1 reported issue from unRAID users - No user intervention needed in most cases - Clear feedback in logs about what happened - Graceful degradation with helpful error messages - Works on fresh installs without manual permission setup The entrypoint runs as root before supervisor drops to node user, giving it the ability to fix ownership automatically. Addresses: Issue #538 feedback
Yeraze
added a commit
that referenced
this pull request
Nov 20, 2025
This commit fixes three critical bugs that prevented security flags from being cleared properly, causing nodes to accumulate permanently in the security list. ## Bug #1: updateNodeLowEntropyFlag preserved old details when clearing **File:** src/services/database.ts:1758 When clearing the low-entropy flag, the function incorrectly preserved the old "Known low-entropy key detected" message in keySecurityIssueDetails even though the flag was set to 0. This left nodes with confusing/stale security messages. **Fix:** Rewrote the logic to properly clean up details when clearing flags: - When setting flag: Combine low-entropy details with existing duplicate info - When clearing flag: Remove low-entropy text, preserve only duplicate info - Properly clear all details when no security issues remain ## Bug #2: Scanner never processed nodes without public keys **File:** src/server/services/duplicateKeySchedulerService.ts:103-116 The scanner only processed nodes with public keys. If a node had security flags but later lost its key (went offline, key cleared, etc.), the scanner would skip it entirely and never clear the orphaned flags. **Fix:** Added second pass to check ALL nodes for orphaned security flags: - After main scan, iterate through all nodes in database - Identify nodes without keys that still have security flags set - Clear those orphaned flags with appropriate logging ## Bug #3: Security flags ignored by upsertNode **File:** src/services/database.ts:1569-1682 When meshtasticManager detected security issues and set flags in nodeData, those flags were completely ignored by upsertNode() because INSERT/UPDATE statements didn't include the security flag columns. **Fix:** Added security flag support to upsertNode: - Added keyIsLowEntropy, duplicateKeyDetected, keySecurityIssueDetails to UPDATE - Added same columns to INSERT statement - Added proper parameter handling with boolean-to-integer conversion - Used COALESCE to preserve existing values when not explicitly provided ## Impact - Nodes no longer accumulate permanently in security list - Flags properly cleared when nodes go offline or fix their keys - Security warnings cleared within 24 hours (next scheduled scan) - Details text properly cleaned up when security issues resolved ## Testing - TypeScript compilation: ✓ Pass - Build: ✓ Pass - No database migrations required (columns already exist) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
5 tasks
Yeraze
added a commit
that referenced
this pull request
Nov 23, 2025
- Implement infinite scrolling with @tanstack/react-virtual - Load packets in batches of 100 as user scrolls down - Add packet number column showing position in list (#1, #2, etc.) - Preserve scroll position during polling updates - Merge new packets intelligently to avoid scroll resets - Show loading indicator when fetching more packets - Only render visible rows for performance (virtual scrolling) Fixes scroll position being reset to row 100 on each poll by preserving already-loaded packets beyond the first batch and only updating when new packets arrive. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
8 tasks
6 tasks
3 tasks
Yeraze
added a commit
that referenced
this pull request
May 6, 2026
…ault' (#2913) Issue #2902: clicking "Override Node Position" appeared to succeed but the node never moved on the map. PostgreSQL/MySQL deployments ended up with two rows per node — the live-source row (untouched) and a stray sourceId='default' row containing the override coordinates. Root cause ========== DatabaseService.setNodePositionOverride() (Postgres/MySQL path): - Looks up the cached node with the correct live sourceId — OK. - Mutates the cached node's override fields in place — OK. - Calls `nodesRepo.upsertNode(existingNode)` — BROKEN. The second arg (sourceId) was omitted, so NodesRepository.upsertNode fell back to `sourceId ?? 'default'`. It then ran getNode(nodeNum, 'default'), got null (no such row existed), and INSERTed a brand-new row with sourceId='default'. The live-source row never received the override, so the map (which renders from the live row) never moved. Fixes ===== 1. NodesRepository.upsertNode: when the caller omits the sourceId arg, fall back to `nodeData.sourceId` before defaulting to 'default'. Cached node objects always carry their sourceId; honoring it prevents the silent stray-row bug for any current or future caller. 2. DatabaseService.setNodePositionOverride (line ~7187): pass the sourceId argument explicitly to nodesRepo.upsertNode. Belt and suspenders with fix #1, but makes intent obvious at the call site. 3. DatabaseService.upsertNode (line ~2147): same explicit-sourceId pattern applied to the other bare nodesRepo.upsertNode call. The merged node already carries `sourceId: upsertSourceId`, but passing it explicitly removes the implicit dependency on fix #1. Regression test =============== nodes.test.ts: new test 'upsertNode - falls back to nodeData.sourceId when sourceId arg omitted' verifies that calling upsertNode with a node object whose sourceId field is set (mirroring the cached-node path) writes to that source's row and does NOT create a 'default' row. Runs against all three backend harnesses (SQLite/Postgres/MySQL). SQLite was unaffected — its raw-SQL path in setNodePositionOverride already used the correct sourceId. Fixes #2902 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 tasks
This was referenced May 19, 2026
Closed
Yeraze
added a commit
to tanrax/meshmonitor
that referenced
this pull request
May 21, 2026
The actions router was the only per-source v1 mount that hand-rolled the 401/hasPermission checks instead of delegating to the `attachSource` middleware every other resource uses. Practical fallout: - `/sources/default/actions/*` did not resolve the `default` alias and fell back to the legacy singleton — the exact thing the original review item Yeraze#1 was meant to prevent. - Permission checks were duplicated inline four times. - `req.source` was never populated, so handlers couldn't read the canonical Source row. This switches to per-route `attachSource(resource, action)` so the endpoint can keep its split between `traceroute:write` and `messages:write` while reusing the same source-resolution + per-source 403 machinery as the rest of v1. Handlers drop the inline auth blocks and read `req.params.sourceId` after attachSource canonicalises it. Tests gain mocks for `databaseService.sources.{getSource,getAllSources}`, update the 403 body assertions to the attachSource response shape (`required: { resource, action, sourceId }`), and add coverage for the `default` alias 200 / 404 paths. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Yeraze
added a commit
that referenced
this pull request
May 21, 2026
* feat: add v1 API node action endpoints
Add POST endpoints under /api/v1/actions/ for interacting with
mesh nodes via Bearer token authentication:
- POST /api/v1/actions/traceroute
- POST /api/v1/actions/request-position
- POST /api/v1/actions/request-nodeinfo
- POST /api/v1/actions/request-neighbors
These mirror the existing internal API endpoints but are
accessible with API token auth, enabling external clients
(CLI tools, Emacs, scripts) to trigger node actions without
session cookies or CSRF tokens.
All endpoints accept destination as nodeId ("!a1b2c3d4"),
nodeNum (number), or hex string. They respect the same
permissions and rate limits as the internal API.
* fix: remove unused destructured variables in neighbor info request
* test: add actions endpoint to v1 API version info test
* fix: use req.user and await hasPermission correctly in v1 actions
The middleware sets req.user (not req.apiTokenUser), and hasPermission
is async and takes a User object, not user.permissions. Both bugs caused
TypeError crashes on any request to /api/v1/actions/*.
* fix: address code review issues in v1 node actions
- Use resolveSourceManager instead of deprecated meshtasticManager singleton
- Scope rate-limit map key to sourceId to prevent cross-source leakage
- Add pruneNeighborRateLimit to prevent unbounded map growth
- Fix message ID format to canonical sourceId_nodeNum_packetId
- Pass sourceId as second arg to insertMessage for proper per-source storage
- Fix resolveDestination to reject null/undefined with == null check
- Add consistent channel override support to all four action endpoints
- Move actionsRouter mount to per-source path /sources/:sourceId/actions
- Add comprehensive handler tests covering auth, permissions, rate-limiting,
destination validation, source isolation, and canonical ID format
* refactor(v1/actions): use per-route attachSource for source + permission
The actions router was the only per-source v1 mount that hand-rolled the
401/hasPermission checks instead of delegating to the `attachSource`
middleware every other resource uses. Practical fallout:
- `/sources/default/actions/*` did not resolve the `default` alias and
fell back to the legacy singleton — the exact thing the original
review item #1 was meant to prevent.
- Permission checks were duplicated inline four times.
- `req.source` was never populated, so handlers couldn't read the
canonical Source row.
This switches to per-route `attachSource(resource, action)` so the
endpoint can keep its split between `traceroute:write` and
`messages:write` while reusing the same source-resolution + per-source
403 machinery as the rest of v1. Handlers drop the inline auth blocks
and read `req.params.sourceId` after attachSource canonicalises it.
Tests gain mocks for `databaseService.sources.{getSource,getAllSources}`,
update the 403 body assertions to the attachSource response shape
(`required: { resource, action, sourceId }`), and add coverage for the
`default` alias 200 / 404 paths.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Randall Hand <randall.hand@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 tasks
Yeraze
added a commit
to wilhel1812/meshmonitor
that referenced
this pull request
Jun 8, 2026
…prop Addresses review feedback on PR Yeraze#3344. Yeraze#1 Theme gallery (ThemeDocumentation) no longer calls the legacy setTheme, which forced appearanceMode='dark' and overwrote both theme slots — silently kicking system-mode users into dark mode and clobbering their light theme. Each card now offers "Apply as Dark" / "Apply as Light" that update only the corresponding slot and never change the appearance mode, matching the custom theme cards. Adds regression tests for the per-slot behavior. Yeraze#2 Remove the now-dead onThemeChange prop from SettingsTabProps and its two pass-sites (App.tsx, GlobalSettingsPage.tsx), plus the now-unused setTheme destructuring. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Yeraze
added a commit
that referenced
this pull request
Jun 8, 2026
* feat: add system appearance theme selection * fix(theme): per-slot apply in theme gallery; drop dead onThemeChange prop Addresses review feedback on PR #3344. #1 Theme gallery (ThemeDocumentation) no longer calls the legacy setTheme, which forced appearanceMode='dark' and overwrote both theme slots — silently kicking system-mode users into dark mode and clobbering their light theme. Each card now offers "Apply as Dark" / "Apply as Light" that update only the corresponding slot and never change the appearance mode, matching the custom theme cards. Adds regression tests for the per-slot behavior. #2 Remove the now-dead onThemeChange prop from SettingsTabProps and its two pass-sites (App.tsx, GlobalSettingsPage.tsx), plus the now-unused setTheme destructuring. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Randall Hand <randall.hand@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
5 tasks
This was referenced Jun 18, 2026
Merged
TheWISPRer
pushed a commit
to TheWISPRer/meshmonitor
that referenced
this pull request
Jun 20, 2026
- Mark messages played from the delivery-success callback, not at enqueue:
handleCommand returns { responses, playOnDelivery }; a dropped body DM now
leaves the message pending instead of losing it. (Yeraze#1)
- Wire purgeExpired into databaseMaintenanceService so expired rows are
reclaimed daily (purgeExpired returns a count). (Yeraze#2)
- Count the per-recipient cap across the recipient's identity forms via an
injected node resolver, so it can't be bypassed by addressing one node by
several name forms. (Yeraze#3)
- Mailbox bypasses the per-node cooldown (interactive flow). (Yeraze#4)
- inbox play <sender> filter matches !hex/node-num forms too. (Yeraze#5)
- Non-DM commands return [] (no unsolicited DM). (Yeraze#6)
- inbox delete returns the same response for not-yours vs non-existent ids
(no id enumeration). (Yeraze#7)
- Wrap the mailbox dispatch in try/catch like the script branch. (Yeraze#8)
- Remove the command-prefix tolerance: canonical msg/inbox only. (Yeraze#9)
- Use shared nodeIdHex (unsigned coerce) for the mailbox log target. (Yeraze#10)
Docs + tests updated to match.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Yeraze
added a commit
that referenced
this pull request
Jun 20, 2026
…gaps (#3578) Addresses Claude Code Review findings on PR #3578: - Sanitize device-controlled message before logging/forwarding: strip control chars (log-injection defense) and bound length to 500 (#9, #10). - Widen protected-cap regex to {1,8} hex digits so a short node id still reconciles (#4). - Exclude clientNotification from the unknown-FromRadio debug JSON.stringify dump (#3). - Drop the redundant `&& this.sourceId` guard (always set) and comment why the toast still fires when the DB revert fails (#2, #5). - Frontend: name the level magic numbers and note they mirror the backend NOTIFICATION_LEVEL (#1). - Tests: sanitizer (control chars/whitespace/truncation/empty), short-hex-id parse, and the DB-revert-failure path (#6). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4
Yeraze
added a commit
that referenced
this pull request
Jun 20, 2026
…8 favorite/ignore cap (#3548) (#3578) * feat(notifications): surface device ClientNotifications + handle firmware 2.8 favorite/ignore cap (#3548) MeshMonitor decoded FromRadio.ClientNotification (mesh.proto field 16) and dropped it. Surface these device-originated warnings/errors as toasts, and handle the firmware 2.8 protected-node-cap refusal for Set Favorite / Ignore. Backend: - clientNotificationPolicy.ts (pure/testable): suppression patterns (recurring power-save "sleeping for N interval" INFO + key-verification variants + empty messages), the 2.8 protected-node-cap refusal parser, level->severity mapping, and a per-source ToastThrottle that dedupes identical messages within a window. - meshtasticProtobufService.ts: add the clientNotification dispatch branch (was falling through to the generic catch-all). - dataEventEmitter.ts: client-notification event type + emitClientNotification(). - meshtasticManager.ts: handleClientNotification() reverts the optimistic favorite/ignore flag and re-broadcasts the node when the device refuses at the protected-node cap, then applies the suppression/throttle policy and emits the toast event. Source-scoped throughout. Frontend: - DeviceNotificationToaster.tsx: listens for client-notification inside ToastProvider, maps level->severity, shows the toast. Wired into App.tsx. - WS forwarding + per-source room filtering needed no changes. Scope: the 2.8 NodeDB warm-tier restructure and the on-disk snr_q4 field do NOT affect the over-the-air wire MeshMonitor reads. OTA NodeInfo.snr stays a float in dB; no protobuf/decode change. A regression test guards this. The cap-refusal warning is only emitted by firmware for the locally-connected node (from == 0). Tests (20 new, full suite green): policy unit tests, manager handler tests (reconciliation/suppression/throttle, per-source), and protobuf dispatch + SNR float guard. Docs: FAQ (node count + blocked-node 2.8 behavior; device-notification toasts), IgnoredNodesSection inline help, CHANGELOG, and the support plan dev-note. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4 * address review: sanitize device notification text, robustness + test gaps (#3578) Addresses Claude Code Review findings on PR #3578: - Sanitize device-controlled message before logging/forwarding: strip control chars (log-injection defense) and bound length to 500 (#9, #10). - Widen protected-cap regex to {1,8} hex digits so a short node id still reconciles (#4). - Exclude clientNotification from the unknown-FromRadio debug JSON.stringify dump (#3). - Drop the redundant `&& this.sourceId` guard (always set) and comment why the toast still fires when the DB revert fails (#2, #5). - Frontend: name the level magic numbers and note they mirror the backend NOTIFICATION_LEVEL (#1). - Tests: sanitizer (control chars/whitespace/truncation/empty), short-hex-id parse, and the DB-revert-failure path (#6). 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>
TheWISPRer
pushed a commit
to TheWISPRer/meshmonitor
that referenced
this pull request
Jun 21, 2026
- Mark messages played from the delivery-success callback, not at enqueue:
handleCommand returns { responses, playOnDelivery }; a dropped body DM now
leaves the message pending instead of losing it. (Yeraze#1)
- Wire purgeExpired into databaseMaintenanceService so expired rows are
reclaimed daily (purgeExpired returns a count). (Yeraze#2)
- Count the per-recipient cap across the recipient's identity forms via an
injected node resolver, so it can't be bypassed by addressing one node by
several name forms. (Yeraze#3)
- Mailbox bypasses the per-node cooldown (interactive flow). (Yeraze#4)
- inbox play <sender> filter matches !hex/node-num forms too. (Yeraze#5)
- Non-DM commands return [] (no unsolicited DM). (Yeraze#6)
- inbox delete returns the same response for not-yours vs non-existent ids
(no id enumeration). (Yeraze#7)
- Wrap the mailbox dispatch in try/catch like the script branch. (Yeraze#8)
- Remove the command-prefix tolerance: canonical msg/inbox only. (Yeraze#9)
- Use shared nodeIdHex (unsigned coerce) for the mailbox log target. (Yeraze#10)
Docs + tests updated to match.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Yeraze
added a commit
that referenced
this pull request
Jun 21, 2026
…ore) (#3538) * feat: add Dead Drop / Mailbox auto-responder (async message store) A per-source 'mesh voicemail': a node DMs the radio `msg <name> <text>` and the message is held until the named recipient retrieves it via `inbox` / `inbox play`. Implemented as a new auto-responder responseType ('mailbox'), reusing the existing DM-gating, per-node cooldown, param extraction, and per-source scoping. - DB: dead_drop_messages table (SQLite/PostgreSQL/MySQL) + migration 092 - Repository (Drizzle-only) + DatabaseService.deadDrop accessor - DeadDropService: command brain (store/inbox/play[/sender]/delete/clear, 180-byte cap, per-recipient & per-sender caps, 7-day expiry, batch play) - meshtasticManager: 'mailbox' responseType dispatch branch - UI: 'Mailbox' response type option + guidance in the auto-responder editor - Tests: 34 (migration registry, repository perSource, service) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(dead-drop): add Mailbox option to the Add-Trigger form select The Mailbox response type was only added to the per-trigger edit view (TriggerItem); the separate Add-Trigger form in AutoResponderSection had its own type <select> (Text/HTTP/Script) that was missed, so new mailbox triggers couldn't be created from the UI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(dead-drop): don't require response text to add a Mailbox trigger The Add button's disabled gate required a non-empty response field for all types; Mailbox has no response, so the button stayed greyed out. Exempt mailbox from the response-required check (matches validateResponse). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(dead-drop): accept mailbox responseType in settings save validation The settings-save validator required a non-empty response for every trigger and only allowed text/http/script responseTypes, so saving a Mailbox trigger failed with a generic 400. Exempt mailbox from the response-required check and add it to the responseType allowlist. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(dead-drop): settings-save accepts mailbox triggers without response text Regression coverage for the mailbox responseType in the autoResponderTriggers validator: a mailbox trigger with empty response now saves (200), while non-mailbox empty responses and unknown responseTypes still 400. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(dead-drop): tolerate optional command keyword prefix The mailbox service parsed hardcoded msg/inbox, but a trigger configured with prefixed keywords (e.g. betamsg/betainbox, to coexist with another responder already using msg/inbox) would fire the handler yet fall through to help. Strip an optional non-space prefix from the leading verb so prefixed keywords parse correctly; no-op for plain msg/inbox. Caught by live over-the-air testing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(dead-drop): add Mailbox feature docs + live testing brief - automation.md: Mailbox response type + 'Mailbox (Dead Drop)' section (commands, recipient matching, delivery format, limits, command-prefix coexistence, configuration). - dev-notes/DEAD_DROP_TESTING.md: architecture, automated coverage, and the over-the-air validation results (ALTO MF / ALTO LF / ZN Office). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(dead-drop): register dead_drop_messages in migrate-db table lists The cross-database migrate-db CLI tracks every schema table in TABLE_ORDER / SKIP_TABLES; migrationTables.test.ts fails if a new schema table isn't listed. Add dead_drop_messages to TABLE_ORDER and SOURCE_SCOPED_TABLES (it carries a sourceId, like auto_favorite_targets). Caught by the full Vitest suite. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(dead-drop): address PR review feedback - Mark messages played from the delivery-success callback, not at enqueue: handleCommand returns { responses, playOnDelivery }; a dropped body DM now leaves the message pending instead of losing it. (#1) - Wire purgeExpired into databaseMaintenanceService so expired rows are reclaimed daily (purgeExpired returns a count). (#2) - Count the per-recipient cap across the recipient's identity forms via an injected node resolver, so it can't be bypassed by addressing one node by several name forms. (#3) - Mailbox bypasses the per-node cooldown (interactive flow). (#4) - inbox play <sender> filter matches !hex/node-num forms too. (#5) - Non-DM commands return [] (no unsolicited DM). (#6) - inbox delete returns the same response for not-yours vs non-existent ids (no id enumeration). (#7) - Wrap the mailbox dispatch in try/catch like the script branch. (#8) - Remove the command-prefix tolerance: canonical msg/inbox only. (#9) - Use shared nodeIdHex (unsigned coerce) for the mailbox log target. (#10) Docs + tests updated to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(dead-drop): recommend enabling Verify response on the mailbox trigger Played-state is committed from the delivery-success callback; with Verify response off (maxAttempts=1) a single unacked send could mark a voicemail played on transmit. Document enabling Verify response so undelivered bodies resurface. (PR #3538 review follow-up) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: chrisn <chrisn@DebDev1.corp.tlclocal.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Randall Hand <randall.hand@gmail.com>
This was referenced Jun 23, 2026
Yeraze
added a commit
that referenced
this pull request
Jun 24, 2026
…ration counters - Remove docker-compose.dev.local.yml from the PR (machine-specific dev override) and add it to .gitignore so `git add -A` can't re-stage it. - Migration 102 MySQL: build explicit `IN (?, ?)` placeholders from MQTT_TYPES instead of relying on mysql2's nested-array `IN (?)` expansion, removing any ambiguity that Part B could silently no-op on MySQL. (review issue #3) - Migration 102 PostgreSQL + MySQL: log merged/collapsed/repointed counts to match the SQLite path, so post-deploy auditing is consistent. (review issue #1) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJPe6J5vKrcbwzt6vCdtrt
Yeraze
added a commit
that referenced
this pull request
Jun 24, 2026
…hash (#3708) * fix(mqtt): consolidate channels by name instead of splitting by slot/hash MQTT sources fragmented one logical channel (e.g. LongFast) across the per-source Channels tab and Unified Messages because channel identity was keyed off the per-packet `channel` byte — a channel *hash* (0-255) on MQTT, not a stable 0-7 slot. Three splitters, all observed in live data: 1. `recordChannelFromEnvelope` wrote a `channels` row keyed by the hash, so LongFast landed on rows 0/1/8/40, MediumFast on 0/31, etc. 2. `findOrCreatePassiveByNameAsync` was a non-atomic find-then-create with no unique constraint, so concurrent MQTT packets raced in byte-identical duplicate `channel_database` rows (Primary 3&4, Wong 5&6, …) — splitting messages across CHANNEL_DB_OFFSET+dupId. 3. Messages whose name didn't resolve at ingest were stranded on the raw hash. Canonical identity is now the `channel_database` row, surfaced everywhere as `CHANNEL_DB_OFFSET + dbId` (decrypted packets stay key-verified via decoded.channelDatabaseId; name-only packets resolve by channelId): - Ingestion: stop writing hash-keyed `channels` rows for MQTT. The channel surfaces by name through its channel_database row (message rows on CHANNEL_DB_OFFSET+dbId + the virtual-channel path in /api/unified/channels). - Repo: `findOrCreatePassiveByNameAsync` serializes concurrent creates per lower(name) via an in-flight promise cache (the race is in-process; a cross-backend unique text index is awkward). - Migration 102: merge duplicate channel_database rows by (lower(name), psk) — repointing messages + permissions — then, for MQTT/bridge sources only (never TCP slots 0-7), collapse every hash-keyed channels row and repoint unambiguous raw-hash (< OFFSET) messages onto CHANNEL_DB_OFFSET+dbId. Tests: migration consolidation + idempotency (incl. hash >= OFFSET and TCP untouched), and the passive-create race guard. Full suite: 7391 pass / 0 fail. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJPe6J5vKrcbwzt6vCdtrt * address review: untrack dev override, MySQL IN binding + PG/MySQL migration counters - Remove docker-compose.dev.local.yml from the PR (machine-specific dev override) and add it to .gitignore so `git add -A` can't re-stage it. - Migration 102 MySQL: build explicit `IN (?, ?)` placeholders from MQTT_TYPES instead of relying on mysql2's nested-array `IN (?)` expansion, removing any ambiguity that Part B could silently no-op on MySQL. (review issue #3) - Migration 102 PostgreSQL + MySQL: log merged/collapsed/repointed counts to match the SQLite path, so post-deploy auditing is consistent. (review issue #1) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJPe6J5vKrcbwzt6vCdtrt --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.