Repository navigation
siblings.py and shape-doctor.py: a link to nothing at ../<Project> is NOT A CLONE, reported and left as it is, so the dry run no longer says would clone where the real run ends CLONE FAILED, and the doctor's members row no longer calls the slot absent (#784) - #788
Conversation
…, at `../<Project>` is NOT A CLONE, reported and left as it is, so the run no longer ends in a traceback at `iterdir` before the members after it are placed, and `make park` no longer ends in one over a folder it cannot enter (#735) `place` asked only whether a folder had something in it: `iterdir` raised `NotADirectoryError` for a file and `PermissionError` for a folder with mode 0311 or 000, a traceback, exit 1. `not_a_clone` now gives the finding's words for each slot nothing is cloned into: the folder of files keeps its finding byte for byte, a file "is a file, not a folder", and a folder it cannot list "is a folder that cannot be listed", the words the doctor's `members` row says of the same slots. `holds_git` asks for a `.git` and reads an `OSError` as none, for `place` and for `dispatch` (`--make`), which Python 3.12 answered with `PermissionError` in a folder that cannot be entered. The doctor's agreement test (#705) now passes for a file and for both locked folders, so its strict xfail is gone; the doctor's output is unchanged, and its comments now say a holder pinned before this change still ends in the traceback. `siblings.py` is a family-root copy carried by digest: a holder pinned before this change shows an `upstream-changed` row for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…is NOT A CLONE, reported and left as it is, so the dry run no longer says `would clone` where the real run ends CLONE FAILED, and the doctor's `members` row no longer calls the slot `absent` and says `make siblings` places the member there (#784) `exists` follows a link, so a dangling one read as nothing at all. In `siblings.py`, `not_a_clone` now answers "is a link to nothing" for it, in the finding the other NOT A CLONE slots get. In the doctor, `unclonable` answers `dangling`, so `sibling_slot` says `not-a-clone`, and the row says "is a link to nothing" and nothing of what `make siblings` does there: a holder pinned before this change still ends CLONE FAILED on it. `make park` and `make resume` keep `SKIPPED no clone`. `siblings.py` is a family-root copy carried by digest: a holder pinned before this change shows an `upstream-changed` row for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewer's GuideThe PR closes the gap where Sequence diagram for dangling-link classificationsequenceDiagram
participant User
participant Siblings as siblings.py
participant Doctor as shape-doctor.py
participant Slot as ProjectSlot
User->>Siblings: not_a_clone(ProjectSlot)
Siblings->>Slot: exists()
Slot-->>Siblings: false
Siblings->>Slot: is_symlink()
Slot-->>Siblings: true
Siblings-->>User: NOT A CLONE
Siblings-->>User: leave link unchanged
User->>Doctor: sibling_slot(ProjectSlot)
Doctor->>Slot: exists()
Slot-->>Doctor: false
Doctor->>Slot: is_symlink()
Slot-->>Doctor: true
Doctor->>Doctor: unclonable(ProjectSlot)
Doctor->>Doctor: beside_sentence(ProjectSlot)
Doctor-->>User: not-a-clone, is a link to nothing
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
(lane openRepoShape-3, 2026-10-17T05:16:27Z) Independent review of #788 by RV-d (opus), on head Each link at
Answers:
NITs (optional):
Mutants: all 5 are killed by the four
Tests:
Merges: clean with Lane: openreposhape-3 (openRepoShape-3) |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
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 2 days and 11 hours by commenting |
…ep 1 of 3) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… to nothing at `../<Project>` (`exists()` says no and `os.path.isjunction` says yes) is NOT A CLONE, as a link to nothing is, so the dry run no longer says `would clone` and the doctor's `members` row no longer calls the slot `absent` (#793) (#794) Closes #793. #788 tells a link to nothing from an empty slot with `Path.is_symlink()`, which says no to a directory junction, the link Windows makes without privilege. A junction to nothing at `../<Project>` therefore read as an empty slot: with the junction simulated, the dry run said `would clone`, the real run tried to clone into it, and the doctor's `members` row called the slot `absent`. Now `not_a_clone` in `templates/family-root/scripts/siblings.py` and `unclonable` in `shape-doctor.py` also ask the junction check, spelled as `family_link` spells it, `getattr(os.path, "isjunction", lambda _: False)`, after `exists()`. Where it says yes for a slot that does not exist, the slot gets the answer a link to nothing gets: `NOT A CLONE` in the dry run and `not-a-clone` in the doctor, and the junction is left as it is. `os.path.isjunction` is Python 3.12's. Before 3.12 there is none, so there a junction to nothing still reads as an empty slot. Windows itself is not measured: `tests/test_family_siblings_placement.py` and `tests/test_shape_doctor.py` simulate the junction by making `os.path.isjunction` say yes for the slot, for one to nothing and for one to a live folder, so the check stays after `exists()`. Lane 3's independent reviewer RV-d (opus) found it READY (#794 issuecomment-6232574289). Lane 3 checked the test-only NIT round after it, and RV-d's READY stood (#794 issuecomment-6232681374). After #788 landed, it was restacked onto #788's squash by three merges, and its changed lines equal the reviewed delta (#794 issuecomment-6245446016). 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>



Lane: openreposhape-3 (openRepoShape-3)
Claim: #784 (comment)
Closes #784.
Stacked on #772; lands after it. Lands after the v1.1.0 tag.
What changed, and why
A dangling symbolic link at
../<Project>read as an empty slot, becauseexistsfollows a link. Measured with #772's head1d149933and a link to nothing at../IRRSin the two-member holder. Every claim in the issue held:make siblings --dry-run:[IRRS] would clone ... -> .../IRRS(statewould clone), from siblings.py: a file, or a foldermake siblingscannot list or enter, at../<Project>is NOT A CLONE, reported and left as it is, so the run no longer ends in a traceback atiterdirbefore the members after it are placed, andmake parkno longer ends in one over a folder it cannot enter (#735) #772'splacecalled on its own.make siblings: the layout row wassibling IRRS CLONE FAILED -. git cannot clone into a path that is a link to nothing:fatal: could not create work tree dir 'slot': File exists, exit 128 (measured).membersrow:siblingwas'absent', so the row saidmake siblingsplaces the member there.make parkandmake resume:SKIPPED no clone, as siblings.py: a file, or a foldermake siblingscannot list or enter, at../<Project>is NOT A CLONE, reported and left as it is, so the run no longer ends in a traceback atiterdirbefore the members after it are placed, andmake parkno longer ends in one over a folder it cannot enter (#735) #772 left them.templates/family-root/scripts/siblings.py:not_a_clone(:471) now answers "is a link to nothing", withlinkas the kind of thing (:496). The docstring is at:487.placetherefore reports the slot asNOT A CLONE, in the finding the other NOT A CLONE slots get: "<who>:<at>is a link to nothing, so this command will not write into it. Move it aside or name the link something else; nothing here overwrites a link somebody made."NOT A CLONE, notwould clone.dispatch(--make) is unchanged:holds_git(:460) answers "no" for a link to nothing (:776), somake parkandmake resumekeepSKIPPED no clone.shape-doctor.py:unclonable(:7974) answersdanglingfor a link to nothing (:7996), sosibling_slot(:8004) saysnot-a-clone, and the doctor andmake siblingsagree again.UNREADABLE_BESIDE(:8174,"dangling": "is a link to nothing"at:8176). It says what is there and nothing of whatmake siblingsdoes with it. That holds for every holder, because one whose pinnedsiblings.pypredates this change still endsCLONE FAILEDon the link.sibling_slot,UNREADABLE_BESIDEandbeside_sentence(:8179) say so.What is tested
tests/test_shape_doctor.py:UNREADABLE_SLOTS(:4071) gainsa-link-to-nothing(:4077), skipped on Windows, where a symbolic link needs a privilege (LINKS_HOLD,:4065).holder_with_slotbuilds it at:4103.:4131) assertsnot-a-clone,UNREADABLE_SAYS["dangling"](:4016), no word ofmake siblings,okandCOMPLIANT.:4164) asserts that the holder's ownsiblings.py --dry-runprintsNOT A CLONEfor it.tests/test_family.py:test_siblings_reports_a_slot_it_cannot_read_as_not_a_clone(:1976) gainsa-link-to-nothing(:1940). On a real run it asserts:sibling IRRS NOT A CLONE -;"Unchanged" is checked with
as_it_is(:1944): a link and where it leads, a file and what it says, or a folder's files. It replaces siblings.py: a file, or a foldermake siblingscannot list or enter, at../<Project>is NOT A CLONE, reported and left as it is, so the run no longer ends in a traceback atiterdirbefore the members after it are placed, andmake parkno longer ends in one over a folder it cannot enter (#735) #772's two separate checks.test_a_make_verb_skips_a_slot_with_no_clone(:2016, siblings.py: a file, or a foldermake siblingscannot list or enter, at../<Project>is NOT A CLONE, reported and left as it is, so the run no longer ends in a traceback atiterdirbefore the members after it are placed, andmake parkno longer ends in one over a folder it cannot enter (#735) #772's mode-000test, now parametrized) assertsSKIPPED no clonefor the link too.make siblingscannot list or enter, at../<Project>is NOT A CLONE, reported and left as it is, so the run no longer ends in a traceback atiterdirbefore the members after it are placed, andmake parkno longer ends in one over a folder it cannot enter (#735) #772's head'ssiblings.pyandshape-doctor.py, the three new NOT A CLONE cases fail (3 failed, 31 passed). The real run's layout row issibling IRRS CLONE FAILED -, and the doctor gives'absent' == 'not-a-clone'false. The--makecase passes there too, becauseSKIPPED no clonewas already the behaviour.Commands, with a stub
gh(exit 97) first on PATH,GH_TOKEN=bogusand an emptyGH_CONFIG_DIR, ate966a684, on #772's head1d149933(maine3137010):Pinned shape copies
templates/family-root/scripts/siblings.pyis a family-root copy carried by digest. A holder pinned before this change shows anupstream-changedrow for it untilupdate-shape.pybrings it forward. No other pinned copy is touched.Notes
LINKS_HOLD, notconftest.WINDOWS_SKIP. It skips on Windows alike, but its reason is the true one, "a symbolic link needs a privilege on Windows".WINDOWS_SKIP's reason is a POSIX shell, which these tests do not need.siblings.py's--helpis unchanged.🤖 Generated with Claude Code
Summary by Sourcery
Handle dangling sibling links consistently as non-cloneable slots across sibling placement and shape diagnostics.
New Features:
Bug Fixes:
Tests: