Skip to content

release: 4.12.0 — version bump + PR audit & docs-site catch-up#3802

Merged
Yeraze merged 3 commits into
mainfrom
release/4.12.0
Jun 26, 2026
Merged

release: 4.12.0 — version bump + PR audit & docs-site catch-up#3802
Yeraze merged 3 commits into
mainfrom
release/4.12.0

Conversation

@Yeraze

@Yeraze Yeraze commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Summary

Finalizes 4.12.0 (from 4.12.0-rc2). Includes the version bump across all release files, plus a documentation catch-up driven by an audit of every one of the 74 PRs merged since v4.11.5. System tests are enabled on this PR.

Changes

Version → 4.12.0

  • package.json, package-lock.json, desktop/package.json, desktop/src-tauri/tauri.conf.json, helm/meshmonitor/Chart.yaml
  • CHANGELOG.md: [Unreleased][4.12.0] - 2026-06-26

Documentation (docs site / meshmonitor.org)

Two large user-facing feature areas had shipped with no public docs, plus several smaller gaps — all closed:

PR audit — 2 release-risk items flagged (FYI, not introduced here)

The audit flagged two pre-existing items (already shipped in rc1/rc2) worth a second look:

  1. [high] Migration 104 (PR fix(migration): rebuild channel_database on PostgreSQL tombstone exhaustion (#3751) #3753) — the PostgreSQL channel_database rebuild on tombstone exhaustion (attnum ≥1500) does a destructive DROP TABLE … CASCADE + copy. A mid-rebuild failure on a production PG DB risks channel-key/PSK loss. Worth verifying the live-column copy + FK re-attach and adding backup guidance.
  2. [medium] MeshCore contact out_path_len packed encoding (PR feat(meshcore): 2/3-byte path hash support in Define Path editor (#3670) #3686) — now stored in firmware PACKED format (top 2 bits = hash_size−1), contradicting prior project understanding. Harmless for 1-byte paths; could misroute 2/3-byte manual paths if the firmware assumption is wrong. PR claims firmware verification; a second confirmation is prudent.

Issues Resolved

Release of 4.12.0. Documentation for #3653 and #3667 feature sets.

Documentation Updates

See the Documentation section above. vitepress build docs passes; {{ }} tokens verified to render literally.

Testing

  • Full unit suite: 7668 passed, 0 failed, 0 suite failures
  • npm run docs:build (VitePress) builds clean
  • System tests enabled on this PR (label)
  • Reviewer: skim the new automation-engine.md and the meshcore Regions / Scopes section for accuracy; consider the two flagged release-risk items above before cutting the release tag

🤖 Generated with Claude Code

Yeraze and others added 2 commits June 26, 2026 18:30
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
…I 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
@Yeraze Yeraze added the system-test Trigger hardware system tests label Jun 26, 2026
@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown

Claude finished @Yeraze's task —— View job


PR Review: release/4.12.0

Tasks:

  • Gather context and understand PR scope
  • Review version bump files for consistency
  • Review CHANGELOG.md
  • Review new automation-engine.md documentation
  • Review meshcore.md updates
  • Review other documentation updates
  • Check VitePress config changes
  • Summarize findings

Overview

This is a clean release-finalization PR — version bumps + documentation catch-up. No production code changes. All version bumps are consistent. The main review focus is the documentation quality and the two flagged release-risk items.


Version Consistency — ✅ Clean

All five required files are aligned at 4.12.0:

File Version
package.json 4.12.0 ✓
package-lock.json 4.12.0 ✓
desktop/package.json 4.12.0 ✓
desktop/src-tauri/tauri.conf.json 4.12.0 ✓
helm/meshmonitor/Chart.yaml version: 4.12.0 + appVersion: "4.12.0"

CHANGELOG.md correctly moves [Unreleased] section to [4.12.0] - 2026-06-26 with an empty [Unreleased] stub above it. ✓


Documentation Quality

automation-engine.md — New, 300 lines ✅ Generally good

The v-pre wrapper for the {{ }} token syntax is the right call — VitePress/Vue would otherwise interpolate them. The approach is documented in the comment at the top.

Minor concerns:

  1. geofence-triggers cross-reference — Line 101 links to /features/geofence-triggers, but that page already exists and handles the legacy geofence triggers feature from the Meshtastic automation tab. This link may be ambiguous — it's not clear whether the Engine's geofence trigger shares that page or has its own section. If the existing geofence-triggers page doesn't cover the Engine's builder-based geofence, this link will confuse users. Worth verifying the target is correct.

  2. "Run a script" dry-run behavior — The docs say scripts are "stubbed in the dry-run, so testing never spawns a process" (line 282). This is good security behavior but it means users can't test the actual script output path during dry-run. Consider adding a note about how to validate script output separately.

  3. Missing "Apprise" → link — Line 171 mentions [Apprise](/features/notifications) — this link looks correct and is consistent with the rest of the docs.

  4. No mention of the automation permission required — The permission is mentioned as "gated by a dedicated global automations permission" but there's no explanation of where an admin grants it. A forward reference to Per-Source Permissions or the admin UI would help new users.

  5. The FINALLY section description — "run its actions based on how the rules turned out: ANY, ALL, NONE, or ALWAYS" is clear, but the doc doesn't explain that FINALLY is optional and doesn't fire if no rules ran. Worth a clarifying sentence.

meshcore.md — Updates ✅ Well-documented

The Regions/Scopes section (lines 237–290) is thorough and accurate. Several improvements noted:

Good:

  • The "One global scope on the device" warning callout is important and correctly placed.
  • The 0-hop discovery rationale is explained clearly.
  • The per-message override behavior (never persisted, resets on channel switch) is explicitly called out.

Concerns:

  1. out_path_len / Define Path encoding — The PR description flags that PR feat(meshcore): 2/3-byte path hash support in Define Path editor (#3670) #3686 stores paths in firmware PACKED format (top 2 bits = hash_size−1). The documentation at line 141 describes the Define Path editor as allowing users to pick "per-hop hash width (1, 2, or 3 bytes)" but doesn't mention the packed encoding or its implications. If there's any risk of misrouting (as flagged), this warrants at minimum a note that MeshCore firmware is authoritative on encoding, or pointing users to firmware docs. The docs currently don't surface this risk to operators.

  2. "Heard repeaters" section (line 128) correctly notes this is "a heuristic, not a delivery receipt" — good disclosure.

  3. Send bar byte limits table — The 130/120/150 limits match what's documented. No issues.

automation.md — Auto-favorite eligibility correction ✅

The updated eligibility table at lines 1941–1951 correctly reflects the behavior after PRs #3786/#3774. The Client and Client_Mute roles are now explicitly documented as "Never" auto-favorited, with a clear rationale. The Tip callout for Client_Base owners at line 1959 is helpful.

This is a meaningful correctness fix — the previous docs would have led operators to expect behavior that didn't match reality.

maps.md — Channel routing section ✅

Lines 87–99 document the traceroute channel routing logic (lowest-numbered mesh-readable channel vs. hardcoded slot 0). This is correct per the implementation and usefully explains why the channel dropdown exists.

map-analysis.md — Multi-source node popups ✅

The changes correctly document that the inspector panel now shows nodes from multiple sources (the cross-source union fix from #3792).

device.md — Unmessagable nodes ✅

The "Unmessagable Nodes" section (lines 49–60) clearly explains the is_unmessagable / is_licensed=false behavior and what MeshMonitor does in response (hides the DM composer). Good disclosure of the "misleading delivered acknowledgements" reason for hiding it.


VitePress Config — config.mts

The single added line is a correctly-placed sidebar entry:

{ text: 'Automation Engine', link: '/features/automation-engine' },

It sits between Automation and Geofence Triggers, which is the right logical position.


Release-Risk Items (From PR Description)

The author flagged these proactively. My assessment:

[1] Migration 104 PostgreSQL DROP TABLE … CASCADE — This is a legitimate high-severity concern. A destructive table rebuild on a live PG channel_database mid-upgrade could lose PSKs if the process is interrupted. Since this shipped in rc1/rc2 and isn't introduced here, it's pre-existing risk — but the docs and changelog don't mention a backup recommendation before upgrading for PostgreSQL users. Would recommend adding a note in CHANGELOG.md or the upgrade docs flagging this for PG deployments, even as a post-merge follow-up.

[2] MeshCore out_path_len packed encoding (PR #3686) — The PR author says firmware was verified. If that verification is solid, the risk is low for the 1-byte case. The documentation gap noted above (no mention of the packed format in user-facing docs) is minor. No action needed here before merge if the firmware claim has been validated.


Test Coverage

The PR itself contains no production code changes, so no new tests are needed. The PR description reports 7668 passed, 0 failed, and VitePress builds clean. System tests are enabled.


Summary

Recommendation: ✅ Approve with minor follow-ups

This is a well-prepared release PR. The version bump is correct and consistent. The documentation is detailed, accurate, and fills real gaps (Automation Engine and MeshCore Regions/Scopes were genuinely undocumented).

Minor items to consider before or after merging:

  1. Verify the geofence-triggers cross-link in automation-engine.md (line 101) resolves to the right page for the Engine's geofence trigger.
  2. Consider adding a PostgreSQL backup advisory to the upgrade notes for Migration 104 — even a sentence in the changelog pointing PG operators to back up channel_database before upgrading from sub-4.12.

@github-actions

Copy link
Copy Markdown
System Test Results

MeshMonitor System Test Results

Test Run: 2026-06-26 19:03:23 EDT

Test Summary

Test Suite Result
Configuration Import ✅ PASSED
Quick Start Test ✅ PASSED
Security Test ✅ PASSED
V1 API Test ✅ PASSED
Reverse Proxy Test ✅ PASSED
Reverse Proxy + OIDC ✅ PASSED
Virtual Node CLI Test ✅ PASSED
Backup & Restore Test ✅ PASSED
Database Migration Test ✅ PASSED
DB Backing Consistency ✅ PASSED
API Exercise (3 DBs) ✅ PASSED

✅ Overall Result: PASSED

All deployment configurations are working correctly!

Test Details

Configuration Import:

  • Tests configuration import and device reboot cycle
  • Verifies channel roles, PSKs, and LoRa configuration
  • Note: Channel name verification skipped due to architectural limitation

Quick Start Test:

  • Zero-config deployment (no SESSION_SECRET or COOKIE_SECURE required)
  • HTTP access without HSTS
  • Auto-generated admin user with default credentials
  • Session cookies work over HTTP
  • Meshtastic node connection and message exchange verified

Security Test:

  • Verifies Node IP address hidden from anonymous users in API responses
  • Verifies MQTT configuration hidden from anonymous users
  • Verifies Node IP address visible to authenticated users
  • Verifies MQTT configuration visible to authenticated users
  • Verifies protected endpoints require authentication

V1 API Test:

  • Tests v1 REST API endpoints with Bearer token authentication
  • Verifies Bearer token requests bypass CSRF protection
  • Verifies POST/PUT/DELETE work without CSRF token when using Bearer auth
  • Verifies session-based requests still require CSRF token

Reverse Proxy Test:

  • Production deployment with COOKIE_SECURE=true
  • HTTPS-ready configuration
  • Trust proxy enabled for reverse proxy compatibility
  • CORS configured for HTTPS domain
  • Meshtastic node connection and message exchange verified

Reverse Proxy + OIDC Test:

  • OIDC authentication integration
  • Mock OIDC provider health checks
  • Authorization flow and session creation
  • Hybrid mode (OIDC + local auth)
  • Meshtastic node connection verified

Virtual Node CLI Test:

  • Virtual Node Server enabled on TCP port 4404
  • Meshtastic Python client successfully connects
  • Node data download and synchronization verified
  • Test message sent on gauntlet channel (index 3)
  • Message delivery confirmed via Web UI API
  • Virtual Node Server connection logging verified

Backup & Restore Test:

  • System backup created from running dev container
  • New container spun up with RESTORE_FROM_BACKUP env var
  • Data integrity verified (node count, message count, settings)
  • Restore event logged in audit log
  • Dev container unaffected by restore test

Database Migration Test:

  • SQLite to PostgreSQL migration verified
  • SQLite to MySQL migration verified
  • Data integrity confirmed for both target databases
  • Row counts match between source and target

DB Backing Consistency Test:

  • SQLite, PostgreSQL, and MySQL backends tested with same device
  • Node counts within ±10 across all three backends
  • Favorite counts identical across all backends
  • Key station verified as favorite on all backends

…d 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
@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown

Claude encountered an error —— View job


I'll analyze this and get back to you.

@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown

Claude finished @Yeraze's task —— View job


PR Review: release/4.12.0

Tasks:

  • Gather context and understand PR scope
  • Review migration 104 changes (only production code change)
  • Review version consistency
  • Review documentation changes
  • Summarize findings

Overview

This is a release-finalization PR with no general application code changes — just version bumps, a CHANGELOG update, and documentation. The one production code change is an update to migration 104, which resolves the issue flagged in the original PR description about PostgreSQL atomicity.


Migration 104 — PostgreSQL Rebuild (the important one) ✅ Now Correct

The 16-line addition to src/server/migrations/104_add_channel_database_hash.ts wraps the entire PostgreSQL DROP TABLE … CASCADE + copy in a single transaction, directly addressing the release-risk item flagged in the PR description.

What changed:

// Lines 74–162: explicit BEGIN / COMMIT / ROLLBACK wrapping rebuildChannelDatabasePostgres()
await client.query('BEGIN');
try {
  // ... DROP TABLE channel_database CASCADE, copy, RENAME ...
  await client.query('COMMIT');
} catch (err) {
  await client.query('ROLLBACK');
  throw err;
}

Assessment:

  1. Transaction is correctly scoped — the BEGIN is the very first statement before the scratch cleanup DROP TABLE IF EXISTS channel_database_new, so even a failure there rolls back cleanly.

  2. Idempotency preserved — the outer runMigration104Postgres function still does the channelHash column check first (lines 169–180) and returns early if the column already exists. A partial rebuild that committed would have created the column; a failed/rolled-back rebuild leaves the original table intact with no channelHash, so the migration re-runs correctly on the next start.

  3. Sequence rename is within the transactionALTER SEQUENCE channel_database_new_id_seq RENAME TO channel_database_id_seq (line 137) is inside the try block, so it rolls back with the rest on failure. Good.

  4. FK re-attachment is inside the transaction — re-attaching channel_database_permissions FK (lines 140–155) also rolls back on failure.

  5. ⚠️ Minor: indentation inconsistency — The try block body (lines 76–156) is at column 2 while the surrounding rebuildChannelDatabasePostgres body is at column 2 as well, but the await client.query('BEGIN') (line 74) and await client.query('COMMIT') (line 157) are at column 2 while the try { ... } catch block is also at column 2. The content inside the try block appears unindented relative to the try (lines 76–156 vs the try at line 75). This is cosmetic and doesn't affect behavior, but it makes the nesting hard to read. Not a blocker.

  6. 💡 No backup advisory in changelog — For PostgreSQL users upgrading from before 4.12.0 who have a non-trivial channel_database (e.g. with custom PSKs), the changelog gives no heads-up that a destructive table rebuild may occur if they've hit ≥1500 attnum slots. The migration is safe under the transaction, but a brief note in CHANGELOG.md like: "PostgreSQL: migration 104 may rebuild channel_database to clear attnum tombstones; a backup before upgrading is recommended for deployments with custom PSK entries" would help cautious operators. This is a nice-to-have, not a blocker.


Version Consistency — ✅ Clean

All five files are aligned at 4.12.0:

File Version
package.json 4.12.0 ✓
package-lock.json 4.12.0 ✓
desktop/package.json 4.12.0 ✓
desktop/src-tauri/tauri.conf.json 4.12.0 ✓
helm/meshmonitor/Chart.yaml version: 4.12.0 + appVersion: "4.12.0"

CHANGELOG.md correctly moves [Unreleased] to [4.12.0] - 2026-06-26 with a clean empty [Unreleased] stub above.


Documentation — ✅ Generally Good

automation-engine.md (new, 300 lines)

The v-pre wrapper is the right call for the {{ }} token syntax. Key observations:

  • The FINALLY modes (ANY / ALL / NONE / ALWAYS) are documented, and the "Do nothing" action / FINALLY interaction is clear.
  • The Variables → Scopes table is well-organized.
  • Dry-run / test panel behavior is accurately described.
  • Gap: automation permission grant — the doc notes the feature is "gated by a dedicated global automations permission" but doesn't say where an admin grants it. New users will search the admin UI without guidance. A sentence pointing to the user/permissions admin panel would help.
  • Gap: FINALLY fires even with 0 rules — the doc doesn't clarify whether FINALLY runs if there are no RULE blocks at all. Edge case but could surprise users who add FINALLY without any RULE.
  • The geofence-triggers cross-link (line 101: See also the dedicated [Geofence Triggers](/features/geofence-triggers) page) — the existing page covers the legacy Meshtastic geofence trigger, not the Automation Engine's builder-based one. This may confuse users if the two share a page; if they're separate, the link is to the wrong page. Worth verifying.

meshcore.md (updates)

  • Regions/Scopes section (lines 237–289) is thorough and accurate.
  • The "One global scope on the device" warning callout is well-placed.
  • The 0-hop discovery rationale is clearly explained.
  • The per-message override "never persisted" note is explicit. ✅
  • The out_path_len / Define Path packed encoding concern (flagged in PR description) is not mentioned in docs — but the PR author indicated firmware was verified, so this is a documentation gap rather than a runtime bug. Low risk.

Other doc changes ✅

  • automation.md: auto-favorite eligibility table correction is a meaningful accuracy fix.
  • maps.md: channel routing / traceroute logic is correctly described.
  • map-analysis.md: multi-source union popup behavior is accurate.
  • device.md: unmessagable node / DM-hidden behavior clearly explained.

Test Coverage

No production application code was changed (only the migration, which is covered by the existing migration test suite). The PR reports 7668 passed / 0 failed and all 11 system test suites passed including Database Migration Test (which exercises SQLite→PostgreSQL and SQLite→MySQL migration paths).


Summary

Recommendation: ✅ Approve

The migration 104 transaction-safety fix directly addresses the high-priority release risk flagged in rc2. The logic is correct: BEGIN before any destructive DDL, COMMIT on success, ROLLBACK on any error — with idempotency preserved at the outer function level. Version bumps are consistent. Documentation fills real gaps (Automation Engine and MeshCore Regions/Scopes were undocumented). All tests pass.

Minor items (non-blocking):

  1. Consider a PostgreSQL backup advisory sentence in CHANGELOG.md for migration 104 (for operators with custom PSKs who may have hit the attnum limit).
  2. Verify the geofence-triggers cross-link in automation-engine.md (line 101) — confirm it points to the right page for the Engine's builder-based geofence vs. the legacy Meshtastic geofence tab.
  3. Minor indentation inconsistency inside rebuildChannelDatabasePostgres (cosmetic only).

@github-actions

Copy link
Copy Markdown
System Test Results

MeshMonitor System Test Results

Test Run: 2026-06-26 19:09:32 EDT

❌ Overall Result: FAILED

Aborted on first failing test (fail-fast mode). Remaining tests skipped.

Failed Test

  • Configuration Import

@github-actions

Copy link
Copy Markdown
System Test Results

MeshMonitor System Test Results

Test Run: 2026-06-26 19:25:12 EDT

Test Summary

Test Suite Result
Configuration Import ✅ PASSED
Quick Start Test ✅ PASSED
Security Test ✅ PASSED
V1 API Test ✅ PASSED
Reverse Proxy Test ✅ PASSED
Reverse Proxy + OIDC ✅ PASSED
Virtual Node CLI Test ✅ PASSED
Backup & Restore Test ✅ PASSED
Database Migration Test ✅ PASSED
DB Backing Consistency ✅ PASSED
API Exercise (3 DBs) ✅ PASSED

✅ Overall Result: PASSED

All deployment configurations are working correctly!

Test Details

Configuration Import:

  • Tests configuration import and device reboot cycle
  • Verifies channel roles, PSKs, and LoRa configuration
  • Note: Channel name verification skipped due to architectural limitation

Quick Start Test:

  • Zero-config deployment (no SESSION_SECRET or COOKIE_SECURE required)
  • HTTP access without HSTS
  • Auto-generated admin user with default credentials
  • Session cookies work over HTTP
  • Meshtastic node connection and message exchange verified

Security Test:

  • Verifies Node IP address hidden from anonymous users in API responses
  • Verifies MQTT configuration hidden from anonymous users
  • Verifies Node IP address visible to authenticated users
  • Verifies MQTT configuration visible to authenticated users
  • Verifies protected endpoints require authentication

V1 API Test:

  • Tests v1 REST API endpoints with Bearer token authentication
  • Verifies Bearer token requests bypass CSRF protection
  • Verifies POST/PUT/DELETE work without CSRF token when using Bearer auth
  • Verifies session-based requests still require CSRF token

Reverse Proxy Test:

  • Production deployment with COOKIE_SECURE=true
  • HTTPS-ready configuration
  • Trust proxy enabled for reverse proxy compatibility
  • CORS configured for HTTPS domain
  • Meshtastic node connection and message exchange verified

Reverse Proxy + OIDC Test:

  • OIDC authentication integration
  • Mock OIDC provider health checks
  • Authorization flow and session creation
  • Hybrid mode (OIDC + local auth)
  • Meshtastic node connection verified

Virtual Node CLI Test:

  • Virtual Node Server enabled on TCP port 4404
  • Meshtastic Python client successfully connects
  • Node data download and synchronization verified
  • Test message sent on gauntlet channel (index 3)
  • Message delivery confirmed via Web UI API
  • Virtual Node Server connection logging verified

Backup & Restore Test:

  • System backup created from running dev container
  • New container spun up with RESTORE_FROM_BACKUP env var
  • Data integrity verified (node count, message count, settings)
  • Restore event logged in audit log
  • Dev container unaffected by restore test

Database Migration Test:

  • SQLite to PostgreSQL migration verified
  • SQLite to MySQL migration verified
  • Data integrity confirmed for both target databases
  • Row counts match between source and target

DB Backing Consistency Test:

  • SQLite, PostgreSQL, and MySQL backends tested with same device
  • Node counts within ±10 across all three backends
  • Favorite counts identical across all backends
  • Key station verified as favorite on all backends

@Yeraze Yeraze merged commit d17a535 into main Jun 26, 2026
24 of 26 checks passed
@Yeraze Yeraze deleted the release/4.12.0 branch June 26, 2026 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

system-test Trigger hardware system tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant