Skip to content

tests/test_update_shape_merged_away.py: the pins row's merged-away check is tested where check refuses the standard, and beside a both, an upstream-removed and an unmapped row, so a refusals_ahead that answers a refusal with nothing ahead, or counts copy-is-link alone, fails a test (#755) - #770

Merged
brettheap merged 2 commits into
mainfrom
l3-755-merged-away-tests
Oct 18, 2026

Conversation

@brettheap

@brettheap brettheap commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Lane: openreposhape-3 (openRepoShape-3)
Claim: #755 (comment)

Closes #755.

Lands after the v1.1.0 tag. (#751, the issue's "Lands after", is in main as e3137010.)

Tests only. No tool changes.

Re-measured on main e3137010

The issue's claims still hold. refusals_ahead has moved since b7312258: it now starts at shape-doctor.py:2813, its prepare refusal returns at :2843 and its conflict list is at :2845. Both of RV-f's mutants, applied on this main, pass every test the file held before:

  • M1, :2843 return None → return {}.
  • M2, :2845 if row.is_conflict → if row.state == us.COPY_IS_LINK.

What changed

All in tests/test_update_shape_merged_away.py:

  • test_the_pins_row_keeps_the_gate_where_check_refuses_the_standard (:509). Both copies are merged away, and the doctor runs from a standard of another history (test_shape_doctor.standard_of_another_history), which lacks the pinned commit.

    • check refuses it, update-revision-unresolvable, as the test asserts first.
    • So refusals_ahead cannot ask its question, and the pins row must keep its gate: no merged_away key, and a NEXT that is not update-shape.py.
    • This is the issue's first option. A promisor = false-alone clone was the other; a standard short of the pinned commit needs no partial clone.
  • test_the_pins_row_keeps_the_gate_beside_each_conflict_check_names[both|upstream-removed|unmapped] (:592). shape/Makefile is merged away, and beside it one of these:

    • both (both_beside, :550): the project's kept edit of AGENTS-shape.md, pinned as it stands, which is what apply --accept-local leaves, beside the standard's own edit of that copy one commit on.
    • upstream-removed (upstream_removed_beside, :562): the standard one commit on, without the AGENTS-shape.md template.
    • unmapped (unmapped_beside, :574): a pin row for a file of the project's own, as the issue suggests.

    Each case asserts four things in turn:

    1. check itself calls the path that state.
    2. The pins row keeps its gate, with refusal_ahead == {path: state} and the REFUSAL AHEAD clause naming it (the existing assert_the_pins_row_keeps_its_gate).
    3. The apply that check prints, pasted, exits 2.
    4. That exit is REFUSED update-conflict, as RV-f measured.
  • Shared helpers:

    • pinned_as_it_stands (:531) rewrites, or adds, one pin row from the bytes on disk, matching shape_materialize.py's row form quoted or not, and commits.
    • assert_the_pins_row_is_the_gate (:502) is now used by the new test and by …_where_check_would_fetch (:488), whose two asserts it replaces.
  • The builders are one table, CONFLICTS_BESIDE (:584), so the three cases share one test body.

Each named mutant, killed

Each mutant was applied to 837920c2 in a scratch clone, and the whole file run against it:

  • M1 (return {}): 1 failed, 17 passed. The one failure is test_the_pins_row_keeps_the_gate_where_check_refuses_the_standard.
  • M2 (copy-is-link alone): 3 failed, 15 passed. The failures are …_beside_each_conflict_check_names[both], [upstream-removed] and [unmapped].

Tested

With a stub gh first on PATH, GH_TOKEN=bogus and an empty GH_CONFIG_DIR:

/usr/bin/python3 -m pytest -q -p no:cacheprovider --basetemp=<scratch>/bt-w755-T -o tmp_path_retention_policy=failed tests/test_update_shape_merged_away.py tests/test_doctor_partial_clone.py tests/test_repo_hygiene.py tests/test_cli_reference.py

Result: 138 passed in 84.08s (0:01:24). The file needs git filter-repo, which this machine has, so nothing in it was skipped.

Pinned copies

None.

Docs

None. The tests pin behaviour the docs do not state.

🤖 Generated with Claude Code

Summary by Sourcery

Strengthen merged-away update tests so refusal-ahead classification preserves the pins gate across unresolved and conflicting standard states.

Enhancements:

  • Expand merged-away shape update coverage to ensure the pins row remains gated when the standard is unresolvable and when it is adjacent to both, upstream-removed, or unmapped conflicts.

Tests:

  • Add regression tests covering refusal-ahead handling and verifying that generated conflict updates remain refused.

…check is tested where `check` refuses the standard, and beside a `both`, an `upstream-removed` and an `unmapped` row, so a `refusals_ahead` that answers a refusal with nothing ahead, or counts `copy-is-link` alone, fails a test (#755)

`refusals_ahead` (#676, PR #751) had two branches no test reached, and
RV-f's two mutants of them survived:
- a `prepare` refusal answered `{}` instead of None: the `pins` row then
  named a `check` that exits 2. Now run from a standard of another
  history (`update-revision-unresolvable`), the row must keep its gate.
- a conflict list narrowed to `copy-is-link`: only the link was tested.
  Now `both` (the project's kept edit, pinned as it stands, beside the
  standard's own edit), `upstream-removed` (the standard drops the copy)
  and `unmapped` (a pin row for the project's own file) each sit beside a
  merged-away row: `check` says that state, the row keeps its gate and
  names it, and the `apply` `check` prints, pasted, exits 2 with
  `update-conflict`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Oct 17, 2026

Copy link
Copy Markdown

Reviewer's Guide

Tests add focused regression coverage for issue #755: the pins row must remain a gated doctor step when standard resolution is unavailable and when each relevant conflict state is adjacent to a merged-away row, preventing incorrect refusals_ahead implementations from passing.

File-Level Changes

Change Details Files
Add regression coverage ensuring the pins row retains its gate when standard resolution is refused or when specific conflict states appear beside a merged-away row.
  • Cover a standard from another history, verifying check refuses before classification while the doctor still preserves the gate.
  • Parameterize both, upstream-removed, and unmapped neighboring conflict scenarios and verify their refusal-ahead state, generated apply command, and update-conflict refusal.
  • Add helpers to rewrite or add pin entries from current file contents and centralize gate assertions and scenario builders.
  • Import hashing, regex, and standard-history helpers needed to construct and validate the fixtures.
tests/test_update_shape_merged_away.py

Assessment against linked issues

Issue Objective Addressed Explanation
#755 Test that when check refuses the standard before classifying rows, the pins row keeps its gate and has no merged_away detail. ✅
#755 Test both, upstream-removed, and unmapped rows beside a merged-away row, asserting that the pins row keeps its gate and names the conflict state, and that the printed apply command exits 2 with update-conflict. ✅

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-3, 2026-10-17T01:09:28Z) Independent review of #770 by RV-f (opus), on head 837920c2: READY. No MUST and no SHOULD; three optional NITs. It lands only after the v1.1.0 tag, once its Linux tests is green.

The two mutants #751 left alive are now killed (applied to shape-doctor.py at e3137010, whole file run):

mutant main's 14 tests the head's 18
M1: :2843 return None → return {} (a prepare refusal reads as nothing ahead) 14 passed 1 failed: test_the_pins_row_keeps_the_gate_where_check_refuses_the_standard
M2: :2845 row.is_conflict → state == COPY_IS_LINK 14 passed 3 failed: [both], [upstream-removed], [unmapped]

RV-f ran four more mutants:

  • dropping both, upstream-removed or unmapped from the conflict states each fails only its own case;
  • return ahead or None fails four tests already on main.

Each case builds the state it names. RV-f copied each root out of tmp_path and ran update-shape.py check on it:

  • prepare refuses → exit 2, update-revision-unresolvable;
  • both → exit 1, REFUSAL AHEAD on AGENTS-shape.md;
  • upstream-removed → exit 1, REFUSAL AHEAD on AGENTS-shape.md;
  • unmapped → exit 1, REFUSAL AHEAD on notes-of-our-own.md;
  • the control, merged-away alone → no REFUSAL AHEAD.

In every root, the root's own validate-pins.py reports only the merged-away finding.

Hygiene:

  • no composite asserts;
  • SonarCloud measures 0.0% new duplication;
  • bytes only, so it holds on Windows;
  • the file's time went from 36.30s to 43.99s.

NITs (optional):

  • N1 :606-609: assert argv[1:3] == ["update-shape.py", "apply"] before running the pasted NEXT, as the first test in the file does.
  • N2 :441 (assert_the_pins_row_keeps_its_gate): M2's kill is a KeyError. Use pins_row["detail"].get("refusal_ahead") == ahead, pins_row so a failure shows the row.
  • N3 :531: pinned_as_it_stands overlaps tests/test_update_shape.py:944 set_pin_row_sha256. That helper uses write_text, which writes CRLF on Windows. Optionally have it call the new, byte-level helper.

Tests:

  • the writer's set: 138 passed;
  • the file on the head: 18 passed in 43.99s;
  • the file on main: 14 passed.

Merges. All clean, each run with the file passing (18 passed, or 42 with test_doctor_partial_clone.py on the #754 merge):

Lane: openreposhape-3 (openRepoShape-3)

This was referenced Oct 17, 2026
@sonarqubecloud

Copy link
Copy Markdown

@brettheap
brettheap marked this pull request as ready for review October 18, 2026 11:17
@sourcery-ai

sourcery-ai Bot commented Oct 18, 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 day and 13 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@brettheap
brettheap merged commit c094cd9 into main Oct 18, 2026
5 checks passed
@brettheap
brettheap deleted the l3-755-merged-away-tests branch October 18, 2026 11:18
brettheap pushed a commit that referenced this pull request Oct 18, 2026
…ith #815, #770, #869 and #802 (#883)

Round 5 of #883, a refresh. Each line comes from its squash body and was
checked against the code at main 0d5d2b1:

- #815 (#764): a project's bootstrap ends a validator's exit 2 as
  `bootstrap REFUSED`, exit 2, takes an upstream path, cache or pin it
  cannot read as no answer, and leaves a reftable leg's cherry-pick or
  revert alone. A line in "What changed", one in "What 1.1.1 fixes", and
  a note under "What a script sees" on the direct run's exit code. Its
  body's leftovers, two tracebacks on Python 3.12 and 3.13 and two
  "failed" texts beneath a REFUSED line, are a new limit.
- #770 (#755) and #869 (#853, #854): tests, in the Tests line. The test
  limit for #853 and #854, and the skip #845 left, which #869 removes, are
  retired.
- #802 (#675): update-shape.py's `git show` lines are shell-quoted and its
  kept-copy readers read some Python as Python does. Its one-hop read and
  what it reads as running are a new limit.

67 pull requests; 69 of the milestone's 72 issues closed at 11:31Z, and
the open list is the 3 that read leaves: #707, #879 and #884. The
shape-copy lists stand: the assembly root's bootstrap.py, which #815
changes, is on them. No other file changes.

Lane: openreposhape-1 (openRepoShape-1)
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