Skip to content

feat(sweep): enumerate the org for repo settings, not the body map - #292

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/repo-settings-org-enumeration
Aug 26, 2026
Merged

Jammy2211 merged 1 commit into
mainfrom
feature/repo-settings-org-enumeration

Conversation

@Jammy2211

Copy link
Copy Markdown
Contributor

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.md create a visiting scientist's own private repo under their account; the clone conductor has no create call at all (clone/DESIGN.md:148 still lists repo creation as an open v0 question); /spawn force-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 -template repos, PyAutoProject, autolens_jax_joss, autoproject_workspace{,_test}, and the typo repo autolens_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-owner supplies. 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_themselves asserted it must not be, and that assertion still holds — targets() and SWEEPABLE_CATEGORIES are untouched, still yielding the same 25 slugs for branch_sweep_all.yml and branch_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.

ORG and MODE also move into the step env: 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 (.github and 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).

  • Removed: bin/branch_sweep_targets.py --include-self-sweeping, and the include_self_sweeping= parameter of targets(). 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".
  • Added: bin/branch_sweep_targets.py --outside-owner <owner>, and outside_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 ones targets() excludes, a filtered complement would always be empty.
  • Unchanged: targets() behaviour and SWEEPABLE_CATEGORIES.

Verification

  • pytest tests/ -q in the worktree — 548 passed. Baseline was measured at 542 before the change, not assumed: 542 − 1 removed + 7 new = 548, reconciles exactly.
  • Plain derivation measured before and after: 25 slugs both times, so the branch sweep's boundary demonstrably did not move.
  • --outside-owner PyAutoLabs against the real body map → exactly Jammy2211/euclid_assistant, Jammy2211/admin_jammy.
  • Retired flag and a valueless --outside-owner both fail closed (exit 2, no slug printed).
  • The run: block was extracted and control-tested against a stubbed gh across 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.
  • Live 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 to true by hand while filing this.
  • Tenant firewall OK against the worktree, and proven non-vacuous: injecting a deliberate instance-fact leak turned it RED naming the file and line, then reverted.
  • check_skill_line_counts.sh 47/47 within budget; YAML parses; bash -n clean.

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 at 5ac5586. 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: audit first — expect 44 in-org + 2 out-of-org rows, every one "already on", green. Only then apply. If a repo reports refused (needs admin), that is PAT_PYAUTOLABS scope, and widening a PAT is a human decision rather than a retry; audit mode surfaces it without reddening the schedule.


Generated by Claude Code

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
@Jammy2211
Jammy2211 merged commit 475d292 into main Aug 26, 2026
2 checks passed
@Jammy2211
Jammy2211 deleted the feature/repo-settings-org-enumeration branch August 26, 2026 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(sweep): enumerate the org for repo settings, not the body map

1 participant