Repository navigation
shape-doctor.py: a conflicted shape pin's NEXT takes the side whose pin reads, and names no line where no side's pin reads, so run as printed it no longer leaves the doctor naming the same NEXT again (#752) - #779
Conversation
…in reads, and names no line where no side's pin reads, so run as printed it no longer leaves the doctor naming the same NEXT again (#752) `pin_restore` took `--ours` wherever ours held a pin, read or not, and `--theirs` only where ours held none. A side whose committed pin does not read, taken whole, left the pin as it was, so the doctor named the same `checkout` again, run after run. - `side_to_take` takes ours where its pin reads, else theirs where that reads, and the `why` then says only that side's pin reads instead of offering `--theirs takes the other side`, which would offer the circle. - Where no side's pin reads, both the `shape currency` and the `manifest kinds` rows name no NEXT, and say that taking a side whole puts back no pin that reads, so finishing the merge, or aborting it to put back first the pin a side broke, is a person's call. `unreadable_pin_row` keeps its `update-shape.py check` line for the `none` case alone, and `unreadable_next` says the stuck pin's `why` rather than send the reader to this doctor again. - The side taken now always reads, so `other_sides_copies` loses #736's wording for a kept pin that does not read; its other words are the same. Tests: one side's pin unreadable, each side, with the NEXT run as printed and the doctor read after it; no side's pin readable, with both sides holding one and with one. Each fails on the doctor before this commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewer's GuideUpdates conflicted shape-pin restoration so the doctor only checks out a side whose pin reads, and names no NEXT when neither side is readable; output propagation, copy messaging, documentation, and regression tests are adjusted accordingly. Sequence diagram for readable conflicted-pin restorationsequenceDiagram
participant Doctor
participant GitIndex
participant PinReader
Doctor->>GitIndex: ls-files -u
GitIndex-->>Doctor: Pin stages
Doctor->>PinReader: pin_reads_at(:2, pin)
PinReader-->>Doctor: Readable or unreadable
Doctor->>PinReader: pin_reads_at(:3, pin)
PinReader-->>Doctor: Readable or unreadable
alt Ours reads or both read
Doctor-->>Doctor: Return --ours and stage 2
else Only theirs reads
Doctor-->>Doctor: Return --theirs and stage 3
end
Doctor-->>Doctor: Include explanatory why
Sequence diagram for unreadable conflicted-pin reportingsequenceDiagram
participant Doctor
participant PinRestore
participant ShapeCurrency
participant ManifestKinds
Doctor->>PinRestore: pin_restore(detail)
PinRestore-->>Doctor: unmerged, no command, why
Doctor->>ShapeCurrency: Keep no NEXT and explain person's call
Doctor->>ManifestKinds: Propagate the same why
ManifestKinds-->>Doctor: No fallback shape-doctor command
Flow diagram for conflicted shape-pin restorationflowchart TD
A[Conflicted shape pin] --> B{Which side's pin reads?}
B -->|Ours reads| C[Choose --ours]
B -->|Only theirs reads| D[Choose --theirs]
B -->|Both read| E[Choose a side and explain alternative]
B -->|Neither reads| F[No NEXT command]
C --> G[Return unmerged restore with checkout command]
D --> G
E --> G
F --> H[Return unmerged restore with person's-call explanation]
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
(lane openRepoShape-3, 2026-10-17T04:11:08Z) Independent review of #779 by RV-b (opus), on head The issue's loop holds on main
On the head every state ends somewhere new. "After finish" means every conflicted path taken from the NEXT's side, then the merge committed.
What RV-b checked in the code:
Mutants:
Tests: the four targeted files gave Merges and CI:
Lane: openreposhape-3 (openRepoShape-3) |
|
|
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 39 minutes by commenting |
…ted under a name no pin has a row for, is named in a conflicted shape pin's `why` and `left_for_a_person` as renamed from that copy, for a person to settle, and never taken (#753) (#781) Closes #753. Ours renamed the `Makefile` copy to `build.mk` and theirs edited the `Makefile`. git carries the conflict to `build.mk`, a name no pin lists, so the conflicted shape pin's `why` and `left_for_a_person` said nothing of it, and only the `merge` row listed the path. Now `pin_restore` in `shape-doctor.py` keeps each conflicted path's stage-1 object, and `copies_renamed` calls a path no pin lists a copy's rename only on exact evidence: the merge base holds nothing at that path, and its stage-1 blob is the blob of exactly one path of the whole base, a copy. No similarity is guessed at. The new name joins `left_for_a_person` and the `why` ("build.mk, renamed from the copy Makefile, is conflicted too ... a person merges it by hand"), and is never taken. Where the pin taken still lists the old name, the `why` adds that the doctor will report it missing once the merge is finished, unless it is renamed back. `tests/test_doctor_pin_restore_merges.py` builds the real merges, and pins the cases that name no rename. Lane 3's independent reviewer RV-b (opus) found it READY in three rounds (#781 issuecomment-6229486930, -6229640251 and -6229719143). After #779 landed, it was restacked onto #779's squash by three merges, and its changed lines equal the reviewed delta. It lands on Brett Heap's word "merge lane 3's v1.1.1 drafts after the v1.1.0 tag" (2026-10-17T13:00:57Z). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in #827 (#712, 9f235da), whose gate words the doctor copies, and #779 (#752, c100843), lane 3's doctor PR. One path conflicted, shape-doctor.py, in one hunk of `unreadable_next`: this branch's `command = doctor_line(ctx)` against #779's `stuck` branch. Resolved with #779's lines as they are on main (the second lander takes the first's lines), so `unreadable_next` is byte for byte main's and `doctor_line` is used by this branch's own rows only. Lane: openreposhape-4 (openRepoShape-4) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…trap_after_bump.py` imports both `appended_to_command_scope` and `needs_a_byte_name` (#715) Main moved from `0dee22b3` to `ca47b71d` while round 3 was paused (#846, #779, #772, #738, #842, #814, #790, #820, #774, #830 and #841). `git merge-tree` of `8b4dbcf6` with it stopped in one path: - `tests/test_bootstrap_after_bump.py`, its imports. Main's `aec3b38f` (tests append what they tell git to the command scope) added `appended_to_command_scope` to the `from conftest import (...)` list. This branch added `from test_bootstrap_spelling import needs_a_byte_name` below it (#715, round 1). Both are kept. `scaffold-project.py`, `scripts/bump-leg.py` and `scripts/shape_materialize.py` merged without a conflict. Lane: openreposhape-4 (openRepoShape-4) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Lane: openreposhape-3 (openRepoShape-3)
Claim: #752 (comment)
Closes #752.
Lands after the v1.1.0 tag. (The issue's "Lands after: #736" is met: #736 landed as
bf1f099b, this branch's base.)What happened
A conflicted shape pin's NEXT took
--ourswherever ours held a pin, whether it read or not, and--theirsonly where ours held none. A side whose committed pin does not read, taken whole, left the pin as it was, so the doctor named the samecheckoutagain on every run.Reproduced on #736's head
3dfe2fdeand on mainbf1f099b's tree (f596d9cd, the predicted squash, equal to the landed one). Inboth_pure's merge:files: [(RV-b's state): the NEXT wascheckout --ours -- contracts/shape-pin.yaml. Run as printed, the doctor printed the same NEXT again.--oursNEXT, again after it ran.checkout --theirs, a pin that does not read.The issue's claim holds on current main.
What changed (
shape-doctor.py)side_to_take(:4125-4174), called bypin_restore(:3957-3959), picks the side. It takes ours where ours' pin reads, else theirs where that reads.whystarts as before: "--theirs takes the other side. Take one side of the pin whole".pin_restorereturns("unmerged", None, why). Thewhysays that no side taken whole puts back a pin that reads, and that this doctor would name the same line again. It ends: "A pin is never mended by hand, so no line is named here: whether to finish the merge, or to abort it and first put back the pin a side broke, is a person's call". When only one side holds a pin, it says "the one side of it that holds a pin holds one that does not read".whyand name no NEXT:unreadable_pin_row(:4638) keeps itsupdate-shape.py checkline for thenonerestore alone.unreadable_next(:4561-4590) keeps thewhyof a pin left stuck that way, instead of sending the reader to this doctor again withUNREADABLE_BY_HAND. That text would say no tool-written file has a pin that reads in its history. Themanifest kindsrow therefore prints what theshape currencyrow prints. Its return type now admits aNonecommand.other_sides_copies(:4085-4121) loses shape-doctor.py: a conflicted shape pin's NEXT reads both sides' pins, so a copy conflicted beside it that only the side not taken has afiles:row for is named in itswhyandleft_for_a_personfor a person to merge, and never taken (#687) #736's kept-pin-does-not-read wording. The pin taken here now always reads. Its words are otherwise unchanged; I checked the oldkept_reads=Trueconcatenation against the new one.pin_restore'sunmergedentry (:3773-3782), EVERY PIN … IS READ FIRST (:3884-3886), and the two callers'.Tests (
tests/test_doctor_pin_restore_merges.py)test_the_side_taken_is_one_whose_pin_reads[ours-does-not-read|theirs-does-not-read](:826):checkout --theirsor--oursrespectively, and nothing is taken (the proof reads both pins);project.yamlandbootstrap.pyto a person;whystarts with the new note;shape currencyrow carries no readerror, and themanifest kindsrow no longer lists the pin.test_no_line_is_named_where_no_sides_pin_reads[both|one](:864): both rows havenext: nulland the samewhy, quoted whole, and both rows'restoreisunmerged.files:row for is named in itswhyandleft_for_a_personfor a person to merge, and never taken (#687) #736's plural test no longer has an[unreadable]case. That state is shape-doctor.pypin_restore: where the side taken in a conflicted shape pin does not read as a pin, the NEXT still takes that side, and run as printed it leaves the doctor naming the same NEXT again #752's, and its expectations are the first test's now.shape-doctor.pyonly): with--oursor--theirsNEXTs where none or the other was expected, and with "--theirs takes the other side".Each run used a stub
ghfirst on PATH that exits 97,GH_TOKEN=bogusand an emptyGH_CONFIG_DIR, at the head:Pinned shape copies
None.
shape-doctor.pyis in no copy list.Docs
None changed. No doc describes the conflicted-pin restore. README.md, AGENTS.md and
docs/cli.mdare untouched, and so isdocs/release-notes/.For the reviewer
whypoints to two acts without naming them as lines. Where no side's pin reads, the way out is a person's: finish the merge, or abort it and put back the pin a side broke. On a branch, the pin a commit broke is thecommittedrestore this doctor already names. Thewhymentionsmerge --abortand that restore only as acts, not as NEXT lines.pin_restore: a shape copy renamed on one side of a merge conflicts under its new name, which no pin's row lists, so thewhynever names it and only themergerow does #753 (a copy renamed on one side) stacks on this branch. Its PR changes the same lines ofpin_restore.🤖 Generated with Claude Code
Summary by Sourcery
Fix conflicted shape-pin remediation so generated NEXT commands leave a readable pin and unresolved cases are deferred to the user.
Bug Fixes:
Enhancements:
Tests: