Repository navigation
update-shape.py apply: a rollback line fails over a read-only contracts/ unsaid, committed on <branch>: lists a path the commit lacks, --branch v1.0.0 cannot push beside a tag v1.0.0, and a quoted "files": header is refused #674
Description
Goal: update-shape.py says what it did and what a person must do next without a line that fails as printed, and finds the pin's files: and the manifest's shape: headers wherever the reader finds them.
Filed by lane openRepoShape-5 on Brett Heap's word of 2026-10-16T12:17:02Z ("#458's update-shape/bump-leg (~22)"), from lines on #458: the body (AT-scaffold N9) with 6172776355, 6175499929 (the header finder), 6192496098 (the rollback line and its test gap), 6214576643 (the branch that shares a tag's name) and 6214653267 (the validator's environment). Lane 4 judged all but N9 OPEN or DOUBTFUL on main 95780dd (#473 comment 6215386495); lane 5 re-measured each on main 879d804.
Lands after: nothing. update-shape.py is not a pinned copy, so no project re-pins. No open PR touches it.
Lines (path:line at main 879d804; measured on that tree, git 2.43.0, a scaffolded project with local bare remotes unless a line says otherwise)
- A rollback's by-hand line fails over a read-only directory and does not say so.
Rollback._restore(update-shape.py:2806-2857) words an absent file's line as the command alone (:2851-2855), and_restore_by_hand(:2897-2950) asksos.access(self._nearest_directory(path.parent), os.W_OK)only for thegit checkout HEADform (:2932-2936); thecat-file blob <id> > <path>form (:2937-2947) is given whatever the directory is. Measured with the ledger in a harness: a validator that deletedcontracts/shape-pin.yamland leftcontracts/at 0555 gives...its bytes before this run are kept as blob d0556e470b5e in this repository, then: git -C <root> cat-file blob d0556e47... > <root>/contracts/shape-pin.yaml, and pasted it exits 1permission denied. (Tracking: update-shape.py and bump-leg.py, keeping a project's shape copies and leg pins current #458's 6192496098, first line.) -
committed on <branch>:lists a path the commit lacks.cmd_applyalways puts{SHAPE_PIN, kind.manifest}inpaths(:3359) and_landprints every one (:4408). Measured: anapply --branchthat drops a merged-away row (the pin'sshape/Makefilerow with the file at the root'sMakefile) printscommitted on shape/update-x: contracts/shape-pin.yaml, project.yaml, andgit show --name-only HEADlists onlycontracts/shape-pin.yaml:project.yamlwas rewritten with the same bytes. (The body's AT-scaffold N9, and 6172776355;bump-leg.py's half is in the issue forbump-leg.py.) - A branch that shares a name with a tag cannot be pushed, and is read as
heads/<b>.push_branch(:4607-4620) runsgit push -q -u -- origin <branch>with the name bare, and the landing NEXT lines do too (:4582, :5218). Measured: in a root holding a tagv1.0.0,apply --yes --branch v1.0.0 --pushcommits, thenREFUSED pushing v1.0.0(exit 2,error: src refspec v1.0.0 matches more than one), and the NEXT line it prints,git -C <root> push -u -- origin v1.0.0 && gh pr create ..., fails the same way when pasted.current_branch(:2223-2231) usessymbolic-ref --short, which printsheads/<b>in that state (measured at git level), andhere(:2471) and_awaits_its_pull_request(:4640) compare it with the bare name; read from the code, not run. The line's other half, a branch starting with+, is REFUTED for this tool:BRANCH_RE(:201) demands a letter or a digit first, andapply --branch +xis refusedupdate-branch-invalid(R421 O4). (Tracking: update-shape.py and bump-leg.py, keeping a project's shape copies and leg pins current #458's 6214576643, second line,update-shape.pyhalf.) - The header finder misses a quoted key or a space before the colon.
_is_block_header(:1378-1384) is_strip_comment(line) == f"{key}:", used for the pin'sfiles:(:1444) and the manifest'sshape:(:1584-1585); update-shape.py: afiles:orshape:header with a trailing comment is rewritten and keeps it,--branchis judged the same from any directory, andapply's messages say what is true (#437, #431, #535) #558's docstrings say "a quoted key or a space before the colon is read as the key by the reader and is not found here, as before" (:1422-1423, :1571-1573). Measured withrewrite_shape_pinon a pin whose header is"files":,'files':orfiles :: the reader (load_yaml) reads the keyfilesin each, and the rewrite refuses all threeupdate-pin-unrecognised("has 0filesline(s)"), whilefiles:andfiles: # crewrite. Forshape:the refusal isupdate-manifest-no-shape, whose "has noshape:block" is false of a manifest the reader gives ashapekey (by the same reading; the manifest side was not run). The validators andcheckpass such a file, andchecksends the person to theapplythat refuses. (Tracking: update-shape.py and bump-leg.py, keeping a project's shape copies and leg pins current #458's 6175499929, third line.)
Rides along (backlog; tick it on #458 if the same change covers it)
- Untested: the
os.path.lexistschoice for "so make it writable" (:2851-2852).tests/test_update_shape_partial_rollback.pyholds the file-present, unwritable cases (head_line, :217-223, and the 0555contracts/with the pin at 0444, :567-606) and the directory-deleted cases (:609-650, which assertsmake it writableis absent, and :654-700), and nothing for a directory that exists at 0555 over an ABSENT file, which is the case in the first line. Its test closes this gap; R560v's mutant MN7c is the measurement (not re-run; the test file is unchanged since update-shape.py:applyrefuses to rewrite a file that has a second, hard-linked name, and a rollback that cannot put a byte back names it with the line that finishes it and puts back the rest (#422, #428) #560). (Tracking: update-shape.py and bump-leg.py, keeping a project's shape copies and leg pins current #458's 6192496098, second line, first item; the second item, thetry/else/finallyimports, is in the issue for the kept-copy check.) -
run_validatorstarts the root's own validator withsiteon and the whole environment.update-shape.py:2206-2220runs[sys.executable, script]withinherited_child_environment(), where the doctor's children start with-Sand withoutPYTHONPATH(shape-doctor.py:1622-1627, shape-doctor.py:run_validatorstarts a root's OWN validator under the doctor's interpreter withsiteprocessing on, so a.pthin the operator's user site or in a virtualenv's site-packages that names a directory holdingrepo_shape.pystands in for the copy the root lost, and themanifestrow saysok ... passesfor a gate that fails in CI onModuleNotFoundError: the false pass #238 removed and #306 closes forPYTHONPATHalone #342). Measured, so it is not a verdict bug here: with the root'sscripts/repo_shape.pylost,applyis refusedupdate-conflict(the row iscopy-missing) before any validator starts, so no gate runs without the copy. (Tracking: update-shape.py and bump-leg.py, keeping a project's shape copies and leg pins current #458's 6214653267;bump-leg.py's half, where the gate is reached and still red, is in the issue forbump-leg.py.)
Direction
- Rollback line: when the file is absent and
_nearest_directory's answer is not writable, the line saysmake <that directory> writable, then:before the command, as it says "make it writable" of a present file; test it with the directory present and 0555 (WINDOWS_SKIP, as its neighbours). committed: after the commit, name the paths git reports (git show --name-only --format= HEAD, through the tool's own git helper) and notpaths.- Branch names: read HEAD's branch without
--short(symbolic-ref --quiet HEAD, striprefs/heads/), and print and run the push with a name no tag can take:refs/heads/<branch>(measured:git push -u origin refs/heads/v1pushes beside a tagv1, andrefs/heads/+xpushes unforced), the same form as the one in the issue forbump-leg.pyand on Tracking: setup, scaffold, family and the shared helpers, creating projects and families #459 forfamily.py, inpush_branchand both NEXT lines. The tests that hold today's form change with it (tests/test_update_shape_landing.py:293,416,tests/test_update_shape_next_quoting.py:264,376), and AGENTS.md:283 and :339 and README.md:525 showpush -u origin <branch>as a placeholder line, to be kept or matched. - Headers:
_split_key(_strip_comment(line)) == (key, "")at column 0 (R558's suggestion;_split_keyisscripts/repo_shape.py:322), writing the header back as the line was (_header_as_it_was), and update both docstrings' "not found here" sentences with it. Both validators' own finders are the reader's, so nothing else moves. - Validator environment (rides along): no change here is needed for a verdict; a one-rule match with the doctor is optional.
Overlaps: none with open PRs (#634's files are scaffold-project.py, scripts/repo_shape.py, scripts/shape_materialize.py, scripts/validate-repository-naming.py, templates/*). The issue for the kept-copy check also edits update-shape.py, at merge_by_hand (:3495) and the _names_* readers (:3837-4186), regions apart from these (the nearest, run_validator at :2206-2220 and current_branch at :2223, are in this issue). The push-line form is shared with the issue for bump-leg.py: whichever lands second matches the first.
Mark each line → this issue on #458, and tick it there when this closes. The body's AT-scaffold N9, the --short line and the validator-environment line each have a second half in the issue for bump-leg.py: tick them when both close.
🤖 Generated with Claude Code
Activity
brettheap commentedon Oct 16, 2026
CLAIMED — lane openRepoShape-4, session 11c6c0ef-495a-4a05-94cf-811b7b0a1012@Eagle, 2026-10-16T13:28:08Z, for #674
Logged in
lanes/log/openRepoShape-4.mdat49c1f3c3e63f26ad94d57fa6c4e81840ecc392a6.The three reads (lane-collision-protocol Rule 1):
Merge main bf1f099 into fix/674-update-shape-apply
update-shape.py: `current_branch` and `Rollback.new_branch` read a br…
render-cli-reference.py and tests/: the CLI reference's children writ…
update-shape.py: `apply`'s rollback line says to make a shut director…
Merge origin/main (bad05d2) into l3-563-docs
docs/release-notes/v1.1.0.md: entries for #748, #731, #810, #809, #816,