Skip to content

openRepoShape: --doctor's shape_checkout runs git clone before checked_ref, so a ref it refuses (a.lock/b, a//b, one over 255 characters) costs a whole clone first, and where the clone fails the ref's refusal is never reached #942

Closed

Description

@brettheap

Goal: the launcher's --doctor checks $OPENREPOSHAPE_REF before it clones the standard. A ref checked_ref refuses (a.lock/b, a/.b, a//b, a/b/, a., topic.lock, one over 255 characters) then makes no clone, and the test that names this order pins it.

Filed by lane openRepoShape-2 on Brett Heap's word ("file all", 2026-10-18T14:45:31Z).

Lands on: main at 50178305, the v1.1.1 release commit. Every path:line below is read there. None of the six open PRs touches openRepoShape or tests/test_openreposhape_command.py (the coordinator's check, 2026-10-18T14:48Z).

Lines

  • shape_checkout clones, then checks the ref.
    • The clone is openRepoShape:834: git clone --quiet -- "$url" "$SHAPE_DIR" || (:834-837). The check is :839, checked_ref "$REF", inside if [ "$REF_NAMED" -eq 1 ]; then (:838), and git checkout is :845.
    • Nothing between them needs the clone. :835-837 is the clone's own refusal text and :838 is the if. checked_ref (:920-924) calls ref_fault (:882-898), which reads only the value and the name it is given. Nothing in ref_fault or checked_ref looks at $SHAPE_DIR.
    • run_doctor (:1010-1024) reaches shape_checkout only where no checkout of the standard sits beside the command: the installed copy, or a script arriving on stdin.
  • A refused ref costs a whole clone first.
    • Measured with an installed copy of the launcher at 50178305 (no checkout beside it), --doctor <an empty directory>, OPENREPOSHAPE_REPO a local bare repository (a copy of this repository's object database: 14,372 loose objects and 48 packs), bash 5.2.21, git 2.43.0, LC_ALL=C.UTF-8, and a git first on PATH that logs its arguments and runs /usr/bin/git. The host's load average was 51, which is why the same clone took 3.6 s in one row and 16.3 s in another:

      OPENREPOSHAPE_REF exit git clone git checkout whole run left in $TMPDIR
      a.lock/b 2 1 0 15.7 s nothing
      a/.b 2 1 0 17.7 s nothing
      a//b 2 1 0 9.3 s nothing
      a/b/ 2 1 0 4.4 s nothing
      a. 2 1 0 5.2 s nothing
      topic.lock 2 1 0 4.5 s nothing
      a 256 times 2 1 0 13.7 s nothing
      main, a ref that is taken 2 (the empty directory is no shape root) 1 1 16.1 s the clone, kept by design (openRepoShape --doctor, the form AGENTS.md names first and the one --install gives a person, prints every NEXT command as a path into its temporary clone of the standard, which its EXIT trap deletes before the person can paste the command, so each one fails with can't open file; and it refuses --json and --placement-plan, which AGENTS.md's doctor steps 7 and 4 use #500)
    • Each refusal is ref_fault's sentence for that value, as it is without the clone: REFUSED: $OPENREPOSHAPE_REF is 'a.lock/b', which is not a branch, tag or commit this tool will pass to `git checkout`: a ref starts with an ASCII letter or digit, uses only ASCII letters, digits, '.', '_', '/', '-', has no '..' (git reads it as a revision range), no empty part between slashes ('//', or a '/' at the end), no part that starts with '.' or ends in '.lock' (the name git gives the lock file it writes beside a ref), and does not end in '.'. The 256-character one is $OPENREPOSHAPE_REF is 256 characters long; a branch, tag or commit this tool will pass to `git checkout` is at most 255 characters. (:887).

    • The size of the clone (--doctor's clone has no --depth, :821-825): du -sk of the clone is 418,780 KB in 14,910 files. A clone of a local path hardlinks objects/ (404,116 KB of that), so about 14.7 MB is new on disk, the 366 files of the working tree. A URL clone sends a pack instead: the objects reachable from that copy's heads and tags, git rev-list --objects --branches --tags | git pack-objects --stdout, are 9,504,547 bytes (8,087 objects).

    • The folder is removed: every refused row leaves $TMPDIR empty, because the EXIT trap removes the clone. Only a doctor that ran keeps one.

  • Where the clone fails, the ref's refusal is never reached.
    • Measured with OPENREPOSHAPE_REPO=/nonexistent/openRepoShape.git and OPENREPOSHAPE_REF=a.lock/b: exit 2 and REFUSED: could not clone /nonexistent/openRepoShape.git into a temporary directory, so there is no standard to check against. `--doctor` needs one: ..., after 1 git clone. The ref is not named. With the check first (a scratch copy), the same run is the ref's refusal and no git call.
    • So offline, or with a mirror that is down, a person who typed a bad ref is told to make the clone work, then told the ref is bad once it does.
  • refuse_bad_values checks only a ref's characters, so only those are caught before the clone.
  • The test names this order, and does not pin it.
    • test_a_ref_the_doctor_would_check_out_is_validated (tests/test_openreposhape_command.py:1718-1743), five refs (-x, --upload-pack=touch /tmp/pwned, 256 a, refs/heads/.., x.lock). openRepoShape in Git Bash: the machine: row finds python, a drive-letter $OPENREPOSHAPE_REPO is a path, a Windows-spelled $OPENREPOSHAPE_BIN_DIR is respelled or refused, and tests-git-bash runs #598's installer cases (#649) #656 left its docstring, :1721-1729:

      "$OPENREPOSHAPE_REF reaches git checkout, so it is checked first. ... Run from STDIN so the clone path is the one taken: the command clones this checkout first, then checks the ref, and refuses before git checkout is ever handed it."

    • It asserts exit 2, OPENREPOSHAPE_REF and git checkout in stderr, and that the 256-character value is not echoed. It does not look at what ran, so it passes with the check above or below the clone. Measured, on a clone of the repository at 50178305 with and without the call moved: this test (5 cases), test_a_checkout_without_the_doctor_refuses_by_name and the 14 cases of test_a_clone_is_handed_a_path_or_url_as_it_is are 20 passed on both, unchanged.

    • It runs OPENREPOSHAPE_REPO as this checkout, so each of its five cases makes a real clone of the whole repository: the 20 took 188.4 s as it is and 5.4 s with the call moved (a load average above 100 on both runs).

What is checked today

Direction

  • Call checked_ref "$REF" before the clone, in shape_checkout, between url="$(shape_clone_url)" (:831) and workdir (:832): [ "$REF_NAMED" -eq 0 ] || checked_ref "$REF", and drop the call at :839. The diff is one line added and one removed (measured on a scratch copy).
    • Keep it in shape_checkout, not in refuse_bad_values: the up-front check is characters only on purpose (above), and --doctor beside a checkout never uses the ref.
  • Make the test pin it: a git that leaves a mark if it is asked to clone, as a_repository_to_clone does (tests/test_openreposhape_command.py:1264-1283) or as cloned_for does (:2157-2183). Each of the five refs, and a.lock/b, a//b, a., a/b/ and topic.lock, makes no clone and ends in the refusal with exit 2; a ref that is taken still clones once and checks out once. The test then needs no real clone.
  • Reword the docstring (:1721-1729) to say the check comes first and the refusal arrives before any clone, as it said before openRepoShape in Git Bash: the machine: row finds python, a drive-letter $OPENREPOSHAPE_REPO is a path, a Windows-spelled $OPENREPOSHAPE_BIN_DIR is respelled or refused, and tests-git-bash runs #598's installer cases (#649) #656, which is then true.
  • Nothing else says the order: a search of docs/, README.md, AGENTS.md and openRepoShape for "clones this checkout", "before any clone", "checks the ref" and "clone comes first" finds no sentence to change.

Verify

  • tests/test_openreposhape_command.py passes on Linux.
  • New cases: a refused ref makes no clone (the fake git sees no clone) and no checkout; a good ref still clones once and checks out once; the refusal's words are ref_fault's; and OPENREPOSHAPE_REPO=/nonexistent/... with a bad ref ends in the ref's refusal, not "could not clone".
  • A stand-in of that test, run in a scratch copy against the launcher as it is and with the call moved (ten refs, a fake git whose clone fails and logs, plus a good ref): 10 failed, 1 passed as it is (each refused ref asked for a clone), 11 passed with the call moved.
  • Mutants for the writer to run, each of which the new cases must kill:
    • the check moved back below the clone (measured: the stand-in's 10 failures);
    • the call dropped;
    • the test of REF_NAMED inverted, so a named ref is not checked.

Overlaps

Parent: #459: the launcher's own items went there, such as #649's machine: block and drive-letter lines, and #649's docstring is this issue's source.

Milestone: v1.2.0. v1.1.1 is released, and lane 3 places issues. A refused ref still exits 2 with the right words wherever the clone works; what is wrong is the wasted clone, and the words where it fails. It needs a ref the person mistyped in $OPENREPOSHAPE_REF, run with --doctor where no checkout sits beside the command.

🤖 Generated with Claude Code

Activity

  1. added this to the v1.2.0 milestone on Oct 18, 2026
  2. brettheap commented on Oct 18, 2026

    @brettheap
    ContributorAuthor

    CLAIMED — lane openRepoShape-2, session 81650e29-c906-4fe8-96c9-55580bfe0c44@Eagle, 2026-10-18T17:39:38Z, for #942

    Logged in lanes/log/openRepoShape-2.md at 99c4e3678a3f94be365c2a5082e108d68c3cee22.

    The three reads (lane-collision-protocol Rule 1):

    1. existing `CLAIMED —` comments on opensoft/openRepoShape#942:
       none
    2. `gh pr list --repo opensoft/openRepoShape --state all --search "#942"`, kept where the row or its body names `#942`:
    947	standard.py: the package's `openRepoShape` refuses a repository or ref holding U+202E, U+200B or another character the launcher refuses, by code point, before `--version` or any `git` call names it, and refuses `a.lock/b`, `a/.b`, `a//b`, `a/b/` and `a.` before it clones, in the launcher's words (#939, #941)	l3-939-941-package-standard	OPEN
    3. `git ls-remote --heads git@github.com:opensoft/openRepoShape` branches naming `942` as a whole token:
       none
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions