Skip to content

Band Advisor v1: flagged recommendations, personal PSK analytics, propagation alerts, backend scaffold - #917

Open
patrickrb wants to merge 8 commits into
devfrom
feat/band-advisor
Open

patrickrb wants to merge 8 commits into
devfrom
feat/band-advisor

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

What this is

First vertical slice of Band Advisor — "what band should I work right now?" — combining VOACAP predictions, live regional PSK Reporter observations, and (optionally) the operator's own reception reports into a deterministic, explainable recommendation. No LLM/generative AI anywhere in the runtime path.

Everything is behind feature flags and off by default in release builds; debug builds default on. Full architecture, contract, scoring model, privacy notes, and staged-rollout guide: docs/band-advisor.md.

Highlights

  • Feature flags (radio.ks3ckc.ft8af.flags): BAND_ADVISOR, PERSONAL_PSK_ANALYTICS, PROPAGATION_ALERTS. Precedence: debug override → fresh cached remote config (/v1/feature-config, validated, expiry-honoring, never blocks startup) → BuildConfig default. Debug-only tri-state override screen (Settings → Advanced) showing each flag's effective value and source. Explicitly documented as rollout controls, not access control.
  • Domain + repository (radio.ks3ckc.ft8af.bandadvisor): framework-free models for the versioned recommendation contract, validating parser, deterministic goal-weighted scorer (weights renormalize when inputs are missing) with a separate confidence function, API repository (60s cooldown, 429/503 back-off, stale/offline cache fallback), and a debug-only fixture repository that runs through the real scorer — fixtures cannot ship as live data.
  • UI: compact advisor card in the Band & Mode sheet (nullable slot keeps the sheet decoupled) + detail overlay with goal chips (Contact/DX/Target/POTA), expandable "Why this band" evidence + score components, alternatives with reasons, freshness/partial/offline/no-grid states.
  • One-tap tuning reuses selectBandIndex (RigDialTarget protection, per-band level restore, CAT push only in CAT/RTS/DTR). Refuses dials not in the band plan; degrades to "Set radio to 14.074 MHz" without CAT. Never transmits, never band-hops.
  • Personal PSK analytics (flag + valid callsign required): reuses PskReporterClient (its 5-min etiquette applies), pure stats computation, small-sample suppression (≥10 reports + ≥3 stored sessions before any baseline comparison), explicit "reception reports are not contacts" copy, clearable local history.
  • Propagation alerts (opt-in, flagged): WorkManager 30-min network-constrained check against a lightweight /v1/conditions endpoint; pure policy with evidence thresholds, 90-min opening identities persisted 48h for dedup, per-band (3h) + global (30 min) cooldowns, quiet hours with midnight wrap; own notification channel, Android 13 permission flow; tap opens the advisor detail. Disabling the flag or preference cancels scheduled work.
  • Backend scaffold (server/band-advisor/): containerized FastAPI service wrapping voacapl (external GPL tool, built from source in Docker, not linked/vendored) with a documented FT8 SNR profile (−21 dB @ 2500 Hz → 13 dB·Hz + 3 dB margin), centralized PSK Reporter aggregation (gzip, defusedxml, appcontact, band-hour baseline normalization so raw volume can't always crown 20m), spec'd cache keying, deterministic errors, structured logs.

Safety

Failure of Band Advisor, VOACAP, PSK Reporter, remote config, or alerts cannot interfere with decode/TX/logging/USB/CAT: flag-off composes no UI and schedules no work; every network call is time-boxed and maps to a typed UI state or a skipped background round; the FT8 engine, audio, JNI, and rig-control code paths are untouched except for the two documented reuse points (selectBandIndex, notification-intent handling).

Tests & builds run

  • ./gradlew testDebugUnitTest — 4165 tests, 0 failures (includes ~120 new tests: flag precedence/expiry/overrides, contract parsing, score normalization + goal weights + confidence, repository cooldown/back-off/offline fallback, fixture determinism, grid/callsign validation, personal-analytics math + suppression, alert thresholds/dedup/cooldowns/quiet-hours, WorkManager schedule/cancel via work-testing, tune-index lookup)
  • ./gradlew assembleDebug — success (native build included)
  • ./gradlew ktlintCheck — clean; detekt — no new findings (11 pre-existing baseline-adjacent findings remain in untouched files; detekt is warn-only in CI)
  • server/band-advisor: pytest — 190 passed (no network; fixture voacapl output, mocked HTTP, fixed clock)

Known gaps / follow-ups

  • voacapl deck format + invocation follow published conventions but haven't run against a real voacapl build yet (Docker-only); lock in a golden fixture from the first real run.
  • /v1/conditions is anonymous, so PERSONAL_IMPROVEMENT alerts never fire yet.
  • Client-side country counting is deferred to the server payload (local panel shows grid fields); Kotlin scorer is a mirrored reference implementation of the Python one — changes must be made in both.
  • Personal baseline records once per sufficient panel load (could over-sample a long session).
  • Remote feature-config + band-advisor endpoints need deployment behind ft8af.app before flags can be flipped in release.

🤖 Generated with Claude Code

patrickrb and others added 7 commits September 27, 2026 07:59
Tri-layer precedence (debug override > fresh cached remote config >
BuildConfig default), SharedPreferences-backed stores, validated remote
feature-config fetch that never blocks startup or runs in tests.
Debug builds default the three flags on; release ships them off.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Framework-free recommendation contract models with validating parser,
deterministic goal-weighted scorer with renormalization + separate
confidence, API repository (cooldown, 429 back-off, stale/offline cache
fallback) and a debug-only deterministic fixture repository that runs
through the real scorer. Personal PSK Reporter analytics computation
with small-sample suppression and a bounded local baseline store.

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

Compact advisor card in the Band & Mode sheet (slot param keeps the
sheet decoupled), detail overlay with goal chips, expandable evidence,
score components, alternatives, freshness/partial/offline states, and
the personal PSK Reporter panel (sender reports only, explicit
not-a-contact disclaimer, small-sample suppression). One-tap tuning
reuses selectBandIndex and refuses dials not in the band plan.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tri-state override per flag (Default / Force on / Force off) with the
effective value and its source, plus the fixture-data toggle. Reached
from a BuildConfig.DEBUG-gated row in Advanced settings; absent from
release builds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pure alert policy (evidence thresholds, 90-min opening identities,
48h dedup history, per-band + global cooldowns, quiet hours with
midnight wrap), WorkManager periodic check (30 min, network-constrained,
cancelled whenever the flag or preference turns off), dedicated
notification channel with Android 13 permission handling, tap-through
to the Band Advisor detail, and the Band Advisor settings screen with
per-type opt-ins, quiet hours, watched bands/regions, privacy note,
and local-data clear.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Containerized FastAPI service: voacapl wrapper (deck builder with a
documented FT8 dB-Hz SNR profile, short-filename handling, per
grid4/month/hour/power/antenna/noise/region caching), centralized
PSK Reporter aggregation (5-min etiquette, gzip, defusedxml, band-hour
baseline normalization), deterministic goal-weighted scoring with
renormalization + separate confidence, and versioned endpoints:
/healthz, /v1/feature-config, /v1/recommendation, /v1/conditions.
190 pytest tests, no network. Dockerfile builds voacapl from source
(invoked as an external GPL tool, not linked or vendored).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
docs/band-advisor.md covers the flag precedence, client architecture,
contract, scoring model, alert policy, privacy, testing, and staged
rollout. The catch-clause changes replace generic Exception catches
with IOException / runCatching so the new code adds no detekt findings.

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

codecov Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 47.65033% with 1036 lines in your changes missing coverage. Please review.
✅ Project coverage is 41.85%. Comparing base (0677e40) to head (985046a).

Files with missing lines Patch % Lines
...io/ks3ckc/ft8af/ui/bandadvisor/BandAdvisorSheet.kt 9.70% 372 Missing ⚠️
...io/ks3ckc/ft8af/ui/settings/BandAdvisorSettings.kt 7.69% 144 Missing ⚠️
...dio/ks3ckc/ft8af/ui/bandadvisor/BandAdvisorCard.kt 0.00% 93 Missing ⚠️
...adio/ks3ckc/ft8af/ui/settings/FeatureFlagScreen.kt 11.76% 75 Missing ⚠️
...8af/bandadvisor/alerts/PropagationAlertNotifier.kt 0.00% 52 Missing ⚠️
...app/src/main/kotlin/radio/ks3ckc/ft8af/FT8AFApp.kt 0.00% 45 Missing ⚠️
...io/ks3ckc/ft8af/ui/bandadvisor/BandAdvisorState.kt 64.83% 23 Missing and 9 partials ⚠️
...af/bandadvisor/alerts/PropagationAlertScheduler.kt 45.09% 27 Missing and 1 partial ⚠️
...ks3ckc/ft8af/ui/bandadvisor/PersonalPanelLoader.kt 37.50% 23 Missing and 2 partials ⚠️
...kc/ft8af/bandadvisor/model/RecommendationParser.kt 69.62% 1 Missing and 23 partials ⚠️
... and 19 more
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##                dev     #917      +/-   ##
============================================
+ Coverage     41.51%   41.85%   +0.33%     
- Complexity      252      336      +84     
============================================
  Files           280      310      +30     
  Lines         33993    35972    +1979     
  Branches       4034     4415     +381     
============================================
+ Hits          14112    15055     +943     
- Misses        19592    20547     +955     
- Partials        289      370      +81     
Flag Coverage Δ
android 20.40% <47.65%> (+2.77%) ⬆️
native 9.93% <ø> (ø)

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

Files with missing lines Coverage Δ
...main/kotlin/radio/ks3ckc/ft8af/FT8AFApplication.kt 100.00% <100.00%> (ø)
.../ks3ckc/ft8af/bandadvisor/BandAdvisorRepository.kt 100.00% <100.00%> (ø)
...3ckc/ft8af/bandadvisor/alerts/AlertHistoryStore.kt 100.00% <100.00%> (ø)
...s3ckc/ft8af/bandadvisor/alerts/AlertPreferences.kt 100.00% <100.00%> (ø)
...ain/kotlin/radio/ks3ckc/ft8af/flags/FeatureFlag.kt 100.00% <100.00%> (ø)
.../radio/ks3ckc/ft8af/flags/FeatureFlagRepository.kt 100.00% <100.00%> (ø)
.../radio/ks3ckc/ft8af/flags/SharedPrefsFlagStores.kt 100.00% <100.00%> (ø)
...8af/bandadvisor/personal/PersonalAnalyticsStore.kt 95.00% <95.00%> (ø)
...otlin/radio/ks3ckc/ft8af/flags/RemoteFlagConfig.kt 96.77% <96.77%> (ø)
...dio/ks3ckc/ft8af/bandadvisor/scoring/BandScorer.kt 97.84% <97.84%> (ø)
... and 26 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

🟡 Changes recommended

One or more issues must be addressed before approval.

17 open issues
What changed in this PR

Introduces a feature-flagged Band Advisor for Android, backed by a FastAPI propagation service.

Changes:

  • Adds advisor UI, recommendation models, personal analytics, and tuning integration.
  • Adds remote feature flags and opt-in background propagation alerts.
  • Adds VOACAP integration, PSK aggregation, caching, containerization, and tests.
File Description
server/​band-advisor/​tests/​test_scoring.py Updated as part of this pull request.
server/​band-advisor/​tests/​test_runner.py Updated as part of this pull request.
server/​band-advisor/​tests/​test_regions.py Updated as part of this pull request.
server/​band-advisor/​tests/​test_parser.py Updated as part of this pull request.
server/​band-advisor/​tests/​test_input_builder.py Updated as part of this pull request.
server/​band-advisor/​tests/​test_geo.py Updated as part of this pull request.
server/​band-advisor/​tests/​test_ft8_profile.py Updated as part of this pull request.
server/​band-advisor/​tests/​test_caches.py Updated as part of this pull request.
server/​band-advisor/​tests/​test_baseline.py Updated as part of this pull request.
server/​band-advisor/​tests/​test_aggregator.py Updated as part of this pull request.
server/​band-advisor/​tests/​conftest.py Updated as part of this pull request.
server/​band-advisor/​pyproject.toml Updated as part of this pull request.
server/​band-advisor/​feature-config.example.json Updated as part of this pull request.
server/​band-advisor/​Dockerfile Updated as part of this pull request.
server/​band-advisor/​docker-compose.yml Updated as part of this pull request.
server/​band-advisor/​app/​voacap/​service.py Updated as part of this pull request.
server/​band-advisor/​app/​voacap/​runner.py Updated as part of this pull request.
server/​band-advisor/​app/​voacap/​regions.py Updated as part of this pull request.
server/​band-advisor/​app/​voacap/​parser.py Updated as part of this pull request.
server/​band-advisor/​app/​voacap/​input_builder.py Updated as part of this pull request.
server/​band-advisor/​app/​voacap/​ft8_profile.py Updated as part of this pull request.
server/​band-advisor/​app/​voacap/​cache.py Updated as part of this pull request.
server/​band-advisor/​app/​voacap/​__init__.py Updated as part of this pull request.
server/​band-advisor/​app/​ttl_cache.py Updated as part of this pull request.
server/​band-advisor/​app/​pskreporter/​cache.py Updated as part of this pull request.
server/​band-advisor/​app/​pskreporter/​baseline.py Updated as part of this pull request.
server/​band-advisor/​app/​pskreporter/​aggregator.py Updated as part of this pull request.
server/​band-advisor/​app/​pskreporter/​__init__.py Updated as part of this pull request.
server/​band-advisor/​app/​main.py Updated as part of this pull request.
server/​band-advisor/​app/​logging_config.py Updated as part of this pull request.
server/​band-advisor/​app/​geo.py Updated as part of this pull request.
server/​band-advisor/​app/​config.py Updated as part of this pull request.
server/​band-advisor/​app/​clock.py Updated as part of this pull request.
server/​band-advisor/​app/​bands.py Updated as part of this pull request.
server/​band-advisor/​app/​__init__.py Updated as part of this pull request.
server/​band-advisor/​.gitignore Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​ui/​settings/​FeatureFlagScreenTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​ui/​settings/​BandAdvisorSettingsTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​ui/​bandadvisor/​PersonalPanelLoaderTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​ui/​bandadvisor/​BandAdvisorStateHolderTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​flags/​SharedPrefsFlagStoresTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​flags/​RemoteFlagConfigTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​flags/​RemoteFlagConfigFetcherTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​flags/​FeatureFlagRepositoryTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​personal/​PersonalAnalyticsStoreTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​model/​ValidationTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​FixtureBandAdvisorRepositoryTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​alerts/​PropagationAlertSchedulerTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​alerts/​ConditionsClientTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​alerts/​AlertStoresTest.kt Updated as part of this pull request.
ft8af/​app/​src/​test/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​alerts/​AlertGridTest.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​ui/​settings/​SettingsScreen.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​ui/​settings/​FeatureFlagScreen.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​ui/​settings/​AdvancedSettings.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​ui/​components/​BandModeSheet.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​ui/​bandadvisor/​PersonalPanelLoader.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​ui/​bandadvisor/​BandAdvisorTuning.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​ui/​bandadvisor/​BandAdvisorTelemetry.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​FT8AFApplication.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​FT8AFApp.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​flags/​SharedPrefsFlagStores.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​flags/​RemoteFlagConfigFetcher.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​flags/​RemoteFlagConfig.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​flags/​FeatureFlags.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​flags/​FeatureFlagRepository.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​flags/​FeatureFlag.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​ComposeMainActivity.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​personal/​PersonalAnalyticsStore.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​model/​Validation.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​model/​RecommendationParser.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​model/​Models.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​BandAdvisorRepository.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​BandAdvisor.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​alerts/​PropagationAlertScheduler.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​alerts/​PropagationAlertNotifier.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​alerts/​ConditionsClient.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​alerts/​AlertPreferences.kt Updated as part of this pull request.
ft8af/​app/​src/​main/​kotlin/​radio/​ks3ckc/​ft8af/​bandadvisor/​alerts/​AlertHistoryStore.kt Updated as part of this pull request.
ft8af/​app/​build.gradle Updated as part of this pull request.

Review effort: Balanced

# voacapl ships an autotools build; makeitshfbc installs the itshfbc data
# directory (ionospheric coefficients, antenna files) into $HOME/itshfbc.
RUN ./configure && make && make install \
&& HOME=/build make makeitshfbc
RUN useradd --create-home --uid 10001 advisor

COPY --from=voacapl-build /usr/local/bin/voacapl /usr/local/bin/voacapl
COPY --from=voacapl-build /build/itshfbc /opt/itshfbc
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl -fsS http://127.0.0.1:8000/healthz || exit 1

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(JsonFormatter())
root.handlers = [handler]
root.setLevel(level)

ANTENNA_CLASS_FILE: dict[AntennaClass, str] = {
AntennaClass.ISOTROPE: "default/isotrope",
AntennaClass.WIRE: "default/dipole.voa",
androidx.compose.runtime.key(flag, revision) {
FlagRow(
flag = flag,
onChanged = { revision++ },
GRID6_RE = re.compile(r"^[A-R]{2}[0-9]{2}[A-X]{2}$")
FIELD_RE = re.compile(r"^[A-R]{2}$")

CALLSIGN_RE = re.compile(r"^[A-Z0-9]{1,3}[0-9][A-Z0-9]{0,3}[A-Z](/[A-Z0-9]{1,4})?$")
Comment on lines +29 to +30
field = normalize_grid4(observer_grid)[:2]
return (field, band or "ALL", mode.upper(), int(window_s))
Comment on lines +113 to +116
remaining = float(item.get("ttl_remaining", 0))
if remaining > 0:
self._entries[tuple(item["key"])] = (
now + remaining,

val title = context.getString(R.string.prop_alerts_notif_opening_title, decision.band)
val regionText = decision.region ?: context.getString(R.string.band_advisor_goal_dx)
val time = SimpleDateFormat("HH:mm", Locale.US).format(Date(decision.conditionsAtMs))
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