You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The bare and prefixed spellings of several body-map repos normalise to two
different keys, so a policy map filed under one is invisible to the other. _target_sets.names_for registers BOTH spellings of every PyAuto* repo as a
known target (name.lower() and name.lower()[2:]), but repo_aliases in config/policy.yaml only joins them for the libraries. Reproduced live on main: @autobrain normalises to autobrain, which is a known target with no test_witness row, so pyauto-brain refactor reports [unwitnessed: autobrain]
and advises "strengthen tests first" for the best-tested repo in the organism; pyauto-brain intake on the same mention files Target: autobrain, a folder
that does not exist (the real one is draft/bug/pyautobrain/).
This is the fourth instance of one defect class — PyAutoNerves (#267),
PyAutoCTI and PyAutoReduce (#269) were the first three. The shared cause is
that repo_aliases is HAND-MAINTAINED while the known-target set is DERIVED
from the body map, so the two drift silently and the gap only ever surfaces as
a wrong-but-plausible conductor message. This task closes the class, not the
instance.
The keying decision (answered before any edit, as the prompt requires)
Organs key on the PREFIXED form (pyautobrain), extending the rule #269/#271
already wrote down: the canonical key is the bare package name where the repo
ships one, the repo name where it does not. Organs ship no package — PyAutoNerves
is the exception and already keys bare (autonerves). Everything downstream is
already filed prefixed for organs: test_witness, target_signals, REPO_DISPLAY, target_default_wiki, and the Mind's own target folders
(draft/*/pyautobrain/, pyautomind/, pyautoheart/, pyautomemory/, pyautohands/). Keying bare would rekey five maps plus Mind folders for no gain.
Scope found beyond the prompt's list
Reproduction swept every body-map repo, not just the five organs named:
Repo
Category
Spellings
Today
PyAutoBrain / Heart / Memory / Mind / Gut
organ
pyauto* vs auto*
split — bare form resolves to a key nothing is filed under
PyAutoScientist
project
pyautoscientist vs autoscientist
split (not in the prompt)
pyautolabs.github.io
project
dotted name
never resolves — normalise_repo truncates at the first ., giving pyautolabs, which is in no map at all (not in the prompt)
No live Mind prompt uses any bare organ spelling (only the two files that
discuss this defect), so every change here is latent-closing and
behaviour-preserving for every spelling that resolves today.
Plan
Write the canonical-key rule down where the maps live, and settle organs on the prefixed form.
Give the body map the one bit the rule needs per repo — does it ship a package, and under what name — since the package a repo ships is repo identity.
Derive the bare/prefixed/package alias join from that, so repo_aliases shrinks to what genuinely cannot be derived: short forms (aa, af) and historical renames (autoconf, pyautobuild).
Add coverage guards that fail loudly on a future gap: no repo may split across two keys; no alias may point at a key nothing is filed under; the body map's package field and the witness map must agree.
Sweep PyAutoScientist and pyautolabs.github.io in the same pass.
Detailed implementation plan
Work Classification
Infrastructure (organism repos) — no library or workspace code is touched.
Affected Repositories
PyAutoBrain (primary) — the alias table, the derivation, the guards
PyAutoMind — repos.yaml gains the package: identity key
Branch Survey
Repository
Current Branch
Dirty?
./PyAutoBrain
claude/organ-repo-spelling-splits-hbbms0
clean
./PyAutoMind
claude/organ-repo-spelling-splits-hbbms0
clean
Branch:claude/organ-repo-spelling-splits-hbbms0 (session-designated; this
is a web-github session with no task worktrees, so the usual feature/<task-name> name is overridden). worktree_check_conflict organ-repo-spelling-splits PyAutoBrain PyAutoMind returns 0 — no claim conflict.
Worktree root: n/a (web-github — the session's clones are the checkout).
Implementation Steps
PyAutoMind/repos.yaml — add package: to the seven repos that ship
one: PyAutoFit: autofit, PyAutoArray: autoarray, PyAutoGalaxy: autogalaxy, PyAutoLens: autolens, PyAutoCTI: autocti, PyAutoReduce: autoreduce, PyAutoNerves: autonerves. Document the key in the file header next to public_role / front_door: identity only — the import/PyPI name the repo
ships, absent where it ships none. Every value is cross-checked in step 5
against the test_witness rows fix: witness map missed 5 tested repos and split 2 more across keys #271 verified by reading each repo's tree.
PyAutoBrain/agents/faculties/sizing/_sizing.py — derive the join:
_body_map_specs() alongside the existing _body_map_categories(), so the package: field is readable without a second YAML load.
_derived_aliases() — for every repo in a sizing category, map each
registered spelling (name.lower(), the pyauto-stripped bare form, the
package name, and the dot-truncated head for a dotted repo name) onto its
canonical key.
REPO_ALIASES = _derived_aliases() | policy()["repo_aliases"], with a
conflict check: a hand entry that disagrees with the derivation is drift
and must raise, not silently win. Move the REPO_ALIASES assignment above _target_sets() so normalise_repo is usable during set construction.
Leave LIBRARY_REPOS / WORKSPACE_REPOS / ORGANISM_REPOS registering
every spelling. Membership is always tested post-normalisation, and _intake._repos_in scans the set as free-text tokens — narrowing the sets
to canonical keys alone would stop bare mentions being recognised in
unheadered prose.
PyAutoBrain/config/policy.yaml — trim repo_aliases to the
non-derivable rows (aa/af/ag/al; autoconf/pyautoconf and pyautobuild/autobuild renames) and head the block with the canonical-key
rule plus a pointer saying the bare/prefixed join is derived, not typed here.
The library rows and autohands: pyautohands become redundant and go.
PyAutoBrain/tests/test_policy_seams.py — three guards, every name
derived from the body map (the tenant firewall allows only {PyAutoFit, PyAutoLens, autolens_workspace} as literals in this file):
no split spellings — for every body-map repo in a sizing category,
all registered spellings normalise to one key, and that key is itself a
known target. Fails today for five organs and PyAutoScientist.
package field agrees with the witness map — for every test_witness
row of the form <Repo>/test_<pkg>, repos.yaml[<Repo>].package == pkg,
and vice versa. Makes Mind identity and Brain policy check each other.
Validate: pytest PyAutoBrain/tests (468 baseline + new), python3 PyAutoMind/scripts/repos_sync.py --check (tenant firewall + the 11
identity checks), and re-run the reproduction — @autobrain, @autoheart, @automind, @automemory, @autogut, @autoscientist must each reach the
prefixed key and its witness row, and the six library spellings must be
byte-identical to their pre-change resolution.
Key Files
PyAutoMind/repos.yaml — the body map; gains package: on seven repos
PyAutoBrain/tests/test_policy_seams.py — the coverage guards
PyAutoBrain/agents/conductors/refactor/_refactor.py — behaviour_preservation, the surface where the defect shows
PyAutoBrain/agents/conductors/intake/_intake.py — _repos_in / infer_target, the second surface
Trade-offs
package: in the body map vs a Brain-only declaration. A bare_key_categories: [library] + PyAutoNerves-exception block in policy.yaml would keep this a one-repo change, but the exception list is
hand-maintained again — the exact cause this task exists to remove — and the
body map still could not answer what package a repo ships. The package name
is repo identity, so it belongs in repos.yaml; the two-repo cost is
accepted deliberately.
Sets keep every spelling. Narrowing them to canonical keys would be
tidier but silently breaks _intake._repos_in's free-text scan. Not worth it.
Heart is not evaluable here.pyauto-heart is unreachable from a web-github session, so leg 4 of the ship gate will be recorded as NOT
EVALUATED rather than claimed clean.
Testing approach
Guard-first: each new guard is written against the current main state, watched
to fail for the right reason, and only then made to pass by the derivation. The
library spellings serve as the behaviour-preservation witness — their
resolution must not move.
Original Prompt
Click to expand starting prompt
Organ repo spellings split across two normalised keys
Type: bug
Target: pyautobrain
Repos:
PyAutoBrain
Difficulty: large
Autonomy: supervised
Priority: normal
Status: formalised
Filed: 2026-08-24
Found while shipping the refactor witness-map audit (@PyAutoBrain#269 / PR #271).
The defect
The bare spellings of the organ repos do not normalise to the same key as their
repo spellings, so a policy map keyed on one is invisible to the other.
@PyAutoBrain/agents/faculties/sizing/_sizing.py (_target_sets.names_for)
registers BOTH spellings of every PyAuto* repo as known targets
(name.lower() and name.lower()[2:]), but the repo_aliases table in
@PyAutoBrain/config/policy.yaml only joins them for the libraries:
mention
normalises to
resolves?
@PyAutoBrain
pyautobrain
yes
@autobrain
autobrain
no — a known target with nothing filed under it
Same for the bare Heart, Memory, Mind and Gut spellings. @autohands was joined
in PR #271 because extra_organism_targets declares it explicitly and it
reaches real code today; the rest are latent — no prompt in the Mind history
uses them yet.
Decide before fixing
This is NOT a blind alias sweep. Should organs key on the bare form
(autobrain) or the prefixed form (pyautobrain)? target_signals keys the
prefixed form (pyautobrain, pyautomind, pyautoheart, pyautobuild), and
after #271test_witness keys organs prefixed but libraries bare. Whichever way
it goes has to hold across both maps at once, so answer the question first and
let the edit follow.
The wider question this raises
Three separate repos have now hit this same defect class — PyAutoNerves
(#267), PyAutoCTI and PyAutoReduce (#269). The shared cause is that repo_aliases is HAND-MAINTAINED while the known-target set is DERIVED from the
body map, so the two drift silently and the gap only ever surfaces as a
wrong-but-plausible conductor message ("strengthen tests first" for a
well-tested repo).
Guard 2 added in #271 — a witness-map key must be what its repo normalises to —
closes the witness-map instance only. An alias gap in a map with no coverage
guard is still invisible. Consider deriving repo_aliases from the body map so
the class closes rather than its fourth instance.
Notes on this prompt's header
pyauto-brain intake classify scored this bug at high confidence (kept), but
proposed Target: autocti — it read the prior-instance history above as the
subject — and Difficulty: too-large (score 10), inflated by the repo names and
the design-decision keywords. Corrected to pyautobrain / large on review.
An alternative classification is refactor: the fix is behaviour-preserving for
every spelling that resolves today. bug was kept because the Bug Agent's
investigate-first strategy matches the "decide before fixing" requirement above.
Acceptance: every spelling of every body-map repo that _target_sets registers
as a known target resolves to a key the policy maps are actually filed under, or
is deliberately not registered; a guard makes a future alias gap fail loudly
rather than degrade a conductor's advice.
Overview
The bare and prefixed spellings of several body-map repos normalise to two
different keys, so a policy map filed under one is invisible to the other.
_target_sets.names_forregisters BOTH spellings of everyPyAuto*repo as aknown target (
name.lower()andname.lower()[2:]), butrepo_aliasesinconfig/policy.yamlonly joins them for the libraries. Reproduced live onmain:@autobrainnormalises toautobrain, which is a known target with notest_witnessrow, sopyauto-brain refactorreports[unwitnessed: autobrain]and advises "strengthen tests first" for the best-tested repo in the organism;
pyauto-brain intakeon the same mention filesTarget: autobrain, a folderthat does not exist (the real one is
draft/bug/pyautobrain/).This is the fourth instance of one defect class — PyAutoNerves (#267),
PyAutoCTI and PyAutoReduce (#269) were the first three. The shared cause is
that
repo_aliasesis HAND-MAINTAINED while the known-target set is DERIVEDfrom the body map, so the two drift silently and the gap only ever surfaces as
a wrong-but-plausible conductor message. This task closes the class, not the
instance.
The keying decision (answered before any edit, as the prompt requires)
Organs key on the PREFIXED form (
pyautobrain), extending the rule #269/#271already wrote down: the canonical key is the bare package name where the repo
ships one, the repo name where it does not. Organs ship no package — PyAutoNerves
is the exception and already keys bare (
autonerves). Everything downstream isalready filed prefixed for organs:
test_witness,target_signals,REPO_DISPLAY,target_default_wiki, and the Mind's own target folders(
draft/*/pyautobrain/,pyautomind/,pyautoheart/,pyautomemory/,pyautohands/). Keying bare would rekey five maps plus Mind folders for no gain.Scope found beyond the prompt's list
Reproduction swept every body-map repo, not just the five organs named:
pyauto*vsauto*pyautoscientistvsautoscientistpyautolabs.github.ionormalise_repotruncates at the first., givingpyautolabs, which is in no map at all (not in the prompt)No live Mind prompt uses any bare organ spelling (only the two files that
discuss this defect), so every change here is latent-closing and
behaviour-preserving for every spelling that resolves today.
Plan
repo_aliasesshrinks to what genuinely cannot be derived: short forms (aa,af) and historical renames (autoconf,pyautobuild).pyautolabs.github.ioin the same pass.Detailed implementation plan
Work Classification
Infrastructure (organism repos) — no library or workspace code is touched.
Affected Repositories
PyAutoBrain(primary) — the alias table, the derivation, the guardsPyAutoMind—repos.yamlgains thepackage:identity keyBranch Survey
claude/organ-repo-spelling-splits-hbbms0claude/organ-repo-spelling-splits-hbbms0Branch:
claude/organ-repo-spelling-splits-hbbms0(session-designated; thisis a
web-githubsession with no task worktrees, so the usualfeature/<task-name>name is overridden).worktree_check_conflict organ-repo-spelling-splits PyAutoBrain PyAutoMindreturns 0 — no claim conflict.Worktree root: n/a (
web-github— the session's clones are the checkout).Implementation Steps
PyAutoMind/repos.yaml— addpackage:to the seven repos that shipone:
PyAutoFit: autofit,PyAutoArray: autoarray,PyAutoGalaxy: autogalaxy,PyAutoLens: autolens,PyAutoCTI: autocti,PyAutoReduce: autoreduce,PyAutoNerves: autonerves. Document the key in the file header next topublic_role/front_door: identity only — the import/PyPI name the repoships, absent where it ships none. Every value is cross-checked in step 5
against the
test_witnessrows fix: witness map missed 5 tested repos and split 2 more across keys #271 verified by reading each repo's tree.PyAutoBrain/agents/faculties/sizing/_sizing.py— derive the join:_body_map_specs()alongside the existing_body_map_categories(), so thepackage:field is readable without a second YAML load._canonical_key(name, spec)=spec["package"].lower()when present, elsename.lower(). This is the fix: witness map missed 5 tested repos and split 2 more across keys #271 rule, now executable rather than prose._derived_aliases()— for every repo in a sizing category, map eachregistered spelling (
name.lower(), thepyauto-stripped bare form, thepackage name, and the dot-truncated head for a dotted repo name) onto its
canonical key.
REPO_ALIASES = _derived_aliases() | policy()["repo_aliases"], with aconflict check: a hand entry that disagrees with the derivation is drift
and must raise, not silently win. Move the
REPO_ALIASESassignment above_target_sets()sonormalise_repois usable during set construction.LIBRARY_REPOS/WORKSPACE_REPOS/ORGANISM_REPOSregisteringevery spelling. Membership is always tested post-normalisation, and
_intake._repos_inscans the set as free-text tokens — narrowing the setsto canonical keys alone would stop bare mentions being recognised in
unheadered prose.
PyAutoBrain/config/policy.yaml— trimrepo_aliasesto thenon-derivable rows (
aa/af/ag/al;autoconf/pyautoconfandpyautobuild/autobuildrenames) and head the block with the canonical-keyrule plus a pointer saying the bare/prefixed join is derived, not typed here.
The library rows and
autohands: pyautohandsbecome redundant and go.PyAutoBrain/tests/test_policy_seams.py— three guards, every namederived from the body map (the tenant firewall allows only
{PyAutoFit, PyAutoLens, autolens_workspace}as literals in this file):all registered spellings normalise to one key, and that key is itself a
known target. Fails today for five organs and PyAutoScientist.
table is the canonical key of some body-map repo. This is the
pyautoconf -> autoconfdefect (fix: retire PyAutoConf rename leftovers in Brain functional surfaces #267) killed at source.test_witnessrow of the form
<Repo>/test_<pkg>,repos.yaml[<Repo>].package == pkg,and vice versa. Makes Mind identity and Brain policy check each other.
Mutation-test the guards (the fix: witness map missed 5 tested repos and split 2 more across keys #271 practice): drop one derived organ
alias, mis-key one
package:value, and restore the pre-fixpolicy.yaml— each must fail a named guard. Record which guard caught what.
Validate:
pytest PyAutoBrain/tests(468 baseline + new),python3 PyAutoMind/scripts/repos_sync.py --check(tenant firewall + the 11identity checks), and re-run the reproduction —
@autobrain,@autoheart,@automind,@automemory,@autogut,@autoscientistmust each reach theprefixed key and its witness row, and the six library spellings must be
byte-identical to their pre-change resolution.
Key Files
PyAutoMind/repos.yaml— the body map; gainspackage:on seven reposPyAutoBrain/agents/faculties/sizing/_sizing.py—_target_sets,normalise_repo,REPO_ALIASESPyAutoBrain/config/policy.yaml—repo_aliases,test_witness,sizing_categoriesPyAutoBrain/tests/test_policy_seams.py— the coverage guardsPyAutoBrain/agents/conductors/refactor/_refactor.py—behaviour_preservation, the surface where the defect showsPyAutoBrain/agents/conductors/intake/_intake.py—_repos_in/infer_target, the second surfaceTrade-offs
package:in the body map vs a Brain-only declaration. Abare_key_categories: [library]+ PyAutoNerves-exception block inpolicy.yamlwould keep this a one-repo change, but the exception list ishand-maintained again — the exact cause this task exists to remove — and the
body map still could not answer what package a repo ships. The package name
is repo identity, so it belongs in
repos.yaml; the two-repo cost isaccepted deliberately.
tidier but silently breaks
_intake._repos_in's free-text scan. Not worth it.pyauto-heartis unreachable from aweb-githubsession, so leg 4 of the ship gate will be recorded as NOTEVALUATED rather than claimed clean.
Testing approach
Guard-first: each new guard is written against the current
mainstate, watchedto fail for the right reason, and only then made to pass by the derivation. The
library spellings serve as the behaviour-preservation witness — their
resolution must not move.
Original Prompt
Click to expand starting prompt
Organ repo spellings split across two normalised keys
Type: bug
Target: pyautobrain
Repos:
Difficulty: large
Autonomy: supervised
Priority: normal
Status: formalised
Filed: 2026-08-24
Found while shipping the refactor witness-map audit (@PyAutoBrain#269 / PR #271).
The defect
The bare spellings of the organ repos do not normalise to the same key as their
repo spellings, so a policy map keyed on one is invisible to the other.
@PyAutoBrain/agents/faculties/sizing/_sizing.py (
_target_sets.names_for)registers BOTH spellings of every
PyAuto*repo as known targets(
name.lower()andname.lower()[2:]), but therepo_aliasestable in@PyAutoBrain/config/policy.yaml only joins them for the libraries:
@PyAutoBrainpyautobrain@autobrainautobrainSame for the bare Heart, Memory, Mind and Gut spellings.
@autohandswas joinedin PR #271 because
extra_organism_targetsdeclares it explicitly and itreaches real code today; the rest are latent — no prompt in the Mind history
uses them yet.
Decide before fixing
This is NOT a blind alias sweep. Should organs key on the bare form
(
autobrain) or the prefixed form (pyautobrain)?target_signalskeys theprefixed form (
pyautobrain,pyautomind,pyautoheart,pyautobuild), andafter #271
test_witnesskeys organs prefixed but libraries bare. Whichever wayit goes has to hold across both maps at once, so answer the question first and
let the edit follow.
The wider question this raises
Three separate repos have now hit this same defect class — PyAutoNerves
(#267), PyAutoCTI and PyAutoReduce (#269). The shared cause is that
repo_aliasesis HAND-MAINTAINED while the known-target set is DERIVED from thebody map, so the two drift silently and the gap only ever surfaces as a
wrong-but-plausible conductor message ("strengthen tests first" for a
well-tested repo).
Guard 2 added in #271 — a witness-map key must be what its repo normalises to —
closes the witness-map instance only. An alias gap in a map with no coverage
guard is still invisible. Consider deriving
repo_aliasesfrom the body map sothe class closes rather than its fourth instance.
Notes on this prompt's header
pyauto-brain intake classifyscored thisbugat high confidence (kept), butproposed
Target: autocti— it read the prior-instance history above as thesubject — and
Difficulty: too-large(score 10), inflated by the repo names andthe design-decision keywords. Corrected to
pyautobrain/largeon review.An alternative classification is
refactor: the fix is behaviour-preserving forevery spelling that resolves today.
bugwas kept because the Bug Agent'sinvestigate-first strategy matches the "decide before fixing" requirement above.
Acceptance: every spelling of every body-map repo that
_target_setsregistersas a known target resolves to a key the policy maps are actually filed under, or
is deliberately not registered; a guard makes a future alias gap fail loudly
rather than degrade a conductor's advice.