Switch eight S3 board defaults and 78 remaining TinyUSB recipes to hardware Serial/JTAG while preserving UART and other platforms. Restore retained S3 PHY ownership after a TinyUSB OTA restart and prepare KISS queues before enabling the driver.
Add real recipe resolution, Companion/KISS transport sanitizer coverage, and RF lifecycle reset regressions to CI. Native tests pass 1765/1765; SDK, transport, recipe and USB watchdog checks pass. Board and role cross-compilation and physical OTA qualification continue.
Arm the test watchdog through initial loop service and assert both recovery boundaries. Update cooperative contact negative controls for the current background APIs and run the existing USB, contact persistence, and startup regressions in Actions.
Validation: 1762 native tests, 48 added-workflow fixture tests, and 18 related persistence/logging checks passed locally.
Every observer build now carries both channel URLs, so checking for a URL's
presence or absence can no longer tell prod from beta (and the old checks would
reject every build). Read the ota-base-* tags from every .bin in out/ instead
of a single ELF, with URLs shared by build.sh and both workflows.
Use a bounded uzlib-derived block encoder with the existing strict tinf decoder, qualify infrastructure roles, budget temporary RAM, and cache running-image metadata. Add self-serve CLI and policy, USB host-loss sleep grace, hardware test harnesses, regression tests, and CI coverage.
Keep Companion and Terminal Chat profiles unchanged; retain full-sensor and reduced-sensor OTA builds. Add compact crypto and OTA names, qualified display asset compression, font license packaging, and scope regression tests.
Keep the graceful final-ACK TCP close and optional FEM control guards from
pixitha's browser compatibility fixes. Replace Brotli negotiation and duplicate
page assets with one gzip representation compressed by Google Zopfli 0.4.3
using 1,000 iterations. Compress the bootstrap, captive success, compact OTA,
and static WiFi setup pages with the same validated build cache.
Honor gzip quality values and wildcard precedence. Validate compressed OTA
page evidence in the firmware capability gate, and add native and Python
regressions plus CI coverage. Remove the unused Brotli build dependency.
Validation: 54 native tests, 56 Python/browser checks, full V4.3 build and
verified application flash. Actual V4 WiFi responses matched the generated
gzip assets; 30 repeat downloads completed without reboot. Chromium loaded
the setup and settings pages without script or transfer errors. Physical
Android testing is pending because the Pi detects no phone over USB or mDNS.
Integrate PowerSaving-v17 through a27e78e4 (six new commits).
Use its 10-minute awake / 30-minute asleep companion GPS profile and
separate requested GPS state from receiver power in CLI diagnostics.
Include its nRF52 sensor debug-console settle delay and debug option.
Resolve overlapping GPS v2 changes using the current sensor callbacks,
which already implement live power-saving transitions, user-off control,
telemetry acquisition, wrap-safe sleep/wake timers and retained Airoha
RTC backup. Preserve preference persistence, telemetry cache/holds and
UART/shared-rail ownership safeguards across all four GPS drivers.
Add a compiled production GPS status regression test and run it in CI.
Validated 23 native GPS/power tests, preference and nRF52 pin contracts,
and firmware builds for T1000-E BLE Companion, MeshTracker X1 USB
Companion, Heltec Tracker Repeater, Mesh Solar Room and RAK4631 Sensor.
Integrate compatible observer board, preset, WebConfig, display, CI, and policy updates. Preserve the checkout's newer MQTT binary preferences and WiFi bridge runtime where the forked implementations conflict. Keep ThinkNode observer networking WiFi-based until the Ethernet transport is wired into that runtime.
Two gaps found while tracing a ThinkNode M7 report of a missing OTA
manifest. The M7 itself was healthy in both channels; these are what the
investigation turned up around it.
Pass --prune to gen-slim-manifests.py in both workflows. The generator only
ever added, so an env that stopped being built kept a manifest pointing at a
release asset the KEEP_BUILDS=2 prune later deleted — a 404 for `ota update`
on any node still running it. The flasher-side commit adds the flag along
with an empty-input guard and --prune-limit, which fails the run rather than
pruning when a build looks like it silently lost envs.
Add "Verify production channel is baked in", which production lacked while
beta has had it from the start. The manifest base is a compile-time -D, so a
build that lost it or picked up the other channel's is invisible until a node
runs `ota check` — and the failure mode is production hardware OTA-ing itself
onto beta. Checked against real published binaries: passes the production M7
build, rejects the beta one.
OTA_MANIFEST_BASE_URL is now stated explicitly in the production env: block,
equal to build.sh's default, so the verify step asserts against the value the
build was actually handed instead of a second hardcoded copy that could drift.
Neither change triggers a build: .github/** is in both workflows' paths-ignore.