Repository navigation
Description
Overview
PyAutoBrain#290 shipped repo_settings.yml, a weekly sweep that turns on
"Automatically delete head branches" per repo, and removed /prm's
remote-delete step. That much works. But the sweep picks its targets from
PyAutoMind/repos.yaml, so it cannot see a repo until someone registers it —
and org repos are created by hand on github.com, with no gh repo create path
in the organism to hook. Nine live org repos are absent from the body map
entirely and ten more are excluded by category, so 27 of 44 are swept.
This switches the sweep to enumerate the organisation live from the GitHub API,
which closes the new-repo hole, the unregistered-repo hole and the category hole
at once — and removes the need for a category boundary on this consumer at all.
Plan
- PyAutoBrain#290 shipped the sweep and removed
/prm's remote-delete step. That half is done and is not reopened here. - The sweep reads
repos.yaml, so a repo is invisible until registered — and nothing in the organism creates org repos, so there is no birth-time hook to add. - Nine live org repos are absent from the body map; ten more are excluded by category. 27 of 44 org repos are swept.
- Switch to live org enumeration (non-archived repos under the workflow's own owner), union any body-map repo whose owner is not the org.
- Split the failure policy: an in-org repo refusing the PATCH is an error; a personal-account repo is a warning, since the org PAT's admin scope there is unverified by design.
- Retire the now-unused
--include-self-sweepingflag, whose only consumer is the line being replaced. - Leave the assistants'
start-new-project.mdalone: it creates a visiting scientist's own repo under their own account.
Detailed implementation plan
Affected Repositories
- PyAutoBrain (primary)
Branch Survey
| Repository | Current Branch | Dirty? |
|---|---|---|
| ./PyAutoBrain | main | clean |
Suggested branch: feature/repo-settings-org-enumeration
Implementation Steps
1. .github/workflows/repo_settings.yml
- Add
ORG: ${{ github.repository_owner }}to the stepenv:alongsideGH_TOKEN, rather than interpolating${{ }}inline in therun:block. - Replace the single
targets=line (currently line 84) with two lists:in_org=$(gh api --paginate "orgs/$ORG/repos?per_page=100" \ --jq '.[] | select(.archived == false) | .full_name') outside=$(python3 bin/branch_sweep_targets.py --outside-owner "$ORG" .mind/repos.yaml)
- Retarget the refuse-to-continue guard: an empty
in_orgis an error, never a clean run. - Failure-policy split in the loop: in-org PATCH refusal or unreadable setting keeps
failed=1; out-of-org refusal emits::warning::only. Today every refusal setsfailed=1, which would make the weekly schedule permanently red once personal-account repos are included. - Add a Scope/Owner column to the
$GITHUB_STEP_SUMMARYtable so the split is visible in the run. - Rewrite the header comment: the "27 repos" count and the "a repo added to the body map after today is corrected on the next run" sentence both become false. Replace with the real reason enumeration is live — a new repo is not in the body map at the moment it is created.
2. bin/branch_sweep_targets.py
- Add
--outside-owner <owner>→ body-map slugs whose owner part !=<owner>. Deliberately no category filter: the org enumeration has no category boundary, so its complement must not have one; filtering would yield nothing, since the only two foreign repos are categoriesadminandassistant. - Remove
--include-self-sweepingand theinclude_self_sweepingparameter. Sole consumer verified to berepo_settings.yml:84. An unused widening flag on a boundary whose other modes delete refs is a trap. - Do not touch
targets()orSWEEPABLE_CATEGORIES— they still servebranch_sweep_all.yml:98andbranch_archive.yml:110, where the action is deleting refs and the narrow boundary is correct. - Update the module docstring: drop the
--include-self-sweepingparagraph, add the--outside-ownerrationale.
3. tests/test_branch_sweep_targets.py
- Delete
test_include_self_sweeping_keeps_the_organs_that_sweep_themselveswith the flag. - Repoint
test_cli_flag_matches_the_functionat--outside-owner. - Add: foreign-owner slugs yielded regardless of category; an all-in-org body map yields empty; CLI/function parity for the new flag.
- Keep the fail-closed tests as they are (unknown flag → exit 2, missing body map → exit 1, unknown/missing category excluded).
- Fixtures keep invented repo names — this file is
.pyunder a framework organ and the tenant firewall scans it.
4. Stale prose
skills/repo_cleanup/SKILL.md:133— "body-map-wide" becomes org-wide.skills/repo_cleanup/reference.md:164— one sentence noting the settings sweep no longer uses this module's category boundary.skills/prm/reference.md:311andskills/GITHUB_ACCESS.md:81say only that the setting is kept on per repo — still true, unchanged.
Key Files
.github/workflows/repo_settings.yml— the sweep; target derivation and failure policybin/branch_sweep_targets.py— body-map derivation; gains--outside-owner, loses--include-self-sweepingtests/test_branch_sweep_targets.py— the boundary's test surfaceskills/repo_cleanup/{SKILL.md,reference.md}— prose that goes stale
Trade-offs / risks
- Reverses part of PR#290, merged hours earlier. That PR added a test asserting the category boundary must not widen. This task does not widen it — it bypasses it for one consumer that enumerates the org instead — but the
--include-self-sweepingflag it introduced is retired. The PR body must say so and why. - Org enumeration sweeps repos nobody classified (
.github,PyAutoLogo, both-templaterepos, the typo repoautolens_workspace_developer-). Flipping a reversible boolean there is harmless, but it is a real widening. - Main risk:
PAT_PYAUTOLABSmay lack admin on some org repo a personal token can reach. Unknown until the workflow runs — it never has.
Testing
python3 bin/branch_sweep_targets.py --outside-owner PyAutoLabs ../PyAutoMind/repos.yaml→ exactlyJammy2211/admin_jammyandJammy2211/euclid_assistant.python3 bin/branch_sweep_targets.py ../PyAutoMind/repos.yaml | wc -l→ still 25 (measured before the change; the plain derivation must not move).pytest tests/ -q→ baseline measured at 542 passed (4m25s), minus the one removed test, plus the new ones.bash bin/check_skill_line_counts.sh; YAML parse of the workflow;repos_sync.py --check --only "tenant firewall (organ code)".- Post-merge: dispatch the workflow in
auditmode first (it has never run) — expect ~44 in-org + 2 out-of-org rows, all "already on", green. Only then dispatchapply.
Original Prompt
Click to expand starting prompt
The repo-settings sweep should enumerate the org, not the body map
Type: feature
Target: pyautobrain
Repos:
- PyAutoBrain
Difficulty: small
Autonomy: supervised
Priority: normal
Status: formalised
Filed: 2026-08-26
The original request (verbatim)
I want to make it so that when a branch merges via PR, on all repos, its auto
deleted. Can we do that here or do I need to manually go to each repo on
Github.com and do it?
and, once told PyAutoBrain#290 had already shipped most of it:
make it so new repos do inherit this, we should of also just made it so prm
doesnt try to delete anymore, I think the mobile chat pushed but chec
What is already done — do not redo it
PyAutoBrain#290 (merged 5ac5586, 2026-08-26, from a mobile session) shipped:
.github/workflows/repo_settings.yml— a weekly + dispatchable sweep that
PATCHesdelete_branch_on_merge=true, targets derived from the body map.bin/branch_sweep_targets.py --include-self-sweeping— the widened organ
boundary that sweep uses, plustests/test_branch_sweep_targets.py./prmdeletes no remote branch on any surface (skills/prm/prm.md:43,
step 5.6). The second half of the request above is therefore already
satisfied — do not reopen it.
Separately, all 46 live repos (44 PyAutoLabs/* + Jammy2211/admin_jammy +
Jammy2211/euclid_assistant) were PATCHed to true by hand in the filing
session and verified by re-reading the API. This task is about durability for
repos the sweep cannot currently see — not about today's state.
The hole
The sweep derives its targets from PyAutoMind/repos.yaml. Two consequences:
- A new repo is invisible until someone registers it. Org repos are created
by hand on github.com — there is nogh repo createpath in the organism for
them (checked: the four assistants'start-new-project.mdcreate a visiting
scientist's own private project 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). So birth-time is not a hook we have, and registration is the
only thing standing between a new repo and the sweep. - Nine live org repos are absent from the body map and so are never swept:
.github,PyAutoLogo,PyAutoMemory-template,PyAutoMind-template,
PyAutoProject,autolens_jax_joss,autoproject_workspace,
autoproject_workspace_test, and the typo repo
autolens_workspace_developer-.
A third, smaller gap: the category boundary excludes assistant (5),
pipeline (1), project (3) and admin (1), so 10 of the 37 registered
repos are skipped too — 27 of 37 swept. Those exclusions are correct for the
branch sweep, whose action is deleting refs, and PR#290 added a test
asserting they must not widen. They do not transfer to flipping a reversible
boolean on repos that demonstrably merge PRs (autolens_assistant#115,
autogalaxy_assistant#19, autocti_assistant#26 all merged this week).
Decision (human, at filing time)
Enumerate the org live. Targets become every non-archived repo under
${{ github.repository_owner }} read from the API, union any body-map repo
whose owner is not the org. This closes all three gaps at once and needs no
category boundary at all. The owner comes from the GitHub context, so no
instance fact enters organ code and the tenant firewall stays satisfied.
Do not touch the assistants' start-new-project.md. That repo belongs to
the visiting scientist, under their own account, and the skill presents it as a
backup/collaboration surface that may not use PRs. Imposing our merge policy on
it is our convention leaking into someone else's workspace.
Notes for the implementer
--include-self-sweepinghas exactly one consumer,repo_settings.yml:84.
Org enumeration removes that consumer, so the flag becomes dead code on a
safety-relevant boundary — retire it with its two tests rather than leaving it
loaded. This reverses part of a PR merged hours earlier; say so in the PR body.- The plain derivation still has two consumers (
branch_sweep_all.yml:98,
branch_archive.yml:110) and its narrow category boundary must not move. - Out-of-org repos are the user's own (
Jammy2211/*);PAT_PYAUTOLABSadmin
scope there is unverified. A PATCH refusal on those must warn, not fail —
the job currently setsfailed=1on any refusal and would go red every week. - Stale claims to update once the source changes: the workflow's own header
comment ("27 repos", body-map framing),skills/repo_cleanup/SKILL.md:133
("body-map-wide"), and the derivation paragraph at
skills/repo_cleanup/reference.md:164if it describes the settings consumer. - The workflow has never actually run. Dispatching it after merge is the smoke
test: with every repo alreadytrue,applyshould report all-already-on.
Activity
Jammy2211 commentedon Aug 26, 2026
Library PR created — #292
feature/repo-settings-org-enumeration@dcce212, 5 files.Scope changed during implementation. The filed prompt's "Gap 2" (patch the
gh repo createcall sites so new repos inherit the setting at birth) turned out not to exist: the four assistants'start-new-project.mdcreate a visiting scientist's own repo under their account, the clone conductor has no create call (clone/DESIGN.md:148— still an open v0 question), and/spawnsyncs template repos that already exist. There is no org repo-creation path to hook, which is why live org enumeration is the fix rather than a birth-time PATCH.Verification — 548 passed (baseline measured at 542; 542 − 1 removed + 7 new reconciles exactly). Plain derivation measured before and after at 25 slugs, so the branch sweep's boundary provably did not move. The workflow's
run:block was extracted and control-tested against a stubbedghacross 7 scenarios, since it has never executed; live org enumeration returns 44 non-archived repos. Tenant firewall OK and proven non-vacuous with a deliberate leak probe.Heart was RED at ship time —
release validation FAILED(integrate:fail), standing since 2026-08-23 and unrelated to this diff. Shipped on an explicit human override, not the corrective-PR exception.Workspace impact: none (option iii). This touches a CI workflow, a derivation script, its tests and skill prose — no PyAuto library API, so no workspace script imports anything that changed and
/smoke_testhas nothing to exercise here.Before merge: dispatch
repo_settings.ymlinauditmode first — it has never run.Jammy2211 commentedon Aug 26, 2026
Shipped — #292 merged
Merge commit
475d292e0, CI green on both matrix legs (pytest (3.12),pytest (3.13)) atdcce212.The change validated itself on its own merge: GitHub auto-deleted
feature/repo-settings-org-enumerationthe moment #292 landed — confirmed bygit ls-remotereturning nothing for that ref. That isdelete_branch_on_mergedoing exactly what #290 and this PR set out to make automatic, with no session credential involved.What shipped
repo_settings.ymlnow enumerates the organisation live (non-archived repos under the workflow's own owner), union the out-of-org complement from--outside-owner. A repo created by hand on github.com is covered the run after it exists, rather than waiting on someone to register it inrepos.yaml.--include-self-sweepingretired (org enumeration removed its only consumer); a regression test asserts a stale caller fails rather than silently falling back to the narrow set.targets()/SWEEPABLE_CATEGORIESuntouched — the branch sweep's boundary is unchanged at 25 slugs, measured before and after.Still to do, and it needs a human: the workflow has never executed. Dispatch it in
mode: auditfirst — expect 44 in-org + 2 out-of-org rows, all "already on". Only thenapply. Anyrefused (needs admin)row isPAT_PYAUTOLABSscope, which is a decision rather than a retry.