build(mqtt): make the preset table byte-identical across channels

The preset table is fleet state, not a build detail. A slot's preset is stored
in /mqtt.json by name, and firmware that does not know a name does not merely
ignore it: MQTTPrefsSerializer repairs it to "none" and CommonCLI writes the
repaired file back to flash. A node that rolls back to a channel missing a
preset therefore loses that slot permanently, and re-upgrading does not bring
it back.

The parity gate compared preset names only, deliberately allowing URL, CA and
credential drift. It now requires src/helpers/MQTTPresets.h to be byte-identical
between the channels, which also catches that drift — the two channels are meant
to dial the same brokers.

That is only workable if the file holds no channel-specific code, so
mqttPresetEnforcesTokenExp() moves to the new MQTTPresetPolicy.h. It was the
sole difference between the two channels' copies, and with it moved they match
exactly today. Policy keyed off the table belongs there from now on; the table
itself stays pure data.

The older name-only comparison stays available without --exact for ad-hoc use,
and the checker's self-test now covers both modes, including that --exact
rejects a config-only change the name check waves through.
This commit is contained in:
agessaman
2026-09-19 16:46:55 -07:00
parent 01c0131a59
commit 1bfbbf4bd8
5 changed files with 145 additions and 27 deletions
@@ -1,7 +1,11 @@
name: Check MQTT Preset Name Parity
# Ensures observer-firmware and observer-firmware-dev share the same built-in
# MQTT preset *names* (config details may differ). See scripts/check_mqtt_preset_parity.py.
# Ensures observer-firmware and observer-firmware-dev ship an identical
# src/helpers/MQTTPresets.h. A slot's preset is stored in /mqtt.json by name, and
# firmware that does not know a name repairs it to "none" and writes the file
# back, so a node that rolls back between channels loses that slot for good.
# Behaviour that differs per channel belongs in MQTTPresetPolicy.h, which is not
# compared. See scripts/check_mqtt_preset_parity.py.
permissions:
contents: read
@@ -81,9 +85,9 @@ jobs:
- name: Self-test checker
run: python3 scripts/check_mqtt_preset_parity.py --self-test
- name: Compare preset names
- name: Compare preset tables
run: |
python3 scripts/check_mqtt_preset_parity.py \
python3 scripts/check_mqtt_preset_parity.py --exact \
/tmp/preset-parity/prod.h \
/tmp/preset-parity/dev.h \
--label-a observer-firmware \