feat(clone): a sync mode, and the shared rename table birth and sync now both use - #316
Merged
Conversation
…onto the born siblings Birth copies the reference once. Nothing re-synced afterwards, so the four copies of skills/start-new-project.md and wiki/project/* grew four distinct hashes and the autofit_assistant copy diverged by ~343 lines. The conductor listed those files as _SHARED_GENERIC but had only a birth mode. `clone sync` closes that loop for the generic set, and ONLY that set: - it takes the REFERENCE's own diff over a commit range, restricted to that reference's `generic` patterns (reusing REFERENCE_PROFILES/match_any, not a second list), rewrites the names in it for each sibling, and applies it with GNU patch; - it is not an overwrite. A hunk the sibling has adapted away is REJECTED and reported by number — on --apply it lands as a .rej for a human. A sibling's domain adaptation outranks the reference's prose, and a conflict is a human decision, never a silent resolution; - per file it reports applied / created / already-applied / rejected / absent / skipped / unsupported, so the report says what a human must look at; - dry run is the default; --apply writes; exit 1 means something was rejected. "Since the sibling's last sync" is read from the sibling's own history via a `Clone-sync: <reference>@<sha>` commit trailer — no state file, and the pointer travels with the commit that consumed the patch. A first sync needs an explicit --since rather than a guessed range. The substitutions add the UPPERCASE rule birth omits, which is why a sibling born from autolens_assistant still names $AUTOLENS_ASSISTANT in its generated project scaffold; synced lines are right even where the old ones are not. tests/test_clone_sync.py: 9 hermetic tests over a temp workspace of three fake assistants, one of which has adapted the prose the reference changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GZceRRca9F5ojAtjpRp3me
Birth and sync each built their own rename list, and birth's was missing two
rules. Both gaps were still visible in a sibling cell: its generated project
scaffold pointed at the REFERENCE's `$..._ASSISTANT` variable, and its profile
template still headed its first section with the reference's domain noun
("Lensing background", in a CTI cell). Neither is reachable by the identity
rules — the uppercase form is not the package, and a domain noun is not a
package at all.
- `name_substitutions()` is now the ONE table, used by `apply_seed` (which
serialises it for PyAutoHands' `clone_seed`) and by `sync_substitutions`. A
file that lands in a sibling reads the same whichever route brought it.
- It carries the UPPERCASE package rule (birth omitted it) and, new,
`DOMAIN_NOUNS`: the science's own noun and its longer phrase, per package.
- `DOMAIN_ALIASES` handles the qualified compounds first, because
"strong-lensing" -> "strong-CTI" is a phrase in no science; the qualifier
belongs to the reference's domain, so the compound resolves to the target's
bare noun. Word-anchored throughout, so `microlensing` survives and
`lensing-fluent` keeps its own tail.
- A target package absent from `DOMAIN_NOUNS` gets NO domain rule and a printed
warning at birth. A science's own noun is never guessed.
Sync only ever touches the lines in the patch, so these rules correct newly
synced lines; they do not retro-fix a line an earlier birth got wrong — one of
the new tests pins exactly that, so nobody expects a silent rewrite.
tests/test_clone_sync.py: 9 -> 16 (domain-noun rename, the compound rule, the
word anchor, the never-guess rule, birth/sync table identity, an end-to-end
sync that lands both closed, and the no-retro-fix pin).
Checks: `pytest tests/ -q` 634 passed (627 before); tenant firewall OK.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZceRRca9F5ojAtjpRp3me
This was referenced Aug 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A fresh agent chat pointed at a science project folder should work out where the
project got to, how to resume, and what its history is — by default. This is the
organ-side half of that: a
syncmode on the clone conductor, so the changelands in the sibling assistants from the reference's own diff rather than as four
hand edits.
clone synctakes the reference assistant's diff over a commit range, restrictsit to that reference's
genericpattern set (reusingREFERENCE_PROFILES/match_any— not a second list), rewrites the names for the target, and appliesit with GNU
patch, reporting per fileapplied/created/already-applied/
rejected (hunks #n)/absent/skipped/unsupported. Dry run bydefault;
--applywrites and leaves.rejfiles; exit 1 when anything wasrejected. "Since the sibling's last sync" is read from the sibling's own history
via a
Clone-sync: <reference>@<sha>commit trailer — no state file.The second commit closes the seam that made birth and sync disagree: birth and
sync each built their own rename list, and birth's was missing two rules.
name_substitutions()is now the one table both use, carrying the UPPERCASEpackage rule birth omitted plus
DOMAIN_NOUNS/DOMAIN_ALIASES(the science'sown noun, word-anchored so
microlensingsurvives andlensing-fluentkeeps itstail). A target package absent from the table gets no domain rule and a
printed warning — a science's own noun is never guessed.
Commits on this branch:
55e9fd4feat(clone): add asyncmode — replay the reference's generic diff onto the born siblingsd2b1af9clone sync: domain + env-var substitution rules (feat: science-project memory — a fresh chat resumes a project by default #315)API Changes
New capability, nothing removed or renamed:
bin/pyauto-brain clone syncis anew CLI mode, and the clone conductor gains a shared
name_substitutions()rename table that both birth (
apply_seed) and sync now read instead of eachbuilding its own. Existing
clonebehaviour is unchanged apart from birthpicking up the two rules it was missing. See full details below.
Test Plan
pytest tests/ -q→ 634 passed (627 before this branch's second commit;tests/test_clone_sync.py9 → 16 tests)PyAutoMindmain,2b764e48)clone sync --since ee306ac --target autofit_assistant --applyreproduced its dry run exactly (1 applied · 2 created · 4 rejected)Full API Changes (for automation & release notes)
Added
bin/pyauto-brain clone sync [--since <rev>] [--target <assistant>] [--apply]— replay the reference assistant's generic-file diff onto a born sibling as a reviewable three-way patch; dry run by default, exit 1 on any rejected hunk.agents/conductors/clone/_clone.py::name_substitutions()— the single source of the birth/sync rename table (package names incl. UPPERCASE env-var form,DOMAIN_NOUNS,DOMAIN_ALIASES).agents/conductors/clone/_clone.py::sync_substitutions()— sync's view of that table.Clone-sync: <reference>@<sha>commit trailer — how a sibling records the point it last synced from.Changed Behaviour
apply_seednow serialisesname_substitutions()for PyAutoHands'clone_seedinstead of building its own list, so a birth picks up the UPPERCASE package rule and the domain-noun rules it previously omitted.Migration
cloneinvocations are unaffected;syncis additive.Closes #315.
Generated by the PyAutoLabs agent workflow.