Repository navigation
feat(sweep): enumerate the org for repo settings, not the body map - #292
Merged
Merged
Conversation
A body-map-derived target set is blind in exactly the wrong place: a repo is created *before* anyone registers it, so the repos most in need of "delete the head branch on merge" were the ones repo_settings.yml could not see. Nine live org repos were absent from the body map entirely, and ten more fell outside the sweepable categories — a boundary drawn around *deleting refs*, which has no bearing on flipping a reversible boolean. The sweep now lists the organisation from the GitHub API (non-archived repos under the workflow's own owner), so a new repo is covered the run after it exists and no category question arises. `--outside-owner` supplies the complement an org listing cannot return: body-map repos under another account. Because those sit under a personal account whose PAT admin scope is unverified by design, the failure policy is now scope-aware — an in-org refusal is an error, an out-of-org one a warning. Without that split the weekly unattended run would go red permanently the first time it touched one. `--include-self-sweeping` is retired: org enumeration removed its only consumer, and an unused widening flag on a boundary whose other modes delete refs is a trap. The category boundary itself is unchanged — `targets()` still yields the same 25 slugs for branch_sweep_all.yml and branch_archive.yml. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EqUT9Wc6mVLiJmbcstT7Z3
This was referenced Aug 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #291. Follows #290, merged earlier the same day — read that one first; this changes where its sweep gets its targets.
The hole #290 left
#290 fixed the cause of undeleted branches: turn on "Automatically delete head branches" per repo, and no session credential is involved at merge. That part works. But it derived its targets from
PyAutoMind/repos.yaml, and a body map is the one source that is guaranteed to be stale for exactly the repos in question — a repo is created before anyone registers it. The repos most in need of the setting were the ones the sweep could not see.There is no birth-time hook to add instead. I checked all three candidates: the four assistants'
start-new-project.mdcreate a visiting scientist's own private repo under their account; the clone conductor has no create call at all (clone/DESIGN.md:148still lists repo creation as an open v0 question);/spawnforce-syncs template repos that already exist. Org repos are made by hand on github.com. Registration was the only gate, and it is the one that gets forgotten.Two smaller gaps fell out of the same source. Nine live org repos are absent from the body map entirely (
.github,PyAutoLogo, both-templaterepos,PyAutoProject,autolens_jax_joss,autoproject_workspace{,_test}, and the typo repoautolens_workspace_developer-). Ten more registered repos are excluded by category —assistant,project,pipeline,admin— despite merging PRs like anything else (autolens_assistant#115, autogalaxy_assistant#19, autocti_assistant#26, all merged that week). 27 of 44 org repos were swept.Enumerate the organisation instead
Targets are now every non-archived repo under
${{ github.repository_owner }}, read from the API, union the body-map repos under another account — which an org listing cannot return, and which--outside-ownersupplies. A new repo is covered the run after it exists, and the category question does not arise at all.The category boundary is not widened. #290's
test_include_self_sweeping_keeps_the_organs_that_sweep_themselvesasserted it must not be, and that assertion still holds —targets()andSWEEPABLE_CATEGORIESare untouched, still yielding the same 25 slugs forbranch_sweep_all.ymlandbranch_archive.yml, where the action is deleting refs and the narrow boundary is right. This bypasses that boundary for one consumer rather than moving it.It does retire
--include-self-sweeping, which #290 added hours ago. Org enumeration removed its only consumer (repo_settings.yml:84). An unused widening flag on a module whose other modes delete refs is a trap, so it is gone rather than left loaded, and a regression test now asserts a stale caller fails rather than silently falling back to the narrow set.The failure policy is now scope-aware. Out-of-org repos sit under a personal account whose PAT admin scope is unverified by design. Previously every refusal set
failed=1; including those repos unchanged would have turned the weekly unattended run red permanently. In-org refusal or unreadable setting stays an error; out-of-org emits::warning::only. The step-summary table gains a Scope column so the split is visible.ORGandMODEalso move into the stepenv:rather than being interpolated into the shell, so a value cannot become shell.Honest widening
This now sweeps repos nobody has classified — the nine listed above. Flipping a reversible boolean on them is harmless and arguably correct (
.githuband the templates merge PRs too), but it is a real change in blast radius and not a side effect worth discovering later.API Changes
Internal CLI only; no public package API is touched (PyAutoBrain is not a released package).
bin/branch_sweep_targets.py --include-self-sweeping, and theinclude_self_sweeping=parameter oftargets().targets()is now single-signature. Sole consumer was the line this PR replaces; a stale caller now exits 2 rather than reading as "no flag".bin/branch_sweep_targets.py --outside-owner <owner>, andoutside_owner(body_map, owner). Yields body-map slugs whose owner differs, in body-map order, with no category filter — deliberate, and tested: the org listing it complements has none either, and since the categories that end up under a personal account are precisely the onestargets()excludes, a filtered complement would always be empty.targets()behaviour andSWEEPABLE_CATEGORIES.Verification
pytest tests/ -qin the worktree — 548 passed. Baseline was measured at 542 before the change, not assumed: 542 − 1 removed + 7 new = 548, reconciles exactly.--outside-owner PyAutoLabsagainst the real body map → exactlyJammy2211/euclid_assistant,Jammy2211/admin_jammy.--outside-ownerboth fail closed (exit 2, no slug printed).run:block was extracted and control-tested against a stubbedghacross 7 scenarios, since this workflow has never executed: all-on → 0 · empty org listing → 1 (refuses rather than reporting a clean sweep) · in-org unreadable → 1 · in-org PATCH refused → 1 · out-of-org refused → 0 with a warning · out-of-org unreadable → 0 ·audit→ 0. Summary table and counters checked.gh api --paginate "orgs/PyAutoLabs/repos?per_page=100" --jq '.[] | select(.archived == false) | .full_name'→ 44 repos, 0 archived. With the 2 out-of-org repos that is 46 — the same set already set totrueby hand while filing this.check_skill_line_counts.sh47/47 within budget; YAML parses;bash -nclean.Before merging
Heart was RED when this shipped —
release validation FAILED(integrate:fail, v2026.8.25.1.dev73701), standing since 2026-08-23 and unrelated to this diff, which touches a CI workflow, a derivation script, its tests and skill prose. PyAutoBrain's own CI was green at5ac5586. Shipped on an explicit human override, not the corrective-PR exception; merge remains a separate human act.After merging
The workflow has never run. Dispatch
mode: auditfirst — expect 44 in-org + 2 out-of-org rows, every one "already on", green. Only thenapply. If a repo reportsrefused (needs admin), that isPAT_PYAUTOLABSscope, and widening a PAT is a human decision rather than a retry; audit mode surfaces it without reddening the schedule.Generated by Claude Code