From b2bc0f3e051581f7aa1e26b1117dc15188115039 Mon Sep 17 00:00:00 2001 From: Toshihiko SHIMOKAWA Date: Tue, 11 Aug 2026 21:31:38 +0900 Subject: [PATCH 1/2] fix(cli): narrow parse_subnet_option/1 spec to the value it returns Dialyzer runs with :underspecs and reported contract_supertype: the spec said {atom(), map()} while the function only ever returns an :edns_client_subnet tagged tuple whose map has four known keys. Declare the shape as a type instead. The spec now says what the caller can rely on, and a change to the returned map is reported rather than absorbed by map(). No behaviour change; the existing parse_subnet_option/1 tests cover the IPv4 and IPv6 paths unchanged. Resolves #46 Claude-Session: https://claude.ai/code/session_01YAjSJR67tWTvYDJLcQThbQ --- lib/tdig/cli.ex | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/tdig/cli.ex b/lib/tdig/cli.ex index b945a5a..cb3fc87 100644 --- a/lib/tdig/cli.ex +++ b/lib/tdig/cli.ex @@ -236,7 +236,24 @@ defmodule Tdig.CLI do |> Map.put(:options, [ecs_option]) end - @spec parse_subnet_option(String.t()) :: {atom(), map()} + @typedoc """ + An EDNS Client Subnet option, shaped as `Tenbin.DNS` expects in `:options`. + + `family` is 1 for IPv4 and 2 for IPv6 (RFC 7871). `source_prefix` is the + prefix length given on the command line, capped at the family's width; + `scope_prefix` is always 0 in a query, and only a response carries a + meaningful value. + """ + @type edns_client_subnet :: + {:edns_client_subnet, + %{ + family: 1 | 2, + client_subnet: :inet.ip_address(), + source_prefix: integer(), + scope_prefix: 0 + }} + + @spec parse_subnet_option(String.t()) :: edns_client_subnet() def parse_subnet_option(subnet) do case String.split(subnet, "/") do [addr_str, prefix_str] -> From 3466955b5a191621f99d68916b0adcba69267817 Mon Sep 17 00:00:00 2001 From: Toshihiko SHIMOKAWA Date: Tue, 11 Aug 2026 21:32:48 +0900 Subject: [PATCH 2/2] fix: anchor the escript ignore pattern to the repository root The pattern was a bare `tdig`, which matches any path component with that name -- including the lib/tdig/ source directory. A file added there was ignored and did not appear in `git status`, so it could be lost silently. Existing files were unaffected because ignore rules do not apply to tracked paths, which is why this went unnoticed. Anchor it to the root so it covers only the escript binary. Claude-Session: https://claude.ai/code/session_01YAjSJR67tWTvYDJLcQThbQ --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6273195..e52cf90 100644 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,10 @@ tdig-*.tar /tmp/ mix.lock -tdig +# The escript binary, at the repository root only. Unanchored, this pattern +# also matches the lib/tdig/ directory, and a file added there is ignored +# without ever showing up in `git status`. +/tdig test_release/ # Dialyzer PLT files (contain absolute paths from local build env; regenerated by CI)