Skip to content

chore: cut v4.1.0 — version stamp, CHANGELOG cut, and ship the LED strip in every build - #149

Merged
TheAngryRaven merged 2 commits into
BETAfrom
claude/beta-release-prep-7sy1wd
Aug 23, 2026
Merged

chore: cut v4.1.0 — version stamp, CHANGELOG cut, and ship the LED strip in every build#149
TheAngryRaven merged 2 commits into
BETAfrom
claude/beta-release-prep-7sy1wd

Conversation

@TheAngryRaven

@TheAngryRaven TheAngryRaven commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Summary

Release-prep for 4.1.0, plus the decision that defines what 4.1.0 is: the NeoPixel strip stops being a beta-only build and ships in the normal firmware. Merge this into BETA first; #151 stacks on it and the BETA -> master promotion (#150) then carries both.

1. Ship the LED strip in every build

BIRDSEYE_ENABLE_NEOPIXEL's #ifndef default in project.h goes 0 → 1. That single line is the whole mechanism: every workflow already installs the Adafruit NeoPixel library, release.yml passes no feature flags at all, and compile-sketch.yml's non-BETA arm passes an empty FEATURE_FLAGS — so all three channels pick the new default up on their own. beta.yml's explicit =1 is now redundant but harmless and left alone.

What it costs, stated plainly because no later firmware can undo it. The subsystem's first boot programs UICR->NFCPINS to convert the two NFC pads to GPIO and self-resets once so the latch takes effect. That is one-way — reversing it needs a full chip erase and a bootloader reflash over USB — and with the flag on by default it is charged to every device that installs 4.1.0, wired for LEDs or not, because the firmware cannot tell the difference. The trade is deliberate: this hardware never uses NFC, the pads are otherwise idle, and gating a headline feature behind a separate build had kept it out of everyone's hands. Anyone who wants those pads for something else must not install 4.1.0, so the CHANGELOG now leads its 4.1.0 section with an upgrade note saying exactly that, including the one extra reboot to expect.

Verified that no other translation unit changes: #if BIRDSEYE_ENABLE_NEOPIXEL appears nowhere outside neopixel.ino, so nothing else compiles differently and the simulator (which excludes that file) is untouched — 6/6 sim ctest still green with the flag flipped, goldens and both lap oracles included.

2. The release cut

FIRMWARE_VERSION 4.0.0 → 4.1.0. MINOR is right by this repo's policy: new settings and behaviour, nothing removed, no format break — track files, the DOVEX layout, log filenames and the BLE command protocol are byte-for-byte what 4.0.0 wrote.

[Unreleased] had accreted the same shape it did last release — two separate ### Changed headings and a trailing ### Added sitting after ### Fixed. Consolidated into one Added/Changed/Fixed set under [4.1.0] - 2026-08-22. All 20 entries and every body line moved verbatim, verified by diffing the sorted line multiset before and after, not by eye.

[Unreleased]'s link ref was still comparing from v3.1.0 (stale since the 4.0.0 cut) and [4.0.0] never got a ref at all. Both fixed, [4.1.0] added.

3. Docs follow the decision rather than trailing it

The per-entry (beta channel) markers come off the LED entries — they aren't beta any more. Updated: CLAUDE.md subsystem 16, its flags list, constants table, File Map intro and workflows row; the ARCHITECTURE.md LED bullet; CONTRIBUTING.md's flag table (now noting this is the one flag defaulting to 1); and compile-sketch.yml's channel comment, where the difference between the two arms is now just SensorEgg and the DovesLapTimer ref. Two in-code comments still calling the strip beta-only are corrected.

DovesLapTimer pin: no bump needed

compile-sketch.yml warns that promoting the channel means bumping the library pin deliberately. Checked rather than assumed: git diff v4.3.0 origin/BETA in TheAngryRaven/DovesLapTimer touches nothing under src/ — five CI workflow files and that is all. Nothing to bump in any of the three workflows.

Type of change

  • Bug fix (no user-visible behavior change beyond the fix)
  • New feature / behavior
  • Refactor (no behavior change)
  • Tests only
  • CI / tooling / docs
  • Breaking change (track files, log format, BLE protocol, or a removed mode)

Not a breaking change by the CHANGELOG's definition — no track file, log format, BLE protocol or removed mode — but the UICR conversion is irreversible per device, which is why it gets an upgrade note rather than a bullet.

How it was verified

  • Host unit tests pass — 507 cases / 325,581 assertions
  • Sim suite green with the flag flipped — 6/6 ctest, goldens and both lap oracles
  • Flag flip confirmed to change no other TU (#if BIRDSEYE_ENABLE_NEOPIXEL grep)
  • clang-tidy clean — CI
  • Compiles for the XIAO nRF52840 Sense — CI
  • Tested on real hardware — the UICR conversion on a stock unit has not been exercised on a device from this branch. It has been running on beta units since plan 0006, which is the same code path, but the fleet-wide first-boot-converts-and-reboots sequence is worth confirming on one non-beta unit before tagging.

Changelog restructure verified mechanically: sorted body-line multiset identical before/after, 20 entries before and after. project.h keeps its CRLF endings (the first attempt normalized them and was redone byte-precise).

Checklist

Related issues

Prep for the BETA -> master promotion (#150). #151 stacks on this with the review fixes. Deliberately excludes #148 (drag mode), slated for the next beta.

Release steps after merge

  1. Merge this, then fix: release-review findings for 4.1.0 — BLE settings list, LED rail, strict setting parse #151, into BETA; then Release 4.1.0 — LED strip subsystem, BLE download rework, RPM filter, menu escapes #150 into master.
  2. Wait for compile-sketch on the master push to go green — the only run that compiles the real release configuration, since this PR's own compile job builds with BETA's flags and library ref.
  3. Watch the OTA image-size gate on that run. The both-flags-on beta build is at 86.5% of the 417,792 B cap; NeoPixel-on/SensorEgg-off will land a little under it, still inside the 90% warn line but worth reading.
  4. Tag v4.1.0.

…lease notes

FIRMWARE_VERSION 4.0.0 -> 4.1.0 (matches the v4.1.0 tag to come). MINOR is
right: new settings and device behaviour, nothing removed and no format
break — track files, the DOVEX layout, log filenames and the BLE command
protocol are byte-for-byte what 4.0.0 wrote.

CHANGELOG: [Unreleased] had accreted the same shape as last cut — two
separate "### Changed" headings and a trailing "### Added" after "### Fixed"
from successive merges. Consolidated into one Added/Changed/Fixed set under
[4.1.0] - 2026-08-22. All 20 entries and every body line moved VERBATIM
(verified by diffing the sorted line multiset before and after); only the
five entries below gained a channel marker.

The marker is the substantive change here. Most of this release's headline
work — the whole NeoPixel subsystem — is behind BIRDSEYE_ENABLE_NEOPIXEL,
which is off in the published images, so a reader of these notes would
otherwise go looking for LEDs that a release build never lights. Each
affected entry is now marked *(beta channel)*, and the section intro says
plainly which half of the release is live for every user. Two plan-0007
behaviours are NOT gated and were being described as if they were: the tach
page's corrected *OVER REV* header (display_pages.ino reads
settingOverrevLimit outside any #if) and the pace page's STOPPED state
(raceEngineStopped(), same) both ship active — those entries now say
*(every build)* on that half and *(beta channel)* on the LED half.

Link refs: [Unreleased] was still comparing from v3.1.0, stale since the
4.0.0 cut, and [4.0.0] never got a ref at all. Both fixed, [4.1.0] added.

DovesLapTimer pins are deliberately untouched. compile-sketch.yml warns that
promoting the channel means bumping them, but the library's BETA branch is
source-identical to the v4.3.0 tag master already pins (the only difference
between the two refs is five CI workflow files), so there is nothing to bump.

Verified: 507 host test cases / 325,581 assertions pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U6kd8xwnUbXyd2Ce6m8ydX
@github-actions

Copy link
Copy Markdown

Coverage — host-testable units

📂 Overall coverage

Metric Coverage
Lines 🟢 1612/1635 (98.6%)
Functions 🟢 172/172 (100.0%)
Branches 🟡 1213/1349 (89.9%)

📄 File coverage

File Lines Functions Branches
BirdsEye/ble_stream.cpp 🟢 34/34 (100.0%) 🟢 8/8 (100.0%) 🟡 17/20 (85.0%)
BirdsEye/camera_fsm.cpp 🟢 238/246 (96.7%) 🟢 20/20 (100.0%) 🟡 142/160 (88.8%)
BirdsEye/course_creator.cpp 🟢 213/221 (96.4%) 🟢 21/21 (100.0%) 🟡 119/136 (87.5%)
BirdsEye/course_prune.cpp 🟢 37/37 (100.0%) 🟢 5/5 (100.0%) 🟢 47/50 (94.0%)
BirdsEye/crc32.cpp 🟢 30/30 (100.0%) 🟢 4/4 (100.0%) 🟢 24/24 (100.0%)
BirdsEye/crossing_pattern.cpp 🟢 15/15 (100.0%) 🟢 1/1 (100.0%) 🟢 12/12 (100.0%)
BirdsEye/dovex_header.cpp 🟢 106/107 (99.1%) 🟢 7/7 (100.0%) 🔴 62/88 (70.5%)
BirdsEye/filename_validator.cpp 🟢 14/14 (100.0%) 🟢 1/1 (100.0%) 🟢 30/30 (100.0%)
BirdsEye/gps_stats.cpp 🟢 25/25 (100.0%) 🟢 3/3 (100.0%) 🟢 8/8 (100.0%)
BirdsEye/gps_status_page.cpp 🟢 29/29 (100.0%) 🟢 4/4 (100.0%) 🟢 28/28 (100.0%)
BirdsEye/gps_time.cpp 🟢 45/45 (100.0%) 🟢 6/6 (100.0%) 🟢 30/32 (93.8%)
BirdsEye/gps_validation.cpp 🟢 24/24 (100.0%) 🟢 2/2 (100.0%) 🟢 66/66 (100.0%)
BirdsEye/haversine.cpp 🟢 8/8 (100.0%) 🟢 1/1 (100.0%) ⚫ 0/0 (0.0%)
BirdsEye/idle_policy.cpp 🟢 17/17 (100.0%) 🟢 2/2 (100.0%) 🟢 14/14 (100.0%)
BirdsEye/insta360_protocol.cpp 🟢 140/140 (100.0%) 🟢 16/16 (100.0%) 🟡 86/98 (87.8%)
BirdsEye/lap_format.cpp 🟢 18/18 (100.0%) 🟢 1/1 (100.0%) 🟢 9/9 (100.0%)
BirdsEye/led_animations.cpp 🟢 76/76 (100.0%) 🟢 5/5 (100.0%) 🟢 43/46 (93.5%)
BirdsEye/led_frame.cpp 🟢 21/21 (100.0%) 🟢 7/7 (100.0%) 🟢 6/6 (100.0%)
BirdsEye/led_modes.cpp 🟢 64/65 (98.5%) 🟢 5/5 (100.0%) 🟢 48/50 (96.0%)
BirdsEye/local_time.cpp 🟢 48/48 (100.0%) 🟢 6/6 (100.0%) 🟢 46/50 (92.0%)
BirdsEye/sat_bars.cpp 🟢 33/33 (100.0%) 🟢 2/2 (100.0%) 🟢 51/54 (94.4%)
BirdsEye/sd_access_policy.cpp 🟢 9/9 (100.0%) 🟢 3/3 (100.0%) 🟢 18/18 (100.0%)
BirdsEye/sd_format_page.cpp 🟢 25/25 (100.0%) 🟢 3/3 (100.0%) 🟢 25/26 (96.2%)
BirdsEye/sector_purple.cpp 🟢 51/51 (100.0%) 🟢 2/2 (100.0%) 🟡 42/50 (84.0%)
BirdsEye/sensoregg_protocol.cpp 🟢 44/45 (97.8%) 🟢 7/7 (100.0%) 🟢 33/34 (97.1%)
BirdsEye/sprint_select.cpp 🟢 25/25 (100.0%) 🟢 4/4 (100.0%) 🟢 46/48 (95.8%)
BirdsEye/tach_filter.cpp 🟢 93/93 (100.0%) 🟢 12/12 (100.0%) 🟡 74/84 (88.1%)
BirdsEye/track_json.cpp 🟢 116/120 (96.7%) 🟢 12/12 (100.0%) 🟡 67/88 (76.1%)
BirdsEye/wake_cause.cpp 🟢 14/14 (100.0%) 🟢 2/2 (100.0%) 🟢 20/20 (100.0%)

…EL defaults to 1

The LED strip stops being a beta-only build and becomes a core feature in
4.1.0: a stock logger drives a strip the moment someone wires one, with no
special firmware. The flag's #ifndef default in project.h goes 0 -> 1, which
is the whole mechanism — every workflow already installs the Adafruit
NeoPixel library, release.yml passes no feature flags at all, and
compile-sketch.yml's non-BETA arm passes an empty FEATURE_FLAGS, so all three
channels pick the new default up on their own. beta.yml's explicit
-DBIRDSEYE_ENABLE_NEOPIXEL=1 is now redundant but harmless, and left alone.

WHAT THIS COSTS, stated plainly because no later firmware can undo it: the
subsystem's first boot programs UICR->NFCPINS to convert the two NFC pads to
GPIO and self-resets once so the latch takes effect. That is a ONE-WAY change
— reversing it needs a full chip erase and a bootloader reflash over USB —
and with the flag on by default it is charged to EVERY device that installs
4.1.0, wired for LEDs or not, since the firmware cannot tell the difference.
The trade was made deliberately: this hardware never uses NFC, the pads are
otherwise idle, and gating a headline feature behind a separate build had
kept it out of everyone's hands. Users who want the pads for something else
must not install 4.1.0, so the CHANGELOG leads its 4.1.0 section with an
upgrade note saying exactly that, including the extra reboot to expect.

No other translation unit changes: grep confirms `#if BIRDSEYE_ENABLE_NEOPIXEL`
appears nowhere outside neopixel.ino, so nothing else compiles differently and
the simulator (which excludes that file) is untouched — 6/6 sim ctest still
green with the flag flipped, goldens and both lap oracles included.

Docs follow the decision rather than trailing it: the CHANGELOG's channel note
is replaced by the upgrade warning and the per-entry "(beta channel)" markers
come off the LED entries (they are not beta any more); CLAUDE.md subsystem 16,
its flags list, constants table, File Map intro and workflows row; the
ARCHITECTURE LED bullet; CONTRIBUTING's flag table (now noting this is the one
flag defaulting to 1); and compile-sketch.yml's channel comment, where the
difference between the two arms is now just SensorEgg and the library ref.
Two in-code comments still calling the strip beta-only are corrected too.

Verified: 507 host test cases / 325,581 assertions and 6/6 sim ctest.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U6kd8xwnUbXyd2Ce6m8ydX
@TheAngryRaven TheAngryRaven changed the title chore: cut v4.1.0 — version stamp, CHANGELOG cut, channel-accurate release notes chore: cut v4.1.0 — version stamp, CHANGELOG cut, and ship the LED strip in every build Aug 22, 2026
@TheAngryRaven
TheAngryRaven merged commit df98764 into BETA Aug 23, 2026
8 checks passed
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.

2 participants