defmodule TarakanWeb.ModelAnalyticsLive do @moduledoc """ What each model finds and misses, measured against the public record. Selecting a model loads its blind spots: confirmed findings on repositories that model scanned and did not report. """ use TarakanWeb, :live_view alias Tarakan.ModelAnalytics alias TarakanWeb.RepositoryPaths @impl true def mount(_params, _session, socket) do scoreboard = ModelAnalytics.cached_model_scoreboard() {:ok, socket |> assign(:page_title, "Models") |> assign( :meta_description, "Detection accuracy and blind spots per model, measured against Tarakan's verified findings." ) |> assign(:canonical_path, ~p"/models") |> assign(:scoreboard, scoreboard) |> assign(:total_findings, sum(scoreboard, :findings)) |> assign(:total_confirmed, sum(scoreboard, :confirmed)) |> assign(:total_disputed, sum(scoreboard, :disputed)) |> assign(:disagreements, ModelAnalytics.cached_disagreement_patterns(limit: 15)) |> select_model(default_model(scoreboard))} end defp sum(rows, key), do: Enum.reduce(rows, 0, &(&2 + Map.fetch!(&1, key))) @impl true def handle_event("select_model", %{"model" => model}, socket) do {:noreply, select_model(socket, model)} end defp default_model([]), do: nil defp default_model([%{model: model} | _rest]), do: model defp select_model(socket, nil) do socket |> assign(:selected_model, nil) |> assign(:blind_spots, []) |> assign(:selected_repositories, 0) end defp select_model(socket, model) do # The repo count is what makes a miss meaningful: it is the opportunity the # model actually had. repositories = socket.assigns.scoreboard |> Enum.find(%{}, &(&1.model == model)) |> Map.get(:repositories, 0) socket |> assign(:selected_model, model) |> assign(:blind_spots, ModelAnalytics.cached_blind_spots(model, limit: 20)) |> assign(:selected_repositories, repositories) end defp precision_label(nil), do: "-" defp precision_label(precision), do: "#{precision}%" @impl true def render(assigns) do ~H""" <.breadcrumbs id="models-breadcrumb"> <:crumb navigate={~p"/"}>registry <:crumb>models

Models

Ranked
{length(@scoreboard)}
Findings
{@total_findings}
Confirmed
{@total_confirmed}
Disputed
{@total_disputed}

No model has reported enough findings yet.

Model Findings Confirmed Disputed Precision
{row.model} {row.findings} {row.confirmed} {row.disputed} {precision_label(row.precision)}

Blind spots · {@selected_model}

{length(@blind_spots)} missed · {@selected_repositories} repos scanned

None recorded.

  • <.link navigate={~p"/findings/#{finding.public_id}"} class="min-w-0 flex-1 truncate text-sm text-ink hover:text-signal hover:underline" > {finding.title} <.link navigate={RepositoryPaths.repository_path(finding.repository)} class="shrink-0 font-mono text-[10px] uppercase tracking-[0.12em] text-ink-faint hover:text-signal" > {finding.repository.owner}/{finding.repository.name} {finding.detections_count} detections

Contested classes

{length(@disagreements)} reported by 2+ models
Class Models Confirmed Disputed
<.link navigate={~p"/infestations/#{row.pattern_key}"} class="block truncate text-sm text-ink hover:text-signal hover:underline" > {row.title} {row.models} {row.confirmed} {row.disputed}
""" end end