Skip to content

Commit 2300747

Browse files
foobartoclaude
andcommitted
fix(gep-validator): clean up Credo --strict findings after GEP-12 flip
GEP-12 commit 3dc1f9a enabled `Credo.Check.Warning.UnsafeToAtom` but left 7 pre-existing Credo findings in the GEP validator that hadn't tripped the previous disabled config. Most Credo categories exit non-zero individually under --strict (refactor-opportunities = exit code 8), which GitHub Actions treats as a failing step even when the local `mix credo --strict` exits 0. CI went red on e3122f7. Findings fixed: lib/gep/validator.ex - `unless X do ... else ...` → `if X do ... else ...` (2 sites: check_history_entries :314, check_readme_index :589). - Nested-too-deep reduce bodies (2 sites in check_bidirectional) extracted into `check_superseded_by/4` and `check_back_ref/4` helpers. Added `nil`-head clauses for the "referenced GEP doesn't exist in number_map" case so the call site doesn't carry the nil-check. - Credo's "avoid negated conditions in if-else" flagged `not in back_refs` — inverted the branches, kept the detail-building arm as the else clause. test/gep/validator_test.exs - `Enum.map(coll, f) |> Enum.join(sep)` → `Enum.map_join(coll, sep, f)` at 3 call sites in `build_frontmatter/1`. Zero semantic change. Verification ------------ - `mix format --check-formatted` — clean. - `mix compile --warnings-as-errors` — clean. - `mix credo --strict` — exit 0, 0 findings. (Was exit 8 before.) - `mix test --exclude inotify` — 588 tests, 0 failures. - `mix test test/gep/validator_test.exs` — 27 tests, 0 failures. - `mix gep.validate` — all 12 GEPs green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e3122f7 commit 2300747

2 files changed

Lines changed: 57 additions & 59 deletions

File tree

lib/gep/validator.ex

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,9 @@ defmodule Gep.Validator do
311311
entry_errors ++
312312
[%{severity: :error, idx: idx, detail: "history[#{idx}] missing date"}]
313313
else
314-
unless Regex.match?(@date_re, to_string(entry["date"])) do
314+
if Regex.match?(@date_re, to_string(entry["date"])) do
315+
entry_errors
316+
else
315317
entry_errors ++
316318
[
317319
%{
@@ -320,8 +322,6 @@ defmodule Gep.Validator do
320322
detail: "history[#{idx}] invalid date format: #{entry["date"]}"
321323
}
322324
]
323-
else
324-
entry_errors
325325
end
326326
end
327327

@@ -492,54 +492,14 @@ defmodule Gep.Validator do
492492
acc =
493493
(record.supersedes || [])
494494
|> Enum.reduce(acc, fn ref_n, acc ->
495-
ref = number_map[ref_n]
496-
497-
if ref == nil do
498-
acc
499-
else
500-
if ref.superseded_by != record.number do
501-
acc ++
502-
[
503-
%{
504-
severity: :error,
505-
label: "Bidirectional links",
506-
detail:
507-
"GEP-#{gep_label(record.number)} supersedes GEP-#{gep_label(ref_n)} but GEP-#{gep_label(ref_n)} has no superseded-by: #{record.number}",
508-
gep_number: record.number
509-
}
510-
]
511-
else
512-
acc
513-
end
514-
end
495+
check_superseded_by(acc, record, number_map[ref_n], ref_n)
515496
end)
516497

517498
# extended-by → see-also or requires on target
518499
acc =
519500
(record.extended_by || [])
520501
|> Enum.reduce(acc, fn ref_n, acc ->
521-
ref = number_map[ref_n]
522-
523-
if ref == nil do
524-
acc
525-
else
526-
back_refs = (ref.see_also || []) ++ (ref.requires || []) ++ (ref.extended_by || [])
527-
528-
if record.number not in back_refs do
529-
acc ++
530-
[
531-
%{
532-
severity: :error,
533-
label: "Bidirectional links",
534-
detail:
535-
"GEP-#{gep_label(record.number)} extended-by GEP-#{gep_label(ref_n)} but GEP-#{gep_label(ref_n)} does not reference back",
536-
gep_number: record.number
537-
}
538-
]
539-
else
540-
acc
541-
end
542-
end
502+
check_back_ref(acc, record, number_map[ref_n], ref_n)
543503
end)
544504

545505
acc
@@ -551,6 +511,46 @@ defmodule Gep.Validator do
551511
end
552512
end
553513

514+
defp check_superseded_by(acc, _record, nil, _ref_n), do: acc
515+
516+
defp check_superseded_by(acc, record, ref, ref_n) do
517+
if ref.superseded_by == record.number do
518+
acc
519+
else
520+
acc ++
521+
[
522+
%{
523+
severity: :error,
524+
label: "Bidirectional links",
525+
detail:
526+
"GEP-#{gep_label(record.number)} supersedes GEP-#{gep_label(ref_n)} but GEP-#{gep_label(ref_n)} has no superseded-by: #{record.number}",
527+
gep_number: record.number
528+
}
529+
]
530+
end
531+
end
532+
533+
defp check_back_ref(acc, _record, nil, _ref_n), do: acc
534+
535+
defp check_back_ref(acc, record, ref, ref_n) do
536+
back_refs = (ref.see_also || []) ++ (ref.requires || []) ++ (ref.extended_by || [])
537+
538+
if record.number in back_refs do
539+
acc
540+
else
541+
acc ++
542+
[
543+
%{
544+
severity: :error,
545+
label: "Bidirectional links",
546+
detail:
547+
"GEP-#{gep_label(record.number)} extended-by GEP-#{gep_label(ref_n)} but GEP-#{gep_label(ref_n)} does not reference back",
548+
gep_number: record.number
549+
}
550+
]
551+
end
552+
end
553+
554554
defp check_cross_references(records, number_map) do
555555
all_refs =
556556
records
@@ -586,15 +586,7 @@ defmodule Gep.Validator do
586586
end
587587

588588
defp check_readme_index(records, readme_path) do
589-
unless File.exists?(readme_path) do
590-
[
591-
%{
592-
severity: :error,
593-
label: "README index",
594-
detail: "README.md not found at #{readme_path}"
595-
}
596-
]
597-
else
589+
if File.exists?(readme_path) do
598590
content = File.read!(readme_path)
599591

600592
index_entries = parse_readme_index(content)
@@ -673,6 +665,14 @@ defmodule Gep.Validator do
673665
[] -> [%{severity: :pass, label: "README index", detail: "All entries valid"}]
674666
_ -> errors
675667
end
668+
else
669+
[
670+
%{
671+
severity: :error,
672+
label: "README index",
673+
detail: "README.md not found at #{readme_path}"
674+
}
675+
]
676676
end
677677
end
678678

test/gep/validator_test.exs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -470,10 +470,9 @@ defmodule Gep.ValidatorTest do
470470

471471
defp build_frontmatter(gep) do
472472
history_yaml =
473-
Enum.map(gep.history, fn h ->
473+
Enum.map_join(gep.history, "\n", fn h ->
474474
" - date: #{h["date"]}\n status: #{h["status"]}\n note: #{h["note"]}"
475475
end)
476-
|> Enum.join("\n")
477476

478477
optional_fields =
479478
[
@@ -484,17 +483,16 @@ defmodule Gep.ValidatorTest do
484483
{"see-also", gep.see_also}
485484
]
486485
|> Enum.reject(fn {_k, v} -> v == nil end)
487-
|> Enum.map(fn {k, v} ->
486+
|> Enum.map_join("\n", fn {k, v} ->
488487
yaml_val =
489488
if is_list(v) do
490-
"[" <> Enum.join(Enum.map(v, &to_string/1), ", ") <> "]"
489+
"[" <> Enum.map_join(v, ", ", &to_string/1) <> "]"
491490
else
492491
to_string(v)
493492
end
494493

495494
"#{k}: #{yaml_val}"
496495
end)
497-
|> Enum.join("\n")
498496

499497
optional_block =
500498
if optional_fields != "" do

0 commit comments

Comments
 (0)