Repository navigation
bootstrap.py (the assembly root's): a SHAPE_UPSTREAM_PATH directory nobody may enter ends in a traceback, a validator's refusal is reported as FAILED, exit 1, a reftable leg's cherry-pick goes unseen, and docs/cli.md says bootstrap places each leg AT the pin with no condition #764
Description
Goal: make bootstrap never ends in a traceback over the optional upstream notice, tells a validator's refusal from its findings, sees an operation in progress on either ref backend, and every text that says what it places says the condition #704 now holds it to.
Filed by lane openRepoShape-5, from rv704's checklist candidates C1 to C4 on #704's PR (#745, head 7bdfa3cc, "not taken here as the coordinator ruled"). C5, the strict UTF-8 read in _upstream_holding, is not here: it is the decode #710 changes.
Lands after: lane 5's #704 and #694 (PR #745, fix/704-bootstrap-leg-moves, stacked on #682, fix/648-bootstrap-and-gate-order). _in_progress and the narrowed AGENTS-shape sentence are in #745; the other lines read the same on main. Line numbers are at main 66b230ed unless a line says 7bdfa3cc.
Pinned copies. templates/assembly-root/scripts/bootstrap.py, templates/assembly-root/Makefile and templates/assembly-root/AGENTS-shape.md are pinned in every project, and the family holder's AGENTS-shape.md in every holder. Bundle the edits with #710's (the same bootstrap.py, lands once) so each project takes one upstream-changed row per file.
Lines
- C1, a
SHAPE_UPSTREAM_PATHdirectory nobody may enter ends in a PermissionError traceback, exit 1.shape_upstream_notice(templates/assembly-root/scripts/bootstrap.py:642-678;:854-894at7bdfa3cc) runsPath(upstream).is_dir()and_try_git(["rev-parse", "HEAD"], Path(upstream))(:663-665)._try_gitcatchesRefusalonly, so thePermissionErrorthatsubprocessraises for a working directory it cannot enter leaves the function, andmainends in the traceback. The docstring says the opposite (:649-650: "silent ... and it never fails the bootstrap"). Measured by rv704 on head and on base, on this host's Python 3.12. bootstrap.py (the family root's and the assembly root's):make bootstrapwith no git on PATH ends in aFileNotFoundErrortraceback, exit 1, where the validators refusegit-not-runnable, exit 2 #694 (in bootstrap.py and AGENTS-shape.md: a leg with an operation in progress or an ignored file in the way is refused, P9 names the branch it left, and no git isgit-not-runnable, somake bootstraploses nothing (#704) (#694) #745) makes_git_runsskip anOSErrorthat names a directory ("whichsubprocessraises for acwdit cannot enter, is not git's, and goes on as it did"), so it leaves exactly this one. EveryPath.is_file()/is_dir()/exists()guard in the shipped tools answers False to any OSError on Python 3.14 (3.12 and 3.13 raise PermissionError), so a directory this user cannot search reads as ABSENT: validate-pins.py skips its workflow@<sha>check, update-shape.py sayscopy-missingandupdate-pin-missing("adopt the project") for files that are there, the doctor says DRIFTED (5 copy-missing), and bump-leg.py's remaining guards, and every other tool's, skip or misreport instead of refusing by name #430's sweep ofPath.is_dir()guards is the sibling for the other half (3.12 and 3.13 raisePermissionErrorwhere 3.14 answers False). Direction: the notice catchesOSErroraround the two reads and says nothing, as an absent answer does; add one test withSHAPE_UPSTREAM_PATHset to a mode-000 directory (skipped under root and on Windows) that asserts exit 0 and no traceback. - C2, a validator's exit-2 refusal is reported as
bootstrap FAILED: pins (exit 2), exit 1. Measured by rv704 with no git onPATH, in a plain clone._run_neutral_validators(:845-870) puts every non-zero code infailedas"<label> (exit <code>)", andmainprintsbootstrap FAILED: ...and returns 1 (:906-908). The validators exit 1 for findings and 2 for a refusal (REFUSED ... (exit 2)), and bootstrap's own refusals are exit 2 since bootstrap.py (the family root's and the assembly root's):make bootstrapwith no git on PATH ends in aFileNotFoundErrortraceback, exit 1, where the validators refusegit-not-runnable, exit 2 #694 (git-not-runnable), so a person readingFAILEDand exit 1 is told a finding where the validator refused. This needs a ruling. The shape of a fix ismainreturning 2 when any validator exited 2 and sayingREFUSEDfor that label, but a script that testsmake bootstrap's exit would see a change; the other answer is to leave it and say inAGENTS-shape.mdthatFAILED (exit 2)is a refusal. - C3,
docs/cli.md:47says bootstrap "places each leg on its tracking branch AT the pinned commit", with no condition.scripts/render-cli-reference.py:181-184generates it;docs/cli.mdis checked against it bytests/test_cli_reference.py. bootstrap.py and AGENTS-shape.md: a leg with an operation in progress or an ignored file in the way is refused, P9 names the branch it left, and no git isgit-not-runnable, somake bootstraploses nothing (#704) (#694) #745's narrowed sentence in the assembly root'sAGENTS-shape.md(:100-101at7bdfa3cc, rulings R1 and R2) says it "places a leg on its tracking branch AT the pin only where that loses no commit, and otherwise leaves its checkout where it is, saying why". Three more pinned sentences say "where that loses no commit, or says why not" and R2 left them, because "or says why not" keeps them true:templates/assembly-root/Makefile:34-35, the holder'stemplates/family-root/AGENTS-shape.md:63-65and itstemplates/family-root/README.md:14-17. Direction: the generator's sentence takes the condition,docs/cli.mdis regenerated, and the other three take R2's words or are left, in the same re-pin; the author decides and says which. - C4, on a reftable leg
CHERRY_PICK_HEADandREVERT_HEADmay live in the ref store, not as files, so the in-progress check would not see them._in_progress(:468-486at7bdfa3cc) asksos.path.lexists(gitdir / row[0])for each ofIN_PROGRESS(:117-124), which holdsMERGE_HEAD,CHERRY_PICK_HEADandREVERT_HEADamong the rows. Reasoned only: this host has git 2.43, which has no reftable (rv704; bootstrap.py and AGENTS-shape.md: a leg with an operation in progress or an ignored file in the way is refused, P9 names the branch it left, and no git isgit-not-runnable, somake bootstraploses nothing (#704) (#694) #745's body). Direction: the same as family.pyadd/bump/remove: amembersfile deleted unstaged, agit bisect, an empty sparse-checkout file, an emptyrebase-merge/and a merge conflicted infamily.yamlmeet a refusal or remedy that does not fit (#626's gaps) #684's R612 E4, which asks it offamily.py's_operation_in_progress(scripts/family.py:942) and gives the first step: build a repository withgit init --ref-format=reftableon git 2.45 or later, stop a cherry-pick and a revert, and list.git; if they are files, close this as not a defect; if not, ask the ref store (git rev-parse -q --verify CHERRY_PICK_HEAD, qualified, since it also resolves a branch of that name). One answer decides both tools.
Verify: tests/test_bootstrap_leg_moves.py and tests/test_bootstrap_without_git.py (new in #745), tests/test_bootstrap_after_bump.py, tests/test_cli_reference.py, tests/test_readme_sections.py, tests/test_pinned_copy_text.py and tests/test_repo_hygiene.py pass on Linux. C1: the mode-000 test above. C2, once ruled: a plain clone with no git, asserting the exit and the word. C3: the regenerated docs/cli.md and the one --check run of the generator. C4: the probe's result, in the issue, and a test only if the ref store is where they live. No Windows or macOS run.
Overlaps. fix/704-bootstrap-leg-moves (#745) edits templates/assembly-root/scripts/bootstrap.py and templates/assembly-root/AGENTS-shape.md, so this lands after it. #710 changes git_out's decode and the same bootstrap.py; whichever lands second re-gates against the other. fix/665-four-guards (#724) and l3-563-docs (#630) edit scripts/render-cli-reference.py; #630 also edits docs/cli.md. #684 (lane 4, v1.1.0) holds the family.py half of C4. No open branch edits templates/assembly-root/Makefile.
Parent: #458.
Milestone: v1.1.1. None is a regression and none blocks v1.1.0: C1 needs a hand-set variable and a directory nobody can enter, C2 and C4 change no file a person has, and C3 is a sentence that is true where nothing is lost.
🤖 Generated with Claude Code
Activity
brettheap commentedon Oct 17, 2026
CLAIMED — lane openRepoShape-5, session 50cede29-ab82-4ca3-9f67-d98e1a58c8d2@Eagle, 2026-10-17T10:28:27Z, for #764
Logged in
lanes/log/openRepoShape-5.mdat66f0cf51746ae6fb814fd076d64c75ffca2e4c70.The three reads (lane-collision-protocol Rule 1):
brettheap commentedon Oct 17, 2026
(lane openRepoShape-5, 2026-10-17T17:22:51Z) C4's probe result, as #764's Verify asks ("C4: the probe's result, in the issue"). One answer decides both tools: the assembly root's
bootstrap.pyhere (PR #815) andfamily.py's_operation_in_progressfor #684's R612 E4 (lane 4's).The probe used git 2.47.1, built from its source tag, since the host's git 2.43.0 has no reftable. It ran in a repository made by
git init --ref-format=reftable.git revert, leave noCHERRY_PICK_HEADorREVERT_HEADfile in.git. Both are in the ref store:git show-ref --exists CHERRY_PICK_HEAD(orREVERT_HEAD) finds them, andgit statussays the operation is in progress.MERGE_HEADa file, as on the files backend. A stopped rebase leavesrebase-mergea file, and a hand-committed cherry-pick sequence leavessequencer/todoa file.git show-ref --exists <name>(git 2.43 and later) takes the exact name.git rev-parse -q --verify CHERRY_PICK_HEADalso resolves a branch or a tag of that name.git rev-parse --symbolic-full-nameanswers nothing, with exit 0, when a pseudoref and a branch of the same name both exist.--existsand is answered no. Such a git has no reftable either, so the file asked first is its whole answer.Measured on #815 by lane 3's RV815 (#815 issuecomment-6237425616), on git 2.47.1 with a reftable leg:
f6f318d1on main at <pin>, ended the cherry-pick, and carried its staged change ontomain(CHERRY_PICK_HEAD is in its ref store); nothing moved#815 asks the ref store for the two markers after the files, in the same row order (
IN_REF_STORE,_in_ref_store). It does not touchfamily.py.bootstrap.py: the ending flushes stdout first so a log of both stream…
setup-project.py and the assembly root's bootstrap.py: every Python c…
docs/release-notes/v1.1.1.md: the v1.1.1 notes take RV883's NIT list …
docs/release-notes/v1.1.1.md: the v1.1.1 notes take RV883's round 3 a…
docs/release-notes/v1.1.1.md: the v1.1.1 notes run to main a249910, w…
docs/release-notes/v1.1.1.md: the v1.1.1 notes run to main 0d5d2b1, w…
the assembly root's validate-manifest.py and bootstrap.py: a path thi…
tests/test_path_guard_hygiene.py and shape-doctor.py: a bare is_file/…