Skip to content

20261021 - Stop shipping and passing on the tracker's dead minimum SNR - #50

Merged
Purple10101 merged 1 commit into
mainfrom
20261021-drop-min-snr
Oct 21, 2026
Merged

Purple10101 merged 1 commit into
mainfrom
20261021-drop-min-snr

Conversation

@Purple10101

Copy link
Copy Markdown
Collaborator

What

Every node is handed min_snr: 7.0 for retina-tracker, a setting nothing reads any more. This stops shipping it, drops the copy every node holds in user.yml, and makes sure removing it cannot crash the tracker.

Why

retina-tracker v0.5.0 tracks every detection. Its per-site SNR gate is gone (retina-tracker ed9bbea, "Track every detection: no per-site SNR threshold"), and a config that still sets min_snr is loaded and ignored. retina-gui stopped offering the field in retina-gui#119. Here, though, default.yml still shipped it and the merger still wrote it into retina-tracker.yaml.

Two things made "just delete the line" wrong:

  • It would reach no node. The merger seeds user.yml with a whole copy of default.yml on first boot, so every node already holds retina_tracker: {min_snr: 7.0}, or whatever retina-gui wrote there. This is the same first-boot copy problem migrate_remove_tracker() and the other migrations solve.
  • It would crash the tracker on every node. An empty retina_tracker: section reads as null, and the merger would have written tracker: null. retina-tracker's load_config() calls .update() on each section it finds, so that raises TypeError and the tracker crash-loops.

Fix

  • config/default.yml: the retina_tracker section is removed, so the tracker runs on its own built-in defaults. A comment says how a section would map if one is added again.
  • migrate_remove_min_snr(user):
    • Drops retina_tracker.min_snr from the user overlay at merge time.
    • Unconditional, like migrate_remove_tracker(), because the setting configures nothing.
    • Drops the section once it is empty, or if it is already empty or null.
    • Leaves user.yml on disk untouched, so it stays load-bearing and a Mender rollback regenerates the old config from the old default.yml.
  • generate_retina_tracker_config():
    • Writes retina-tracker.yaml on every run, as {} when there is nothing to override, and never as tracker: null.
    • Before, an absent section skipped the write and left the previous merge's file on disk, still saying min_snr: 7.0.

Testing

  • Tests:
    • The three generic retina-tracker.yaml tests move off min_snr to gate_threshold.
    • New tests cover the first-boot copy and a value retina-gui wrote, another tracker key surviving, an empty and a null section, a stale file being overwritten, user.yml left untouched, and the shipped default.yml.
    • Every tracker file is loaded through a mirror of retina-tracker's own load_config(), so a tracker: null would fail the test.
  • CI's commands locally: pytest config-merger/test/ scripts/test/ gives 83 passed. ruff check . and the pre-commit dead-code hook are clean.
  • On a test node with an RSPduo, using its real retina-config-merger:v0.4.8.0-dev and retina-tracker:v0.5.0 images, with the new script and default.yml mounted over the baked-in ones, against a copy of its real user.yml, writing to a scratch folder:
    • The merger logged "Dropping retina_tracker.min_snr (7.0) from user config" and wrote {}.
    • user.yml was unchanged.
    • The merged config.yml differed from the live one by retina_tracker.min_snr alone.
    • The tracker image loaded the {} file and fell back to its defaults.
    • As a control, the same tracker image crashed with TypeError: 'NoneType' object is not iterable on a tracker: null file.

Not verified: a full stack run with this merger in place. The merger image is only built at release, so the live stack on the test node was not touched.

Docs

retina-node has no docs/ folder, and the README does not mention the tracker section. The explanation lives in the default.yml comment and the two docstrings.

After this

  • It reaches nodes with the next retina-node release, which bumps CONFIG_MERGER_V to its own tag as usual. The change is in the merger image, which bakes in default.yml.
  • retina-tracker's docs/measurement-noise.md lists retina-node's min_snr as an outstanding follow-up, which can be closed once this ships.

🤖 Generated with Claude Code

retina-tracker v0.5.0 tracks every detection. Its per-site SNR gate is
gone (retina-tracker ed9bbea), and a config that still sets min_snr is
loaded and ignored. retina-gui stopped offering the field in #119, but
default.yml still shipped min_snr: 7.0 and the merger still wrote it into
retina-tracker.yaml, so every node was handed a setting nothing reads.

Removing it from default.yml alone would reach no node. The merger seeds
user.yml with a whole copy of default.yml on first boot, so every node on
the estate still holds retina_tracker: {min_snr: 7.0}, or whatever
retina-gui wrote there. migrate_remove_min_snr() drops the key from the
user overlay at merge time, unconditionally like migrate_remove_tracker(),
and drops the section once it is empty. user.yml on disk is left alone, so
the migration stays load-bearing and a Mender rollback regenerates the old
config from the old default.yml.

Simply deleting the key would have left an empty retina_tracker section,
which YAML reads as null and the merger would have written as tracker:
null. retina-tracker's load_config() calls .update() on each section it
finds, so that crashes it with TypeError and the tracker would crash-loop
on every node. An empty or null section is now dropped by the migration,
and generate_retina_tracker_config() treats one as nothing to override.
It also writes the file on every run, as {} when there is nothing to
override, because skipping it left the previous merge's file on disk still
saying min_snr: 7.0.

Tests: the three generic retina-tracker.yaml tests move off min_snr to
gate_threshold, and new ones cover the first-boot copy and a value
retina-gui wrote, another tracker key surviving, an empty and a null
section, a stale file being overwritten, user.yml left untouched and the
shipped default.yml. Every tracker file is loaded through a mirror of the
tracker's own load_config(). Full merger suite 83 passed, ruff and the
dead-code hook clean. On a test node, the real config-merger and
retina-tracker v0.5.0 images were run against a copy of its user.yml: the
merged config differed from the live one by retina_tracker.min_snr alone,
the tracker loaded the {} file cleanly, and the same tracker crashed on a
tracker: null file.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Purple10101
Purple10101 merged commit 9388bf6 into main Oct 21, 2026
1 check passed
@Purple10101
Purple10101 deleted the 20261021-drop-min-snr branch October 21, 2026 10:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant