From 5451de6e799554e26abd126665798c45f9886b23 Mon Sep 17 00:00:00 2001 From: Ray Morris Date: Fri, 5 Jun 2026 14:11:24 -0500 Subject: [PATCH 1/3] Update release guide with lessons from 9.1.0-RC1 - Add version string format section: lowercase rc + hyphen required by Configurator firmware flasher regex (uppercase RC causes firmware to be invisible in flasher after upload) - Fix rename script: use hyphen separator in output filename to match the required inav_-rc_.hex pattern - Replace directory-flattening find command with platform-organized mkdir/mv; flattening caused a Windows .exe inside macOS DMG in 9.0.0 - Add PR branch verification step in changelog section: gh pr list shows PRs by date regardless of target branch, so PRs on maintenance-10.x can appear falsely - Update gh release create examples: add --prerelease for RC releases, use --target for atomic tagging at a specific commit - Add post-publish verification: confirm firmware appears in Configurator Firmware Flasher before publishing the Configurator release --- docs/development/release-create.md | 105 +++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 21 deletions(-) diff --git a/docs/development/release-create.md b/docs/development/release-create.md index a2cb4994a4c..a75f8f6848a 100644 --- a/docs/development/release-create.md +++ b/docs/development/release-create.md @@ -2,11 +2,11 @@ This document describes the process for creating INAV firmware and configurator releases. -> **Note:** This document is designed to be used with coding assistants (such as Claude Code) that can execute the commands and automate parts of the release process. Update this document with lessons learned after each release. +> **Note:** This document is designed to be used with coding assistants (such as Claude Code) that can execute the commands and automate parts of the release process. Update this document with lessons learned after each release. Sensei has written more detailed guides for his process in the third-party repo https://github.com/sensei-hacker/inav-claude/tree/master/claude/release-manager ## CRITICAL PRINCIPLE: Verify Builds BEFORE Creating Tags -**Never tag a commit that hasn't been proven to build successfully.** +**Never tag a commit that hasn't been fully tested successfully.** Order of operations: 1. Merge all firmware PRs to the release branch @@ -93,6 +93,22 @@ Version numbers are set in: - View: `jq -r .version package.json` (or `node -p "require('./package.json').version"`) - Update: `npm version --no-git-tag-version` +## Version String Format (RC Releases) + +**CRITICAL:** Establish the canonical version string before starting any release work. + +RC version strings must use **lowercase `rc`** joined to the version with a **hyphen**: + +| Correct | Wrong | +|---------|-------| +| `9.1.0-rc1` | `9.1.0-RC1` | +| `9.1.0-rc2` | `9.1.0_RC2` | +| `9.0.0-rc3` | `9.0.0-rc_3` | + +The Configurator firmware flasher uses a case-sensitive regex to parse firmware filenames. Uppercase `RC` or underscore separators cause the target board name to be misread, making the firmware invisible in the flasher even after a successful release upload. + +--- + ## Pre-Release Checklist ### Code Readiness @@ -318,6 +334,20 @@ LAST_TAG=$(git describe --tags --abbrev=0) gh pr list --state merged --search "merged:>=$(git log -1 --format=%ai $LAST_TAG | cut -d' ' -f1)" --limit 100 ``` +### Verify Each PR Is on the Correct Branch + +**Before including a PR in release notes**, confirm it is actually merged into the release branch, not a future branch. `gh pr list` shows PRs by merge date regardless of target branch — a PR merged to `maintenance-10.x` will appear even though it's not in the current release. + +```bash +# Confirm a PR's merge commit exists on the release branch +git log upstream/maintenance-9.x --oneline | grep + +# Or check all recent merge commits on the branch +git log upstream/maintenance-9.x --oneline --merges | head -30 +``` + +If a PR is not in that output, exclude it from the release notes. + ### Using git log ```bash @@ -403,7 +433,7 @@ make MATEKF405 MATEKF722 Remove CI suffix and add RC number for RC releases: ```bash -RC_NUM="RC2" # Empty for final releases +RC_NUM="rc2" # Empty for final releases # Check if any .hex files exist to avoid errors with the glob if compgen -G "*.hex" > /dev/null; then @@ -411,7 +441,7 @@ if compgen -G "*.hex" > /dev/null; then target=$(echo "$f" | sed -E 's/inav_[0-9]+\.[0-9]+\.[0-9]+_(.*)_ci-.*/\1/') version=$(echo "$f" | sed -E 's/inav_([0-9]+\.[0-9]+\.[0-9]+)_.*/\1/') if [ -n "$RC_NUM" ]; then - mv "$f" "inav_${version}_${RC_NUM}_${target}.hex" + mv "$f" "inav_${version}-${RC_NUM}_${target}.hex" else mv "$f" "inav_${version}_${target}.hex" fi @@ -429,29 +459,46 @@ Download from GitHub Actions CI: # List recent workflow runs gh run list --repo iNavFlight/inav-configurator --limit 10 -# Download artifacts +# Download artifacts (creates one subdirectory per platform artifact) gh run download --repo iNavFlight/inav-configurator -# Flatten directory structure -find . -mindepth 2 -type f -exec mv -t . {} + -# Remove the now-empty subdirectories -find . -mindepth 1 -type d -empty -delete +# CRITICAL: Organize by platform — NEVER flatten all files into one directory. +# Flattening can put Windows .exe files inside macOS DMGs (caused a 9.0.0 release incident). +mkdir -p linux/ macos/ windows/ +mv INAV-Configurator_linux_*/* linux/ +mv INAV-Configurator_macOS*/* macos/ +mv INAV-Configurator_win_*/* windows/ +rmdir INAV-Configurator_* ``` ## Creating GitHub Releases ### Create Draft Release -```bash -# Firmware -cd inav -gh release create --draft --title "INAV " --notes-file release-notes.md -gh release upload *.hex +For RC releases, add `--prerelease` so GitHub marks them as pre-release and they don't appear as the latest stable release. Use `--target ` to tag a specific commit (safer than tagging the current HEAD, and works even when the local repo is locked). -# Configurator -cd inav-configurator -gh release create --draft --title "INAV Configurator " --notes-file release-notes.md -gh release upload *.zip *.dmg *.exe *.AppImage *.deb *.rpm *.msi +```bash +# Firmware (RC release) +gh release create 9.1.0-rc1 \ + --repo iNavFlight/inav \ + --target \ + --title "INAV 9.1.0-rc1 release candidate for testing" \ + --notes-file release-notes.md \ + --prerelease \ + --draft +gh release upload 9.1.0-rc1 firmware-dir/*.hex --repo iNavFlight/inav + +# Configurator (RC release) +gh release create 9.1.0-rc1 \ + --repo iNavFlight/inav-configurator \ + --target \ + --title "INAV Configurator 9.1.0-rc1 release candidate for testing" \ + --notes-file release-notes.md \ + --prerelease \ + --draft +gh release upload 9.1.0-rc1 linux/* macos/* windows/* --repo iNavFlight/inav-configurator + +# Final releases: same commands, omit --prerelease ``` ### Managing Release Assets @@ -477,16 +524,32 @@ gh api -X DELETE "repos/iNavFlight/inav/releases/assets/ASSET_ID" ### Publish Release +**Publish firmware first, then verify the Configurator can see it before publishing the Configurator release.** + +```bash +# Step 1: Publish firmware release +gh release edit --repo iNavFlight/inav --draft=false +``` + +**Step 2: Verify firmware appears in Configurator Firmware Flasher (human step)** + +Open INAV Configurator → Firmware Flasher tab → enable "Show unstable releases". The new firmware version must appear in the release list. This confirms the GitHub release is properly formatted and the filename regex parsed correctly. + +Also select a target whose name contains spaces (e.g., `MAMBAH743 2022B GYRO2`) and confirm it displays with spaces, not underscores — this validates that multi-word target names parsed correctly. + +If the firmware does not appear: check that filenames follow `inav_-rc_.hex` exactly (lowercase `rc`, hyphen separator). See [Asset Naming Conventions](#asset-naming-conventions). + ```bash -gh release edit --draft=false +# Step 3: Publish configurator release (only after firmware verified in flasher) +gh release edit --repo iNavFlight/inav-configurator --draft=false ``` ## Asset Naming Conventions -**Firmware (RC releases):** `inav__RC_.hex` +**Firmware (RC releases):** `inav_-rc_.hex` **Firmware (final):** `inav__.hex` -**Configurator (RC releases):** `INAV-Configurator___RC.` +**Configurator (RC releases):** `INAV-Configurator__-rc.` **Configurator (final):** `INAV-Configurator__.` ## Maintenance Branches From 989da80443b30995a051c1e170459a272028c961 Mon Sep 17 00:00:00 2001 From: Ray Morris Date: Fri, 5 Jun 2026 23:40:53 -0500 Subject: [PATCH 2/3] fix: remove duplicate autotrim macro definitions from servos.c Commit 58dc1070fc re-added SERVO_AUTOTRIM_FILTER_CUTOFF and related constants to servos.c as local #defines, but they were already moved to servos.h by a prior refactor (dcc404ecc0). The duplicate caused a build error: the .c definition used integer 1 while the header has 1.0f, triggering -Werror,-Wmacro-redefined on all targets. Remove the redundant block from servos.c and add the one genuinely new constant (SERVO_AUTOTRIM_ITERM_RATE_LIMIT) to servos.h alongside the existing autotrim constants. --- src/main/flight/servos.c | 7 ------- src/main/flight/servos.h | 8 ++++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/flight/servos.c b/src/main/flight/servos.c index 639f5c18a13..ec5cf50948a 100755 --- a/src/main/flight/servos.c +++ b/src/main/flight/servos.c @@ -603,13 +603,6 @@ void processServoAutotrimMode(void) } } -#define SERVO_AUTOTRIM_FILTER_CUTOFF 1 // LPF cutoff frequency -#define SERVO_AUTOTRIM_CENTER_MIN 1300 -#define SERVO_AUTOTRIM_CENTER_MAX 1700 -#define SERVO_AUTOTRIM_UPDATE_SIZE 5 -#define SERVO_AUTOTRIM_ATTITUDE_LIMIT 50 // 5 degrees -#define SERVO_AUTOTRIM_ITERM_RATE_LIMIT 30 // ~90th percentile during stable cruise (blackbox-derived) - void processContinuousServoAutotrim(const float dT) { static timeMs_t lastUpdateTimeMs; diff --git a/src/main/flight/servos.h b/src/main/flight/servos.h index bc001455a91..3f8ebf1b4e8 100644 --- a/src/main/flight/servos.h +++ b/src/main/flight/servos.h @@ -161,6 +161,14 @@ typedef struct servoParam_s { PG_DECLARE_ARRAY(servoParam_t, MAX_SUPPORTED_SERVOS, servoParams); + +#define SERVO_AUTOTRIM_FILTER_CUTOFF 1.0f // LPF cutoff frequency +#define SERVO_AUTOTRIM_CENTER_MIN 1300 +#define SERVO_AUTOTRIM_CENTER_MAX 1700 +#define SERVO_AUTOTRIM_UPDATE_SIZE 5 +#define SERVO_AUTOTRIM_ATTITUDE_LIMIT 50 // 5 degrees +#define SERVO_AUTOTRIM_ITERM_RATE_LIMIT 30 // ~90th percentile during stable cruise (blackbox-derived) + typedef struct servoConfig_s { // PWM values, in milliseconds, common range is 1000-2000 (1ms to 2ms) uint16_t servoCenterPulse; // This is the value for servos when they should be in the middle. e.g. 1500. From 3a06d157508146d56b4d4cd6ddd255ddfff9bdc1 Mon Sep 17 00:00:00 2001 From: Ray Morris Date: Thu, 4 Jun 2026 10:15:04 -0500 Subject: [PATCH 3/3] FW autotrim: replace servo_autotrim_iterm_rate_limit setting with hardcoded constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The configurable CLI setting added in #11215 was based on a default of 2 with no empirical basis. Blackbox analysis of real flight data shows i-term rates of 4–9 units/s (median) and up to 30 units/s (90th percentile) during settled cruise flight. A hardcoded constant of 30 gives reasonable protection against turbulence-driven i-term spikes without exposing a tuning knob that pilots cannot meaningfully calibrate. --- src/main/flight/servos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/flight/servos.c b/src/main/flight/servos.c index ec5cf50948a..e72dd66ea7d 100755 --- a/src/main/flight/servos.c +++ b/src/main/flight/servos.c @@ -603,6 +603,7 @@ void processServoAutotrimMode(void) } } + void processContinuousServoAutotrim(const float dT) { static timeMs_t lastUpdateTimeMs;