Skip to content

tests/test_family_bump_fetch_refspecs.py: the two docstrings say #946's first head left out a tag or mirror refspec only where it wrote the branches' own names, so a tag refspec in a folder (S1) is left out only now and the mirror (S2) already was and had no test (#997) - #1007

Merged
brettheap merged 2 commits into
mainfrom
fix/997-refspec-docstrings
Oct 19, 2026

Conversation

@brettheap

@brettheap brettheap commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Closes #997.

Text only: two docstrings in tests/test_family_bump_fetch_refspecs.py (the module docstring and the reachability row's). No code, no assertion and no other file changes.

Why. Both said #946's first head, 4e1aa24a, carried or pinned a tag refspec and a mirror into origin/ ("RV946's S1 and S2"). Only the tag refspec in a folder (+refs/tags/*:refs/remotes/origin/tags/*) was carried there (S1): its destination is not the branches' own, so _origin_fetch_refspecs's destination clause did not skip it. The mirror (+refs/*:refs/remotes/origin/*) was already skipped by that clause, and S2 asked only for a test of it. From RV946's round 2, NIT N6 (issuecomment-6266641009).

Now.

Runs (stub gh, one run at a time, -p no:cacheprovider):

  • tests/test_family_bump_fetch_refspecs.py alone: 13 passed.
  • with tests/test_repo_hygiene.py, tests/test_agents_md_codes.py and tests/test_cli_reference.py: 183 passed.
  • Facts re-measured: this file's rows from 5d5d06bb against 4e1aa24a's tree fail only the two [tags-in-a-folder] rows (2 failed, 11 passed); both [mirror-into-origin] rows pass.

Lane: openreposhape-4 (openRepoShape-4)

🤖 Generated with Claude Code

Summary by Sourcery

Correct the fetch-refspec test documentation to reflect the tested behavior of tag and mirror refspecs.

Enhancements:

  • Clarify the fetch-refspec documentation to accurately distinguish tag refspecs placed in folders from mirror refspecs and document coverage for both cases.

Documentation:

  • Update test docstrings to correct the historical behavior and reachability coverage described for tag-in-folder and mirror refspecs.

…s first head left out a tag or mirror refspec only where it wrote the branches' own names, so a tag refspec in a folder (S1) is left out only now and the mirror (S2) already was and had no test (#997)

Text only, in two docstrings; no code and no assertion changes.

The module docstring said a tag refspec and a mirror into `origin/` were
"now left out (RV946's S1 and S2)", and the reachability row's docstring
said both pinned the commit "in a folder or a mirror" on #946's first
head, `4e1aa24a`. Only the tag refspec in a folder
(`+refs/tags/*:refs/remotes/origin/tags/*`) was carried there: its
destination is not the branches' own, so `_origin_fetch_refspecs`'s
destination clause did not skip it. The mirror
(`+refs/*:refs/remotes/origin/*`) was already skipped by that clause, and
RV946's S2 asked only for a test of it. Measured against `4e1aa24a`, the
file fails only the two `[tags-in-a-folder]` rows and both
`[mirror-into-origin]` rows pass (RV946's round 2, NIT N6).

Closes #997

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Oct 19, 2026

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

This text-only change fixes two docstrings so they accurately describe which refspec cases were already excluded, which tag-in-folder behavior is covered, and that mirror behavior now has explicit test rows; no code or assertions change.

File-Level Changes

Change Details Files
Correct the documentation of fetch-refspec coverage and distinguish the tested tag-folder case from the previously untested mirror case.
  • Clarify that the destination-based filtering rule excludes tag or mirror refspecs when they write branch names.
  • Document that the tag refspec in an origin/tags/ folder is now covered while mirror behavior was already present and now has test rows.
  • Update the reachability scenario to identify S1 as the tag-folder case and S2 as previously untested.
tests/test_family_bump_fetch_refspecs.py

Assessment against linked issues

Issue Objective Addressed Explanation
#997 Correct the module docstring to distinguish the tag refspec in a folder, which #946’s first head did not leave out, from the mirror refspec, which it already left out and which S2 added rows to test. ✅
#997 Correct the reachability-row docstring to say the foldered tag refspec was present on #946’s first head, while the mirror had no test. ✅

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@brettheap

Copy link
Copy Markdown
Contributor Author

(lane openRepoShape-4, 2026-10-19T21:35:06Z) RV1007's review of #1007 at 0541a48c: READY

RV1007 is lane 4's independent reviewer for #1007 (closes #997). W997 wrote the change; I did not. No MUST, no SHOULD, one NIT. Each claim of both new docstrings is true of the code for the refspecs it names; the NIT is wording at the edges of two phrases.

Findings

  • NIT N1 (wording only, take or leave): tests/test_family_bump_fetch_refspecs.py:25-27 and :246-247. "left out a tag or mirror refspec only where it wrote the branches' own names" and "the mirror (S2) had no test" are exact for the refspecs S1 and S2 are about, and loose at three edges. Measured by calling _origin_fetch_refspecs on a scratch mount (table in item 3):
    1. The first head had two skipping clauses, not one. family.py:8213 (a destination outside refs/remotes/origin/) also left out +refs/*:refs/* and +refs/tags/*:refs/tags/*; only :8215-8217 (a destination equal to refs/remotes/origin/*, a source not under refs/heads/) is the one the sentence describes. It is exact for a refspec that writes under origin/, which is the bullet's subject.
    2. A mirror into origin/ does not write the branches' own names; it writes origin/heads/* and origin/tags/* (this file's own comment, :90-91). It was left out for sharing the branches' destination glob, destination == _ORIGIN_BRANCH_NAMES.
    3. "the mirror" is only +refs/*:refs/remotes/origin/*. A mirror in a folder, +refs/*:refs/remotes/origin/all/*, is carried on the first head and on the landed one, and the U182 row [mirror] (+refs/*:refs/*) did have a test on the first head. So "had no test" is true of the mirror into origin/ only.
    • Suggested: :25-27 "only where its destination was the branches' own glob, refs/remotes/origin/*"; :247 "the mirror into origin/ (S2) had no test".

Observation outside the diff (not a finding against #1007). On the landed function (9e6263e, identical to 5d5d06bb's), a mirror in a folder, +refs/*:refs/remotes/origin/all/*, is still carried. Measured in a scratch worktree at 9e6263e with this PR's test file plus one extra parametrize id (mirror-in-a-folder, not in the PR): both rows fail. The clash row fails with bump's note "could not fetch members/IRRS from its origin"; the reachability row fails with "member HEAD changed", a commit only a tag reaches was pinned. It is S1's class in another form. I filed nothing; lane 4 may want an issue.

What I checked and ran

  1. Read in full: tests/test_family_bump_fetch_refspecs.py: two docstrings say a mirror into origin/ was carried on #946's first head, where only a tag refspec in a folder was #997; RV946 round 1 (issuecomment-6252861452) and round 2 (issuecomment-6266641009, NIT N6); the PR body and gh pr diff 1007.

  2. The diff. One commit, 0541a48c, on base 04923f10d (main is now 3864b18cc; the test file's blob is 0730095e on the base, on main and at 9e6263e and 5d5d06bb). One file, +7/-4, two hunks (at old lines 25 and 243), both inside docstrings. Parsed with ast, the module with its docstrings stripped is identical to the base's (code identical: True), and only the module docstring and test_a_tag_a_mount_maps_into_origin_does_not_answer_for_a_branch's differ. A word diff shows only: (RV946's S1 and S2) out of the module docstring, the two new sentences in; or a mirror out and S1 and S2 replaced by S1); the mirror (S2) had no test in the row's. Non-ASCII in the file: 0. git diff --check: clean. Longest added line: 77 columns. git grep -n "first head" finds both places (:25, :246), and no other "S1 and S2" is left in the tree.

  3. The code, from git show 4e1aa24a:scripts/family.py and git show 9e6263e:scripts/family.py. At 4e1aa24a the function skips a destination outside refs/remotes/origin/ (:8213) and a destination equal to refs/remotes/origin/* with a source not under refs/heads/ (:8215-8217); it has no refs/tags/ clause. The function text at 9e6263e equals 5d5d06bb's (diff empty) and adds if source.startswith("refs/tags/") (:8571). Probe, eight refspecs one at a time:

    refspec 4e1aa24a landed
    +refs/tags/*:refs/remotes/origin/* left out left out
    +refs/tags/*:refs/remotes/origin/tags/* CARRIED left out
    refs/tags/v1:refs/remotes/origin/v1 CARRIED left out
    +refs/*:refs/remotes/origin/* left out left out
    +refs/*:refs/remotes/origin/all/* CARRIED CARRIED
    +refs/*:refs/* left out left out
    +refs/tags/*:refs/tags/* left out left out
    +refs/pull/*/head:refs/remotes/origin/pr/* CARRIED CARRIED

    So a tag refspec in a folder (S1) was carried on the first head and is left out now, and the mirror into origin/ was left out on both heads: the claims the docstrings make about those two hold.

  4. S1 and S2 map to the right refspecs. RV946 round 1, item 2: S1 is "B plus +refs/tags/*:refs/remotes/origin/tags/* is still carried (family.py:8215-8217)"; S2 is "the exclusion for a mirror into origin/ has no test". Round 2 N6 and tests/test_family_bump_fetch_refspecs.py: two docstrings say a mirror into origin/ was carried on #946's first head, where only a tag refspec in a folder was #997 say the same. Row ids from --collect-only (13 collected): S1 is [tags-in-a-folder] in test_tags_mapped_into_origin_fetch_a_branch_and_a_tag_of_one_name and in test_a_tag_a_mount_maps_into_origin_does_not_answer_for_a_branch; S2 is [mirror-into-origin] in the same two, so "now has rows" is two rows. origin/tags/v-release is what the folder refspec makes of the row's tag v-release. At 4e1aa24a, git grep -F 'refs/*:refs/remotes/origin' -- tests scripts finds only a docstring in family.py, so the mirror into origin/ had no test.

  5. Measured on the first head: a detached worktree at 4e1aa24a (scripts/family.py blob 695d40bf) with the PR head's test file copied in, that file alone: 2 failed, 11 passed. The two failures are both [tags-in-a-folder] rows; both [mirror-into-origin] rows pass. The reachability row's failure is "member HEAD changed", so the real run pinned the commit, as :246 says.

  6. Run at the head, 0541a48c: tests/test_family_bump_fetch_refspecs.py alone, /usr/bin/python3 -m pytest -q -p no:cacheprovider -o tmp_path_retention_policy=failed with one --basetemp under the lane's scratchpad: 13 passed in 27.94 s, exit 0. Before it: df -i / showed 83% used, 23146911 free; EMAIL set to a .invalid address; GIT_SSH_COMMAND, GIT_ALLOW_PROTOCOL and every LANES_* variable unset (env | grep found none); a stub gh that exits 97 first on PATH (it printed gh exit=97), GH_TOKEN=bogus, an empty GH_CONFIG_DIR.

  7. Not run: the PR body's wider 183-test run (repo_hygiene, agents_md_codes, cli_reference) and the full suite. The ast check shows no code or assertion moved, so the one file's 13 rows are the whole exposure.

No commit, push or review state was made on the PR; my scratch worktrees are under _lane4-scratch/ and are in my clone only.

Lane: openreposhape-4 (openRepoShape-4)

@sourcery-ai

sourcery-ai Bot commented Oct 19, 2026

Copy link
Copy Markdown

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 hour and 17 minutes by commenting @sourcery-ai review. Upgrade to get a review now.

@sonarqubecloud

Copy link
Copy Markdown

@brettheap
brettheap merged commit 259743a into main Oct 19, 2026
4 of 5 checks passed
@brettheap
brettheap deleted the fix/997-refspec-docstrings branch October 19, 2026 22:35
brettheap added a commit that referenced this pull request Oct 20, 2026
…se source can name a tag, a pattern such as `refs/*` and a short name too, so a mirror in a folder, `+refs/*:refs/remotes/origin/all/*`, no longer fails the fetch on a branch and a tag of one name or pins a commit only a tag reaches (#1009) (#1027)

`family.py bump` fetches the member's `origin` with
`+refs/heads/*:refs/remotes/origin/*` and the mount's own refspecs that
write under `refs/remotes/origin/` (#686), so that `--prune` keeps what
they write. #946 (#905) left out a refspec whose source is under
`refs/tags/`, and a non-branch source onto the branches' glob
`refs/remotes/origin/*`. A mirror in a folder,
`+refs/*:refs/remotes/origin/all/*`, met neither, so it was carried. Its
`refs/*` takes every tag and writes it under `origin/all/tags/`, where
`bump` reads branches. Where a branch and a tag share a name, the fetch
failed ("could not fetch members/IRRS from its origin"). Where none did,
a commit only a tag reaches was pinned. Lane 4's RV1007 found it while
reviewing #1007.

`_origin_fetch_refspecs` now asks three clauses of each positive
refspec of the mount's own. Negative ones are skipped, as before. The
first clause that matches leaves the refspec out:
1. A destination outside `refs/remotes/origin/`. Unchanged.
2. A source that `_can_name_a_tag`, wherever under `origin/` it writes.
   This is a new helper, with `_TAGS_PREFIX = "refs/tags/"`. A source
   can name a tag three ways:
   a. It is under `refs/tags/` (#946's clause).
   b. It is a pattern whose part before the `*` is a start of
      `refs/tags/`: `refs/*`, `refs/t*` or `*`. Git matches a pattern
      against each ref's whole name and never completes it.
   c. It is no pattern and not under `refs/`. That is either a short
      name or an exact object id. Git completes a short name, trying the
      name, then `refs/<name>`, then `refs/tags/<name>` before
      `refs/heads/<name>`: `+x:` took the tag `x` over the branch `x`,
      and `+heads/main:` took the branch `main`. An exact object id
      (`+<40 hex>:refs/remotes/origin/pinned`) names no branch.
3. The branches' glob, `refs/remotes/origin/*`, written from a source
   not under `refs/heads/`. Unchanged. It is now the only clause that
   leaves out a source that can name no tag, such as
   `+refs/pull/*/head:refs/remotes/origin/*`.

Everything else is carried, forced, after the branches' refspec and
without duplicates. That includes the pull requests
(`+refs/pull/*/head:refs/remotes/origin/pr/*`), a `refs/review/`
refspec whose name is not UTF-8, one branch, and branches in a folder.
These were measured on git 2.43.

The issue's own wording, every source that can match a ref outside
`refs/heads/`, would also leave out the pull-request and review
refspecs that #946 carries on purpose: its two U184 rows fail on that
mutant. Keyed on tags, the rule leaves out neither.

tests/test_family_bump_fetch_refspecs.py now has 33 rows; it had 13
on main.
- `mirror-in-a-folder` is added to `TAGS_UNDER_ORIGIN`, so both U183
  tests run it end to end: the clash row and the reachability row.
- `WHICH_CLAUSE` adds 18 rows, run in process. Each says which clause
  leaves a refspec out, or that it is carried. They include
  `tag-short-name-heads-main` and `tag-object-id`.
- The docstrings name the clause for each refspec, with #1007's NIT
  N1 wording.

On main `5b41d44fc`'s `family.py`, the new file gives 9 failed and 24
passed: the two end-to-end rows and 7 table rows for 2(b) and 2(c).
Here, all 33 pass. The targeted runs at `a79c957b0` all passed:
- `-k bump` over every `tests/test_family*.py`: 277;
- `test_repo_hygiene.py`: 100;
- `test_cli_reference.py`: 23;
- `test_agents_md_codes.py`: 47;
- `test_no_auto_maintenance.py`: 60;
- `test_family_dry_run.py`: 61.

Ten mutants of the rule are killed, RV1027's RM1 and RM2 among them.
Two that drop a guard survive. They change only a pattern outside
`refs/` that takes no tag (`heads/*`), or a source that is no ref
name (`refs/t`).

Limits:
- `bump-leg.py`'s `_leg_fetch_refspecs` has no tag clause, so a leg's
  fetch still carries every tag-capable refspec (#1037).
- A full name that is no pattern can still bring a tag. Where the
  remote had no branch `zz`, `+refs/heads/zz:refs/remotes/origin/zz`
  took the tag `refs/tags/refs/heads/zz`. Leaving out every full name
  would drop the pull-request and review refspecs.
- 2(c) leaves out every short name, `heads/main` and `HEAD` included.
  Where the branches' refspec writes the same name, nothing is lost.
  Elsewhere, the prune drops the copy until the mount's next
  `git fetch origin`.
- A non-tag refspec in a folder can still clash with a branch. The pull
  requests onto `origin/pr/*` clash with a branch `pr/7` where the
  mount keeps no branch refspec of its own. They are carried so that
  their refs survive the prune.

Lane 4's RV1027 found it READY at `669d611e`, with no MUST and no
SHOULD. Its four NITs are taken in `a79c957b0`.

Closes #1009

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant