Repository navigation
siblings.py: a file, or a folder make siblings cannot list or enter, 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) - #772
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>
Reviewer's GuideThe PR makes Sequence diagram for resilient sibling placementsequenceDiagram
participant Make as make siblings
participant Place as place
participant FS as Filesystem
participant Next as Later members
Make->>Place: place(root, row, urls, prefix)
Place->>FS: holds_git(target)
FS-->>Place: false or OSError
Place->>FS: not_a_clone(target)
alt file or unreadable directory
FS-->>Place: occupied slot
Place-->>Make: NOT A CLONE
Place->>FS: preserve existing target
else empty or absent target
FS-->>Place: cloneable target
Place->>FS: git clone
end
Place->>Next: continue placing later members
Sequence diagram for safe park or resume dispatchsequenceDiagram
participant Make as make park or resume
participant Dispatch as dispatch
participant FS as Filesystem
Make->>Dispatch: dispatch(root, row, urls, target)
Dispatch->>FS: holds_git(path)
alt path cannot be entered or has no .git
FS-->>Dispatch: false after OSError handling
Dispatch-->>Make: SKIPPED no clone
else working clone
FS-->>Dispatch: true
Dispatch->>FS: run requested make action
end
Flow diagram for unreadable sibling slot handlingflowchart TD
A[Inspect sibling target] --> B{"holds_git(target)?"}
B -->|yes| C[Use existing clone]
B -->|no or filesystem error| D{"not_a_clone(target)"}
D -->|file or unreadable directory| E[Report NOT A CLONE]
E --> F[Leave target unchanged]
F --> G[Continue with later members]
D -->|absent or empty directory| H[Clone member]
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-17T01:10:10Z) Independent review of #772 by RV-d (opus), on head Each slot on a real two-member holder (IRRS, then IRSS), measured with
Answers:
NITs:
Mutants: RV-d tried seven mutants of
Tests:
Merges. All clean:
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 35 minutes by commenting |
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>
…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) Closes #784. A dangling symbolic link at `../<Project>` read as an empty slot, because `exists` follows a link. `make siblings --dry-run` said `would clone`, the real run ended `CLONE FAILED` (git cannot clone onto a link to nothing, exit 128), and the doctor's `members` row called the slot `absent` and said `make siblings` places the member there. Now `not_a_clone` in `templates/family-root/scripts/siblings.py` answers "is a link to nothing", so `place` reports `NOT A CLONE`, in the finding the other such slots get, and leaves the link as it is. `make park` and `make resume` keep `SKIPPED no clone`. In `shape-doctor.py`, `unclonable` answers `dangling`, so `sibling_slot` says `not-a-clone` and the row says "is a link to nothing", and the doctor and `make siblings` agree again. `tests/test_shape_doctor.py` and `tests/test_family.py` hold a new slot, `a-link-to-nothing`, skipped on Windows. Lane 3's independent reviewer RV-d (opus) found it READY on `e966a684`, then stacked on #772 (#788 issuecomment-6230059337). Its optional NIT N2, that a dangling Windows junction still reads as an empty slot, is #793, in #794. After #772 landed as `112eeed2`, lane 3 restacked the branch as `bec71bb5` (#788 issuecomment-6243557591), in three merges: `f204abe1` takes #772's final head `bcb8e54a`; `5f7ea9b3` takes the squash `112eeed2`, ours for #772's four files, on which `git diff bcb8e54 112eeed` is empty; `bec71bb5` takes main `e62b5e17`. Against main the diff is #788's four files, the delta RV-d reviewed, `1d149933..e966a68`, patch for patch (+120/-53). On `bec71bb5`, the nine family and siblings files of its gate set pass (607 passed) and `tests/test_shape_doctor.py` passes (441 passed, 3 skipped). The restack carries lane 3's own check, not a reviewer's verdict. 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: #735 (comment)
Closes #735.
Lands after the v1.1.0 tag. The issue's own "Lands after: #705" is met: #705 landed as
3ceabef0.What changed, and why
make siblingsended in a traceback on three slots at../<Project>, exit 1, and never placed the members after them. #705's doctor calls each of these slotsnot-a-clone. Measured with this PR's tests against maine3137010'ssiblings.py: all 7 new cases fail.any(target.iterdir())atsiblings.py:558raisedNotADirectoryError.0311(it can be entered but not listed;711is common for another user's directory): the same line raisedPermissionError.000: the traceback comes one line earlier on Python 3.12.(target / ".git").exists()at:557raisesPermissionError, becausePath.existsignores onlyENOENT,ENOTDIR,EBADFandELOOP. The issue puts all three at:558; for mode000it is:557.templates/family-root/scripts/siblings.py:holds_git(:460) asks whether a path holds a.git, and reads anOSErroras "no". Two places use it:place's.gitquestion (:596);dispatch's.gitquestion (:768), the--makepath thatmake parkandmake resumerun. Python 3.12 raised there in a folder that cannot be entered, somake parkended in the same traceback. That member is nowSKIPPED no clone, as any member with no working clone is.not_a_clone(:471) gives theNOT A CLONEfinding's words for each slot nothing is cloned into::491);:496).These are the words the doctor's
membersrow uses for the same slots.git clonerefuses a folder it cannot read (measured:destination path ... is not an empty directory, exit 128), so nothing could be cloned there.place(:596-605) reports each such slot asNOT A CLONE, in the finding sentence the folder of files already had: "<who>:<at><what>, so this command will not write into it. Move it aside or name the<file|directory>something else; nothing here overwrites a<file|directory>somebody made." The slot is left exactly as it is, and the members after it are placed.shape-doctor.py: comments only, at:8012,:8163and:8182. Its output is unchanged. For these slots, the row says what stands there and nothing of whatmake siblingsdoes with it. That stays true of every holder, because a holder whose pinnedsiblings.pypredates this change still ends in the traceback. The comments now say so, where they saidmake siblings"ends in a traceback ... today".What is tested
tests/test_shape_doctor.py: the agreement testtest_make_siblings_dry_run_gives_the_rows_word_for_each_slot(:4152) loses its strict xfail ona-file.UNREADABLE_SLOTS(:4063): a file, and the0o311and0o000folders, which are skipped on Windows and as root.siblings.py --dry-runprintsNOT A CLONEfor each, the word the doctor'snot-a-clonemaps to.:4119) shares the same list.tests/test_family.py:test_siblings_reports_a_slot_it_cannot_read_as_not_a_clone(:1948) runs over the same three slots, on a real run in a correct layout. It asserts:sibling IRRS NOT A CLONE -;.gitwritten into the slot.test_a_make_verb_skips_a_folder_it_cannot_enter(:1981) runs--make park --dry-runover a mode-000folder: no traceback, andsibling IRRS SKIPPED no clone -.siblings.py, all 7 new cases fail (7 failed, 12 passed). They pass on this branch.Commands, at
1d149933on maine3137010, with a stubgh(exit 97) first on PATH,GH_TOKEN=bogusand an emptyGH_CONFIG_DIR: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.Coordination
#690 changes the same file. Its branch
fix/690-siblings-inputsis a WIP checkpoint with no PR yet.argument_faultand_bytes_forbetweenrun_member_bootstrapandplace, a block beforeif target == root:, and a line after the clone.project_id, and edits onlyplace's.gitand NOT A CLONE lines anddispatch's.gitline. So the two branches change different lines. A merge may still need a small context fix where siblings.py (make siblings): the printedmvgoes astray over an existing.holder/.folderor a dangling link, a lone surrogate or NUL inproject:is a traceback, a url with NEL or U+2028 is cut, two warnings print paths raw #690's block sits aboveplace's.gitline.No docs change: no doc quotes the NOT A CLONE finding or describes these slots, and
siblings.py's--helpis unchanged, sodocs/cli.mdis too.🤖 Generated with Claude Code
Summary by Sourcery
Make sibling and make operations safely handle files and unreadable directories by reporting them as non-clones and continuing without overwriting them.
Bug Fixes:
Enhancements:
Tests: