Skip to content

Add Hunt options: target priority + smart filters (pileup avoidance, min-SNR floor) - #699

Merged
patrickrb merged 2 commits into
devfrom
feat/hunt-options
Jul 28, 2026
Merged

Add Hunt options: target priority + smart filters (pileup avoidance, min-SNR floor)#699
patrickrb merged 2 commits into
devfrom
feat/hunt-options

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

What

The HUNT button gets the same notch / long-press affordance as the CQ button, opening a new Hunt options sheet:

Hunt priority (which CQ Hunt answers first when several decode in one cycle)

  • Latest — most recent decode (historical behavior, default)
  • Strongest — best SNR first, best odds of completing
  • Weakest — weakest first, for QRP/challenge hunting
  • Farthest — chase DX first (grid-distance based)
  • POTA/SOTA — activators first; parks not yet in the hunted log rank above already-hunted parks
  • New DXCC — unworked entities first
  • New grid — unworked grid squares first

Smart filters (features other FT8 apps don't have)

  • Avoid pileups — prefers CQ callers no one else in the decode window is already answering. Soft preference: if every caller has a pileup, Hunt still picks one rather than sit idle.
  • Minimum signal (Off / −10 / −15 / −20 dB) — hard floor so Hunt doesn't start QSOs that are likely to fizzle. Decodes with no SNR still pass (the decoder occasionally omits it).

A non-default priority shows a short tag under the HUNT label (STRONG/WEAK/DX/POTA/DXCC/GRID), mirroring the CQ button's FREE/FD subtitle. Options apply immediately mid-hunt and persist across launches.

How

  • HuntTargetSelector.kt (new): pure ranking logic (selectHuntCandidate, passesSnrFloor, countRepliesTo, huntPriorityFromConfig) plus a @JvmStatic pick() bridge for the Java engine. Distance/park/pileup lookups only run when the active options need them; LATEST with no filters short-circuits to the old behavior with zero extra per-cycle work.
  • FT8TransmitSignal.checkCQMeOrFollowCQMessage: the hunt scan now collects all qualifying CQs (same eligibility filters as before: worked-before skip, exclusions, POTA-only filter, directional-CQ respect) and lets the selector choose, instead of taking the first match. The debug log line now includes the active priority and candidate count.
  • Persistence: three new config keys (huntPriority, huntAvoidPileups, huntMinSnr) following the GeneralVariables static + DatabaseOpr.writeConfig/parse pattern; statics are volatile (UI thread writes, transmit thread reads), matching huntPotaOnly.
  • TxStrip.StackedActionButton: gains an optional options notch + long-press + subtitle, mirroring PrimaryActionButton; the TX-slot button is unchanged.
  • HuntOptionsSheet.kt (new): follows the CqOptionsSheet layout/chip conventions.

Tests

  • HuntTargetSelectorTest — 24 cases: config parsing fallback, SNR-floor semantics (incl. unknown SNR), every priority mode incl. unknown-SNR/-distance handling, freshest-decode tie-breaks, pileup soft-fallback, reply counting.
  • HuntOptionsLogicTest — subtitle tags (exhaustive over the enum, length-bounded), min-SNR chip data/labels.
  • Full testDebugUnitTest suite green; assembleDebug builds.

🤖 Generated with Claude Code

The HUNT button gets the same notch/long-press affordance as the CQ button,
opening a Hunt options sheet:

- Hunt priority (single-select): Latest (historical behavior, default),
  Strongest, Weakest, Farthest, POTA/SOTA activators first (unhunted parks
  rank highest), New DXCC first, New grid first.
- Smart filters: Avoid pileups (prefer CQs no one else is answering this
  cycle; soft preference) and a Minimum-signal floor (Off/-10/-15/-20 dB;
  hard filter so Hunt never starts a QSO that's unlikely to complete).

Engine: the hunt scan in FT8TransmitSignal previously answered the first
qualifying CQ (most recent decode). It now collects all qualifying CQs and
ranks them via HuntTargetSelector, a pure Kotlin selector driven by three
new persisted settings (huntPriority, huntAvoidPileups, huntMinSnr).
LATEST with no filters short-circuits to the old behavior with no extra
per-cycle work. All existing eligibility filters (worked-before, POTA-only,
directional-CQ respect, exclusions) are unchanged.

UI: a non-default priority shows a short tag under the HUNT label
(STRONG/WEAK/DX/POTA/DXCC/GRID), mirroring the CQ button's FREE/FD
subtitle. Options apply immediately, mid-hunt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 14.97175% with 301 lines in your changes missing coverage. Please review.
✅ Project coverage is 29.72%. Comparing base (647b12e) to head (d27210d).
⚠️ Report is 136 commits behind head on dev.

Files with missing lines Patch % Lines
...dio/ks3ckc/ft8af/ui/components/HuntOptionsSheet.kt 5.88% 160 Missing ⚠️
...app/src/main/kotlin/radio/ks3ckc/ft8af/FT8AFApp.kt 0.00% 55 Missing ⚠️
...kotlin/radio/ks3ckc/ft8af/ui/components/TxStrip.kt 0.00% 53 Missing ⚠️
...tlin/radio/ks3ckc/ft8af/hunt/HuntTargetSelector.kt 56.57% 33 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##                dev     #699      +/-   ##
============================================
+ Coverage     29.36%   29.72%   +0.35%     
- Complexity      197      222      +25     
============================================
  Files           179      192      +13     
  Lines         24068    25543    +1475     
  Branches       3263     3545     +282     
============================================
+ Hits           7067     7592     +525     
- Misses        16780    17698     +918     
- Partials        221      253      +32     
Flag Coverage Δ
android 16.36% <14.97%> (+1.84%) ⬆️
native 9.93% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...tlin/radio/ks3ckc/ft8af/hunt/HuntTargetSelector.kt 56.57% <56.57%> (ø)
...kotlin/radio/ks3ckc/ft8af/ui/components/TxStrip.kt 4.40% <0.00%> (-0.46%) ⬇️
...app/src/main/kotlin/radio/ks3ckc/ft8af/FT8AFApp.kt 0.45% <0.00%> (-0.05%) ⬇️
...dio/ks3ckc/ft8af/ui/components/HuntOptionsSheet.kt 5.88% <5.88%> (ø)

... and 37 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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

Adds a new “Hunt options” UX and selection engine so the HUNT feature can rank multiple eligible CQ callers per decode cycle using configurable priority modes plus smart filters (pileup avoidance and a minimum-SNR floor). This extends existing CQ-button affordances (notch/long-press/options sheet) to HUNT and persists the new settings via the existing GeneralVariables + config DB pattern.

Changes:

  • Introduces HuntTargetSelector ranking logic (with a Java-callable bridge) and updates the transmit engine to collect all eligible CQs and delegate selection.
  • Adds a new Compose HuntOptionsSheet, a HUNT subtitle tag on the TX strip, and new localized strings for the sheet.
  • Persists three new hunt settings (huntPriority, huntAvoidPileups, huntMinSnr) and adds unit tests for both the selector and UI helper logic.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/ui/components/HuntOptionsLogicTest.kt Unit tests for pure helpers used by the Hunt options UI (subtitle tag + min-SNR chip helpers).
ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/hunt/HuntTargetSelectorTest.kt Unit tests for candidate selection logic: config parsing, SNR floor, pileup preference, and all priority modes.
ft8af/app/src/main/res/values/strings_compose.xml Adds new strings for the Hunt options notch/description and the sheet UI content.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/components/TxStrip.kt Extends the HUNT stacked button with optional notch/long-press + subtitle support to open options.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/components/HuntOptionsSheet.kt New Compose bottom sheet for Hunt options (priority + smart filters) with extracted pure helpers.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/hunt/HuntTargetSelector.kt New ranking engine + config parsing and Java bridge to pick which eligible CQ to answer.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/FT8AFApp.kt Wires the Hunt options sheet into the app UI, updates persisted settings, and shows subtitle tags.
ft8af/app/src/main/java/com/k1af/ft8af/GeneralVariables.java Adds new volatile hunt config statics and a min-SNR sentinel constant.
ft8af/app/src/main/java/com/k1af/ft8af/ft8transmit/FT8TransmitSignal.java Collects all qualifying CQs and calls HuntTargetSelector.pick(...) to choose among them; logs options context.
ft8af/app/src/main/java/com/k1af/ft8af/database/DatabaseOpr.java Loads the three new hunt config keys from persisted config into GeneralVariables.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/hunt/HuntTargetSelector.kt Outdated
…stability

Per Copilot review on #699: append an explicit HuntCandidate.index
tie-breaker to every priority comparator and pick with minWithOrNull,
so the freshest-decode tie-break is a contract of the comparator (index
is unique => total order) rather than an artifact of sortedWith
stability, and no ranked copy of the pool is allocated per decode cycle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@patrickrb
patrickrb merged commit 1867b8b into dev Jul 28, 2026
17 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