Repository navigation
shape-doctor.py and update-shape.py: run from a partial clone of the standard, the shape currency row asks without fetching whether the clone holds what the comparison reads, and is CANNOT ANSWER with a fetch for a person to run where it does not, and a read that fails is refused, never a copy called both (#683) - #742
Conversation
…standard, the `shape currency` row asks without fetching whether the clone holds what the comparison reads, and is CANNOT ANSWER with a fetch for a person to run where it does not, and a read that fails is refused, never a copy called `both` (#683) Measured again on main de92614 with git 2.43: run from a `--filter=blob:none` clone of the standard, the doctor made five lazy fetches, one under each `git show` of a copy the standard changed since the pin (missing objects at the pin 1255 -> 1250), and with the clone's remote out of reach it said `DRIFTED (5 both)` of copies nobody edited; `update-shape.py check` printed the same five `both` rows. shape-doctor.py: - `partial_clone_row`: where `partial_clone` holds, `objects_lacking` asks `git rev-list --objects --no-walk --missing=print` of the pinned commit and of HEAD, before `prepare` or any `ls-tree` reads them. Where either lacks an object, the row is CANNOT ANSWER (`environment`, exit 3, error `shape-doctor-partial-clone`), and its NEXT is `git -C <shape> fetch --refetch --no-filter <promisor remote>`. - `promisor_remotes`: git 2.43's own reading of a promisor remote. `promisor = false` alone is no longer partial (git fetches nothing there), a `partialclonefilter` is (git fetches there whatever `promisor` says), and `extensions.partialclone` names one. - `check_shape_currency`: a `prepare` refusal of a read that failed (`update-upstream-unreadable`) gets a `why` of its own and no `fetch --all`, which would bring nothing to read it. - `as_the_standard_wrote_it` takes that refusal as "not proved", as it took a None. update-shape.py: - `Upstream.blob` reads with `git cat-file blob`, and where that fails, `files_at` (one `ls-tree -r` per revision) says whether the revision lists a file at the path: None where it does not, a directory included, and `update-upstream-unreadable` where it does, so `check` and `apply` refuse rather than print `both`. tests/test_doctor_partial_clone.py: new; nothing is fetched where `rev-list --missing=print` lists the same objects before and after. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewer's GuidePrevents partial-clone lazy fetches and misleading both verdicts by checking required objects before comparison, accurately recognizing Git promisor configuration, and refusing unreadable upstream files with actionable diagnostics; extensive tests cover the new behavior. Sequence diagram for partial-clone shape currency checksequenceDiagram
participant Doctor as shape-doctor.py
participant Git as Git repository
participant Person as Person
Doctor->>Git: config --type=bool --get-regexp
Git-->>Doctor: promisor remotes
Doctor->>Git: rev-list --objects --no-walk --missing=print pinned
Git-->>Doctor: missing-object count
Doctor->>Git: rev-list --objects --no-walk --missing=print HEAD
Git-->>Doctor: missing-object count
alt objects are missing
Doctor-->>Person: CANNOT ANSWER
Doctor-->>Person: git -C shape fetch --refetch --no-filter remote
else nothing is missing
Doctor->>Git: prepare and compare
Git-->>Doctor: shape currency verdict
end
Sequence diagram for unreadable upstream file refusalsequenceDiagram
participant Tool as update-shape.py
participant Git as Upstream repository
participant Person as Person
Tool->>Git: cat-file blob rev:path
alt read succeeds
Git-->>Tool: file bytes
else read fails
Tool->>Git: ls-tree -r -z --full-tree rev
alt path is absent
Git-->>Tool: no file record
Tool-->>Person: treat as absent
else path exists or listing fails
Git-->>Tool: file record or listing error
Tool-->>Person: REFUSED update-upstream-unreadable
end
end
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
One conflict, in shape-doctor.py's EXIT CODES list, exit 3: this branch added a partial clone lacking what the comparison reads (#683), and main added a validator that crashed or cannot be given what it needs (#278, #410) and a naming policy that does not load (#678). All are kept, in main's form. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
(lane openRepoShape-3, 2026-10-16T23:32:49Z) Lane 3's independent review of #742 at Measured on git 2.43.0. The standard was a bare copy, and Atlas was scaffolded 30 commits back with 5 copies changed since. Fetches were counted twice: by
What else was checked
Mutants: ten of eleven are killed. The survivor:
SHOULD, to the v1.1.1 follow-up
NIT
Tests at the head (stub
Merges: clean with #734, #736, #737 and #740. Lane: openreposhape-3 (openRepoShape-3) |
|
Sorry @brettheap, you've used your own review budget of 250,000 diff characters for the last 7 days. You can request another review in 23 hours and 42 minutes by commenting |
… check` says REFUSAL AHEAD beside a merged-away row, so it no longer says that the `apply` `check` prints drops the row when that `apply` is refused, and the `shape currency` counts name every state `check` counts (#676) (#751) From #460's triage, on Brett Heap's word of 2026-10-16T12:24:41Z ("give #460 to lane 3"). It lands on his standing word, "standing word covers the #460 PRs" (12:58:08Z), after #742, on which it was stacked. Closes #676. The `pins` row named `update-shape.py check` for a merged-away row and said the `apply` it prints drops that row, even where `check` says REFUSAL AHEAD and that `apply` is refused. Now: - The row asks `check`'s own two questions first: a conflict state, and a hard-linked rewrite. Where either holds, it keeps the gate as its NEXT and says why. - Where it cannot ask (an unreadable pin, a partial clone short of what `check` reads, or a `prepare` that refuses), it keeps the gate. It never fetches. - The `shape currency` counts name every state `check` counts, so no row stands under no count. Lane 3's independent reviewer (RV-f) found it READY. The row agrees with `check` in every state built, and each printed `apply` was pasted. Its gate on the squash predicted onto main is in the landing line. Follow-up for v1.1.1: #755. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main gained 25 pull requests since de92614: #634, #699, #671, #719, #701, #717, #700, #702, #722, #720, #725, #721, #728, #705, #727, #718, #744, #743, #749, #740, #737, #734, #742, #751 and #736. No conflict: AGENTS.md, adopt-project.py and docs/cli.md merged as text, and README.md and docs/handbook.html are unchanged by the merge. README.md is 1473 lines, its cap; AGENTS.md 494, its cap; every handbook marker is current; `render-cli-reference.py --check` is ok. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es every reason THIS checkout cannot answer, and the notes are current to main bf1f099 with the 25 pull requests since de92614 (#563, #683) - W683 and RV-f's N4 on #742: README's exit-3 list (Keeping a project's shape current, :1208-1220) and its handbook twin (`doctor`) named only a pin whose commit this checkout does not carry. They now say, as shape-doctor.py's EXIT CODES does: a pin's commit it lacks, a partial clone missing what is compared (#683), a read that fails (`update-upstream-unreadable`), a crashed validator of its own (#278, #410), or its own naming policy not loading (#678). +1 line, with tests/readme-cap.d/683.txt; README.md is 1474, its cap (1422 + 2 + 5 + 12 + 22 + 10 + 1). The two `Keeping a project's shape current` markers move: `doctor` text and marker, `current` marker only. - The notes, "What changed since v1.0.1", one entry per pull request from `git log --first-parent de92614..bf1f099`, each from its squash commit and the issues GitHub says it closes: - adopt-project.py: #699, #719, #749, #727, #717, #728 (with #621's hint), #743 + #720 + #718, #722, #721; - update-shape.py, bump-leg.py and a project's own scripts: #702 (with the pinned validators), #634; - scaffold, setup, family and the shared readers: #725, #671, #744; - shape-doctor.py: #742, #701, #737, #751, #736, #734, #700 + #705, #740; - install, CI and the docs: the exit-3 sentence above. - Counts (99 pull requests since bfed143; 109 of 135 milestone issues closed at 10:28Z), the "current to main" sha and the open list (26) are at main bf1f099, still placeholders for tag time. Left for round B: lane 5's eight lines (#630 issuecomment-6227129879), whose pull requests #726, #747, #682, #724, #746, #745 and #738 are open drafts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main moved from 4ce9045 to bf1f099. The only change to update-shape.py on main in that span is #742 (`Upstream` and `_classify_row`, the partial-clone currency row); none of #674's functions. No conflicts, so nothing was resolved by hand, and no pinned copy changed under the files #674 touches. Lane: openreposhape-4 (openRepoShape-4) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… verification row's colon, `run_validator`'s "costs no child an import" and the decoy test's `sitecustomize` claim say what main does (#666) (#730) Four comments and docstrings said something main no longer does. They now say what the code beneath them does. A fix round after review added two more of the same kind (see "Fix round"). Comments and docstrings only: no behaviour, no `--help` text, no pinned copy, so no README, handbook or `docs/cli.md` change. - **`adopt-project.py`, the module docstring.** It said the verification table reads `code: 0 of N source paths (seeded from template)`. The printed row has no colon (` {leg:<6} {count:>5} of {N} source paths{note}`). It now says the table's `code` row reads `0 of N source paths (seeded from template)`, the words `AGENTS.md` and `README.md` use since #505 and the docstring of the verification function uses too. `git grep 'code: 0 of'` finds nothing now. - **`shape-doctor.py`, `submodule_config`.** The last sentence of the docstring gave a reason that is true of the string and not decisive: "It is also what the row PRINTS, and a lone surrogate is a string no UTF-8 stream can write." The table goes through `ascii_text` and `--json` through `json.dumps`, so neither would raise on a lone surrogate. I dropped the sentence, the issue's first direction. The comparison with `origin_url`'s reading of a clone's remote is the reason, and the paragraph already gives it first. **This hunk carries the bytes of lane 3's #700**, which landed as `55c6ba7d`: the two removed lines and the one added line (` working clone.`) are the same. So the hunk is on main already and drops out of the squash (see "Evidence"). - **`shape-doctor.py`, `run_validator`.** "It costs no child an import" holds for an unedited copy only. A new paragraph says a root whose own copy of a validator gained an `import yaml` read `passes` while `site` was on, and now reads `crashed before reaching a verdict (exit 1): ModuleNotFoundError: No module named 'yaml'`, the crash its own CI gets, because `validate.yml` installs nothing. It calls that row a fair answer and says `-S` does not ask whether a copy was edited. No code change. - **`tests/test_shape_doctor.py`, the decoy test's two comments** (the block above `DECOY_REPO_SHAPE` and the inline comment before `reached`). `run_validator` starts every child as `[sys.executable, "-S", script, ...]`, so no child imports a `sitecustomize`. The comments now say that, say that replace-not-prepend and the #306 review S1 case are held by `test_run_validator_gives_the_child_exactly_the_pythonpath_it_is_given`, and say that the decoy test holds the template row's real verdict under an exported `PYTHONPATH`. The review of the first two commits approved with nits. Two new commits take S1 and N1: `7f2bb36b` makes both edits, and `426877bf` rewrites the last sentence of the N1 comment, which did not parse ("...a future removal of `-S`, which `test_run_validator_starts_every_child_with_no_site` ... is the test that holds"). It now ends "...a future removal of `-S`; `test_run_validator_starts_every_child_with_no_site` (in `tests/test_doctor_validator_site.py`) is the test that holds `-S`." Both are comments and docstrings only. - **S1, a third stale sentence.** The docstring of `test_run_validator_gives_the_child_exactly_the_pythonpath_it_is_given` said that for the callers which pass no `pythonpath`, "only a probe like this one, or (b)'s decoy, can see that they have none". That is false under `-S`: a `run_validator` that keeps the variable for those callers passes the decoy test in all three cases and fails the probe test twice (the second row of the table below). It now says only a probe like this one can see that they have none, and that the decoy of (b) could before `-S` (#342). It is the same defect as the issue's, in a place the issue did not name. "Could" holds for the `manifest` and `pins` cases: with `-S` removed, 2 of the 3 decoy cases fail, and the `family` case never caught it. - **N1, the inline comment overstated the loop.** The comment above `reached` said "What this loop still holds is that no row quotes the decoy or says it exited 86." Under `-S` the loop cannot fire. It now says so, says the loop is kept as a tripwire for a future removal of `-S`, and names `test_run_validator_starts_every_child_with_no_site` in `tests/test_doctor_validator_site.py` as the test that holds `-S`. That test is on main. - **N2, this body.** The merge checks and the notes on #630 were stale (they cited `de926142` and a conflict that is gone). They are rerun and rewritten below. **Only comments and docstrings changed.** `git diff 8062810 426877b` has 74 changed lines (44 added, 30 removed) in three files. A script checked each changed line against the file's comment tokens and docstring spans (both sides of the diff): 0 outside. A second check parsed each file at the base and at the head, blanked every docstring, and compared the ASTs: identical in all three files. For the two fix-round commits together, the AST of `tests/test_shape_doctor.py` with docstrings blanked is identical to the one at `a2113cff`, `git diff --check` is clean, and the longest added line is 75 columns (73 in the second commit). **What the squash holds.** `git merge-tree --write-tree` of this head with origin/main `20c8873b` gives the tree `6ead2ffc`. `git diff 20c8873 6ead2ffc` is 71 changed lines in three files, and `shape-doctor.py` has 8 of them: the new `run_validator` paragraph and nothing else. `git diff` of the two trees has no hunk that mentions `submodule_config`, `surrogate`, `PRINTS` or `working clone`. On main, `submodule_config`'s docstring has no "PRINTS" sentence and ends in `working clone.`. The same two checks on that tree: 0 lines outside comments and docstrings, ASTs identical. On main `2d988200` with the head `426877bf` the squash is the same: 71 changed lines, 8 of them in `shape-doctor.py`, 0 outside comments and docstrings, ASTs identical, and no hunk that mentions `submodule_config`. **`python3 scripts/render-cli-reference.py --check`**, at `426877bf`: `[ok] docs/cli.md is what the generator produces`. Only the first line of a module docstring is help text, and none of the first lines changed. **The decoy comments, measured.** I did not take the issue's reading on trust. In a throwaway clone at the base I put each #306 regression into `run_validator` and ran the two tests (`test_an_exported_pythonpath_does_not_reach_a_template_validator`, three cases, and `test_run_validator_gives_the_child_exactly_the_pythonpath_it_is_given`, six): | mutant | with `-S` (main) | with `-S` removed | |---|---|---| | the standard's `scripts/` put in FRONT of the operator's value | decoy test: 3 of 3 pass. Probe test: 1 of 6 fails | decoy test: 3 of 3 fail | | the variable kept for the callers that pass none (S1) | decoy test: 3 of 3 pass. Probe test: 2 of 6 fail | decoy test: 2 of 3 fail | | the operator's directory AHEAD of the standard's | decoy test: 3 of 3 fail. Probe test: 1 of 6 fails | not run | So on main the decoy test catches neither #306 regression and the probe test catches both, as lane 4's R342 measured on #636's head. The third row is why the comment says the raising `repo_shape.py` "still bites": it kills an operator-first order. The review re-ran these mutants on `a2113cff` and got the same counts. **The `run_validator` paragraph, measured.** A root whose own `validate-manifest.py` is `import yaml` plus a print, run through `run_validator` from this tree: exit 1 and `ModuleNotFoundError: No module named 'yaml'`. The same call with `-S` taken out of the child's argv: exit 0, `manifest ok`. `yaml` is importable from the machine's site-packages and not without `site`. With the real `gh` unreachable (a stub first on PATH, a bogus token, an empty `GH_CONFIG_DIR`). On `a2113cff`, before the fix round: - `tests/test_cli_reference.py`, `tests/test_repo_hygiene.py`, `tests/test_agents_md_codes.py`, `tests/test_scaffold_leg_path_collisions.py`: 250 passed (57.5 s). - `tests/test_doctor_gitmodules_not_utf8.py`, `tests/test_doctor_validator_rows.py`, `tests/test_doctor_validator_site.py`, `tests/test_doctor_validator_verdicts.py`, `tests/test_adopt_spec_only.py`, `tests/test_adopt_entry_paths.py`, `tests/test_adopt_submodules.py` (the files that drive `run_validator`, `submodule_config` or the seeded-leg row): 334 passed (28 min 18 s). - `tests/test_shape_doctor.py`, in two halves run side by side (the first 204 test ids, then the last 204): 204 passed in 11 min 31 s, and 201 passed, 3 skipped in 4 min 58 s. That is all 408 tests. The 3 skips are the PowerShell-line tests, which need `powershell.exe` on a Windows host. - The review ran all of `tests/test_shape_doctor.py` there: 405 passed, 3 skipped (512 s). On the predicted merge with main `2fac9790` it ran `test_shape_doctor.py`, `test_doctor_validator_site.py`, `test_doctor_validator_rows.py`, `test_doctor_validator_verdicts.py`, `test_doctor_gitmodules_not_utf8.py`, `test_repo_hygiene.py`, `test_cli_reference.py` and `test_agents_md_codes.py`: 632 passed, 3 skipped (760 s). On `426877bf`, after the fix round, which changes comments and docstrings only, so the runs above stand: - The two tests the fix round touches, `test_an_exported_pythonpath_does_not_reach_a_template_validator` (3 cases) and `test_run_validator_gives_the_child_exactly_the_pythonpath_it_is_given` (6 cases), run by node id: 9 passed (11.7 s). The same 9 also passed (16.1 s) at `7f2bb36b`. - `tests/test_repo_hygiene.py`: 77 passed (1.9 s). It also passed (2.0 s) at `7f2bb36b`. No test fails on the base, because nothing here changes behaviour. The AST comparison above is the proof in their place. `git merge-tree --write-tree` of this head against origin/main and against every ref on origin that could meet it. The full run was on 2026-10-16, with the head `7f2bb36b` (the one before the last comment commit) and main `20c8873b`: the 41 branches (`fix/*`, `l3-*`, `wip/*`, `docs/*` and `release/v1.0`) and the 55 PR heads from #630 up. That is 96 refs. I ran #731's head `ab55c29f` through the same list. After `426877bf` I re-ran main, now `2d988200`, and the six heads that edit `tests/test_shape_doctor.py`, the one file that commit touches (#705, #737, #740, `l3-669-members-row`, `l3-680-doctor-signals` and `l3-697-crash-cure-next`), and #630: all clean. - **origin/main: clean.** At `20c8873b`, with the head `7f2bb36b`, the predicted tree is `6ead2ffc`. At `2d988200` (three `adopt-project.py` commits later, with their tests and a change in `scripts/shape_materialize.py`), with the head `426877bf`, it is `7ee5caf4`, and the squash is the same three files (43 added, 28 removed). #731's head `ab55c29f` is clean with `2d988200` too. This head with #731's head: clean. - **#630's head `6fd33a93`: clean.** It conflicted with main in `docs/handbook.html` when this body was first drafted, and no longer does, with or without this change. - **#700 and #702 have landed** (`55c6ba7d` and `20c8873b`), and so has #701, and #699, #717 and #719 for `adopt-project.py`. Their heads still merge clean with this head. - **Every ref that edits `shape-doctor.py`, `tests/test_shape_doctor.py` or `adopt-project.py` merges clean with this head**, except the two old heads named in the bullet after next. They include the heads of PRs not on main yet (#705, #721, #737 and #742, and lane 3's `l3-680`, `l3-683`, `l3-687`, `l3-691` and `l3-697`, which were not on origin when this body was first drafted). #673 has no branch or PR head on origin. - **Four refs conflict with origin/main on their own**, and so with this head: `docs/release-notes-v1.0.0` and `release/v1.0`, and the pre-squash heads of the landed #637 and #641. Their conflicts do not come from this change. - **Two landed pre-squash heads conflict with this head only because they are old.** #632 conflicts with main on its own. #636 merges clean with main, but its old head conflicts with this head in `run_validator`'s docstring, next to the text #636 added; main has that text, and this head merges clean with main. - **Refs that conflict with main on their own are not made worse.** #682, #745, #747, `fix/648`, `fix/681` and `fix/704` conflict with main in `templates/family-root/scripts/validate-family.py`; #742 and `l3-683` in `shape-doctor.py`. Each merges clean with this head. - **Every other open head and branch: clean.** Nothing from the issue. Its four lines are done. The decoy test's `sitecustomize` machinery is dead code under `-S` and I left it, because the issue says comment only. The comment above `reached` now says it is kept as a tripwire. - **The decoy test's `sitecustomize.py` and exit-86 trap never run.** `DECOY_SITECUSTOMIZE`, `os._exit(86)` and the `(exit 86)` and `DECOY` clauses in `reached` can only fire for a child started without `-S`. They are kept as a tripwire and the comment says so. The other choice is to remove them; `test_run_validator_starts_every_child_with_no_site` already holds `-S`. Small, tests only. Review: rv666, lane 5's independent review, approved a2113cf with nits; 7f2bb36 and 426877b take its S1 and N1 (above), and codex found no major issue at a2113cf. CI (Brett Heap's ruling 27 and his fast-refresh ruling of 2026-10-15T22:48:35Z): H0 426877b passed tests, tests-git-bash and SonarCloud; the head 32722b3 is a clean update-branch merge of main bf1f099, with tests-git-bash and SonarCloud green; and the local gate passed on its predicted squash tree 55d5d3b over main dcf62ed: the shape_doctor, scaffold_leg_path_collisions, repo_hygiene, agents_md_codes, cli_reference sets, 686 passed, 3 skipped, 1 xfailed. Landed on Brett Heap's word of 2026-10-17T10:59:39Z, relayed by lane 3 on #473: "merge lane 5's approved v1.1.0 drafts". Closes #666 Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d A3 (three SHOULDs, four nits), and notes entries for the seven pull requests landed since bf1f099, current to main 2000488 (#563, #683) Round A4, from lane 2's review (#630 issuecomment-6233033833, READY): - SHOULD 1: the doctor's exit-3 list names "a validator of its own that crashed or could not be run", so the case of one that cannot be given its `PYTHONPATH` (shape-doctor.py's EXIT CODES, #278) is listed too: README.md:1208-1222, its handbook twin (`doctor`) and the notes' docs line. The paragraph re-wraps to one more line: tests/readme-cap.d/683.txt is +2, and its text now says which causes the EXIT CODES block names and that #742 added the partial clone and #701 the naming policy. README.md is 1475 lines, its cap (1422 + 2 + 5 + 12 + 22 + 10 + 2). Both `Keeping a project's shape current` markers move to c728c970: `doctor` text and marker, `current` marker only. - SHOULD 2: #727's entry names the leg description, whose em dash stopped every `execute` against GitHub at the first leg. - SHOULD 3: #749's entry names `source-ambiguous`, for an `org/repo` that is also a directory here. - Nits: the doctor section's three near-duplicate pairs are merged (#636 with #737, #632 with #700 and #705, #586 with #736); #718 has its own bullet; #634's entry names `git_out`'s spelling for every caller and #744's the gate's `--link-source-label` and `--link-remedy`; the header comment says 2026-10-17 at main 2000488. Wave B1, `git log --first-parent bf1f099..2000488`: #706 (#664), #703 (#696), #670 (#646), #682 (#648), #726 (#667), #730 (#666) and #724 (#665), each from its squash commit; #726's and #682's from lane 5's lines (#630 issuecomment-6227129879), #682's with the unmerged `.gitmodules` its last round added, and #724's with lane 5's note that v1.0.0's test-hygiene line on the generator's `.pyc` files closes. The counts (106 pull requests; 116 of 135 milestone issues closed at 11:53Z), "current to main" and the open list (19) are at main 2000488, still placeholders. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…efusals and `family-operation-in-progress` name a path as `shown_source` names it, so an ESC or a line break in a path no longer reaches the terminal (#692) (#731) #622's folder refusals printed a path as it was. `family.py init --into <a file named wd-ESC[31mRED> --dry-run` gave `REFUSED family-folder-cannot-be-made: the family folder .../wd-^[[31mRED/Orbit cannot be made: ...` through `cat -v`. A name with a line break and then `WARNING forged-line: pwned` printed that line as a line of its own. R612's `family-operation-in-progress` printed the mark's path across two lines for a holder whose path holds a newline. Each path is now spelled as `shape_materialize.shown_source` spells a `--pin-source`: as it is, and as Python's `repr` spells it where a character in it is not printable. - `scripts/shape_materialize.py`: both answers of `folder_cannot_be_made` (a file or a bad stat in the way, and a folder this user cannot write in), the folder in `refuse_unmakeable_folder`, and the folder in `make_folder`. - `scaffold-project.py`: `scaffold-target-exists`. - `scripts/family.py`: `family-target-exists`, and the mark's path in `family-operation-in-progress` (`where.as_posix()`). A printable path is named byte for byte, so no existing row changes and `why.endswith(CANNOT_WRITE_IN)` in `refuse_unmakeable_folder` still holds. No help text changed, so `docs/cli.md` is untouched. No README, handbook or template sentence says how a refusal names a path (`git grep` of `shown_source`, `target-exists` and `folder-cannot-be-made` in AGENTS.md, README.md, `docs/handbook.html` and the templates found none), so no doc changes. - **`shown_source`, not `shown_path`.** Since #634, `shape_materialize.shown_source` returns `repo_shape.shown_path(source)` (`scripts/shape_materialize.py`: `return shown_path(source)`), so the seven call sites this change adds (four in `shape_materialize.py`, one in `scaffold-project.py` and two in `family.py`) spell a path as `shown_path` does. Renaming them to `shown_path` stays out of this PR: it would only move imports in `scaffold-project.py` and `family.py` and reword docstrings in `family.py`, `shape_materialize.py` and the test file, and the review's N1 left it optional. I did not take it. The predicted merge with main works with the alias: `family.py --help` and `scaffold-project.py --help` exit 0 on it, and `shown_source` and `shown_path` return the same string for an ESC name, a line-break name and a plain path. - **`shown_source` is imported by name into each file's existing `from shape_materialize import (...)` block.** The first commit put it on a line of its own after the block; lane 4's #660, #688 and #693 add an import at that same place, and `merge-tree` reported add/add conflicts in `scripts/family.py` and `scaffold-project.py`. The second commit moves the name into the block, and those conflicts are gone. - **"The holder in the other refusals of the same block" is one refusal.** The `# What the holder is in the middle of, and what its sparse checkout leaves out` block holds `family-operation-in-progress`, `family-sparse-excluded` and `member-path-unaddable`. Only the first prints a path of the holder's. `family-sparse-excluded` names `members/<Project>` and `.gitmodules`, and `member-path-unaddable` names `members/<Project>`. - **No scaffold row for `--local-remote-dir`.** A control character there is refused earlier as `scaffold-unwritable-value`, which already names the path with `repr`. The unit test covers `make_folder`, which only a race reaches by the command line. `tests/test_dry_run_parity.py`: - `SCAFFOLD_CASES` gains five rows: ESC and line break in the `--work-dir` name, ESC in a folder name above it, and ESC and line break in a work dir that holds a file named `Atlas` (`scaffold-target-exists`). - `FAMILY_CASES` gains five rows: ESC and line break in `--work-dir`, ESC in `--into` (`the family folder`), and ESC and line break in a work dir that holds a file named `Orbit` (`family-target-exists`). - Two rows join `UNWRITABLE_FOLDER_AT` (ESC in the scaffold's and in `init`'s `--work-dir`, a folder this user cannot write in). - Rows named `ESC-...` and `line-break-...` are skipped on Windows, whose file names cannot hold them (`POSIX_NAMES`, `case_params`). Every expectation spells the path with `repr`, and not with `shown_source`. - `assert_refused` now fails any stderr line that starts with `WARNING forged-line`. - Three unit tests: `test_each_folder_question_spells_a_name_that_is_not_printable` (ESC, line break; `folder_cannot_be_made`, `refuse_unmakeable_folder` and `make_folder` by themselves), `test_a_folder_this_user_cannot_write_in_is_spelled_safe_to_show`, and `test_a_printable_name_is_named_byte_for_byte` (a name with a space and an accented letter stays unquoted). `tests/test_family_refuse_up_front.py`: `test_a_holder_path_with_a_newline_still_shows_its_merge` asserted the raw newline in the refusal (`"Ink\nRouter/.git/worktrees/" in ran.stderr`). It is now `test_a_holder_path_with_a_control_character_still_shows_its_merge`, over a line break, an ESC and a forged line, and asserts the one-line `repr` form (`refusal()` fails unless the stderr is two lines). It is the one existing test this change had to edit. Results at head `ab55c29f` (Python 3.12.3, Linux): - `tests/test_dry_run_parity.py tests/test_dry_run_asks_remotes.py tests/test_family_dry_run.py tests/test_family_init_landing.py tests/test_repo_hygiene.py tests/test_pin_source_unreadable.py tests/test_scaffold_leg_path_collisions.py tests/test_scaffold_reuse_seeded_legs.py`: **494 passed**. - `tests/test_family.py tests/test_family_refuse_up_front.py tests/test_family_init_values.py tests/test_family_add_refusals.py`: **356 passed, 19 skipped** (the skips are `test_family_init_values.py:219` and `:291`, template-quoting premises). - Not run: the full suite (the coordinator's gate), and macOS and Windows (CI is Linux-only since #597). The new hostile-name rows are POSIX only by design. On the base code: the review overlaid this head's two test files on main `2fac9790` and ran `tests/test_dry_run_parity.py` and `tests/test_family_refuse_up_front.py` with `-k "dry_run_parity or control_character"`. The result is **20 failed, 87 passed** (76 deselected, 43.5 s). The 20 are exactly the new and edited tests: the 5 scaffold and 5 `init` rows, the 4 unwritable-folder rows, the 3 unit tests (`test_each_folder_question_spells_a_name_that_is_not_printable` in two cases, and `test_a_folder_this_user_cannot_write_in_is_spelled_safe_to_show`), and the 3 cases of the edited `test_a_holder_path_with_a_control_character_still_shows_its_merge`. The one new test that passes on main's code is `test_a_printable_name_is_named_byte_for_byte`, by design: a printable name is named byte for byte on both. An earlier draft of this body said 21 failed, 2 passed. That run was on `8062810d` with a wider selection, and it held a scaffold row for ESC in the local remote dir's name (`ESC-in-the-local-remote-dir-name`) that this head's tests no longer have; its second pass was the existing `test_the_refusal_quotes_gh_s_first_line_and_escapes_what_is_unprintable`, which also passes in the new run, one of the 87. `family.py init` and `scaffold-project.py --dry-run` against a file named `wd-ESC[31mRED`, a file named `wd-\nWARNING forged-line: pwned`, and a work dir with a file `Atlas` or `Orbit` in it, run with a stub `gh` and no real `gh`: - On main, through `cat -v`: `... the family folder /.../wd-^[[31mRED/Orbit cannot be made: /.../wd-^[[31mRED is a file, not a folder`, and a stderr line `WARNING forged-line: pwned cannot be made: ...` of its own. - On this head: `REFUSED family-folder-cannot-be-made: the family folder '.../wd-\x1b[31mRED/Orbit' cannot be made: '.../wd-\x1b[31mRED' is a file, not a folder`, and one line for the forged name: `--work-dir '.../wd-\nWARNING forged-line: pwned' cannot be made: '...' is a file, not a folder`. `scaffold-target-exists` and `family-target-exists` are one line each in the same form. Each spelled site reverted alone in a throwaway clone at `19d126cd` (the call sites are the same at `ab55c29f`); the new tests that fail for each: - `folder_cannot_be_made`, the `_not_a_folder` answer: 8 failed (six CLI rows and the two unit tests). - `folder_cannot_be_made`, the `CANNOT_WRITE_IN` answer: 5 failed (the four unwritable rows and the unit test). - `refuse_unmakeable_folder`: 12 failed. - `make_folder`: 2 failed (the unit test only). - `scaffold-target-exists`: 2 failed (its two rows). - `family-target-exists`: 2 failed (its two rows). - `family-operation-in-progress`: 3 failed (line break, ESC, forged line). `git merge-tree --write-tree` of this head `ab55c29f` against origin/main `20c8873b` and against every ref on origin that could meet it, fetched 2026-10-16: the 41 branches (`fix/*`, `l3-*`, `wip/*`, `docs/*` and `release/v1.0`) and the 55 PR heads from #630 up. That is 96 refs. (The same list was run for #730's head `7f2bb36b`.) - **origin/main `20c8873b`: clean** (the predicted tree `00b5b24c`, which differs from main in these five files only: 216 lines added, 25 removed). - **#630's head `6fd33a93`: clean.** It conflicted with main in `docs/handbook.html` when this body was first drafted, and no longer does, with or without this change. This change touches no README or handbook. - **The refs that edit one of this change's five files**, and so could meet it, all merge clean with this head: `fix/646`, `fix/651`, `fix/654`, `fix/660`, `fix/661`, `fix/684`, `fix/686`, `fix/688`, `fix/689` and `fix/693`, the heads of #670, #725, #728, #743 and #744, and the heads of the landed #634, #638, #639, #640, #643 and #671. #634 has landed (`30676c90`), so the `fix/660` note about a conflict with it is gone. - **Four refs conflict with origin/main on their own**, and so with this head: `docs/release-notes-v1.0.0` and `release/v1.0`, and the pre-squash heads of the landed #637 and #641. Their conflicts do not come from this change. Every other ref, 92 of the 96 in all, is clean with this head, including the refs that conflict with main in `templates/family-root/scripts/validate-family.py` (#682, #745, #747, `fix/648`, `fix/681`, `fix/704`) or in `shape-doctor.py` (#742, `l3-683`) on their own. So do the old heads of the landed #638 and #639, and lane 3's `l3-677-pins-hand-step-wip` branch, and each of them merges clean with this head too. - **Tests on the predicted merge**, run by the review on the merge with main `2fac9790`: `test_dry_run_parity`, `test_family_refuse_up_front`, `test_pinned_copy_text`, `test_pin_source_unreadable`, `test_dry_run_asks_remotes`, `test_family_dry_run` and `test_family_init_landing`: 445 passed in 215 s. `test_family`, `test_family_init_values`, `test_family_add_refusals`, `test_derived_id_refusals`, `test_repo_hygiene`, `test_naming_policy`, `test_scaffold_leg_path_collisions` and `test_scaffold_reuse_seeded_legs`: 758 passed, 19 skipped in 243 s. I did not re-run them on `20c8873b`; the merge is clean, and the two commits since `2fac9790` (#700 and #702) change only `shape-doctor.py`, `templates/assembly-root/scripts/validate-pins.py` and four test files, none of them a file of this change. - Before the second commit, `fix/660`, `fix/688` and `fix/693` each conflicted with this head in the import region of `scripts/family.py` or `scaffold-project.py` (a separate import line each side added at the same place). That is why the import joins the existing block. #634 is on main, and this change does not edit `shown_source` or its docstring in `scripts/shape_materialize.py`. The review approved with nits. Its S1, the stale base-run numbers and merge lines, is taken here, in this body: no code changed, and the head is still `ab55c29f`. Its N1, renaming the call sites to `shown_path`, is not taken (see "Decisions and their evidence"). It also re-ran 5 of the 7 mutation probes on `ab55c29f` and got the same failure counts as above (12, 2, 3, 2 and 2), and ran 144 hostile-name dry runs (16 names in 9 scenarios): on main 69 rows put a control character on stderr and 6 print a forged line of their own; on this head all 144 exit 2 with no traceback, no control character and no forged line. - `scripts/family.py` `init`'s plan prints `folder` and `landing` lines with the path raw (`print(f"landing {holder} ...")`, `print(f"folder {folder} ...")`). On a dry run or a refused run the plan is on stdout before the refusal, so `WARNING forged-line: pwned/Orbit (--work-dir: no family folder)` still appears there. It is the plan, not a refusal, and not one of the issue's lines. - Other refusals that name a holder or folder path raw, none of them in the issue's lines: `family-holder-detached` and `family-on-tracking-branch` (`{family.root}`), `family-index-locked` (`lock.as_posix()` in the detail), `family-landing-in-standard` (`{holder}`, `{checkout}`, `{beside / family / family}`), `family-holder-already-here` (`{into}`), and `family-remote-exists` and `scaffold-remote-exists` (`{target}`, a local remote path). 1. **family.py `init`'s plan prints the holder and folder paths raw.** `scripts/family.py` `landing` and `folder` rows (about :1756-1759) print `holder` and `folder` as they are, so a forged line or an ESC reaches stdout in a `--dry-run` and in a run refused after the plan. Direction: spell them with `shown_source`. 2. **The same raw spelling in the refusals listed above.** `family-holder-detached`, `family-on-tracking-branch`, `family-index-locked`, `family-landing-in-standard`, `family-holder-already-here`, `family-remote-exists` and `scaffold-remote-exists` each print a path the person supplied or git keeps. Direction: the spelling this change gives its sites. Review: rv692, lane 5's independent review, approved ab55c29 with nits, and its body fix (S1) is published. CI (Brett Heap's ruling 27 and his fast-refresh ruling of 2026-10-15T22:48:35Z): H0 ab55c29 passed tests, tests-git-bash and SonarCloud; the head 13f643d is a clean update-branch merge of main 431c8cf, with tests-git-bash and SonarCloud green; and the local gate passed on its predicted squash tree 4327947 over main 431c8cf: the dry_run_parity, family_refuse_up_front, repo_hygiene, agents_md_codes, cli_reference sets, 330 passed. Landed on Brett Heap's word of 2026-10-17T10:59:39Z, relayed by lane 3 on #473: "merge lane 5's approved v1.1.0 drafts". Closes #692 Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Lane: openreposhape-3 (openRepoShape-3)
Claim: #683 (comment)
Closes #683.
Re-measured on main
de926142(git 2.43.0)The issue's two cases still hold. The standard is a bare clone of
de926142withuploadpack.allowFilter, andAtlaswas scaffolded atbf7b19ba(de926142~30).shape-doctor.py --root Atlas, run from a--no-local --filter=blob:noneclone, answersCOMPLIANT, SHAPE BEHIND (5 upstream-changed, 0 upstream-added)(exit 1).rev-list --objects --missing=print).fetch origin ... --filter=blob:none --stdin. Their parents aregit show bf7b19ba…:<source>fortemplates/assembly-root/scripts/validate-pins.py,validate-manifest.py,bootstrap.py,scripts/repo_shape.pyandscripts/validate-repository-naming.py.remote.origin.urlleading nowhere answersDRIFTED (5 both)(exit 1).update-shape.py check --upstream <that clone>prints the same fivebothrows (exit 1).Two claims of the issue's needed amending:
remote.<name>.promisor = falseis not the only key. git 2.43'spromisor-remote.calso makes a remote a promisor whenremote.<name>.partialclonefilteris set, whateverpromisorsays.blob:noneclone:promisor = falseplus the filter git's clone writes still fetched (missing 48 → 47).promisor = falsealone fetched nothing, and the read failed (exit 128).promisor = falseonly by accident: it never read the filter key.Upstream.resolvefetches too.rev-parse --verify <sha>^{commit},prepare's first read of the pinned commit, lazily fetches a commit the clone lacks: 24 trace2 fetch events.rev-list --objects --no-walk --missing=print <sha>exits 128 (bad object) on that commit, with no fetch.prepare, not only before the blob reads.What changed and why
shape-doctor.pypartial_clone_row(shape-doctor.py:4405). It is asked fromcheck_shape_currencyat:4522, afterread_pinand beforeprepare.partial_cloneholds,objects_lacking(:4378) runsgit rev-list --objects --no-walk --missing=printat the pinned commit and at HEAD. That command never fetches, and it runs before anyls-tree.rev-listcannot list a commit (the clone does not hold it), the row is CANNOT ANSWER:detail.environment, exit 3,error: shape-doctor-partial-clone(:4402).pinned,standard,remoteandlacking({commit: count}).--missing=printnames a missing object by its id alone. Finding its path means reading the tree that holds it, which atree:0clone also lacks.prepare's to define. A second list of them in the doctor would drift.promisor_remotes(:4019), withpartial_clone(:3999) nowbool(promisor_remotes(shape)). This is git's own reading of its config:promisoris true (git config --type=bool, so a barepromisorkey counts);partialclonefilter;extensions.partialclonenames, last, as git asks it.check_shape_currency(:4529). Apreparerefusal of a read that failed (update-upstream-unreadable, see below) gets awhyof its own and no NEXT.fetch --alland its "does not carry the commit" would both be false there.promisor = falsealone), or from a damaged one.as_the_standard_wrote_it(:4073) now catchesRefusalbesideOSErrorandValueError, so a readUpstream.blobrefuses is "not proved", asNonewas.files_atwhere it used to giveNone.pin_restoreitself is untouched.:27,:318). The doctor fetches nothing, and that is true again. A partial clone is now asked first, and exit 3 now names "a partial clone lacking what the comparison reads".The NEXT, chosen by the precedent row's rule
The precedent row (
shape-doctor.py:4548) gives a checkout short of the pin's commitgit -C <shape> fetch --all: the command a person runs to put into THIS checkout what it lacks. Itswhynames the other way, a clone that has the commit. This row follows the same rule:git -C <shape> fetch --refetch --no-filter <promisor remote>.fetch --allwould bring no blob, because a promisor remote's fetch keeps itspartialclonefilter.--refetch --no-filtermeasured: 1294 missing → 0, with the config left as it was.fetch --all --refetch --no-filterwith two remotes passed neither option on (1294 → 1294).why: "fetch every object holds, then run the doctor again, or run it from a full clone of the standard".openRepoShape --doctor <root>.--refetchneeds git 2.36. On an older git the NEXT fails with an unknown option, and thewhygives the full-clone way.update-shape.pyUpstream.blob(update-shape.py:393) reads withgit cat-file blob <rev>:<path>.<rev>:<path>and the same bytes asgit showfor every file,./xincluded (measured).files_at(rev)(:427, onels-tree -r -z --full-treeper revision, cached, only after a failed read) says whetherrevlists a file at that exact path.None, as before.update-upstream-unreadable(:452, built byunreadable_upstreamat:455), quoting git's exit and words.checkandapplyrefuse inprepare, before any write, rather than reach_classify_row's pinnedNone(:766) and_row_verdict'sboth.open_upstream's docstring (:472) no longer says "NOTHING IS FETCHED" of a path. A partial clone's git fetches on a read; this tool fetches nothing into it; a failed fetch refuses.Every caller of
Upstream.blob, checked for changed behaviour:source_for(:664).None, so the next candidate is tried.unmapped.None.git showused to return its tree listing as "bytes" with exit 0._classify_row(:794-795).both, orupstream-removedfor the target.upstream_copies(:941,MATERIALIZER). A failed read refuses. It used to give{}, which silently meant "no additions".find_additions(:1199). A failed read refuses. The addition used to be skipped silently._accepted_in_the_pin(:5013,_finish_landing).prepareread the same target in the same run, so this is reachable only through a race.shape-doctor.py'sas_the_standard_wrote_it.Refusal→False, as above.Tested
tests/test_doctor_partial_clone.py(21 cases). The partial clone is built astests/test_doctor_pin_restore_merges.py:702-743builds one:uploadpack.allowFilter,FILE_PROTOCOL,--no-localoverfile://.rev-list --objects --all --missing=printlists the same objects before and after the run, and lists at least one.shape-doctor-partial-clone, nothing fetched. Four cases:blob:noneandtree:0, each with its remote reachable and out of reach.lacking == {C1: 1},remote == "origin", NEXT pasted argvgit -C <clone> fetch --refetch --no-filter origin.COMPLIANT, SHAPE BEHIND (1 upstream-changed, 0 upstream-added).lacking == {C2: 1}, with nothing fetched. A mutant that asks only the pinned commit fails it.promisor = falsealone, remote reachable: the row isupdate-upstream-unreadable, NEXTNone, exit 3, nothing fetched, noboth.update-shape.py checkagainst an unreachable partial clone (blob:none,tree:0): exit 2,REFUSED update-upstream-unreadable: <clone>, noboth.partial_clone/promisor_remoteson a full--no-localclone, with config appended as bytes:[extensions]\n\tpartialclone = origin\n→ True (Tracking: shape-doctor.py, reporting a repository's compliance #460 L14);promisor = false→ False;promisor = true→ True;promisorkey → True;promisor = false→ True;Upstream.blobon a full clone: a file's bytes,Nonefor an absent path, andNonefor a directory.Command, run in four groups at once (stub
ghfirst on PATH,GH_TOKEN=bogus, emptyGH_CONFIG_DIR):Results:
ccdc2c94(this commit onde926142):tests/test_shape_doctor.py:405 passed, 3 skipped in 798.00s (0:13:17).tests/test_update_shape.py:90 passed in 131.57s (0:02:11).tests/test_update_shape_*.py:576 passed, 3 skipped in 535.67s (0:08:55).tests/test_doctor_partial_clone.py,tests/test_doctor_pin_restore_merges.py,tests/test_doctor_next_is_a_command.py,tests/test_repo_hygiene.pyandtests/test_cli_reference.py, together:192 passed in 417.68s (0:06:57).9f24bf31(the same three files, byte for byte, rebased onto30676c90):tests/test_doctor_partial_clone.py,tests/test_doctor_pin_restore_merges.pyandtests/test_repo_hygiene.py, together:114 passed in 209.30s (0:03:29).3027937d, the merge of main66b230ed(shape-doctor.py:submodule_configandgitmodules_entryread a holder's.gitmodulesthrough onegit config -z --list, so a section name holding a space or a byte that is not UTF-8, or a url holding NEL or U+2028, gives the doctor the mount url git andmake siblingsuse, under any locale (#668) #700, shape-doctor.py: a checkout whose owncontracts/repository-naming.yamldoes not load is CANNOT ANSWER, exit 3, for a project, where it readINVALID (naming), exit 1; any other naming exit 2 "refuses"; and the EXIT CODES list names an unfinished merge (#678) #701, validate-pins.py and shape-doctor.py: one leg's gitlink off its pin beside another leg's digest or workflow reference names the step that comes first, that gitlink put back by hand, and then the other leg'sbump-leg.pyline, so neither finding says "First clear that finding" over a finding no line can clear first (#677) #702, shape-doctor.py: themembersrow says, member by member, whatmake siblingsdoes with the directory beside the holder, in its own word and inplace's order, so it no longer says it places a member it leaves exactly as it is, and it spells every value it quotes, so an ESC or a CR in a url no longer reaches the terminal (#669, #673) #705 and others) into this branch. Its one conflict wasshape-doctor.py's EXIT CODES list, exit 3: both sides added a cause, and both are kept in main's form.tests/test_shape_doctor.py:428 passed, 3 skipped, 1 xfailed in 461.66s (0:07:41).tests/test_update_shape.py:90 passed in 94.53s (0:01:34).tests/test_update_shape_*.py:576 passed, 3 skipped in 333.53s (0:05:33).tests/test_doctor_pin_restore_merges.py,tests/test_doctor_next_is_a_command.py,tests/test_repo_hygiene.pyandtests/test_cli_reference.py, together:192 passed in 196.88s (0:03:16).shape-doctor.pyanchors above are this head's.Pinned copies
None.
shape-doctor.pyandupdate-shape.pyare not copied into projects, so no project sees anupstream-changedrow from this.Docs
CANNOT ANSWER)") does not name the partial-clone case.single-repository.yamlrecord arrives asleg: drop, that the adopted Makefile'sCONTRACTS_DIRfollows the spec leg's mount, and that a second setup run is refused at the plan, so the three sentences #566, #572 and #573 left false or incomplete are true of main (#606) #627 and lane 3's 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 are editing both. So that clause is left for lane 3's README turn rather than added here.docs/cli.mdis unaffected: neither tool's--helpchanged.Lands after / before
pinsrow keeps its gate whereupdate-shape.py checksays REFUSAL AHEAD beside a merged-away row, so it no longer says that theapplycheckprints drops the row when thatapplyis refused, and theshape currencycounts name every statecheckcounts (#676) #751 (shape-doctor.py: thepinsrow sayscheck'sapplydrops merged-away rows wherechecksays REFUSAL AHEAD (a pinned copy kept as a link), and theshape currencycounts leave out five ofcheck's states #676, lane 3: the doctor'spinsandshape currencyrows) is stacked on this PR's head3027937dand lands after it.files:row for is named in itswhyandleft_for_a_personfor a person to merge, and never taken (#687) #736 (shape-doctor.pypin_restore: a copy conflicted beside the shape pin that only the side NOT taken has afiles:row for is neither taken nor named, so the conflicted pin'swhyandleft_for_a_personsay nothing of a file the merge still holds unmerged #687, lane 3,pin_restore) is open. This PR does not touchpin_restore, but its one-lineexceptchange inas_the_standard_wrote_it(shape-doctor.py:4073) sits in the function shape-doctor.pypin_restore: a copy conflicted beside the shape pin that only the side NOT taken has afiles:row for is neither taken nor named, so the conflicted pin'swhyandleft_for_a_personsay nothing of a file the merge still holds unmerged #687's issue names. A textual conflict there, if any, is one line.🤖 Generated with Claude Code
Summary by Sourcery
Handle partial and unreadable standard clones safely by refusing unverifiable comparisons instead of fetching or reporting false drift.
New Features:
Bug Fixes:
bothcopy classifications.Enhancements:
Documentation:
Tests: