Repository navigation
Tracking: shape-doctor.py, reporting a repository's compliance #460
Description
Lane: openreposhape-3 (openRepoShape-3)
The parent issue for one area of openRepoShape: answering whether one repository is compliant and naming each fix (shape-doctor.py, openRepoShape --doctor). Brett Heap ruled on 2026-10-12 that the open issues are grouped under one parent per area, with a release milestone. Every open issue in this area is a sub-issue here.
v1.0.0. The first release is "core flows, all OSes": every procedure in AGENTS.md works end to end for ordinary repositories on Linux, macOS and Windows. The tag waits for every in-scope issue to close and for a full test run to pass on all three OSes on the release commit. In this area, the sub-issues in the v1.0.0 milestone are:
- shape-doctor.py
check_shape_currencytakes every refusalupdate-shape.py prepareraises over the ROOT's owncontracts/shape-pin.yaml(a merge conflict, acommit:that is not 40 hex, a deleted file) for this checkout failing to ask, so the verdict is CANNOT ANSWER, exit 3, outranking INVALID, and its NEXTgit -C <standard> fetch --allblames the standard for a fault in the repository #237 (P2): A conflicted shape-pin.yaml (two shape-update merges) reads CANNOT ANSWER, exit 3, with a uselessfetch --allNEXT, instead of INVALID, exit 1. - shape-doctor.py: fifteen NEXT builders end the command with
# <comment>, which a stock interactive zsh (macOS's default shell) does not read as a comment, so pasting the line hands the comment's words to the command as arguments, runs whatever follows a;, and runs themake bootstrapthelegsandmemberscomments put in backticks, then exits 127 #277 (P1): Pasting any doctor NEXT into macOS's default interactive zsh hands the# commentto the command as arguments (exit 127) and runs the backtickedmake bootstrapof legs/members. - shape-doctor.py: the
manifest kindsrow's NEXT for a file that does not load (a conflicted or non-UTF-8contracts/shape-pin.yaml) is "register the kind in shape-doctor.py's MANIFEST_VALIDATORS ... or remove the file from the root", so the one fix the doctor prints for a damaged pin is to delete it #291 (P2): A conflicted or damaged shape or leg pin gets the manifest-kinds NEXT "remove the file from the root"; an agent that obeys deletes the pin. - shape-doctor.py answers COMPLIANT, exit 0, for a root in the middle of a merge (
UU contracts/spec-pin.yaml,UU spec, a MERGE_HEAD,git commitrefusing), because no row asks git for unmerged paths andrecorded_gitlinkanswers an unmerged gitlink from HEAD, so a root an agent cannot commit is reported compliant, including after thegit checkout --oursthat a conflicted pin's NEXT names #424 (P2): A root mid-merge (UUpin, MERGE_HEAD) reads COMPLIANT, exit 0, thoughgit commitrefuses; anyone merging two bump or shape-update branches hits it.
Known limits. Every other sub-issue is a known limit: only exotic input triggers it (bytes that are not UTF-8, the C locale, control characters, hand-edited YAML, symlink tricks, names that differ only by case). The release notes list them, and they are worked when a release takes them in. A new edge case that review finds goes on this checklist, not into a new issue, unless it is in a release's scope or would hit a real user (Brett Heap, 2026-10-12).
Known limits found by lane openRepoShape-3's acceptance passes (standard 36538fd, each re-checked on main 7a8b981) and kept here rather than filed:
- → shape-doctor.py, NOT A SHAPE ROOT on a git repository: print both ways in, as AGENTS.md says, and add
--orgto the adopt line when there is noorigin#545 AT-adopt N8: on an ordinary git repositoryNOT A SHAPE ROOTprints one NEXT, theadopt-project.py plancommand, though AGENTS.md:254-259 says to "report the verdict and both commands" andcheck_the_way_in's own docstring says "both are named and the human chooses" (shape-doctor.py:5265-5322; a directory that is not a repository gets only the scaffold line). - → shape-doctor.py
machinerow quotes "[!!] this machine is not ready yet (see above)." with nothing above it #549 AT-scaffold N5: themachinerow's reason quotes[!!] this machine is not ready yet (see above).with nothing above it, because the preflight's lines are kept only in--json(check_machine, shape-doctor.py:5072-5135,reason += ...at :5118). - Closed 2026-10-14, fixed by 173c00e (openRepoShape --doctor: the installed form keeps the clone of the standard it ran from and names it on the report's last line, so a NEXT line pasted after the command has exited runs instead of dying with
can't open file, and it hands--jsonand--placement-plan <file>on toshape-doctor.pyinstead of refusing them (#500) #510):--helpand docs/cli.md list all seven verdicts. AT-scaffold N10:openRepoShape --helplists five verdicts (openRepoShape:93-94; docs/cli.md:159-160, which is generated from it), with noMISPLACEDand noCANNOT ANSWER, and spellsCOMPLIANT SHAPE BEHINDwithout the comma the doctor prints (shape-doctor.py:410-421); its "3 usage" exit is also the doctor'sCANNOT ANSWER(:219-229).
Edge cases found in review of lane openRepoShape-3's pull requests, kept here rather than filed:
- → Publish openRepoShape to TestPyPI and PyPI as
openreposhape, so onepipx installputs the tools and git-filter-repo on any machine (design first) #563 (rides in README, AGENTS.md, docs/cli.md and the handbook:pipx install openreposhapeis the second way in and the first on native Windows, git-filter-repo is installed in install.sh's order and never with a barepip install, and a first draft of the v1.1.0 release notes (#563) #630) README.md'svalidate-pins.pyparagraph no longer says what a digest that recomputes differently does: README.md, docs/handbook.html and the comments in bump-leg.py and update-shape.py say when a project's own gate reaches a network:validate-pins.pyasksgh apifor a neutral product's pin with the operator'sghcredentials, andmake bootstrap,bump-leg.pyandupdate-shape.py applyrun it in the operator's environment, so none of them says any more that a project runs its own gate offline or thatapplyis otherwise offline (#411) #465 removed a sentence whose other half was false (a pin file the declaration names but that is not there is the refusalneutral-pin-missing, exit 2, not drift) and with it the true half, that such a digest is the findingneutral-pin-digest-mismatch, exit 1 (templates/assembly-root/scripts/validate-pins.py,report.finding). Lane openRepoShape-5's suggested words: "A digest that recomputes differently is the findingneutral-pin-digest-mismatch(exit 1); a pin file the declaration names but that is not there is the refusalneutral-pin-missing(exit 2)." From lane openRepoShape-5's read of README.md, docs/handbook.html and the comments in bump-leg.py and update-shape.py say when a project's own gate reaches a network:validate-pins.pyasksgh apifor a neutral product's pin with the operator'sghcredentials, andmake bootstrap,bump-leg.pyandupdate-shape.py applyrun it in the operator's environment, so none of them says any more that a project runs its own gate offline or thatapplyis otherwise offline (#411) #465. - Closed 2026-10-14, obsolete: d41cc29 (shape-doctor.py: a NEXT is only the command, and the sentence that ended twenty-five of them after
#is the row'swhy, on aWHYline of its own and"why"in--json, so a NEXT pasted into an interactive zsh -- which reads that#as a word -- no longer hands the comment to the command as arguments, runs what follows its;, or runs themake bootstrapin its backticks, and the template validator's line isenv PYTHONPATH=... python3 ...(#277) #402) made the NEXTupdate-shape.py check, and 8beb3d9 (update-shape.py and shape-doctor.py: no NEXT line pre-fills--accept-localfor a locally edited shape copy, so theapplya row names, pasted, meetsupdate-local-driftand its question to the human instead of re-pinning the edit as the standard, and ashape/collision copy merged into its original and removed ismerged-awaytocheck, whoseapplydrops its pin row behind the same yes, so an adopted root that did its follow-up validates green again (#501, #502) #512) dropped--accept-local. Theshape currencyrow's NEXT (shape-doctor.py:2815-2830 on main 8109d7a) pastesapply --at <sha> --yes [--accept-local <path>] --branch shape/update-<sha>for a pinned copy a person edited and left uncommitted, but since update-shape.py:apply --branchcompares the pin, the manifest and every pinned copy with HEAD before its first write and refuses a difference asupdate-branch-uncommitted, so an in-placeapplyleft uncommitted no longer ends in a commit its own validate-pins.py refuses, in git's "nothing to commit", or in "nothing to do" with no branch made (#436) #474apply --branchrefuses that difference asupdate-branch-uncommitted, so the NEXT should say to commit the edit first (or revert it) before theapply; update-shape.pycheck's NEXT, and the doctor'sshape currencyrow that sends the reader to it, already carry--accept-local <path>for every locally edited shape copy, so pasting the command AGENTS.md says to run as named re-pins the project's edit as the standard: no refusal, no question to the human, a greenvalidate-pins.pyand a COMPLIANT doctor, though AGENTS.md says never to pass--accept-localand that keeping the edit is the human's decision #501 would take the--accept-localout of the same line. From the review of update-shape.py:apply --branchcompares the pin, the manifest and every pinned copy with HEAD before its first write and refuses a difference asupdate-branch-uncommitted, so an in-placeapplyleft uncommitted no longer ends in a commit its own validate-pins.py refuses, in git's "nothing to commit", or in "nothing to do" with no branch made (#436) #474. - Kept as a known limit (2026-10-14): deliberate, per
check_merge's docstring. A merge left unfinished INSIDE a leg is not reported by the doctor'smergerow (shape-doctor.py: a root whose index holds an unmerged path gets amergeFINDING naming the paths, withgit -C <root> statusas its NEXT, and the verdictINVALID (merge), exit 1, on a rung above every other but CANNOT ANSWER, so a mergegit commitrefuses no longer reads COMPLIANT, exit 0, oncecheckout --ourstakes the markers out, or DRIFTED about a leg that never moved (#424) #468): the root records the leg's commit and never its index, and only the root's own index is read. From shape-doctor.py: a root whose index holds an unmerged path gets amergeFINDING naming the paths, withgit -C <root> statusas its NEXT, and the verdictINVALID (merge), exit 1, on a rung above every other but CANNOT ANSWER, so a mergegit commitrefuses no longer reads COMPLIANT, exit 0, oncecheckout --ourstakes the markers out, or DRIFTED about a leg that never moved (#424) #468's "Left out". - → shape-doctor.py: a checkout of the standard whose own
contracts/repository-naming.yamldoes not load makes a compliant projectINVALID (naming), exit 1, "the naming policy is not satisfied (exit 2)", so a person is failed for the checkout's fault, and the module's EXIT CODES list leaves out an unfinished merge #678 shape-doctor.py's module docstring EXIT CODES list (shape-doctor.py:235-246 on main 57c85e9) does not nameINVALID (merge)or an unmerged index among exit 1's findings; shape-doctor.py: a root whose index holds an unmerged path gets amergeFINDING naming the paths, withgit -C <root> statusas its NEXT, and the verdictINVALID (merge), exit 1, on a rung above every other but CANNOT ANSWER, so a mergegit commitrefuses no longer reads COMPLIANT, exit 0, oncecheckout --ourstakes the markers out, or DRIFTED about a leg that never moved (#424) #468's paragraph above it (:120) does. From shape-doctor.py: a root whose index holds an unmerged path gets amergeFINDING naming the paths, withgit -C <root> statusas its NEXT, and the verdictINVALID (merge), exit 1, on a rung above every other but CANNOT ANSWER, so a mergegit commitrefuses no longer reads COMPLIANT, exit 0, oncecheckout --ourstakes the markers out, or DRIFTED about a leg that never moved (#424) #468's "Left out". - → Pinned validators: THE LOCKSTEP RULE only where it applies, and remedies that name the
git switch -cstep (one shape bump) #539bump-leg.py --to <the gitlink's or the pin's commit>also curespin-workflow-ref-mismatch(a hand-edited@<sha>in a workflow) andpin-digest-mismatch, but the shipped validate-pins.py still ends both findings at THE LOCKSTEP RULE with no command (templates/assembly-root/scripts/validate-pins.py:513 and :538, the rule at :92, on main 5e02abe), andtest_every_other_pins_row_is_the_gates_ownholds that output in place; only a project's own workflows meet the first, since scaffolded workflows carry no leg reference. Outside a gitlink committed by hand: the doctor'spinsrow and validate-pins.py name no command, though AGENTS.md says a finding names its fix; neitherbump-leg.py(keep the move) nor the restore (undo it) is offered #478. From the review of shape-doctor.py and validate-pins.py: a gitlink that is not its pin is offered both repairs,bump-leg.py --tothe gitlink's commit to keep the move and--tothe pin's to undo it, so a gitlink committed by hand no longer ends at a gate t (#478) #495 (finding 6; the cure is the reviewer's, not re-probed here). - → Printed commands are POSIX-only: quote the bare paste lines in bump-leg.py and update-shape.py, and say in the docs that pasted commands are for a POSIX shell #532 The repair line shape-doctor.py and validate-pins.py: a gitlink that is not its pin is offered both repairs,
bump-leg.py --tothe gitlink's commit to keep the move and--tothe pin's to undo it, so a gitlink committed by hand no longer ends at a gate t (#478) #495 added to the shipped validate-pins.py is quoted for a POSIX shell, so a Windows root whose path holds an apostrophe prints a line PowerShell does not read as one argument; the one rule for every printed command is decided on Tracking: update-shape.py and bump-leg.py, keeping a project's shape copies and leg pins current #458's checklist (PowerShell quoting). From the review of shape-doctor.py and validate-pins.py: a gitlink that is not its pin is offered both repairs,bump-leg.py --tothe gitlink's commit to keep the move and--tothe pin's to undo it, so a gitlink committed by hand no longer ends at a gate t (#478) #495 (codex, finding 3).
Activity
check_shape_currencytakes every refusalupdate-shape.py prepareraises over the ROOT's owncontracts/shape-pin.yaml(a merge conflict, acommit:that is not 40 hex, a deleted file) for this checkout failing to ask, so the verdict is CANNOT ANSWER, exit 3, outranking INVALID, and its NEXTgit -C <standard> fetch --allblames the standard for a fault in the repository #237# <comment>, which a stock interactive zsh (macOS's default shell) does not read as a comment, so pasting the line hands the comment's words to the command as arguments, runs whatever follows a;, and runs themake bootstrapthelegsandmemberscomments put in backticks, then exits 127 #277manifest kindsrow's NEXT for a file that does not load (a conflicted or non-UTF-8contracts/shape-pin.yaml) is "register the kind in shape-doctor.py's MANIFEST_VALIDATORS ... or remove the file from the root", so the one fix the doctor prints for a damaged pin is to delete it #291run_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 #342repository_namesand shape-doctor.pyorigin_urlandorigin_namereadgit remote get-url originthroughgit_outand catchRefusalandOSErroronly, so an origin URL that is not UTF-8 makesreadanswernot-answered(a single repository loses the Triad advisory, a leg clone its pointer to the assembly root) and endsshape-doctor.py --rootin a UnicodeDecodeError traceback, exit 1, where an ASCII origin gives NOT A SHAPE ROOT, exit 2 #385Refusal's remediation, a paragraph of prose that opensRemediation:, in a row's NEXT (placement_policyandrun_checks), so a standard whose owncontracts/path-classification.yamldoes not load hands the project a NEXT about its legs and leg pins, whichshandbashreject as a syntax error and zsh, macOS's default shell, runs, executinggit submodule update --init --recursiveandpython3 scripts/validate-pins.pyin the reader's directory #408namingrows read only the naming script's exit code, so a crash of the STANDARD's ownvalidate-repository-naming.pyis a FINDING about the project (INVALID (naming), exit 1, where #357 makes a crashed template CANNOT ANSWER), and a directory whose name is not UTF-8 getsnaming FINDING Atl?as: UnicodeEncodeError: ..., the script's traceback quoted as a fact about the name #410legsandmembersNEXT after #354 moves a detached HEAD that holds the only copy of a commit, with no reflog note, in three states: an emptied leg mount whose kept gitdir holds the commit, a holder whose ownscripts/bootstrap.pyis the NEXT (any commit made in the pinnedmembers/<P>), and a commit in a member's own leg that--recursivemoves, so after the paste the commit is held by a reflog entry alone #413legsNEXT after #354 does not fit four edge states: a populated mount with no.gitbut its gitdir kept is sent tovalidate-pins.pyunder a sentence saying no update cures it, though the git line does; an unborn HEAD gets the gate, which sayspins okwhile the row stays red; an empty mount with no.gitmodulessection gets a git line that exits 128; and an empty mount whose pin is not 40 hex gets no "run the doctor again" #414UU contracts/spec-pin.yaml,UU spec, a MERGE_HEAD,git commitrefusing), because no row asks git for unmerged paths andrecorded_gitlinkanswers an unmerged gitlink from HEAD, so a root an agent cannot commit is reported compliant, including after thegit checkout --oursthat a conflicted pin's NEXT names #424submodule_configreads a family holder's.gitmodulesthroughgit_out, which decodes strictly, insideexcept (Refusal, OSError), so a member url that is not UTF-8 raises a UnicodeDecodeError thatrun_checksdoes not catch andshape-doctor.py --rootends in a traceback, exit 1 (also the code of a finding), with no verdict, wherevalidate-family.pyandsiblings.pyread the same file as bytes or witherrors="replace"#432manifest kindscounts a file that declares a registered kindvalidatedwherever it sits in a root that runs that kind's check, though each check reads only fixed paths, so acontracts/project.yamlin an assembly root, acontracts/family.yamlorcontracts/spec-pin.yamlin a family holder, and acontracts/<x>-pin.yamlthat no leg or declared descent names areokand COMPLIANT though nothing reads them #439crashed(), still reads a validator killed by a signal (a negative exit, -9 or -15) or one that left byos._exit(1)with nothing printed as one that "reports a finding", becausecrashed()needs a traceback line, so a root's own gate ended by the OOM killer or a timeout's SIGTERM is a FINDING about the project, and the standard's template killed the same way is not CANNOT ANSWER #447manifestrow saysok ... passeswhen the project's ownvalidate-manifest.pyexits 0 after printingWARNING naming-referent-chain: ... not reachable here, and the warning appears nowhere in the text or--jsonreport, so a referent chain nothing on this disk could check reads as checked underCOMPLIANT: the class of theskip#357 makes anote, in the form #357 still drops #448pinsrow and validate-pins.py name no command, though AGENTS.md says a finding names its fix; neitherbump-leg.py(keep the move) nor the restore (undo it) is offered #47837 remaining items
README.md and the handbook: `validate-pins.py`'s paragraph says again…
tests/test_doctor_next_is_a_command.py: the NEXT comment-tail guard r…
shape-doctor.py: a checkout whose own `contracts/repository-naming.ya…
shape-doctor.py: `submodule_config` and `gitmodules_entry` read a hol…
validate-pins.py and shape-doctor.py: one leg's gitlink off its pin b…
shape-doctor.py: the `members` row says, member by member, what `make…
openRepoShape --doctor: a signal sent to the command's shell alone wa…
shape-doctor.py: an own-copy validator row whose crash is a root's lo…
shape-doctor.py: the `placement` row asks a leg's top-level `single-r…
shape-doctor.py and update-shape.py: run from a partial clone of the …
shape-doctor.py: the `pins` row keeps its gate where `update-shape.py…
shape-doctor.py: a conflicted shape pin's NEXT reads both sides' pins…
validate-pins.py: a leg checkout this user cannot search is `pin-subm…
README, AGENTS.md, docs/cli.md and the handbook: `pipx install openre…
README.md, the handbook, AGENTS.md and the family-root docs: `init`'s…