Repository navigation
openreposhape package: ref_fault keeps the old ref rule, so it takes a.lock/b, a/.b, a//b, a/b/ and a., clones the standard in full and fails at git checkout, where the launcher, setup.sh and install.sh refuse them first (#874) #941
Description
Goal: the package's ref_fault holds the rule that the launcher, setup.sh and install.sh hold since #874, in the same words. Then a ref git refuses part by part (a.lock/b, a/.b, a//b, a/b/, a.) is refused before any git call, not after a full clone of the standard, and a test holds the package's copy to git and to the launcher's words as it holds theirs.
Filed by lane openRepoShape-2 on Brett Heap's word ("file all", 2026-10-18T14:45:31Z).
- Source: w874, lane 2's writer of setup.sh, install.sh and the openRepoShape command: each keeps its own copy of the old ref rule (
*..* | *.lock), so a ref git refuses part by part (a.lock/b,a/.b,a//b) clones the standard before it fails #874 (PR setup.sh, install.sh and openRepoShape: a ref git refuses part by part (a.lock/b,a/.b,a//b,a/b/,a.) is refused by each of them before the clone, the fetch or the record, and each refusal states git's rule #875), listed it under "Found and left alone":standard.py:215is "a fourth copy of the old rule and the old sentence", its docstring callsref_fault"the launcher'sref_fault, in its order and its words", and "it needs its own issue". rv874, the independent reviewer of setup.sh, install.sh and openRepoShape: a ref git refuses part by part (a.lock/b,a/.b,a//b,a/b/,a.) is refused by each of them before the clone, the fetch or the record, and each refusal states git's rule #875, confirmed it by probe (its SHOULD 2): a refused-by-git ref gets onegit clone, then the checkout refuses, whiletopic.lockis refused before any clone. setup.sh, install.sh and openRepoShape: a ref git refuses part by part (a.lock/b,a/.b,a//b,a/b/,a.) is refused by each of them before the clone, the fetch or the record, and each refusal states git's rule #875's body names it as a follow-up. - Why it is not setup.sh, install.sh and the openRepoShape command: each keeps its own copy of the old ref rule (
*..* | *.lock), so a ref git refuses part by part (a.lock/b,a/.b,a//b) clones the standard before it fails #874's: setup.sh, install.sh and the openRepoShape command: each keeps its own copy of the old ref rule (*..* | *.lock), so a ref git refuses part by part (a.lock/b,a/.b,a//b) clones the standard before it fails #874 held the three shell copies,setup.sh,install.shandopenRepoShape, which arrive alone down a pipe. The package is Python insrc/openreposhape/and ships in a wheel, so its copy is a fourth file with its own test. - Why it is a new issue: the tracking issues' rule is that a new edge case goes on a checklist (Tracking: setup, scaffold, family and the shared helpers, creating projects and families #459, Tracking: the test suite, CI and the docs #461). Brett Heap's word overrides it for this one.
path:line is at the v1.1.1 release commit 50178305, which holds #874 (33c5128b, PR #875) and #857 (1ef1a018, PR #873).
- How it was measured: bash 5.2.21, Python 3.12.3 and git 2.43.0, each run with an explicit minimal environment, a stub
ghandcurlfirst onPATH,GH_TOKEN=bogus, an emptyGH_CONFIG_DIR,GIT_SSH_COMMAND=falseandGIT_CONFIG_GLOBAL=/dev/null. - No request left the machine:
OPENREPOSHAPE_REPOwas a local bare clone of this repository. - "The package" is a copy of
src/openreposhape/laid out as the wheel lays it, with no checkout beside it, asinstalled_copyintests/test_openreposhape_package.pymakes one.
Lines
-
ref_fault's shape check is the old line.-
The line is
standard.py:215:if not REF_RE.fullmatch(ref) or ".." in ref or ref.endswith(".lock"):. It asks..and.lockof the whole name only, which is what setup.sh, install.sh and the openRepoShape command: each keeps its own copy of the old ref rule (*..* | *.lock), so a ref git refuses part by part (a.lock/b,a/.b,a//b) clones the standard before it fails #874 changed in the other three. -
The launcher's (
openRepoShape:895),setup.sh's (:247) andinstall.sh's (:176) pattern list is the same bytes in all three:[!A-Za-z0-9]* | *..* | */.* | *.lock | *.lock/* | *//* | */ | *. | *[!A-Za-z0-9._/-]*. -
Measured (the package's
ref_fault, the launcher's ownref_faultlifted out and run by/bin/bash,setup-project.py'schecked_refof setup-project.py: a passed-through-- --dry-runstill offersgh auth setup-git, which writes the person's global git config on a typedyes, andchecked_refpassesa.lock/b, which git refuses #857, andgit check-ref-format --branch, each asked of the same ref):ref git launcher, setup.sh,install.shsetup-project.pypackage a.lock/brefuses refuses refuses takes a/.brefuses refuses refuses takes a//brefuses refuses refuses takes a/b/refuses refuses refuses takes a.refuses refuses refuses takes topic.lockrefuses refuses refuses refuses x/y.lock/zrefuses refuses refuses takes release.lock/v1refuses refuses refuses takes a/b/.c/drefuses refuses refuses takes a.lock/refuses refuses refuses takes a/b.refuses refuses refuses takes a/.refuses refuses refuses takes a./b,a.lockb,fix/_tmp,Feature/ABC-123takes takes takes takes HEADrefuses takes takes takes -
HEADis the one row where git disagrees with every other column, and they are right:git check-ref-format --branchrefuses it because it would berefs/heads/HEAD, andgit checkout HEADworks (rv874). -
Over every name of up to five pieces from
a,0,.,/,-and.lockthatREF_REtakes (3,110 names), the package disagrees with git on 1,122. The launcher's line disagrees on 0, and so doessetup-project.py's.
-
- A ref the package takes and git refuses reaches git: one
git ls-remote, one fullgit clone, onegit checkout, and then the refusal.-
prepare(standard.py:621) askstarget(:635), which takes the ref, thenremote_commit(:644), which asksgit ls-remoteand finds nothing for a name git refuses, so the commit is unknown.clone_into(:482) then runsgit clone --quiet --no-checkout(:507), with no--depth, because the doctor's currency row needs the history (standard.py:14to:16).git checkout(:519to:521) fails. -
Measured with
--doctor ., an unstamped copy,OPENREPOSHAPE_REPOa local bare clone, andGIT_TRACEwritten to a file, because the package captures git's stderr:OPENREPOSHAPE_REFgit ls-remotegit clonegit checkoutexit a.lock/b1 1 1 2 a/.b1 1 1 2 a//b1 1 1 2 a/b/1 1 1 2 a.1 1 1 2 topic.lock0 0 0 2 -
Each of the five ends
REFUSED: cloned <repo> but could not check out 'a.lock/b': fatal: invalid reference: a.lock/b. Set $OPENREPOSHAPE_REF to a ref that repository carries, or $OPENREPOSHAPE_REPO to one that carries this one.Fora.git's words end in a period, so the line readsinvalid reference: a... -
topic.lock, which the old line refuses, is refused before any git call, with the old sentence. -
A scaffold run (
Atlas --org acme --shape-ref a.lock/b, andOPENREPOSHAPE_REFset toa/.b) andshape-doctor --helpwithOPENREPOSHAPE_REFset toa/.beach made the same 1, 1, 1.
-
- The sentence (
standard.py:216to:219) states the old rule, and says "letters" where the others say "ASCII letters".- Measured for
topic.lock:REFUSED: $OPENREPOSHAPE_REF is 'topic.lock', which is not a branch, tag or commit this tool will pass to `git checkout`: a ref starts with a letter or digit, uses only letters, digits, '.', '_', '/', '-', has no '..' and does not end in '.lock'. - The launcher's,
setup.sh's andinstall.sh's refusals end in one sentence, byte for byte the same in the three: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 '.'.It isREF_RULE_WORDS(tests/conftest.py:2473).
- Measured for
- The docstring (
standard.py:199to:203) saysref_faultis "the launcher'sref_fault, in its order and its words". It is not, in the words and the rule (here) and in the order (the drawn-as-another check install.sh and openRepoShape: a$OPENREPOSHAPE_BIN_DIRholding a bidi override, U+200B, U+2028 or U+FEFF passes #804's control-character check and is echoed as typed, so the PATH note can show a directory as another #837 put between the length and the control character, which is openreposhape package:openRepoShape --versionprints a repository holding U+202E or U+200B as typed and exits 0, and a ref holding either is refused with the value as typed, where the launcher refuses both before it prints (#866) #939). The comment at:70states the order too. - No test holds the package's rule to git's.
REF_PARTS(tests/conftest.py:2438, 36 rows),git_takes_ref(:2481, which asks git),REF_RULE_WORDS(:2473),assert_a_copy_answers_as_git_does(:2491) andassert_the_refusal_states_the_ref_rule(:2506) have three readers:tests/test_setup_sh.py:925,tests/test_install_sh.py:432andtests/test_openreposhape_command.py:2536.test_a_ref_is_checked_before_anything_is_cloned(tests/test_openreposhape_package.py:482) has six refs:-x,--upload-pack=touch /tmp/pwned, 256 characters,refs/heads/..,x.lockand a two-line value. None is a part-by-part case.
Which runs use the rule
target()(standard.py:249) is called byprint_version(cli.py:383) and byprepare(standard.py:635).prepareis called by--doctor(cli.py:428), a scaffold run (:464, with--shape-refas the typed ref) andrun_tool(:557), forscaffold-project,adopt-project,update-shapeandshape-doctor.--preflightdoes not use it:scaffoldreturns atcli.py:460to:463, beforeprepare. Measured:--preflightwithOPENREPOSHAPE_REFset totopic.lockgave the preflight's own verdict (exit 1 here, becauseghwas not authenticated) and no ref refusal.- Beside a checkout
preparereturns first (standard.py:631), and so doesprint_version, so neither reads the ref. --versionwithOPENREPOSHAPE_REFset toa.lock/bexits 0 and prints@ a.lock/btoday. The port makes it exit 2, as it already does fortopic.lock. The launcher's--versionprints such a ref as typed, because openRepoShape:--versionand two fetch refusals print$OPENREPOSHAPE_REPOand$OPENREPOSHAPE_REFwith no check, so an escape or a bidi override in either reaches the terminal as typed, and a scaffold run sends its fetch with them #866 asks a ref only its characters up front; that difference is there already.
Direction
- Port setup.sh, install.sh and the openRepoShape command: each keeps its own copy of the old ref rule (
*..* | *.lock), so a ref git refuses part by part (a.lock/b,a/.b,a//b) clones the standard before it fails #874's rule and sentence tostandard.py.- The rule is the nine patterns, as
REF_RE.fullmatch,".." in ref,"" in ref.split("/")(//, or a/at the end), a part that starts with., a part that ends in.lock(the last part too), and a name that ends in..setup-project.py'swhy_not_a_ref(:580) is the same rule in Python, and asks.., an empty part, a part that starts with.,.lockat the end, a part that ends in.lock, and.at the end, in that order. - The sentence is the launcher's, word for word (
REF_RULE_WORDS), after the opening$OPENREPOSHAPE_REF is '<ref>', which is not a branch, tag or commit this tool will pass to `git checkout`:thatref_faulthas already.--shape-reftakes the same sentence, with its own opening. - Measured with a prototype of exactly this (scratch only): over the 3,110 names the package disagrees with git on 0 and with the launcher's line on 0; the five refs above, a scaffold run's
--shape-ref a.lock/bandshape-doctorwithOPENREPOSHAPE_REFset toa/.beach make 0git ls-remote, 0git cloneand 0git checkout, and endREFUSED: ... a ref starts with an ASCII letter or digit, ...;--versionwitha.lock/bexits 2; the 58 existing package tests still pass, so none states the old rule or sentence. - The package's order is already right:
target(:635) comes beforeremote_commit(:644) and the clone. Only the rule is old.
- The rule is the nine patterns, as
- Copy it, with a parity test, not a shared table.
- The package ships alone and may not read the launcher,
setup.shorinstall.shat run time. setup.sh, install.sh and the openRepoShape command: each keeps its own copy of the old ref rule (*..* | *.lock), so a ref git refuses part by part (a.lock/b,a/.b,a//b) clones the standard before it fails #874 wrote the list out in each file for the same reason, and tied the three with tests. setup-project.pyis carried in the wheel (standard.py:394), but it is a script, with a hyphen in its name and an argument parser at its entry, sostandard.pycannot importwhy_not_a_reffrom it.- Asking git at run time (
git check-ref-format --branch, asscripts/shape_materialize.py:1275does) does not fit here.--versionandtargetrun before the package knows git is installed (preparelooks for it at:639, aftertarget), and--branchrefusesHEAD, which every copy takes. - The package's test is the fourth reader of
REF_PARTS:package_module("standard", monkeypatch).ref_fault(name, "$OPENREPOSHAPE_REF")for each row, in process, offline, withassert_a_copy_answers_as_git_does("standard.py", ...)andassert_the_refusal_states_the_ref_rule. Git is asked each time and nothing is copied from its answer.
- The package ships alone and may not read the launcher,
- Fix the docstring (
standard.py:199) and the comment at:70: say whatref_faultholds, in the order and words it has once both issues have landed, and which test holds it to the launcher's. - No doc changes. No doc,
--helptext or release note states the rule:git grepfor the old sentence finds onlystandard.py:219.
Verify
tests/test_openreposhape_package.pypasses on Linux (58 passed at50178305).tests/test_setup_sh.py,tests/test_install_sh.pyandtests/test_openreposhape_command.py, the other three readers, pass unchanged.- New cases:
- one parity case per
REF_PARTSrow againststandard.ref_fault, as above. Measured with a scratch module: 36 cases. At50178305, 19 fail (the 13 names the old line takes, and 6 that it refuses with the old sentence) and 17 pass. With the prototype all 36 pass. - the five refs of setup.sh, install.sh and the openRepoShape command: each keeps its own copy of the old ref rule (
*..* | *.lock), so a ref git refuses part by part (a.lock/b,a/.b,a//b) clones the standard before it fails #874 added totest_a_ref_is_checked_before_anything_is_cloned: each exits 2 with$OPENREPOSHAPE_REFin the refusal and no "clone" in it, and the repository there does not exist. Measured: 5 fail at50178305, 5 pass with the prototype.
- one parity case per
- The disagreeing refs are refused before any clone: the five of the table above, with
GIT_TRACEor a stubgitfirst onPATH, make nogitcall. - Mutants, each killed (measured on the prototype, with the cases above):
- The old shape line back, with the new sentence: 18 fail, the 13 names it takes and the 5 refs of the run.
- No empty-part check: 4 fail (
a//b,a/b/, and those two in the run). - No check for a part that starts with
.: 5 fail (a/.b,a/.b/c,a/b/.c/d,x/.y/z/w, anda/.bin the run). .lockasked of the end of the name only: 4 fail (a.lock/b,x/y.lock/z,release.lock/v1, anda.lock/bin the run).- No check for a name that ends in
.: 3 fail (a.,a/b., anda.in the run). - A part that ends in
.refused (over-refusal): 1 fails,a./b. - The first character lower case only (over-refusal): 1 fails,
Feature/ABC-123. - A part that starts with
_or-refused (over-refusal): 2 fail,fix/_tmpandfix/-wip. - The sentence without its empty-part clause: 19 fail, every refused row.
Overlaps
- No open PR touches
src/openreposhape/or its tests (checked at 2026-10-18T14:48Z). - openreposhape package:
openRepoShape --versionprints a repository holding U+202E or U+200B as typed and exits 0, and a ref holding either is refused with the value as typed, where the launcher refuses both before it prints (#866) #939, filed beside this one for the package's--versionand its drawn-as-another check, editsref_faultandtests/test_openreposhape_package.pytoo. Its hunks and this one's do not touch: a three-way merge of the two prototypes'standard.pywithgit merge-fileis clean. Whichever lands second merges the other. - openRepoShape:
--doctor'sshape_checkoutrunsgit clonebeforechecked_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, for the launcher'sshape_checkout, which clones beforechecked_ref, filed with this one, is another file. The package has no such order problem, as above. - The package is not a pinned shape copy, so no
upstream-changedrow follows.
Parent: #459. It tracks setup and scaffold, and the launcher's own items went there. #874's rule is setup's and the launcher's, and this is its fourth copy.
Milestone: v1.2.0. v1.1.1 is released. Each line needs a ref that a person typed and git refuses, and the run ends in a refusal either way, one full clone later. It is not a regression: the package has had this rule since #563, and #874's launcher copies were not a regression either.
🤖 Generated with Claude Code
Activity
brettheap commentedon Oct 18, 2026
CLAIMED — lane openRepoShape-3, session b30e8b49-f249-4668-adb1-1dbfa93c09e1@Eagle, 2026-10-18T16:12:57Z, for #941
Logged in
lanes/log/openRepoShape-3.mdat6d93d8f74e962c3eb5f68508f622ee5e2419ffa9.The three reads (lane-collision-protocol Rule 1):
standard.py: with both values bad, `--doctor` and a scaffold run name…