Skip to content

Operationalize ScorecardReconciler: run the code-scanning alert loop on a schedule (close the Maintained/staleness recurrence) #582

Description

@hyperpolymath

Context

Hypatia.ScorecardReconciler (lib/scorecard_reconciler.ex) plus mix hypatia.reconcile <owner/repo> (lib/mix/tasks/hypatia.reconcile.ex) already implement the full Sense → Classify → Act → Verify → Learn loop that closes GitHub code-scanning alerts (design: #260, #263, #265). The classification core is pure and unit-tested; the write-back dismisses non-actionable findings with rationale and records each by stable fingerprint in ~/.git-private-farm/hypatia-exception-registry.json, so a class adjudicated once is never re-reasoned.

The gap is operational, not code. Nothing runs it on a schedule against the estate. So OpenSSF Scorecard's MaintainedID (the "scorecard staleness" signal) and the other non-actionable / design-exception findings re-accumulate as OPEN on every audit — exactly the recurrence + weekly credit-burn #260 describes. The instrument exists; it just isn't wired to run.

What it would do (grounded in classify/1)

Scorecard rule Action
MaintainedID, ContributorsID, CITestsID, CIIBestPracticesID :dismiss_info — "won't fix" + rationale (activity signal — this is scorecard staleness)
PinnedDependenciesID (SLSA pin-exempt) :dismiss_accept
SASTID :fix (set CodeQL matrix to actions)
PinnedDependenciesID (other) :fix (pin to full SHA)
BranchProtectionID, CodeReviewID :fix_settings (GitHub settings API)
else :open_escalate (leave open + ensure tracking issue)

Preconditions to run it

  1. BEAM host — Elixir/OTP with mix deps.get (absent from the Claude Code web session; any CI runner or standing host works).
  2. security_events-scoped token (read + write, to dismiss alerts). HYPATIA_DISPATCH_PAT exists but must carry security_events — and administration/repo-settings write only if :fix_settings should auto-apply. Run --conservative to avoid settings mutation entirely.
  3. Registry persistence — commit hypatia-exception-registry.json back to .git-private-farm after each run so decisions survive across runs.

Proposed deployment (pick one)

  • A — scheduled GitHub Action (in hypatia or .git-private-farm): weekly cron → erlef/setup-beammix deps.get → loop mix hypatia.reconcile <repo> over the estate repo list → commit the registry. Token from secrets. Simplest; no standing host.
  • B — existing hypatia host: fold a periodic reconcile pass into the OTP learning_scheduler (already polls every 5 min) or a dedicated cron GenServer.

Safe rollout

  1. mix hypatia.reconcile <repo> --dry-run across all repos → review the classification (no mutation).
  2. --conservative → dismiss non-actionable findings, escalate settings findings (no automatic branch-protection changes).
  3. Full-auto once trusted. Run --verify periodically to catch recurrence defects (reopened-with-no-change).

Acceptance

  • MaintainedID / staleness + design-exception alerts are dismissed-with-rationale once and stop re-opening across audits.
  • The registry records every decision by fingerprint (no re-reasoning, no re-billing).
  • Weekly credit-burn from re-accumulated non-actionable findings drops to ~0.

References


Filed as an actionable deployment hand-back. The reconciler code is done and merged; this issue tracks only wiring it to run. Raised from a session that confirmed the task cannot run in the ephemeral web environment (no BEAM; the available token is a proxy placeholder without security_events).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions