Skip to content

feature(branch_sweep): sweep the rest of the organism from the Brain - #280

Merged
Jammy2211 merged 2 commits into
mainfrom
claude/repo-cleanup-82k6kh
Aug 25, 2026
Merged

feature(branch_sweep): sweep the rest of the organism from the Brain#280
Jammy2211 merged 2 commits into
mainfrom
claude/repo-cleanup-82k6kh

Conversation

@Jammy2211

@Jammy2211 Jammy2211 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Why central rather than 25 copies

Mind and Brain now sweep themselves, but a repo's GITHUB_TOKEN reaches only that repo — so covering the rest of the organism's development repos would mean 25 copies of the same workflow, drifting apart the moment one is edited. PAT_PYAUTOLABS already exists for exactly this kind of cross-repo work, so the sweep is written once here and pointed at each repo in turn.

Targets are derived, never listed

The first version of this PR carried a file listing the repos. CI rejected it, and was right to. The tenant firewall keeps instance facts — satellite repo names, GitHub owners — out of the framework organs so they stay adoptable as a config-diff fork, and a hardcoded list of slugs is exactly that leak.

Worse, it had smuggled it past: the firewall scans only .py and .sh, so a .txt list was not clean, only invisible. A hole to close, not a technique to keep.

The hygiene conductor had already solved this, and said so in the allowlist entry it deleted — "derives its repo sets from the body map, so it names no instance fact at all." Same answer here. bin/branch_sweep_targets.py expresses policy as categories (organ, library, workspace, workspace_test, workspace_developer, howto) and reads which repos fill them from repos.yaml.

Both exclusions now fall out of the categories rather than being named twice:

  • The skill's two Never-touched repos live in categories this does not sweep, so no rule has to know them.
  • The Mind and the Brain drop out by organ role, not name — each hosts its own branch_sweep.yml, and sweeping them centrally too would put two sweepers on one repo with different credentials. Roles are generic; an adopting fork has a Mind and a Brain whatever it calls them.

The derived set is 25 repos where the hand-list was 18. Not scope creep — the hand-list had quietly omitted repos indistinguishable from ones it included. A principled boundary includes them; the audit-first gate below is what keeps that safe.

The gate is structural, not procedural

  • mode=delete refuses to run without an explicit repos list. There is no delete-everything form of this workflow; the all-repos path is audit-only.
  • A target the body map does not make sweepable fails the whole run — including a run that also names valid repos. Fail closed, not partially.
  • The scheduled run is audit-only regardless of input.

Why stricter here than for Mind/Brain

Those are solo agent repos. The libraries and workspaces take pull requests from outside contributors, and the per-repo skill's protection for that case — "never enumerate origin-only collaborator branches"cannot hold in a workflow, where every branch it sees is origin-only. A human reading the audit per repo is the substitute, so the mechanism makes that step unskippable rather than trusting a runbook. (Fork PRs are unaffected — their heads live in the fork.)

Checks

pytest tests/507 passed · check_skill_line_counts.sh → OK · repos_sync.py --check in full → all 12 checks green, including the tenant firewall.

That last one is the lesson from the first round: I ran pytest and called it verified, but pytest was never the failing gate — repos_sync.py is a separate CI step I hadn't run locally.

Tests use a synthetic body map throughout. Necessary (this file is .py under an organ, so a fixture naming a real repo would be the same leak), but also better: it pins the contract — categories in, slugs out, unknown category fails closed — rather than today's roster.

The delete gate was exercised directly against the real derived set, 8 cases:

Dispatch Result
audit, no list all sweepable repos
delete, no list refused
delete, one valid repo 1 target
delete, two comma-separated 2 targets
delete, a Never-touched repo refused
delete, a repo not in the set refused
delete, valid + forbidden together refused — whole run
delete, a self-sweeping repo refused

🤖 Generated with Claude Code

https://claude.ai/code/session_01KwqicJpMqmcT5RVbyNwdKq

claude added 2 commits August 25, 2026 14:31
Mind and Brain now sweep themselves, but a repo's GITHUB_TOKEN reaches only
that repo — so covering the other 18 in Scope would mean 18 copies of the same
workflow, drifting apart the moment one is edited. PAT_PYAUTOLABS already
exists for cross-repo work (spawn_drift.yml, arxiv_papers.yml), so the sweep is
written once here and pointed at each repo in turn.

The gate is structural, not procedural. Deleting branches across 18 repos on
one click is not something a report should be able to talk anyone into:

- `mode=delete` REFUSES to run without an explicit `repos` list. There is no
  delete-everything form of this workflow; the all-repos path is audit-only.
- A target outside branch_sweep_set.txt fails the whole run — including a run
  that also names valid repos. Fail closed, not partially.
- The scheduled run is audit-only regardless of input.

Why that is stricter here than for Mind/Brain: those are solo agent repos.
PyAutoFit, PyAutoArray, PyAutoGalaxy, PyAutoLens and the workspaces take pull
requests from outside contributors, and the per-repo skill's protection for
that case — never enumerate origin-only collaborator branches — cannot hold in
a workflow, where every branch it sees IS origin-only. A human reading the
audit per repo is the substitute, so the mechanism makes that step unskippable
rather than trusting a runbook. (Fork PRs are unaffected; their heads live in
the fork.)

branch_sweep_set.txt is policy and so lives in the Brain, not in repos.yaml —
the body map's own header says identity there, per-organ policy with the organ.
It carries its exclusions with reasons: the skill's two Never-touched repos,
the assistants and publication surfaces, a different owner whose PAT scope is
unverified, and Mind/Brain themselves, which would otherwise end up with two
sweepers on different credentials.

Tests pin the boundary rather than the happy path: the Never-touched and
self-sweeping exclusions each fail a test if someone adds them back, and every
entry is checked against the body map so a typo cannot surface as a mid-sweep
clone failure. The gate's eight cases (including valid-plus-forbidden) were
exercised directly against the set file before this landed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KwqicJpMqmcT5RVbyNwdKq
CI rejected the first version, and it was right to. The tenant firewall keeps
instance facts — satellite repo names, GitHub owners — out of the framework
organs, so they stay adoptable as a config-diff fork. A file listing the
organism's repos is exactly that leak.

Worse, the first version had smuggled it past: the firewall scans only .py and
.sh, so a .txt list was not clean, only invisible. That is a hole to close, not
a technique to keep.

The hygiene conductor had already solved this, and said so in the allowlist
entry it deleted — "derives its repo sets from the body map, so it names no
instance fact at all". Same answer here. Policy is expressed as CATEGORIES,
which every organism has; which repos fill them is whatever that organism's
body map says.

Both exclusions now fall out of the categories instead of being named twice:
the skill's two Never-touched repos live in categories this does not sweep, so
no rule has to know them. The Mind and the Brain drop out by organ ROLE, not
name — each hosts its own branch_sweep.yml, and sweeping them centrally too
would put two sweepers on one repo with different credentials. Roles are
generic; an adopting fork has a Mind and a Brain whatever it calls them.

The derived set is 25 repos where the hand-list was 18. The difference is not
scope creep but the absence of arbitrariness: the hand-list had quietly
omitted repos indistinguishable from the ones it included. A principled
boundary includes them; the audit-first gate is what keeps that safe.

Tests use a synthetic body map throughout. Necessary — this file is .py under
an organ, so the firewall scans it and a fixture naming a real repo would be
the same leak — but also better: it pins the contract (categories in, slugs
out, unknown category fails closed) rather than today's roster.

Verified the way the first version was not: `repos_sync.py --check` in full,
locally, all twelve checks green, rather than assuming pytest was the gate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KwqicJpMqmcT5RVbyNwdKq
@Jammy2211
Jammy2211 merged commit b72fc1f into main Aug 25, 2026
2 checks passed
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.

2 participants