Skip to content

fix: derive every repo's spelling join from the body map - #288

Merged
Jammy2211 merged 2 commits into
mainfrom
claude/organ-repo-spelling-splits-hbbms0
Aug 26, 2026
Merged

fix: derive every repo's spelling join from the body map#288
Jammy2211 merged 2 commits into
mainfrom
claude/organ-repo-spelling-splits-hbbms0

Conversation

@Jammy2211

Copy link
Copy Markdown
Contributor

Closes #287. Mind half: PyAutoLabs/PyAutoMind#333 (merge that first; this does not block on it — see the fallback below).

The defect, reproduced on main

The bare and prefixed spellings of seven repos normalised to two different keys, so a policy map filed under one was invisible to the other. _target_sets registered BOTH spellings of every PyAuto* repo as a known target while repo_aliases only joined them for the libraries:

mention before after
@PyAutoBrain pyautobrainPyAutoBrain/tests unchanged
@autobrain autobrainno witness row pyautobrainPyAutoBrain/tests

So pyauto-brain refactor reported [unwitnessed: autobrain] and advised "strengthen tests first" for the best-tested repo in the organism, and pyauto-brain intake on the same mention filed Target: autobrain — a folder that does not exist. Five organs, one project repo and the Hands were split this way. Nothing failed; the advice was just quietly wrong.

The decision, taken before the edit

The prompt required answering the keying question first rather than sweeping aliases blind. Organs key on the PREFIXED form. That is not a new rule — it is #269's rule made executable: the canonical key is the package the repo SHIPS where it ships one, and the repo name where it does not. Organs ship no package; Nerves is the one that does and keys bare (autonerves) already. Everything downstream was filed prefixed for organs — test_witness, target_signals, REPO_DISPLAY, target_default_wiki, and the Mind's own target folders — so keying bare would have rekeyed five maps for no gain.

The class, not the fourth instance

repo_aliases was hand-maintained while the known-target set was derived from the body map, so the two drifted silently. The join is now derived (_derived_aliases), keyed off the body map's new package: field, and a hand row that contradicts the derivation raises instead of quietly winning. What stays hand-written is only what a body map cannot know: short forms (aa, af) and pre-rename spellings.

Two things found that were not in the prompt

  • PyAutoScientist split the same way — joined.
  • pyautolabs.github.io is now deliberately NOT registered. normalise_repo truncates at the first .//, so no mention could ever reach it. The tempting fix — alias the truncated head — is worse than the gap: that head is the org's own name, so @PyAutoLabs/PyAutoFit would have started resolving to the static site instead of PyAutoFit. The acceptance criterion's other branch ("or is deliberately not registered") covers it, and the exclusion is derived from the names, not a hand-kept list. A guard pins both halves.

REPO_DISPLAY also derives from the body map now — it had the beginnings of the same drift, with reachable keys carrying no row, so a header came out as Target: pyautohands.

Guards

Five, each mutation-tested rather than assumed:

Guard Mutation that proves it
no repo splits across two keys removing the derived join names all seven affected repos
no alias points at a key nothing is filed under
body map package: agrees with the witness map mis-keying one package: value raises at import
unreachable repos excluded and their truncated head resolves to nothing forcing the dotted repo back into the set
canonical keys survive a body map with no package: deleting the fallback rows

That last one matters for merge order: CI checks the sibling Mind out at main, pinned, so a Brain half that required the Mind half would sit red until Mind merged. canonical_key falls back to the hand table's library rows when no package: is declared, giving identical keys either way. Those rows become dead weight once PyAutoMind#333 lands and can be deleted then.

Validation


Generated by Claude Code

claude added 2 commits August 26, 2026 01:12
The bare and prefixed spellings of seven repos normalised to two different
keys, so a policy map filed under one was invisible to the other.
`_target_sets` registered BOTH spellings of every `PyAuto*` repo as a known
target while `repo_aliases` only joined them for the libraries. Reproduced on
main: `@autobrain` reached a live known target with no witness row, so the
refactor conductor advised "strengthen tests first" for the best-tested repo in
the organism, and intake filed `Target: autobrain` — a folder that does not
exist. Five organs, one project repo and the Hands were split this way.

THE DECISION, taken before the edit as the prompt required: organs key on the
PREFIXED form. That is not a new rule, it is #269's rule made executable — the
canonical key is the package the repo SHIPS where it ships one, the repo name
where it does not. Organs ship no package; Nerves is the one that does and keys
bare already. Everything downstream was filed prefixed for organs, including the
Mind's own target folders, so the alternative would have rekeyed five maps for
no gain.

THE CLASS, not the fourth instance. `repo_aliases` was hand-maintained while the
known-target set was derived from the body map, so the two drifted silently.
The join is now DERIVED (`_derived_aliases`), keyed off the body map's new
`package:` field, and a hand row that contradicts the derivation raises instead
of quietly winning. What remains hand-written is only what a body map cannot
know: short forms and pre-rename spellings.

Also here:

- A repo whose NAME carries a `.` or `/` is now deliberately NOT registered.
  `normalise_repo` truncates at the first separator, so no mention could ever
  reach it; the tempting alias-the-head fix is worse than the gap, because where
  that head is the org's own name every org-qualified mention would resolve to
  that one repo. Derived from the names, not a hand-kept exclusion list.
- `REPO_DISPLAY` derives from the body map too — it had the beginnings of the
  same drift, with reachable keys carrying no row, so a header came out as
  `Target: pyautohands`.

Five guards, each mutation-tested:

- no repo splits across two keys (removing the derived join names all seven)
- no alias points at a key nothing is filed under
- the body map's `package:` agrees with the witness map
- unreachable repos are excluded AND their truncated head resolves to nothing
- canonical keys survive a body map with no `package:` — the fallback that lets
  this half stand alone against a Mind checkout pinned to main

Verified: 515 tests pass (510 before). `repos_sync --check` all 13 legs OK,
tenant firewall included — it rejected two drafts of this prose for naming
instance repos, which is why the comments read generically. An A/B of every
spelling in the alias table and target sets shows exactly six resolutions
changed, all of them the intended joins; libraries, short forms, renames,
workspaces and org-qualified paths are byte-identical.

Heart NOT EVALUATED — unreachable from a web-github session.

Depends on PyAutoMind e160d40b (the `package:` field). The fallback above means
this does not block on it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nj7cTnL8Ke5WoNsdGVhCKn
CI failed on this PR: `test_body_map_package_agrees_with_the_witness_map`
required `repos.yaml` to DECLARE `package:` for every witness row that names
one, and tests.yml pins the sibling Mind checkout to `main`, where the field
does not exist yet. The rest of the fix already tolerated that — `canonical_key`
falls back to the hand table, with a test pinning it — but this guard did not,
so the half that was designed to stand alone could not.

Absence of the field is an older body map, not a contradiction: a map declaring
NO package anywhere has nothing to corroborate, and the guard stands down. The
moment it declares even one, every witness row that names a package must have
one — so a PARTIALLY declared map still fails, which is what a new library added
without its `package:` would look like. That is a stronger guard than the one it
replaces, not a weakened one.

Verified against CI's exact condition — this branch's Brain against a PyAutoMind
checkout at origin/main, zero `package:` rows: 515 pass. Against the branch's
Mind, with all seven declared: 515 pass. Mutation: declaring one package and not
the rest fails the guard naming the other six.

Also fixes the DeprecationWarning this PR introduced (`maxsplit` passed
positionally in `unreachable_repos`). The identical warning from
`normalise_repo` is pre-existing and left alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nj7cTnL8Ke5WoNsdGVhCKn
@Jammy2211
Jammy2211 merged commit 52ab501 into main Aug 26, 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.

fix: join every body-map repo's spellings onto one canonical key

2 participants