Repository navigation
adopt-project.py --source: a file, a directory inside a repository, an unknown ~user/, an empty value and owner/.git are not refused by name, so plan ends in a traceback, plans only a subtree or the current directory, or hands gh a name it cannot clone #796
Description
Goal: a --source (or a recorded source.local_path) that does not name a repository's top level, or a repository on GitHub, is refused by name with a way out. It never ends in a traceback, never plans the current directory or a subtree, and never reaches gh with a name it cannot clone.
Filed by lane openRepoShape-1 on Brett Heap's word of 2026-10-17T10:21:32Z, under lane 3's v1.1.1 rule (#473, issuecomment-6216697223). Lane 1's triage of its #457 lines grouped these lines into this one issue, because they share _source_spec, Source.open and Source.in_place. They come from:
- L1-64 and L1-77 (#457, comment);
- L1-88 (same comment);
- L1-95, L1-96, L1-100 and L1-101 (#457, comment).
Each line was measured again on main bf1f099b with a stub gh.
Milestone: v1.1.1, not a regression. Each of the following is an ordinary slip:
- passing a README or an archive as
--source; - running
plan --source .from a subdirectory; - one mistyped user name in
~user/; - an unset shell variable.
Lines
- L1-64: a file.
plan,plan --work-dir,check --sourceandexecute --sourceeach exit 1 withNotADirectoryError: [Errno 20] Not a directory: '<path>'. The traceback runsSource.in_place→_remote_repository→_origin_url→repo_shape.git_out. A directory that is not a repository is already refusedgit-failed(exit 2). - L1-88: a directory inside a repository.
plan --source <repo>/srcon a 10-file repository exits 0 with "2 files",local_path: "…/Thing/src"and 1 entry.plan --source .run inside<repo>/docsexits 0 with 1 file.checkthen exits 2:REFUSED a git or gh command failed … fatal: '…/Thing/docs' does not appear to be a git repository.executerefusesadopt-remote-unreadablebefore any leg.- Rider: the
sourcereport line namesorigin's repository even whenplanread a local directory.
- L1-95:
~nouser/x.plan --source '~nouser/x'exits 1 withRuntimeError: Could not determine home directory.from_source_spec'sPath(spec).expanduser().check --sourceandexecute --sourceexit 1 the same way.- A plan whose
local_pathis"~nouser/x"makescheckexit 1 atPlan._recorded_source. - bash passes an unknown
~userthrough unchanged, so one mistyped user name is enough.
- L1-96: an empty
--source. From inside a repositoryhere,plan --source ''exits 0 and writes a plan ofhere. So does--source "$SRC"withSRCunset.- Outside any repository it is refused
git-failed: git rev-parse main in <cwd>, which never names--source. check --source ''andexecute --source ''drop the empty value (if override:) and read the plan's own record.
- Outside any repository it is refused
- L1-100 (rider):
owner/.git.--source owner/.gitandhttps://github.com/owner/.gitreachgh repo clone owner/.gitwith the targetsource-readonly/.git. They are then refusedsource-unclonablewith agh auth statusremedy, because_github_namestrips.gitonly from a longer segment. - L1-101 (rider):
www.github.com.--source https://www.github.com/testorg/Thingis refusedsource-unresolvableas "a repository on www.github.com".www.github.com/testorg/Thingis refused as neither a path nor a name. - L1-77 (rider): a source that lost a blob.
git ls-tree -r -l HEADprintsBADfor the size and still exits 0, andplanthen exits 1 withValueError: invalid literal for int() with base 10: 'BAD'atSource.tree.
Direction
- The checks, in
_source_specandSource.open, before any git runs:- a path that exists but is not a directory;
- a local directory that is not a repository's top level:
git rev-parse --show-prefixis not empty. The refusal names--show-toplevel. - an empty
--source, refused in the style ofpin-source-no-path;open_sourcetestsoverride is not None.
- Each is refused by name, with a remedy: pass the repository's top-level directory, or an
org/repo. - The
sourceline names the local path, with the repository beside it. - Expanding
~: useos.path.expanduser, which leaves an unknown~useras typed, at eachPath(...).expanduser().- An unknown user then becomes
source-unresolvablefor--source. - In a recorded
local_pathit becomes a path that is gone:plan-source-gone, or a re-clone undercloned: true.
- An unknown user then becomes
_github_namerefuses the repository segment.git.www.github.comreads asgithubproxy.fjygbaifeng.eu.orgin_repository_in_urland in the bare url form.Source.treerefuses a size that is neither-nor digits, naming the path andgit fsck.
Tests: extend tests/test_adopt_source_clone_record.py and tests/test_adopt_work_dir_refusal.py.
- For each line,
plan,checkandexecuteexit 2 with the code: no traceback, no plan written, and noghcall where none is needed. - Controls: the top level,
.at the top level, anorg/repo, andhttps://github.com/o/r. - Mutation-check each guard.
Not here: L1-65 (a source-readonly that is a file) goes with the clone-removal hardening issue, beside Source.clone.
Overlaps: #749 (#652) rewrote --source reading; #797 (_default_branch) and #798 (_create_leg_remotes) are lane 1's siblings in the same file.
Lane: openreposhape-1 (openRepoShape-1)
🤖 Generated with Claude Code
Activity
brettheap commentedon Oct 17, 2026
CLAIMED — lane openRepoShape-1, session 300f8f46-004a-4e72-8587-4f192be2e108@Eagle, 2026-10-17T10:43:08Z, for #796
Logged in
lanes/log/openRepoShape-1.mdated0308db2c2633a7c518e5bef9137c4ad68cc826.The three reads (lane-collision-protocol Rule 1):
[-]adopt-project.py: a `--source` that is a file ends `plan`, `check` and `execute` in a NotADirectoryError traceback, so a mistyped path gets no refusal and no way out[/-][+]adopt-project.py `--source`: a file, a directory inside a repository, an unknown `~user/`, an empty value and `owner/.git` are not refused by name, so `plan` ends in a traceback, plans only a subtree or the current directory, or hands `gh` a name it cannot clone[/+]tests/test_adopt_source_clone_record.py: `.` and `..` as the reposito…
tests/test_adopt_source_clone_record.py: `planned_here` stands in for…
adopt-project.py: a directory inside a git directory, a `.git` reposi…
Merge origin/main 3fb30a8 into fix/796-adopt-source-spellings
Merge main fc289dd into fix/803-adopt-clone-claimed (#803)