Skip to content

[codex] Add KiwiSDR protocol metadata scaffolding#3898

Merged
ten9876 merged 6 commits into
aethersdr:mainfrom
rfoust:codex/kiwi-capability-metadata
Jul 1, 2026
Merged

[codex] Add KiwiSDR protocol metadata scaffolding#3898
ten9876 merged 6 commits into
aethersdr:mainfrom
rfoust:codex/kiwi-capability-metadata

Conversation

@rfoust

@rfoust rfoust commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds KiwiSDR protocol/capability scaffolding, richer read-only receiver metadata, diagnostic compressed SND/W/F support, automation snapshots, and monitor/camping state handling. Full-but-API-capable receivers now continue to WebSocket admission so MSG monitor can offer waiting/camping, qpos channel-free notifications are actionable via Connect, and monitor/camping sessions no longer present a controllable Kiwi waterfall.

The automation bridge now exposes get kiwi / get kiwisdr, returning Kiwi profile state, metadata, protocol capability state, stream observations, sequence counters, waterfall availability, and diagnostic compression request state for future non-pixel automation checks.

Constitution principle honored

Principle IV — clean-room contributions. KiwiSDR source was used only as a protocol reference where license-compatible, and provenance is recorded in docs/kiwisdr-cleanroom-design.md.

Consulted KiwiSDR reference:

  • Repository: https://github.com/jks-prv/KiwiSDR.git
  • Commit: a83085fe2222dd3e374910faf2195e0454b556ae
  • Files: rx/rx_waterfall.h, rx/rx_waterfall.cpp, rx/rx_cmd.h, rx/rx_cmd.cpp, rx/rx_sound.h, rx/rx_sound.cpp, rx/rx_sound_cmd.cpp, rx/csdr/ima_adpcm.h, rx/csdr/ima_adpcm.cpp, rx/rx_server.cpp, rx/rx_monitor.cpp, rx/rx_server_ajax.cpp
  • web/kiwi/monitor.js was viewed only to confirm user-facing monitor/camp wording; no JavaScript code was copied or translated.

Test plan

  • Local build passes (cmake --build build --target AetherSDR kiwi_sdr_protocol_test -j8)
  • Behavior verified on a real radio if applicable: N/A, KiwiSDR receive-only path; no Flex radio-side commands are sent for Kiwi profile state
  • Existing tests pass (CI)
  • Reproduction steps documented if user-reported bug: covered by non-network protocol regressions and automation bridge smoke

Additional local validation:

  • ctest --test-dir build -R 'kiwi_sdr_protocol_test|kiwi' --output-on-failure
  • git diff --check
  • python3 tools/check_a11y.py exited 0; only existing warning-only findings were reported
  • Automation bridge smoke with QT_QPA_PLATFORM=offscreen AETHER_AUTOMATION=1 ./build/AetherSDR.app/Contents/MacOS/AetherSDR, then python3 tools/automation_probe.py ping and python3 tools/automation_probe.py get kiwi

Checklist

  • Commits are signed (docs/COMMIT-SIGNING.md)
  • No new flat-key AppSettings calls — use nested-JSON-under-one-key (Principle V)
  • Code is clean-room — not decompiled, disassembled, or reverse-engineered from a proprietary binary (Principle IV)
  • All meter UI uses MeterSmoother (AGENTS.md convention)
  • Documentation updated if user-visible behavior changed, including docs/automation-bridge.md
  • Security-sensitive changes reference a GHSA if applicable: N/A

@rfoust rfoust marked this pull request as ready for review June 29, 2026 03:33
@rfoust rfoust requested review from a team as code owners June 29, 2026 03:33
Copilot AI review requested due to automatic review settings June 29, 2026 03:33

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands AetherSDR’s KiwiSDR receive-only path with protocol/capability scaffolding, richer receiver metadata, monitor/camping state handling, and automation visibility so future work can branch on explicit observed protocol state (instead of logs) while keeping Kiwi control paths safely suppressed during monitor/camp sessions.

Changes:

  • Adds KiwiSDR protocol metadata/capability types plus SND/W/F frame classification and decode support for compressed SND (IMA ADPCM) and compact W/F rows.
  • Extends KiwiSDR client/manager/UI to represent busy/waiting/camping flows, keep monitor sessions non-controllable (esp. waterfall), and surface metadata/protocol summaries.
  • Extends the automation bridge with get kiwi snapshots and adds/expands regression tests and documentation for diagnostic compression flags.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/kiwi_sdr_protocol_test.cpp Adds protocol regression coverage for new frame layouts, decoding, metadata parsing, and camping state tokens.
src/main.cpp Wires MainWindow’s KiwiSDR snapshot provider into the automation server.
src/gui/RadioSetupDialog.cpp Shows richer Kiwi profile status (busy/waiting/camping) and a metadata/protocol summary in the setup UI; refreshes on telemetry/state changes.
src/gui/MainWindow.h Adds automation snapshot API for KiwiSDR and removes legacy single-client members/slots.
src/gui/MainWindow.cpp Removes legacy KiwiSdrClient teardown and tracking sync calls in favor of manager-driven behavior.
src/gui/MainWindow_Wiring.cpp Adjusts panadapter wiring to only enable Kiwi waterfall when the profile can actually control it.
src/gui/MainWindow_KiwiSdr.cpp Adds Kiwi protocol/metadata JSON snapshot for automation, expands overlay messaging, and refines waterfall enable/disable logic.
src/gui/KiwiSdrApplet.h Extends per-receiver UI model with metadata/protocol summary strings.
src/gui/KiwiSdrApplet.cpp Displays metadata/protocol details and improves accessibility text for receiver rows.
src/core/KiwiSdrProtocol.h Introduces protocol metadata/capability structs, enums, and new parsing/decoding APIs (and metatypes).
src/core/KiwiSdrProtocol.cpp Implements API policy inference, metadata parsing/merge, SND ADPCM + compact W/F decode, and frame classification.
src/core/KiwiSdrManager.h Exposes receiver metadata/protocol state accessors and a “reconnect recommended” hint for waiting sessions.
src/core/KiwiSdrManager.cpp Registers new metatypes, propagates telemetry changes, and refines connect/reconnect gating for waiting/camping.
src/core/KiwiSdrClient.h Adds new connection states, monitor/camping hooks, protocol telemetry, and diagnostic compression helpers.
src/core/KiwiSdrClient.cpp Implements monitor/camping state machine, capability/telemetry tracking, compressed SND decode + compact W/F decode, and monitor-safe command suppression.
src/core/AutomationServer.h Documents get kiwi as a supported automation snapshot model.
src/core/AutomationServer.cpp Implements `get kiwi
docs/kiwisdr-cleanroom-design.md Records clean-room provenance and expands protocol notes for compressed SND / compact W/F and camping behavior.
docs/automation-bridge.md Documents Kiwi diagnostic compression env vars and new get kiwi snapshot fields.

Comment thread src/gui/RadioSetupDialog.cpp
Comment thread src/gui/MainWindow_KiwiSdr.cpp
@rfoust rfoust self-assigned this Jun 29, 2026
@rfoust rfoust force-pushed the codex/kiwi-capability-metadata branch from 0262a83 to 6d14cca Compare June 29, 2026 04:02

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, @rfoust — this is an unusually clean, well-structured piece of scaffolding. I read through KiwiSdrProtocol.{h,cpp}, the client/manager wiring, the automation snapshot path, the docs, and the regression tests. All six CI checks (build, macOS, Windows, CodeQL, analyze, a11y) are green, and the design holds up to scrutiny.

What's solid

  • KiwiSdrProtocol is the right shape. The new code is almost entirely pure, side-effect-free functions over byte buffers with a thorough has*/value pattern, consistent std::clamp on every decoded index/level, and explicit FrameLayout/CampStatus/ApiPolicy enums instead of stringly-typed state. That's a big readability win over scattered log strings.
  • Decoder safety is careful. classifySoundFrame/classifyWaterfallFrame reject short/empty/misaligned/stereo/unknown-length payloads as non-fatal (telemetry updated, no samples emitted) before any decode runs. The IMA-ADPCM tables and nibble order match the standard, SoundAdpcmState{valid=true} means a restart frame correctly re-syncs rather than dropping the block, and sequence-gap → state-reset prevents corrupt predictor audio. The compact-W/F path discards the 10 predictor-pad samples and length-checks the 517-byte payload exactly as documented.
  • Test coverage tracks the new paths — compressed SND restart/reset/invalidate/sequence-gap, compact W/F classify+decode, and a captured real-receiver fixture. The clean-room provenance in kiwisdr-cleanroom-design.md is meticulous (per-file, per-commit, license-noted).
  • Conventions honored: no QSettings/flat-key settings introduced, the diagnostic env flags are receive-only and documented in automation-bridge.md, and the automation snapshot reuses the existing set*SnapshotHandler lambda pattern in main.cpp verbatim. Scope is coherent — every touched GUI file is snapshot/telemetry/UI wiring for the Kiwi path.

Copilot findings — both valid, both genuinely addressed

  • RadioSetupDialog telemetry rebuild (3621): confirmed. kiwiTelemetryRefreshTimer (RadioSetupDialog.cpp:3305) is a single-shot 150 ms QTimer(this) (parented, no leak), and only the high-frequency profileTelemetryChanged path arms it; profilesChanged/profileStateChanged still refresh immediately. This correctly coalesces metadata bursts.
  • Asymmetric snapshot flag (795): confirmed. automationKiwiSdrSnapshot() now emits both diagnosticSoundCompressionRequested and diagnosticWaterfallCompressionRequested at top level, so automation can assert launch mode without a live profile.

Minor (non-blocking)

  • diagnosticSoundCompressionRequested() / ...Waterfall...() call qgetenv on each invocation (telemetry-struct construction + every snapshot). Since these are documented as fixed launch-time flags, caching into a function-local static const bool would avoid the repeated env lookups. Not a hot path, so purely optional.

No correctness, null-deref, or resource concerns found. Nice work — LGTM as read-only scaffolding.


🤖 aethersdr-agent · cost: $6.7527 · model: claude-opus-4-8

@rfoust rfoust force-pushed the codex/kiwi-capability-metadata branch from 6d14cca to bd4eef2 Compare June 30, 2026 00:52
@rfoust

rfoust commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up update pushed in bd4eef2d:

  • Waiting/camping text now says AetherSDR is waiting for a free KiwiSDR receiver slot and will reconnect automatically when the server reports one is available.
  • KiwiSdrManager now schedules the existing 3-second normal reconnect path when MSG qpos metadata reports the reload/free-slot hint, including manual Connect attempts that are sitting in Waiting.
  • The Kiwi setup row keeps Waiting sessions as active, so the button remains Disconnect to cancel the wait/retry instead of switching back to Connect.
  • The clean-room design note now records this queue boundary.

Validation:

  • cmake --build build --target AetherSDR kiwi_sdr_protocol_test -j8
  • ctest --test-dir build -R 'kiwi_sdr_protocol_test|kiwi' --output-on-failure
  • git diff --check
  • python3 tools/check_a11y.py (warning-only existing findings)
  • QT_QPA_PLATFORM=offscreen AETHER_AUTOMATION=1 ./build/AetherSDR.app/Contents/MacOS/AetherSDR
  • python3 tools/automation_probe.py ping
  • python3 tools/automation_probe.py get kiwi

Add structured KiwiSDR capability and receiver metadata state, compressed SND/W/F diagnostic decode paths, monitor/camping handling, and automation bridge snapshots.

Validate with focused Kiwi protocol tests, build, a11y checker, diff check, and automation bridge smoke.
@rfoust rfoust force-pushed the codex/kiwi-capability-metadata branch from bd4eef2 to f91b903 Compare June 30, 2026 01:01
@rfoust

rfoust commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up update pushed in f91b903a:

  • The waterfall overlay now uses queue-aware wording during Kiwi monitor/waiting sessions instead of the old generic “monitor sessions do not provide a controllable waterfall” message.
  • Waiting overlays now title as “Waiting for KiwiSDR receiver slot” and explain that AetherSDR will reconnect automatically when the server reports a slot is available.
  • Queue position, free-slot/reconnecting, and camped-monitor cases each get specific waterfall detail text.

Validation:

  • cmake --build build --target AetherSDR kiwi_sdr_protocol_test -j8
  • ctest --test-dir build -R 'kiwi_sdr_protocol_test|kiwi' --output-on-failure
  • git diff --check
  • python3 tools/check_a11y.py (warning-only existing findings)
  • QT_QPA_PLATFORM=offscreen AETHER_AUTOMATION=1 ./build/AetherSDR.app/Contents/MacOS/AetherSDR
  • python3 tools/automation_probe.py ping
  • python3 tools/automation_probe.py get kiwi

@ten9876 ten9876 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: changes requested

High-effort pass over the Kiwi protocol scaffolding (8 finder angles + adversarial verification). CI is green, conventions are clean (receive-only path, no flat-key settings, a11y names present), and the binary parser is genuinely defensive — no crash/UAF/overflow found. Findings are inline; scope notes below.

Blockers (inline)

  • too_busy parse-failure forces busy=true — default MSG path.
  • The camped-receiver read-only safety rests entirely on the client m_monitorMode guard, with nothing binding it to the manager Camping state.
  • Two definitions of "connected" (control-capable vs has-receive-audio) drive inconsistent waterfall/aperture decisions for camped profiles.
  • The full-receiver fail-fast was dropped for the full-AND-not-camp-capable case.

Fast-follow (inline, AETHER_KIWI_SND_COMP-gated diagnostic path)

Connected-but-silent on a no-restart compressed frame, and predictor-0 first-frame ADPCM corruption. Low reachability (diagnostic env var), but real.

Pre-existing — NOT introduced by this PR (recommend a separate issue, not blocking)

  • extractMeterFromSndVerifiedLayout (main line 263) emits a Verified-confidence S-meter from any 1034-byte SND frame without checking the compression flag; under compression it reads ADPCM init bytes as a calibrated meter. The fix is to consult the MeterContext.compressionObserved it already receives but Q_UNUSEDs.
  • parseSoundFrameHeader collapses the 32-bit sequence counter to its low byte (main line 68) — this PR's new ADPCM resync now depends on it, so it's worth widening alongside the compressed work.

Cleanup / altitude (non-blocking)

  • Per-frame double/triple parse on the hot path: each SND header is decoded ~4× and each W/F frame inspected ~3× (build the header/shape once and pass it down).
  • Duplicate IMA-ADPCM nibble decoders; hand-rolled endian readers where qFromLittleEndian/qFromBigEndian already exist; a dead pass-through diagnosticWaterfallCompressionFlagEnabled.
  • Speculative scaffolding the PR itself labels as such: the 8-state CampStatus enum with no camp connect path, and the Q_UNUSED MeterContext.
  • A latent two-parsers-for-one-header hazard: parseWaterfallFrameHeader reads byte[8], inspectWaterfallFrame reads a u16+compression flag at offset 8 — they agree for zoom≤30 but diverge on a malformed frame. Worth collapsing to one parser.

Happy to pair on the m_monitorMode / state-capability-table consolidation — that's the one with on-air-adjacent risk. Thanks for the clean-room provenance and the automation-bridge test notes.

Comment thread src/core/KiwiSdrProtocol.cpp Outdated
Comment thread src/gui/MainWindow_KiwiSdr.cpp
Comment thread src/gui/MainWindow_Wiring.cpp
Comment thread src/core/KiwiSdrClient.cpp
Comment thread src/core/KiwiSdrClient.cpp
Comment thread src/core/KiwiSdrProtocol.cpp
…ety, capacity message

Resolves the blocking findings from the protocol-scaffolding review:

- too_busy parse-failure no longer forces busy=true. A malformed/empty
  `too_busy=` (or an injected MSG) previously marked a reachable receiver
  as busy and could abandon connect/queue. Now guarded on a successful
  parse, matching users/users_max/preempt/max_camp. Adds a regression test.

- Camped-receiver read-only safety is now bound to the Camping STATE, not
  just the m_monitorMode flag. New receiverControlSuppressed() gates all
  five control sends (tracked slice, receiver controls, waterfall view,
  display adjustments, rate) on `m_monitorMode || state == Camping`, so
  tune/mode/AGC commands can never reach a monitored receiver even if the
  flag and state disagree. This also makes the two notions of "connected"
  (has-receive-audio vs allows-receiver-control) consistent at the
  authoritative layer.

- Full-and-not-camp-capable receivers regain the precise capacity message.
  When the status preflight reports the receiver full we still proceed to
  WebSocket admission for a possible monitor/camp offer, but if none arrives
  the failure now carries "(N/M users) at capacity" instead of a generic
  setup-timeout. (Camp-capability is only known post-admission via the
  WS max_camp MSG, so an even-earlier abort is a follow-up.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ten9876 ten9876 dismissed their stale review June 30, 2026 15:47

Blockers addressed in c2ce492: too_busy parse-failure no longer forces busy; camped read-only safety is now bound to the Camping state (receiverControlSuppressed gates all five control sends); and the full-and-not-camp-capable case regains the precise capacity message. Protocol changes verified against the test suite (+ new regression test); client changes compile clean against production flags. Dismissing so the PR can re-evaluate; the strictly-faster post-admission abort remains a follow-up.

ten9876 and others added 2 commits June 30, 2026 13:49
The capacity-message fix reset m_preflightReportedFull only in
connectToEndpoint(), not in retryWithSecureWebSocket(). Since the wss retry
skips the HTTP status preflight, a stale "full" result from the ws attempt
persisted and could make a wss-retry timeout emit the precise "(N/M users)
at capacity" message the secure attempt never re-verified. Reset it alongside
the other per-attempt flags in the retry path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The qpos MSG handler set campStatus=Queued before validating the CSV and
applied each field on its own ok-flag, so a malformed/short `qpos=99` flipped
the status to Queued and left waiters/reload at stale values — rendering as a
nonsensical "position 99 of <stale> waiters" from untrusted server input.

Gate the whole update on BOTH coupled, displayed values (position + waiters)
parsing; `reload` stays an optional hint applied only when present. Same
parse-safety discipline as the too_busy fix. Adds a regression test for
position-only / empty / non-numeric qpos.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ten9876

ten9876 commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Follow-up review pass (HEAD 8c804f0a)

Re-ran the high-effort review against HEAD. The four original blockers are resolved and verified, plus two more parse-safety items were folded in:

  • c2ce492a — original blockers (too_busy default, camped read-only safety via receiverControlSuppressed(), capacity message)
  • 127fe297 — reset m_preflightReportedFull on the wss retry (it was only reset in connectToEndpoint(), so a ws→wss retry timeout could emit a stale capacity message)
  • 8c804f0aqpos now validates position + waiters before applying the queue update (+ regression test), matching the too_busy discipline

Clean-room provenance and the receive-only guarantee (Principle VI) both check out. CI is green.

Outstanding follow-ups (non-blocking — leaving these to you, @rfoust)

Correctness (low reachability):

  1. Waterfall 517-byte misclassifyclassifyWaterfallFrame (KiwiSdrProtocol.cpp ~L827) treats a 517-byte zoomed row as ADPCM-compact via payloadBytes==517 even when the parsed compression flag is false; a direct/uncompressed row of that exact shape would be ADPCM-decoded into garbage. The flag is already parsed in shape.compressed — trust it instead of OR-ing the size heuristic.
  2. metadataValueToMhz sub-1 MHz scaling (~L230) — the magnitude heuristic divides [1000,1e6) by 1000 as "kHz", so an LF/MW Kiwi reporting a sub-1 MHz center_freq displays 1000× high. Standard 0–30 MHz receivers are unaffected. Convert from the known unit rather than guessing by magnitude.

Architecture (the on-air-adjacent one):
3. Camp/monitor state lives in parallel flags (m_monitorMode / m_campAccepted / m_monitorQueueRequested / m_preflightReportedFull) rather than a single source of truth driven from metadata.campStatus. receiverControlSuppressed() = m_monitorMode || state==Camping is itself defensive against those flags disagreeing, and the frame-vs-camp-MSG ordering (briefly lands in Connected before self-correcting to Camping) is another symptom. Happy to pair on consolidating this into a single camp-session state — it's the one with read-only-safety implications.

Cleanup (minor): per-frame header re-parse on the SND/WF decode path (classify+decode both parse), a couple of O(n) per-frame scans (observedLayouts.contains, unsupported-frame dedup), the Q_UNUSED MeterContext, and hand-rolled endian readers where qFromLittleEndian/qFromBigEndian exist.

None of these block merge.

Resolves the AutomationServer.cpp conflict from aethersdr#3920 (bridge verbs):
the `get <model>` help string now lists the union of both PRs' models —
`dsp` (from aethersdr#3920, on main) and `kiwi` (this branch). Both get-model
handlers are present and unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@aethersdr-agent

Copy link
Copy Markdown
Contributor

Hi @rfoust 👋 — thanks for all the work on the KiwiSDR diagnostic/compression + busy-channel/camping support here; this is a big, careful PR and the clean-room attribution notes are excellent. CI is red on 7275c18, so here's a triage to get it green.

What failed: a compile error, not CI infra

All four build jobs failed at the Build step, and the only check that passed is Qt Accessibility Static Analysis (which doesn't compile):

Job Compiler Result
build Linux / gcc ❌ Build
check-macos clang ❌ Build
check-windows MSVC ❌ Build
analyze (cpp) (CodeQL) clang ❌ Build

Every step before Build — checkout, DeepFilterNet setup, FFTW setup, Configure — succeeded on every platform. The same source failing under three independent compilers (gcc, clang, MSVC) is the signature of a real C++ error in the diff, not a runner/toolchain/CI problem. (failed run)

How to see the exact line

I want to be upfront: the log tool I have surfaces only step-level pass/fail, not raw compiler output, and I don't have a Qt6 toolchain here to reproduce — so rather than guess at a line, here's the fast path to the real diagnostic:

Open the failed build (or check-macos) job → expand the Build step → the first error: (gcc/clang) or error C####: (MSVC) line names the file + line.

All four jobs trace to the same root cause, so any one works; the macOS/Windows logs usually have the clearest message.

False leads I already ruled out (so you don't have to)

To narrow it down I checked the usual structural suspects against the commit, and these are all fine — the break is a localized type/semantic error, not one of these:

  • src/core/KiwiSdrProtocol.cpp and the kiwi_sdr_protocol_test target are registered in CMakeLists.txt — not a missing-source issue.
  • ✅ Every KiwiSdrProtocol:: symbol referenced across the changed files is declared in KiwiSdrProtocol.h, and the new KiwiSdrManager::scheduleWaitingReconnectIfRecommended() is defined — not an undefined-reference/link error.
  • ✅ The members you removed from MainWindow.h (m_kiwiSdrClient, syncKiwiSdrTrackingToActiveSlice, setKiwiSdrWaterfallForActiveSlice) aren't referenced anywhere else.
  • ✅ The switches over the expanded KiwiSdrClient::State enum (now incl. Busy/Waiting/Camping/CampDisconnected) in KiwiSdrApplet.cpp handle all cases with a trailing return.

So the most likely home for the error is a const/overload/narrowing/type mismatch in the heavily-changed KiwiSdrProtocol.cpp / KiwiSdrClient.cpp / MainWindow_KiwiSdr.cpp — exactly what that compiler line will pinpoint.

Two unrelated heads-ups for the same push

  1. Rebase to drop the workflow edits. This branch removes the Cache DeepFilterNet3 steps from .github/workflows/*.yml, but main has since reworked that area in d2fa27d8 ("ci: cache third_party/deepfilter across all DFNR setup jobs", ci: cache third_party/deepfilter across all DFNR setup jobs #3916). Rebasing on latest main and dropping those workflow changes avoids a conflict and keeps the new caching. (These edits aren't the build break — the Setup DeepFilterNet3 step still ran and passed.)
  2. @ten9876's review blockers (busy-flag parse defaulting to true, camp/monitor read-only gating, the per-state capability table, and the full-receiver early-abort) are logic issues rather than the compile failure — but folding them in alongside the build fix means the next CI run lands clean.

Once you grab that first error: line, drop it here and I'm happy to help pinpoint the fix. Thanks again for volunteering your time on this — it's a substantial and well-documented contribution. 🙏


🤖 aethersdr-agent · cost: $10.4605 · model: claude-opus-4-8

@ten9876 ten9876 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. High-effort review across three passes (8 finder angles + adversarial verification each): the binary/protocol parser is genuinely defensive (no crash/UAF/overflow), clean-room provenance is solid, and the receive-only/Principle VI guarantee holds via receiverControlSuppressed(). Blockers were fixed and verified (too_busy default, camped read-only safety, capacity message, preflight-flag reset, qpos parse-safety). Remaining items — waterfall-517 ADPCM misclassify, sub-1MHz metadataValueToMhz, and the camp-flag→state-machine consolidation — are non-blocking and documented on the PR as follow-ups for the author. CI green (build/macOS/Windows).

@ten9876 ten9876 enabled auto-merge (squash) June 30, 2026 23:45
@ten9876 ten9876 merged commit 022efb9 into aethersdr:main Jul 1, 2026
6 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.

3 participants