From 019173f3c31a44df4de7e14ef520fd2636eba655 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 17 May 2026 06:50:21 +0100 Subject: [PATCH] fix(reconcile): --verify no longer crashes on JSON-encoding its result MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ScorecardReconciler.verify/2 returns {:ok, summary} | {:error, reason} whereas reconcile/3 returns a bare map. The mix task fed the raw result straight to Jason.encode!/2, which cannot encode a tuple, so `mix hypatia.reconcile owner/repo --verify` crashed on output (the verify logic itself ran correctly — recurrence_defects were computed, just never printed). Surfaced by the live modshells reconcile run while closing the Scorecard epic (hypatia#260). Normalise verify to a bare map at the task boundary (matching reconcile/3's convention): {:ok, summary} -> summary; {:error, reason} -> %{repo, verified: false, error: reason}. Both the success and the no-token error path now emit clean JSON. Task-wrapper only; no change to verify/2 or any tested code path; reconciler suite green. Refs #260 #263. Co-Authored-By: Claude Opus 4.7 --- lib/mix/tasks/hypatia.reconcile.ex | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/mix/tasks/hypatia.reconcile.ex b/lib/mix/tasks/hypatia.reconcile.ex index 851c7d12..700346c2 100644 --- a/lib/mix/tasks/hypatia.reconcile.ex +++ b/lib/mix/tasks/hypatia.reconcile.ex @@ -41,7 +41,14 @@ defmodule Mix.Tasks.Hypatia.Reconcile do result = if opts[:verify] do - ScorecardReconciler.verify(owner, repo) + # verify/2 returns {:ok, summary} | {:error, reason}; reconcile/3 + # returns a bare map. Normalise verify to a bare map so the + # Jason.encode! below never receives a tuple (it cannot encode + # one — `mix hypatia.reconcile --verify` used to crash here). + case ScorecardReconciler.verify(owner, repo) do + {:ok, summary} -> summary + {:error, reason} -> %{repo: "#{owner}/#{repo}", verified: false, error: reason} + end else ScorecardReconciler.reconcile(owner, repo, dry_run: !!opts[:dry_run],