Repository navigation
bump-leg.py and family.py: the tag check compares the commits tags point to, so a lightweight or another annotated tag at the same commit reaches it (#982) - #988
Conversation
…o, with rows for both missed cases, and the test comment that gave a reason that does not hold Lane: openreposhape-1 (openRepoShape-1) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… with rows for both missed cases Lane: openreposhape-1 (openRepoShape-1) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…int to, so a lightweight or another annotated tag at the same commit reaches it (#982) `_remote_tag_reaches` (bump-leg.py) and `_origin_tag_reaches` (family.py) compared the tag objects' ids, so a lightweight `v1` of the leg beside an annotated `v1` of the remote at one commit, two annotated `v1` made apart, and the reverse of the first, got the plain words, "a pin the rest of the world cannot fetch" included, where a tag of the remote does reach the commit. The leg's tags are now read as `%(objectname) %(*objectname)` and the remote is listed with `ls-remote --tags` without `--refs`, so the peeled `<tag>^{}` lines are compared too. The test comment that said a failed fetch must not be answered from the branch it brought gave a reason that does not hold (git's fetch is not atomic); it now says it removes the tracking ref the push wrote. This commit carries no file change: the change is in the two WIP commits before it, pushed as the usage window closed, and the branch cannot be rewritten. Lane: openreposhape-1 (openRepoShape-1) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Reviewer's GuideUpdates bump-leg and family tag reachability checks to compare tag target commits, allowing equivalent lightweight and annotated tags—or independently created annotated tags—to establish reachability at the same commit, with regression coverage and clarified test documentation. Sequence diagram for tag target commit reachabilitysequenceDiagram
participant Checker as Reachability checker
participant LocalRepo as Local repository
participant Remote as Git remote
Checker->>LocalRepo: git for-each-ref --contains commit --format=%(objectname) %(*objectname)
LocalRepo-->>Checker: Tag object IDs and peeled target commit IDs
alt local tag target IDs exist
Checker->>Remote: git ls-remote --tags remote
Remote-->>Checker: Tag IDs and peeled target commit IDs
Checker->>Checker: Compare IDs from both listings
alt matching target commit ID
Checker-->>Checker: Tag reaches commit
else no matching ID or listing fails
Checker-->>Checker: Tag does not establish reachability
end
else no local tag contains commit
Checker-->>Checker: Do not query remote
end
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
(lane openRepoShape-1, 2026-10-19T16:06:05Z) Independent review of #988 (#982) by r988, at Verdict: NOT READY at State: the worktree is clean at FindingsMUST-1: the tag-of-a-tag limit is false on git 2.44 and later, and wrong on 2.43 tooWhere:
Evidence that git changed:
Evidence on git 2.43 (real repositories;
Fix (preferred; measured). In both functions, replace the tags = run(["git", "for-each-ref", "--contains", commit,
"--format=%(objectname)", "refs/tags/"],
cwd=submodule).lower().split()
if not tags:
return False
held = set(tags) | set(run(["git", "rev-parse",
*[f"{tag}^{{}}" for tag in tags]],
cwd=submodule).lower().split())
Docstring wording for that fix. The full text for both files is in PR body Notes: replace the limit bullet with "Tags of tags: each tag of the leg is peeled with MUST-2: "NOT THE TAG OBJECTS" is false, because tag objects are still comparedWhere:
Evidence:
Fix:
SHOULD-1: the controls don't control the new
|
| Case | Remote tag reaches? | base | head | rev-parse fix |
|---|---|---|---|---|
| A: leg lightweight, remote annotated | yes | plain | tag | tag |
| B: two annotated made apart | yes | plain | tag | tag |
| C: leg annotated, remote lightweight | yes | plain | tag | tag |
| D1, D2, D3: tag at another commit (pin, or a sibling the remote holds) | no | plain | plain | plain |
| E1: no tags anywhere | no | plain | plain | plain |
| E2: leg has none, remote annotated (the fetch's auto-follow brings it) | yes | tag | tag | tag |
| F1, F2: shared tag of a tag | yes | tag | tag | tag |
| F3: tags of a tag made apart | yes | plain | plain | tag |
| F4: tags of a tag made apart, inner refs kept | yes | plain | tag | tag |
| F5, F6: leg tag of a tag vs remote lightweight or annotated | yes | plain | plain | tag |
| F7: leg lightweight vs remote tag of a tag | yes | plain | tag | tag |
G1: remote's ^{} line missing (hand-edited packed-refs) |
yes | plain | plain | plain |
| G2: the same, with the tag shared | yes | tag | tag | tag |
H: another tag's ^{} line, at a sibling |
no | plain | plain | plain |
| I: remote's tag at a descendant the leg lacks | yes | plain | plain | plain |
| J: both tag a descendant, made apart | yes | plain | tag | tag |
There are no false positives. A tag object's id can't equal a commit's (barring a hash collision), and every matched id is an object the remote holds.
Mutants
Rows are the new reachability rows that killed each mutant.
| Mutant | bump-leg.py (25 rows) |
family.py (15 rows) |
|---|---|---|
M1: keep --refs |
killed (4) | killed (2) |
M2: drop %(*objectname) |
killed (4) | killed (2) |
| M3: compare only the leg's tag objects | killed (6) | killed (3) |
M4: accept any ^{} line |
survives | survives |
M5: compare only ^{} lines |
killed (2) | killed (1) |
| M6: commits only, no tag-object ids | survives | survives |
M7: that half reverted to cf66102f |
killed (6) | killed (3) |
Test counts
- Head, both reachability files: 40 passed.
- Head, the eight tag-making and hygiene files: 191 + 36 = 227 passed, 0 failed, 0 skipped.
cf66102f's scripts under head's tests: 9 failed, 31 passed.- The rev-parse fix: 40 passed, plus 33 probe rows.
- CI at head: tests, tests-git-bash, package and SonarCloud all succeeded.
Merges
All are clean with git merge-tree --write-tree 203e9410 <x>, and both reachability files pass (40) on each merged tree I ran:
| Target | Merge | 40 rows on merged tree |
|---|---|---|
c7a3ff16 (the brief's main) |
clean | not run |
2a78ae1a (the coordinator's main) |
clean | not run |
dd2cf2e8 (main now; contains 2a78ae1a) |
clean | 40 passed |
#946 5d5d06bb |
clean | 40 passed |
#955 0606cf92 |
clean | 40 passed |
#957 d673e090 |
clean | 40 passed |
#960 dc5277e6 |
clean | 40 passed |
fix/927-bump-family-root 7b42c652 |
clean | 40 passed |
Could not verify
- git 2.44 and later, locally. Only
/usr/bin/git2.43.0 is installed. The claim rests on git's own source, test and docs, and on the CI'sgit version 2.55.0. - Which eleven files the body's count came from.
- Two unmeasured edges:
- a replace ref or graft in the leg, which
--containshonours; the base already had this exposure for shared tag objects; - the fix's command length on Windows, past roughly 700 tags containing the commit.
- a replace ref or graft in the leg, which
Process notes
- Wrong PR-body path: the brief's
pr988-body.mddoesn't exist.pr982-body.mdmatches the live body, apart from Sourcery's appended summary. - A broken shell command:
- What happened: a stray apostrophe made zsh run fragments of my draft prose as commands, in the shared checkout's directory.
- What ran: every fragment was "command not found" or aborted on a glob error, except one bare
git rev-parse, which prints nothing. - Checked afterwards: no file was created, and
git --no-optional-locks status --shortthere shows only?? handoffs.
- Fetches: my fetches of main and the five branches updated their
refs/remotes/origin/*refs, through the brief's fetch command.
Everything I wrote is in /workspace/projects/openRepoShape-worktrees/_lane1-scratch/r988/ (tools, logs, probes, merged trees).
Lane: openreposhape-1 (openRepoShape-1)
…parse <id>^{}`, so a tag of a tag reaches its commit on a git before 2.44 too, and the tag objects are said to be compared as well as the commits (#982)
The fix round from lane 1's review of #988 at 203e941 (#988
issuecomment-6271598576), which found it NOT READY:
- MUST-1: git before 2.44 reads `%(*objectname)` one level, so on git
2.43 a leg's tag of a tag was held as its inner tag and missed a tag
of the remote at the same commit (the review's F3, F5 and F6); the
review traces the full peel to git's 188782ecb1d3, in 2.44, and the
CI runs 2.55. `_remote_tag_reaches` and `_origin_tag_reaches` now
read `%(objectname)` and add the commit `git rev-parse <id>^{}` peels
each id to, the review's measured fix, and both docstrings say so in
the review's proposed words.
- MUST-2: the heading is "NOT THE TAG OBJECTS ALONE", in both scripts
and both tests: the tag objects are still compared.
- SHOULD-1: both same-name controls run over a lightweight and an
annotated tag of the remote, so a check that took any `^{}` line
(mutant M4) fails the annotated row.
- NITs: rows for a tag of a tag the two share, and for the leg's tag of
a tag beside a tag of a tag made apart, a lightweight and an
annotated tag of the remote, in both files; the WHY IT IS ASKED
sentence of each docstring says what `ls-remote` is asked.
Lane: openreposhape-1 (openRepoShape-1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
(lane openRepoShape-1, 2026-10-19T21:52:43Z) Re-check of #988 (#982) by r988, at Verdict: READY at My worktree is clean, detached at My findings, checked at
|
| Case | Remote tag reaches? | At a1a95ff0 |
|---|---|---|
| A, B, C (the issue's three) | yes | tag |
| D1, D2, D3, E1, H | no | plain |
| E2, F1, F2 | yes | tag |
| F3–F7, J | yes | tag (F3, F5, F6 were plain before this round) |
G1: remote lists no ^{} line, leg lacks the remote's tag |
yes | plain, as at the base |
| G2: the same, tag shared | yes | tag |
| I: remote tag at a descendant the leg lacks | yes | plain, as at the base; outside the docstring's definition |
No case gives a false "reaches".
Ruling on M6: its survival is acceptable, and no row is needed
- I measured M6 against the whole table. It differs from
a1a95ff0in one case only: G2, a remote that lists an annotated tag without its^{}line. - Making that state took a hand-edited
packed-refs. A normal git remote lists that line:git ls-remoteasks for it, and upload-pack sends it for every annotated tag. That last point is my reading of git, not a measurement. - I can't check whether git 2.55 still leaves the line out in that state, so a row built on it could fail its own premise on CI.
- Keeping
set(tags) |is still right: under M6, G2 gets the plain words wherecf66102fgave the tag words.
Mutants (both scripts mutated at once, 54 rows)
| Mutant | Result | Killed by |
|---|---|---|
M1: keep --refs |
killed, 12 failed | rows where the remote's tag is annotated or a tag of a tag |
| M2: no peel | killed, 15 failed | |
| M3: only annotated tags | killed, 3 failed | the leg-lightweight rows |
M4: accept any ^{} line |
killed, 2 failed | both [annotated] controls |
M5: only ^{} lines |
killed, 6 failed | the remote-lightweight rows |
| M6: commits only | survives, 54 passed | dies only at G2 (above) |
M9: --points-at for --contains |
survives, 54 passed | — |
cf66102f's scripts |
18 failed, 36 passed | all plain words |
203e9410's scripts |
9 failed | exactly F3, F5, F6 |
M9 is a gap #898 left, not this PR's: no row tags a descendant of the commit, though case J shows the behaviour is right. It should be a follow-up, not a blocker.
Counts (every run with EMAIL exported and the brief's isolation)
- Both reachability files: 54 passed.
- The writer's 17 files: 520 passed and 1 skipped (194 + 1 skip, then 254, then 72). The skip is
tests/test_bump_leg.py:697, which needs a case-insensitive disk.
Merges
git merge-tree --write-tree a1a95ff0is clean against:- main
3864b18c(treead660b96); fix/927-bump-family-rootat1baafc95(fa6b5b78);- that branch's newer head
3df537a4(de907960).
- main
- The 54 rows pass on both merged trees I ran: with main, and with
3df537a4. - family.py:
bump's fetch no longer moves the mount's own branches, works where the mount maps tags intoorigin/instead of telling the person to fix the network, reads its refspecs withgit config --list -z, and asksgit remote get-url originfirst, so a mount with nooriginis not fetched from a path of that name (#905) #946, family.py: a holder, a member or its object store this user cannot read is refused by name, exit 2, on every Python, neverfamily-root-missing,member-uninitializedor "not on disk", and no rollback removes past it (#430) #955, family.py add: a commit that records the member's gitlink anywhere butmembers/<Project>is taken back and refused, naming the path git chose, andmembers: null,Null,NULLor~takes the first member asmembers:does (#920) #957 and family.py init: where the holder's own YAML reader refuses the manifest it would write,family-manifest-invalidnames the value on the line it refuses,--org is '@x', and gives the reader's remedy, not the validator's (#929) #960 have all landed on main, and their branches are deleted, so the main merge covers them.
PR body: exact replacements
I confirm the writer's ten items, with corrections to 3, 4, 6, 7 and 10.
- "now compare the commits tags point to, not the tag objects." becomes "now compare the commits tags point to as well as the tag objects."
- "The leg's own tags are read with
--format=%(objectname) %(*objectname)." becomes "The leg's own tags are read with--format=%(objectname), and each is peeled withgit rev-parse <id>^{}, through a tag of a tag too." - "in three cases that got the plain words before" becomes "in six cases that got the plain words before". Keep the three bullets and add:
- "a tag of a tag in the leg, beside a tag of a tag made apart on the remote;"
- "a tag of a tag in the leg, with a lightweight
v1on the remote;" - "a tag of a tag in the leg, with an annotated
v1on the remote."
- Replace the New rows bullet with:
- "New rows:
test_a_tag_at_the_commit_reaches_it_whatever_its_object_isruns six cases, each viaoriginand via--local-remote-dirintest_bump_leg_reachability_words.pyand once intest_family_bump_reachability_words.py." - "
test_a_tag_of_a_tag_the_two_share_reaches_itis new in both files." - "Both
test_a_tag_of_the_same_name_at_another_commit_keeps_the_plain_wordscontrols now run with a lightweight and an annotated tag of the remote."
- "New rows:
- "Against
cf66102f's code: 6 of the bump-leg rows and 3 of the family rows fail, and every older row passes." becomes "Againstcf66102f's code, 18 of the 54 rows fail (12 bump-leg, 6 family), all with the plain words, and the other 36 pass." - The eleven-files line becomes "Seventeen files (the ten
tests/test_bump_leg*.py, the fivetests/test_family_bump*.py,tests/test_repo_hygiene.pyandtests/test_agents_md_codes.py): 520 passed and 1 skipped (tests/test_bump_leg.py:697, which needs a case-insensitive disk)." - In the environment sentence, add "and an exported
EMAIL" afterGIT_SSH_COMMAND=false. Leave the address itself out of the body. - The limit bullet becomes "Tags of tags: each tag of the leg is peeled with
git rev-parse <id>^{}, since git before 2.44 reads%(*objectname)one level; the CI's git, 2.55, peels it fully." - Delete the bullet "The head's last commit is empty: …". The head is now a real commit.
- The merges bullet becomes "Merges: clean with main at
3864b18c, which carries family.py:bump's fetch no longer moves the mount's own branches, works where the mount maps tags intoorigin/instead of telling the person to fix the network, reads its refspecs withgit config --list -z, and asksgit remote get-url originfirst, so a mount with nooriginis not fetched from a path of that name (#905) #946, family.py: a holder, a member or its object store this user cannot read is refused by name, exit 2, on every Python, neverfamily-root-missing,member-uninitializedor "not on disk", and no rollback removes past it (#430) #955, family.py add: a commit that records the member's gitlink anywhere butmembers/<Project>is taken back and refused, naming the path git chose, andmembers: null,Null,NULLor~takes the first member asmembers:does (#920) #957 and family.py init: where the holder's own YAML reader refuses the manifest it would write,family-manifest-invalidnames the value on the line it refuses,--org is '@x', and gives the reader's remedy, not the validator's (#929) #960, and with lane 1'sfix/927-bump-family-rootat3df537a4. Both reachability files pass on each merged tree."
The title, the "Closes #982" line, the test-comment bullet and the review bullet are still true.
Could not verify
- git 2.44 and later, locally. Only 2.43 is installed, so this rests on the earlier upstream evidence.
- That upload-pack always sends the
^{}line. This is my reading of git, as noted under the M6 ruling, not a measurement.
Scratch is at /workspace/projects/openRepoShape-worktrees/_lane1-scratch/r988/: the new mutator is tools/mutate2.py, the logs are logs/f-*.log and logs/merged-a1-*.log, and the probe results are probes/fn2.json (head) and probes/fn3.json (under M6).
Lane: openreposhape-1 (openRepoShape-1)
|
|
Sorry @brettheap, you've used your own review budget of 250,000 diff characters for the last 7 days. You can request another review in 1 day and 20 hours by commenting |
…nt of the commit `--to` names, so a tag above it reads as one that reaches it and a tag below it keeps the plain words, and `--points-at` for `--contains` no longer survives (#1019) (#1107) No test held that a tag at a DESCENDANT of the refused commit counts as a tag that reaches it, so `--points-at` in place of `--contains` survived in `bump-leg.py` and `family.py` (mutant M9 of #988's review, filed as #1019). This adds the rows the issue asks for to the two reachability test files, and no production code changes. Opened as a draft with no milestone: Brett Heap's ruling of 2026-10-21T10:32:04Z ("leave the follow-ups out of v1.2.0") held it until the v1.2.0 tag, and it is now on the v1.2.1 milestone. Measured on main `2a119f28` before any change, and checked again on `16f9a0e81` and `7e00834c` (the tag questions did not change, only their line numbers): - `scripts/bump-leg.py` `_remote_tag_reaches` and `scripts/family.py` `_origin_tag_reaches` list the tags with `git for-each-ref --contains <commit> --format=%(objectname) refs/tags/`. No other copy of either exists (the `--contains` in `on_a_remote_branch` and `_on_a_remote_branch` asks about branches and is not this question). - The mutant (`--contains` -> `--points-at` on that one line in each script) SURVIVES every row on main: `test_bump_leg_reachability_words.py` 34 passed, `test_family_bump_reachability_words.py` 20 passed, 54 rows, as the issue says. - The production code is right: the new rows pass on unmutated main. So they do not "fail on main"; they fail on the mutant, which is the issue's own acceptance ("With `--points-at`, that row must fail"). No defect was found. `tests/test_bump_leg_reachability_words.py`: - `made_in_the_leg(project, name, on="HEAD")` takes an optional `on`, the commit the new commit is made on top of. Every existing call is unchanged. - `test_a_tag_at_a_descendant_of_the_commit_reaches_it`: a commit `made` and a child `above` on top of it, on no branch of the leg's remote. The leg and the remote each tag `above` (`v1-w1019`), made apart, in three kinds: both annotated (the reviewer's case J), leg lightweight and remote annotated, and the reverse. Both runs (dry run and real) refuse `made` `bump-leg-commit-local-only` in the TAG words, through `origin` and through `--local-remote-dir` (3 kinds x 2 routes = 6 rows), with nothing moved and the leg's own tag as it was. The premises say the tag names the child, that no tag is AT `made` (`for-each-ref --points-at`), and, through #1087's `only_a_tag_reaches`, that a tag of the remote reaches it, no branch does and no remote-tracking ref of the leg does. - `test_a_tag_at_an_ancestor_of_the_commit_alone_keeps_the_plain_words`: the control (x 2 routes). The commit named is the child, and the leg and the remote tag only its parent. The plain words stay, "a pin the rest of the world cannot fetch" included. `tests/test_family_bump_reachability_words.py`: - `made_on(holder, env, parent, name)`: a commit never pushed, made in the mount on top of `parent`, through `commit_in_mount` (which checks `parent` out first), so the holder stays clean. - `test_a_tag_at_a_descendant_of_the_commit_reaches_it`: the same three kinds (3 rows), both `bump --dry-run` and the real `bump` refuse `member-to-local-only` in the tag words, with nothing moved and the mount's own tag as it was. - `test_a_tag_at_an_ancestor_of_the_commit_alone_keeps_the_plain_words`: the control (1 row). No assert joins conditions with `and` or `or`; each premise is its own assert. No README, docs, AGENTS.md or handbook text names these tests or their row counts (grep), so none changes. | Mutant | Rows before (main's) | With these rows | | --- | --- | --- | | `--points-at` in `bump-leg.py` | survives: 34 of 34 pass | killed: 6 failed, 36 passed (all six descendant rows; the two controls pass, as they should) | | `--points-at` in `family.py` | survives: 20 of 20 pass | killed: 3 failed, 21 passed (all three descendant rows) | | `--merged` in `bump-leg.py` (extra: a check read the other way round) | survives: 34 of 34 pass | killed: 8 failed (6 descendant rows and both controls) | | `--merged` in `family.py` (extra) | survives: 20 of 20 pass | killed: 4 failed (3 descendant rows and the control) | The failure is the one the issue names: the plain words ("is reachable from no branch of ...") where the tag words ("and a tag of ... reaches it, but no branch ... does") are expected. Logs: `r-mut-points-at-bump.log`, `r-mut-points-at-family.log`, `r-mut-merged-bump.log`, `r-mut-merged-family.log` (and `mut-main-*.log` for the 34 and 20 on `2a119f28`). On the pushed head `01fcb259`: - git 2.43.0 (`/usr/bin/git`): the two test files, 66 passed (42 + 24; 34 + 20 before). - git 2.43.0: the trio `tests/test_repo_hygiene.py`, `tests/test_agents_md_codes.py`, `tests/test_cli_reference.py` and `tests/test_update_shape_kept_helper.py`, 329 passed. On `1201680f` (the same two files on top of `16f9a0e8`, before `7e00834c`, whose three files no row of mine touches or runs): - git 2.43.0: the trio alone, 170 passed; the two test files that import helpers from mine (`test_bump_leg_fetch_refspecs.py`, `test_family_bump_fetch_refspecs.py`), 102 passed; the two test files, 42 and 24 passed. - git 2.47.1 (`$Q/v115/w764/git247/bin/git` first on PATH, `git --version` printed `git version 2.47.1`): the two test files, 66 passed. No script changed, so no other test runs a changed script. - `git merge-tree --write-tree HEAD origin/main` against a re-fetched `origin/main` (`7e00834c`, which is also the merge base): exit 0, tree `3a852e87fcfda41766ece8c1771e47689c622ad6`, equal to this head's tree. Against `16f9a0e8` before the last rebase: exit 0 too. - Open PRs read with `gh pr list --repo opensoft/openRepoShape --state open --json number,headRefName,isDraft,files`: 8 (#1102, #1101, #1098, #1097, #1091, #1090, #1088, #1075). None touches `tests/test_bump_leg_reachability_words.py` or `tests/test_family_bump_reachability_words.py`, so there is no merge-tree to run against any of them. - **The NIT.** The docstrings of the two descendant rows said "Every row before this one tagged the commit itself, so ... survived all 54 of them". 54 counts the two files together (34 + 20), several earlier rows tag nothing (the no-`origin` and prune rows), and a count goes stale with the next row. - **The fix, docstrings only.** Each now says only what holds: "No row before this one tags a descendant of the commit: the tags in them are at the commit itself or below it, so `--points-at` in place of `--contains`, the mutant M9 of #988's review, survived every row of this file." No row, assert or helper changed. The 54 in "What still held on main" above is the two files together, as it says. - **One commit on top of `01fcb259`, a fast-forward push, no rebase:** head `ee48b5fe9693ebda099d1c0aadaca7bdc16b91c1`, read back with `git ls-remote`. Its tree is `615e571bb62fd1cf481e4152278b0e3628bab059`. - **Runs** (git 2.43.0, through `run9.sh`, `EMAIL=service@opensoft.dev`): `tests/test_bump_leg_reachability_words.py` 42 passed, `tests/test_family_bump_reachability_words.py` 24 passed. They ran on `7186f3cf`, the same tree as the pushed head; only the commit message was shortened after. - **Merge-tree** against a re-fetched `origin/main` (`6da757cb`, merge base `7e00834c`): exit 0, tree `453566df33c886cf7fc2b1c39af02acbbff365dc`. Main moved by nine files, none of mine; its `scripts/bump-leg.py` change (9 lines added) leaves `_remote_tag_reaches` and its `--contains` line alone (now line 1214). Review: rv1104-1107, lane 5's independent opus reviewer, which wrote none of #1107: READY at `ee48b5fe`, the head that lands (issuecomment-6318124100), with no MUST or SHOULD and one optional test NIT that needs no round. CI (Brett Heap's ruling 27): H0 is the head ee48b5f itself, which passed tests, tests-git-bash and SonarCloud; main has touched none of its files since its base 7e00834; and the local gate passed on its predicted squash tree 2f7f587 over main 422a590: the bump_leg_reachability_words, family_bump_reachability_words, repo_hygiene, agents_md_codes, cli_reference sets, 237 passed. Landed on Brett Heap's word of 2026-10-23T13:10:26Z, relayed to every lane by lane 3 (#473 issuecomment-6365697123): "merge v1.2.1 PRs once reviewed and green". Closes #1019 Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Lane: openreposhape-1 (openRepoShape-1)
Closes #982, the follow-up from lane 1's review of #937 (#898), which landed as
d4d11bfe.What
scripts/bump-leg.py_remote_tag_reachesandscripts/family.py_origin_tag_reachesnow compare the commits tags point to as well as the tag objects.--format=%(objectname), and each is peeled withgit rev-parse <id>^{}, through a tag of a tag too.git ls-remote --tagswithout--refs, so the peeled<tag>^{}lines count.v1in the leg, with an annotatedv1at the same commit on the remote;v1tags made apart;v1in the leg, with a lightweight one on the remote;v1on the remote;v1on the remote.tests/test_bump_leg_reachability_words.py).Tests
All runs used
/usr/bin/python3 -m pytestunder a stubgh, a bogusGH_TOKEN, an emptyGH_CONFIG_DIR,GIT_CONFIG_GLOBAL=/dev/null,GIT_SSH_COMMAND=falseand an exportedEMAIL.test_a_tag_at_the_commit_reaches_it_whatever_its_object_isruns six cases, each viaoriginand via--local-remote-dirintest_bump_leg_reachability_words.pyand once intest_family_bump_reachability_words.py.test_a_tag_of_a_tag_the_two_share_reaches_itis new in both files.test_a_tag_of_the_same_name_at_another_commit_keeps_the_plain_wordscontrols now run with a lightweight and an annotated tag of the remote.cf66102f's code: 18 of the 54 rows fail (12 bump-leg, 6 family), all with the plain words, and the other 36 pass.tests/test_bump_leg*.py, the fivetests/test_family_bump*.py,tests/test_repo_hygiene.pyandtests/test_agents_md_codes.py): 520 passed and 1 skipped (tests/test_bump_leg.py:697, which needs a case-insensitive disk).Notes
git rev-parse <id>^{}, since git before 2.44 reads%(*objectname)one level; the CI's git, 2.55, peels it fully.3864b18c, which carries family.py:bump's fetch no longer moves the mount's own branches, works where the mount maps tags intoorigin/instead of telling the person to fix the network, reads its refspecs withgit config --list -z, and asksgit remote get-url originfirst, so a mount with nooriginis not fetched from a path of that name (#905) #946, family.py: a holder, a member or its object store this user cannot read is refused by name, exit 2, on every Python, neverfamily-root-missing,member-uninitializedor "not on disk", and no rollback removes past it (#430) #955, family.py add: a commit that records the member's gitlink anywhere butmembers/<Project>is taken back and refused, naming the path git chose, andmembers: null,Null,NULLor~takes the first member asmembers:does (#920) #957 and family.py init: where the holder's own YAML reader refuses the manifest it would write,family-manifest-invalidnames the value on the line it refuses,--org is '@x', and gives the reader's remedy, not the validator's (#929) #960, and with lane 1'sfix/927-bump-family-rootat3df537a4. Both reachability files pass on each merged tree.🤖 Generated with Claude Code
Summary by Sourcery
Recognize remote tags that reach the same commit regardless of tag representation.
Bug Fixes:
Enhancements:
Tests: