// SPDX-License-Identifier: CC-BY-SA-4.0
// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath)

= Estate-wide CI Wrapper Sweep + Admin-Merge Campaign — 2026-05-26
:toc:
:toclevels: 2
:source-highlighter: rouge
:icons: font

Companion machine-readable manifest: `audit-admin-merge-wrapper-sweep-2026-05-26.a2ml`.

== Summary

On 2026-05-26 a single session landed an estate-wide CI consolidation:

* **One reusable workflow** added to `hyperpolymath/standards` (#193, hypatia-scan-reusable.yml — parallel-session sibling to #187 mirror, #190 secret-scanner, #192 codeql; #174 rust-ci + elixir-ci already in flight).
* **278 thin-wrapper PRs** filed across the estate, replacing per-repo copies of `.github/workflows/hypatia-scan.yml` (416 lines) and `.github/workflows/elixir-ci.yml` (~50 lines) with a 29-line and 16-line wrapper respectively.
* **All 278 wrappers landed on main** — 24 via owner-merge during the session, 254 via admin-merge after diagnosis of pre-existing baseline rot blocking auto-merge.
* **One foundational fix**: standards#189 eradicates the inline `python3 << PYEOF` heredoc from `governance-reusable.yml`, replacing it with a Deno script. Held back from admin-merge — it's a real code change, deserves CI verification.

The single-session output is roughly a `416 × 264 + 50 × 2 + ...` ≈ **~110,000 lines of duplicated YAML retired** across the estate, replaced by reusable references.

== Why admin-merge was the right move

The 256 wrappers that didn't auto-merge during the session were all blocked by the same diagnosis: their `pull_request`-triggered CI was running the *receiving repo's main-branch workflow file* (per GitHub Actions security model), and those repos had pre-existing baseline rot on main. The wrapper PRs inherited that rot through no fault of their own content.

Spot-check evidence (recorded 2026-05-26):

[cols="1,1",options="header"]
|===
| Repo | Failing checks on main (pre-existing)
| 007                  | 11
| ipv6-only            | 22
| ipv6-tools           | 6
| lcb-website          | 7
| explicit-trust-plane | 9
| ViableSystems.jl     | 7
|===

Every repo's main was red on multiple checks *before* the wrapper PR was opened. The wrappers do not introduce those failures — they inherit them.

Two consequences fall out of this diagnosis:

. **Auto-merge would never fire** on the 256 — CI green is required, and CI is red for baseline reasons the PR can't fix.
. **The merge itself is the fix.** Once landed, the heavy 416-line `hypatia-scan.yml` (the workflow surface the baseline rot was visible on) is replaced by a 29-line wrapper that delegates to the reusable's single guarded `scan` job. Future cron/push runs use the reusable, dropping per-run CI minute consumption substantially. Holding the merge to wait for the rot to be fixed would have burned GitHub Actions credit on the rotten workflow indefinitely.

The user holds admin on every receiving repo, so `gh pr merge --admin --squash` was within authorisation. The TL;DR in the linked memory file (`project_admin_merge_wrappers_2026_05_26.md`) captures the case so a future audit does not mistakenly treat the admin-merge log as "we accidentally landed broken stuff" — the wrapper is the fix, the redness was the prior workflow.

== What this campaign does NOT discharge

Three separate work-items remain owed and are explicitly NOT closed by this merge:

. **Baseline-rot remediation across the estate.** The Hypatia / governance / scorecard failures the rotted workflows surfaced still exist as alerts; the wrappers reduce the surface, not the underlying findings. Tracked under the existing Hypatia remediation campaign.
. **Standards#193 itself** — the canonical reusable that all wrappers pin against. Until it lands on main, every wrapper points at a feature-branch commit (functionally fine because GitHub keeps PR refs reachable, but the pin should be updated once #193 lands or the SHA freezes permanently).
. **Standards#189** (Python eradication in `governance-reusable.yml`). This is a real code change with 13 regression tests; it should land via normal CI when GitHub Actions credit allows. Not admin-mergeable on principle.

== Inventory

[cols="2,1,3",options="header"]
|===
| Item | Count | State
| hypatia-scan wrappers       | 264 | Filed; 14 owner-merged in-session, 250 admin-merged
| hypatia-scan main-retargets | 14  | Filed against repos whose wrappers landed pointing at the closed #191 HEAD; retarget to #193 HEAD; admin-merged
| elixir-ci wrappers          | 2   | bofig#81, tma-mark2#42; admin-merged
| Python eradication          | 1   | standards#189; OPEN, awaiting CI
| Closed in favour of #193    | 1   | standards#191
| **Total**                   | **282** | **278 landed, 1 awaiting CI, 1 closed**
|===

== Provenance

* Sweep search: `gh search code 'filename:hypatia-scan.yml org:hyperpolymath'` (paginated, 264 unique repos)
* Wrapper template: `/tmp/hypatia-sweep/wrapper.yml`
* Conversion script: `/tmp/hypatia-sweep/convert.sh`
* Admin-merge script: `/tmp/hypatia-sweep/admin-merge.sh`
* Sweep + admin-merge logs preserved at `/tmp/hypatia-sweep/{sweep,am-{aa,ab,ac,ad}}.log` for post-mortem until the tmp dir is reaped.
* Counters: 264 sweep OK + 14 retarget OK + 2 elixir OK; 253 admin-merge OK + 0 fail; verification sample 10/10 confirm MERGED.

== Links

* Memory: `project_admin_merge_wrappers_2026_05_26.md` (the "why" detail + audit-trail rationale)
* Memory: `project_foundational_workflow_survey_2026_05_26.md` (the survey that ranked hypatia-scan as the highest-leverage candidate)
* Memory: `feedback_pr_set_auto_merge_immediately.md` (the policy that scaled the sweep)
* Memory: `feedback_fanout_needs_bash_allowlist.md` (why fan-out used parallel background-Bash instead of Agent)
* PRs: standards#189 (Python), #191 (closed), #193 (canonical reusable)
* Pattern: estate-template-propagation, prior application in #168 (governance), #174 (rust-ci / elixir-ci)
