Fix all 12 dialyzer warnings

- Replace MapSet with plain list + `in` (features.ex, scorer_diff.ex)
- Remove undefined Beacon.t() type reference (range_estimate.ex)
- Remove dead else branch in find_region (inversion.ex)
- Handle Nx special values in to_float catch-all (recalibrator.ex)
- Remove unreachable catch-all clauses (hrrr_native_client.ex, ncei_metar_client.ex)
- Remove unnecessary nil guards on always-typed values (show.ex)
- Remove dead sky_note/wind_note non-nil clauses (show.ex)
- Remove dead if-guard on always-truthy derive result (hrrr_native_derive.ex)
- Add @spec to path_integrated_conditions (scorer.ex)
This commit is contained in:
Graham McIntire 2026-04-11 18:07:44 -05:00
parent 623bb45aee
commit 1174ecd9e5
10 changed files with 39 additions and 67 deletions

View file

@ -33,24 +33,23 @@ defmodule Microwaveprop.Backtest.Features do
and placeholder stubs that always return nil.
"""
def all_features do
excluded =
MapSet.new([
# 4-arity helper
:duct_usable_for_band,
# Stubs (always nil)
:distance_to_front,
:parallel_to_front,
# Dead features — no discrimination in consolidated backtest (2026-04-11)
:duct_usable_10ghz,
:duct_usable_24ghz,
:duct_usable_47ghz,
:bulk_richardson
])
excluded = [
# 4-arity helper
:duct_usable_for_band,
# Stubs (always nil)
:distance_to_front,
:parallel_to_front,
# Dead features — no discrimination in consolidated backtest (2026-04-11)
:duct_usable_10ghz,
:duct_usable_24ghz,
:duct_usable_47ghz,
:bulk_richardson
]
:functions
|> __MODULE__.__info__()
|> Enum.filter(fn {_name, arity} -> arity == 3 end)
|> Enum.reject(fn {name, _} -> MapSet.member?(excluded, name) end)
|> Enum.reject(fn {name, _} -> name in excluded end)
|> Map.new(fn {name, _} ->
{to_string(name), &apply(__MODULE__, name, [&1, &2, &3])}
end)

View file

@ -59,7 +59,7 @@ defmodule Microwaveprop.Beacons.RangeEstimate do
points within range where the estimated received signal exceeds the
detection floor.
"""
@spec estimate(Microwaveprop.Beacons.Beacon.t()) :: map()
@spec estimate(struct()) :: map()
def estimate(beacon) do
band_mhz = nearest_band_mhz(beacon.frequency_mhz)
band_config = BandConfig.get(band_mhz)

View file

@ -65,21 +65,13 @@ defmodule Microwaveprop.Propagation.Inversion do
defp find_region([], _base), do: nil
defp find_region([pair | rest], base) do
defp find_region([pair | rest], _base) do
[{{_h1, t1}, _i1}, {{_h2, t2}, i2}] = pair
if is_nil(base) do
if t2 > t1 do
find_region_top(rest, i2 - 1, i2)
else
find_region(rest, nil)
end
if t2 > t1 do
find_region_top(rest, i2 - 1, i2)
else
if t2 < t1 do
{base, i2 - 1}
else
find_region(rest, base)
end
find_region(rest, nil)
end
end

View file

@ -311,5 +311,5 @@ defmodule Microwaveprop.Propagation.Recalibrator do
defp to_float(n) when is_float(n), do: n
defp to_float(n) when is_integer(n), do: n * 1.0
defp to_float(n), do: n * 1.0
defp to_float(_), do: 0.0
end

View file

@ -385,6 +385,7 @@ defmodule Microwaveprop.Propagation.Scorer do
- Other factors (temp, dewpoint, PWAT, BL depth): use path AVERAGE
- Time/season/sky: taken from first profile (same for entire path)
"""
@spec path_integrated_conditions([map()], map()) :: map() | nil
def path_integrated_conditions(profiles, contact) do
lon = Kernel.||(contact.pos1["lon"] || contact.pos1["lng"], -97.0)

View file

@ -242,8 +242,6 @@ defmodule Microwaveprop.Weather.HrrrNativeClient do
|> Enum.min(fn -> 0.0 end)
end
defp min_m_gradient(_), do: nil
defp max_duct_thickness([]), do: nil
defp max_duct_thickness(ducts), do: ducts |> Enum.map(& &1.thickness_m) |> Enum.max()

View file

@ -161,7 +161,6 @@ defmodule Microwaveprop.Weather.NceiMetarClient do
defp parse_metar_temp(s), do: String.to_integer(s) * 1.0
defp c_to_f(c) when is_number(c), do: c * 9.0 / 5.0 + 32.0
defp c_to_f(_), do: nil
defp extract_wind_speed(parts) do
with wind when is_binary(wind) <- Enum.find(parts, &Regex.match?(~r/^\d{3}\d{2,3}KT/, &1)),

View file

@ -577,9 +577,13 @@ defmodule MicrowavepropWeb.ContactLive.Show do
<%= if @editing do %>
<div class="bg-base-200 rounded-box p-4 mb-4">
<h3 class="font-semibold mb-3">{if admin?(assigns), do: "Edit Contact", else: "Suggest Edit"}</h3>
<h3 class="font-semibold mb-3">
{if admin?(assigns), do: "Edit Contact", else: "Suggest Edit"}
</h3>
<p class="text-sm opacity-70 mb-4">
{if admin?(assigns), do: "Change any fields below. Changes will be applied immediately.", else: "Change any fields below. Only fields you modify will be submitted for review."}
{if admin?(assigns),
do: "Change any fields below. Changes will be applied immediately.",
else: "Change any fields below. Only fields you modify will be submitted for review."}
</p>
<.form
for={@edit_form}
@ -1503,7 +1507,7 @@ defmodule MicrowavepropWeb.ContactLive.Show do
samples: length(ep.points),
dist: format_dist(ep.dist_km),
source: "SRTM 1-arcsecond",
duct_count: length(ep.ducts || [])
duct_count: length(ep.ducts)
}
end
@ -1768,7 +1772,7 @@ defmodule MicrowavepropWeb.ContactLive.Show do
end
defp time_note(ts, lon) do
solar_hour = ts.hour + ts.minute / 60 + (lon || 0) / 15
solar_hour = ts.hour + ts.minute / 60 + lon / 15
solar_hour = rem_float(solar_hour + 24, 24)
h = round(solar_hour)
@ -1817,7 +1821,6 @@ defmodule MicrowavepropWeb.ContactLive.Show do
end
defp sky_note(nil), do: ""
defp sky_note(pct), do: "#{round(pct)}% cloud cover"
defp season_note(month, band_config) do
month_names = ~w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
@ -1828,20 +1831,6 @@ defmodule MicrowavepropWeb.ContactLive.Show do
defp wind_note(nil), do: ""
defp wind_note(kts) do
k = Float.round(kts, 1)
label =
cond do
k < 5 -> "calm"
k < 15 -> "light"
k < 25 -> "moderate"
true -> "strong"
end
"#{k} kts (#{label})"
end
defp rain_note(rate) when rate > 0, do: "#{Float.round(rate, 1)} mm/hr"
defp rain_note(_), do: "None"

View file

@ -40,16 +40,12 @@ defmodule Mix.Tasks.HrrrNativeDeriveFields do
Enum.count(profiles, fn profile ->
derived = derive(profile)
if derived do
{1, _} =
HrrrNativeProfile
|> where([p], p.id == ^profile.id)
|> Repo.update_all(set: derived)
{1, _} =
HrrrNativeProfile
|> where([p], p.id == ^profile.id)
|> Repo.update_all(set: derived)
true
else
false
end
true
end)
Mix.shell().info("Updated #{count} profiles with derived turbulence fields.")

View file

@ -63,18 +63,16 @@ defmodule Mix.Tasks.ScorerDiff do
end
defp validate_weight_keys!(weights) do
expected_keys =
MapSet.new(~w(humidity time_of_day td_depression refractivity sky season wind rain pressure pwat))
expected_keys = ~w(humidity time_of_day td_depression refractivity sky season wind rain pressure pwat)
provided_keys = Map.keys(weights)
provided_keys = MapSet.new(Map.keys(weights))
missing = MapSet.difference(expected_keys, provided_keys)
extra = MapSet.difference(provided_keys, expected_keys)
missing = expected_keys -- provided_keys
extra = provided_keys -- expected_keys
errors =
[]
|> prepend_if(MapSet.size(missing) > 0, "Missing: #{inspect(MapSet.to_list(missing))}")
|> prepend_if(MapSet.size(extra) > 0, "Extra: #{inspect(MapSet.to_list(extra))}")
|> prepend_if(missing != [], "Missing: #{inspect(missing)}")
|> prepend_if(extra != [], "Extra: #{inspect(extra)}")
if errors != [] do
Mix.raise("Invalid weight keys. " <> Enum.join(errors, " "))