Files
firmware/test/state-manifest.tsv
Thomas Göttgens 14eaa5587d Honor mute when waking the screen for a received message (#11688)
* fix(ui): honor mute when waking the screen for a received message

TextMessageModule fired powerFSM.trigger(EVENT_RECEIVED_MSG) for every text
packet, gated only by shouldWakeOnReceivedMessage(), which checks external
notification, device role and battery level but never the mute flags. A muted
channel therefore suppressed the banner and still lit the screen.

MessageRenderer::handleNewMessage() only computed mute for MessageType::BROADCAST,
so a DM from a muted node produced a banner and a wake.

Add isMutedForPacket() in Channels: a DM addressed to us reads the sender's
NodeInfoLite mute bit, every other packet reads the mute bit of the channel it
arrived on. This is the predicate ExternalNotificationModule already applied to
the buzzer, vibra and LED outputs, hoisted so all three call sites share it.

Bell and alert messages still break through mute on both paths, unchanged.

No protobuf or config change: ChannelSettings.module_settings.is_muted and the
NodeInfoLite mute bit already exist and are already settable from the device menu
and via AdminMessage.toggle_muted_node.

Closes #11674

* fix(ui): let an alert break through mute on the screen wake path

In COLOR display mode TextMessageModule skips handleNewMessage(), so
powerFSM.trigger(EVENT_RECEIVED_MSG) is the only wake an alert gets. Gating it
on mute alone dropped that wake for a bell on a muted channel.

Add MeshService::isAlertPayload(): an ASCII BEL in the payload while at least one
alert_bell_* output is enabled. The wake gate is now "not muted, or an alert".
MessageRenderer uses the same predicate instead of its own inline bell scan,
which also lifts that scan's arbitrary 100 byte cap.

Rename three test cases. Their names carried exactly 35 characters after the
test_ prefix, which matches the Lob API key format and tripped trufflehog in the
trunk check gate.
2026-09-01 11:52:40 +00:00

8.8 KiB

1# Shared-state manifest for the native test suites.
2#
3# Every suite runs inside its own scratch $HOME (bin/pio-test-isolate.sh), so leftovers cannot reach
4# the next suite. This file is not what makes that safe - it is what makes each suite's intent
5#
6# The invariant behind the flags: mutation *inside* a suite is free, carrying state *across* a suite
7# boundary is never permitted. No flag grants cross-suite carry - a suite that needs another suite's
8# output needs an explicit fixture, not inheritance. That is the whole bug, and per-suite isolation
9# keeps it impossible by construction rather than by policy.
10#
11# Format - three tab-separated columns, the same shape as an allowlist entry:
12#
13# <suite><flags><reason>
14#
15# The reason column is mandatory and is reviewed on change. One central file rather than a file per
16# suite, so every opt-out is visible in one diffable list and attracts review pressure; per-suite
17# files hide growth. bin/run-tests.sh prints how many suites declare non-default handling, so the
18# number creeping upward is visible without anyone auditing this file.
19#
20# Flags (space separated; the default is no entry at all):
21#
22# writes=<a,b> files this suite mutates inside its sandbox. Matched against the path relative
23# to the scratch $HOME or just the basename, so `nodes.proto` is enough. A
24# declared write makes the change CLEAN instead of DIRTY - the list is the
25# documentation. A declared file that does NOT change is reported as MISSING,
26# which catches silently-broken persistence.
27# state=per-suite state persists across this suite's own test cases; the default is per-test.
28# Use for persistence round-trips, migration ladders, anything where test N must
29# observe test N-1's write. With this set, only the suite boundary is checked -
30# per-test checking would flag every test by design.
31#
32# state=per-suite is the one to watch. It is legitimate, and it is also the pattern that let
33# test_nodedb_blocked accumulate 198 protected nodes across its test cases. Requiring the flag makes
34# that an explicit, defended choice instead of an accident of setUp().
35#
36# To propose entries from a real run: ./bin/run-tests.sh --write-manifest prints the lines it would
37# add, for a human to paste and justify. It never applies them itself, and CI never applies them at
38# all - an auto-accepted baseline is the same rot as an auto-updated snapshot.
39#
40# errors=<max> | <min>..<max> | <min>.. caps a suite's LOG_ERROR lines, default 100. A range, not a
41# ceiling: for a fuzz suite the floor is the half that matters. test_fuzz_decode logging ~100k
42# rejections is the suite working; the same suite logging none means it stopped feeding malformed
43# input, and every case would still pass. Bounds are wide on purpose - they catch a path that has
44# stopped running, not a drift of a few hundred lines.
45#
46# suiteflagsreason
47test_admin_radiowrites=config.proto,module.proto,device.proto,channels.proto,nodes.proto,warm.dat,Messages_default.msgs errors=400per-test NodeDB fixture, and the admin handlers under test persist config, channels and node metadata
48test_admin_session_reprowrites=config.proto,module.proto,device.proto,channels.proto,nodes.protoconstructs a NodeDB, whose constructor persists a default set when the prefs directory is empty
49test_event_channel_phone_apiwrites=config.proto,module.proto,device.proto,channels.proto,nodes.protoconstructs a NodeDB, whose constructor persists a default set when the prefs directory is empty
50test_event_channel_routerwrites=config.proto,module.proto,device.proto,channels.proto,nodes.proto errors=200subclasses NodeDB for the event-channel fixtures; the base constructor persists a default set when the prefs directory is empty
51test_firmware_editionwrites=config.proto,module.proto,device.proto,channels.proto,nodes.protopersists an event firmware_edition in devicestate, then reboots a NodeDB to prove a vanilla build resets it
52test_fuzz_decodeerrors=20000..250000fuzzes protobuf decode; every rejection logs. A collapse to near zero means the corpus stopped reaching the decoder
53test_fuzz_packetswrites=config.proto,module.proto,device.proto,channels.proto,nodes.proto,warm.dat,Messages_default.msgs errors=5000..60000drives decode of fuzzed packets through the real NodeDB and message store
54test_hop_scalingwrites=config.proto,module.proto,device.proto,channels.proto,nodes.protoconstructs a NodeDB to hold the hop-distance fixtures
55test_hop_start_policywrites=config.proto,module.proto,device.proto,channels.proto,nodes.protoconstructs a NodeDB (isFromUs needs nodeDB->getNodeNum()), whose constructor persists a default set when the prefs directory is empty
56test_mesh_beaconwrites=module.protoexercises the beacon's module-config save path
57test_mesh_modulewrites=config.proto,module.proto,device.proto,channels.proto,nodes.proto,warm.datmodule framework tests construct a NodeDB
58test_mqttwrites=config.proto,module.proto,device.proto,channels.proto,nodes.proto errors=1000..12000constructs a NodeDB for node lookups in the MQTT paths
59test_muted_sourcewrites=config.proto,module.proto,device.proto,channels.proto,nodes.protoconstructs a NodeDB (isToUs needs nodeDB->getNodeNum(), and the DM branch looks the sender up), whose constructor persists a default set when the prefs directory is empty
60test_nexthop_routingwrites=config.proto,module.proto,device.proto,channels.proto,nodes.protonext-hop selection reads and updates the node DB
61test_nodedb_blockedstate=per-suite writes=config.proto,module.proto,device.proto,channels.proto,nodes.proto,warm.datsaturates the DB with MAX_NUM_NODES-2 favourited nodes to test the protected cap; a later test's removeNodeByNum() persists that state, and the cap test depends on the fill from the test before it
62test_nodedb_boot_recoverystate=per-suite writes=config.proto,module.proto,device.proto,channels.proto,nodes.protodeliberate boot-recovery ladder: corrupts/deletes/restores the pref files and reboots a NodeDB per test to pin the DECODE_FAILED identity freeze, so each test observes the previous test's on-disk state
63test_nodedb_identity_hygienewrites=config.proto,module.proto,device.proto,channels.proto,nodes.proto,warm.dat,Messages_default.msgsconstructs a NodeDB; addFromContact persists the node DB after every merge, the reboot test proves the key-erasure guard survives a reload, and the should_ignore path rewrites the message store
64test_nodedb_legacy_migrationwrites=config.proto,module.proto,device.proto,channels.proto,nodes.proto,warm.dateach test hand-writes a v24-format nodes.proto fixture and cold-boots a NodeDB, whose constructor persists the migrated v25 database (warm.dat via the over-cap eviction absorb)
65test_nodedb_v25_roundtripwrites=config.proto,module.proto,device.proto,channels.proto,nodes.proto,warm.datv25 persistence round-trips: every test saves nodes.proto and cold-boots a NodeDB whose constructor persists the default segments; warm.dat on the node-DB save cadence
66test_packet_signingwrites=config.proto,module.proto,device.proto,channels.proto,nodes.proto,warm.dat errors=300needs a NodeDB holding both peers' keys for the PKI encode/decode paths
67test_phone_api_config_dumpwrites=config.proto,module.proto,device.proto,channels.proto,nodes.protoper-test NodeDB fixture backing full PhoneAPI want_config dumps; the constructor persists a default config/channel/node set in a fresh sandbox
68test_pki_admin_fallbackwrites=config.proto,module.proto,device.proto,channels.proto,nodes.protoneeds a NodeDB holding admin keys for the fallback paths
69test_reliable_ack_matrixwrites=config.proto,module.proto,device.proto,channels.proto,nodes.protoconstructs a NodeDB (whose constructor persists a default set when the prefs directory is empty) for the sender-key lookups in the ACK/NAK matrix
70test_stream_apiwrites=config.proto,module.proto,device.proto,channels.proto,nodes.protodrives real PhoneAPI handshakes, which read and persist config and the node DB
71test_traceroute_nexthopwrites=config.proto,module.proto,device.proto,channels.proto,nodes.prototraceroute route selection reads the node DB
72test_traffic_managementwrites=config.proto,module.proto,device.proto,channels.proto,nodes.proto,warm.dat errors=3000..12000constructs a NodeDB for the per-node rate-limit and dedup state; test_tm_fuzz_nodenum_blitz feeds malformed payloads, and each rejection logs (measured 7985)
73test_transmit_historywrites=transmit_history.datpersistence round-trip: what it asserts is that retransmission state survives a save/load
74test_warm_storewrites=warm.datpersistence round-trip of the warm-tier snapshot, which is the tier's whole contract