Repository navigation
adopt-project.py, shape-doctor.py and tests/test_shape_doctor.py: the 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
Conversation
… verification row's colon, `submodule_config`'s reason, `run_validator`'s "costs no child an import" and the decoy test's `sitecustomize` claim say what main does, so four comments no longer describe code that is not there (#666) Comments and docstrings only. No behaviour, no `--help` text, no pinned copy, so `docs/cli.md` is unchanged. - adopt-project.py, module docstring: the verification table's `code` row reads `0 of N source paths (seeded from template)`, with no colon. That is what `AGENTS.md` and `README.md` say since #505, and what the row's print statement writes. - shape-doctor.py, `submodule_config`: the replacement decode is chosen for the comparison with `origin_url`'s reading of a clone's remote, and for nothing else. The row never printed a surrogate: the table goes through `ascii_text` and `--json` through `json.dumps`, neither of which raises on one. The docstring now says what `surrogateescape` would change (`--json`'s `mounted_from` would carry a lone-surrogate escape). - shape-doctor.py, `run_validator`: "it costs no child an import" holds for an unedited copy only. A root whose own validator copy imports from site-packages read `passes` before `-S` and now reads the crash its own CI gets. The docstring says so and calls the row a fair answer. - tests/test_shape_doctor.py, the decoy test's two comments: `-S` starts every child with no `site`, so no child imports a `sitecustomize`. The comments 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 that the decoy test holds the template row's real verdict. Proof that only comments and docstrings changed: the AST of each of the three files is identical before and after once docstrings are blanked. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…at gave printing as a reason, as lane 3's #668 does, so the two changes are one identical edit and merge without a conflict (#666) The sentence "It is also what the row PRINTS, and a lone surrogate is a string no UTF-8 stream can write" is not a reason: the table goes through `ascii_text` and `--json` through `json.dumps`, and neither raises on a lone surrogate. The comparison with `origin_url`'s reading of a clone's remote is the reason, and the paragraph already gives it. The previous commit on this branch replaced the sentence with a longer account of what `surrogateescape` would change in `--json`; that text conflicted with #668's deletion of the same two lines (merge-tree, `shape-doctor.py` around :7079), so this commit takes the issue's first direction, "drop the sentence", with the same bytes #668 leaves. Comment only: the AST of the file is unchanged. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
(lane openRepoShape-5, 2026-10-16T17:22Z) @codex review |
Reviewer's GuideThis documentation-only PR updates stale comments and docstrings to describe the current verification output and validator isolation accurately, including Sequence diagram for isolated validator execution and dependency failuresequenceDiagram
participant Doctor as shape-doctor.py
participant Child as Validator child
participant Site as Python site packages
participant YAML as yaml dependency
Doctor->>Child: run_validator(ctx, script, args)
Doctor->>Child: Start with [sys.executable, -S, script, ...]
Child--xSite: Skip site initialization
Child->>YAML: import yaml
YAML--xChild: ModuleNotFoundError
Child-->>Doctor: Exit 1 with crash text
Doctor-->>Doctor: Report crashed before reaching a verdict
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
… of (b) could see a caller that passes no `pythonpath` only before `-S`, and the decoy loop's comment says it is a tripwire, so two comments no longer say a decoy holds what the probe holds (#666) Comments and docstrings only. The review of the first two commits found two sentences that still described the decoy test as it was before `-S`. - test_run_validator_gives_the_child_exactly_the_pythonpath_it_is_given, docstring: "so only a probe like this one, or (b)'s decoy, can see that they have none" was false under `-S`. A `run_validator` that keeps the variable for the callers that pass none passes the decoy test in all three cases and fails the probe test. It now says only a probe like this one can see that, and that the decoy of (b) could before `-S` (#342). - test_an_exported_pythonpath_does_not_reach_a_template_validator, the comment above `reached`: "What this loop still holds is that no row quotes the decoy or says it exited 86" overstated it. Under `-S` the loop cannot fire. It now says it is kept as a tripwire for a future removal of `-S`, and that `test_run_validator_starts_every_child_with_no_site` in `tests/test_doctor_validator_site.py` is the test that holds `-S`. Proof that only comments and docstrings changed: the AST of tests/test_shape_doctor.py is identical to the previous head's once docstrings are blanked. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ed` ends its tripwire sentence with a semicolon and says the named test holds `-S`, so the sentence parses (#666) Comment only. The fix-round commit 7f2bb36 ended the comment with "removal of `-S`, which `test_run_validator_starts_every_child_with_no_site` (in `tests/test_doctor_validator_site.py`) is the test that holds.", which does not parse. The last three lines now read: "It is kept as a tripwire for 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`." The AST of tests/test_shape_doctor.py is identical to the one at a2113cf once docstrings are blanked. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
submodule_config's reason, run_validator's "costs no child an import" and the decoy test's sitecustomize claim say what main does (#666)run_validator's "costs no child an import" and the decoy test's sitecustomize claim say what main does (#666)
|
main gained #706 (#664), #703 (#696), #670 (#646), #682 (#648), #726 (#667), #730 (#666) and #724 (#665) since bf1f099. No conflict: #682's README sentence and its handbook twin (Families) merged as text, with #682's own Families marker, and every marker reads current. README.md is 1474 lines, its cap; AGENTS.md 494, its cap; `render-cli-reference.py --check` is ok. 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>
…notes entries for the five pull requests landed since 2000488, current to main 40e678e (#563, #683) RV630's review of rounds A3, A4 and B1 (#630 issuecomment-6233641684, READY), its four optional nits: - 1: README.md's drift paragraph ended on the one-word line "finished.". "exactly " and "about the shape " are cut, and the paragraph re-wraps to seven lines with both bold leads whole. README.md is 1474 lines, its cap (1422 + 2 + 5 + 12 + 22 + 10 + 1); tests/readme-cap.d/683.txt is +1, and its text says why. Both `Keeping a project's shape current` markers move to df780eb5; the other 21 read current. - 2: #682's lead reads "A holder's `make bootstrap` that left a member unchecked-out". - 3: #730's entry says "Comments and docstrings", not "Four": its squash makes three claims, comments only. - 4: the doctor's `members` row has one bullet, #705's sentence and #624's together. Wave B2 so far, `git log --first-parent 2000488..40e678e`, each entry from its squash diff: - #713 (#645): the test session turns git's automatic maintenance off (Install, CI and the docs). - #812 (#693): `add --local-remote-dir`'s member clone URL, the remedies and the READMEs' quoted clone URL (the `--local-remote-dir` bullet). - #767 (#685): `members/` renamed with `git mv` is renamed back in two steps, and the git a printed `--sparse` needs (family). - #745 (#704, #694): lane 5's line (#630 issuecomment-6227129879), with v1.0.0's known limit at v1.0.0.md:463 (no git on `PATH`) said closed (Bootstrap). - #805 (#690): `make siblings`'s inputs (family). The counts (111 pull requests; 122 of 135 milestone issues closed at 16:14Z), "current to main" and the open list (13, each with a pull request open) are at main 40e678e, still placeholders. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Lane: openreposhape-5 (openRepoShape-5)
Claim: #666 (comment)
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
--helptext, no pinned copy, so no README, handbook ordocs/cli.mdchange.What changed
adopt-project.py, the module docstring. It said the verification table readscode: 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'scoderow reads0 of N source paths (seeded from template), the wordsAGENTS.mdandREADME.mduse since README.md and AGENTS.md: 28 statements the v1.0.0 accuracy pass found false are corrected to what the tools do on main (#483) #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 throughascii_textand--jsonthroughjson.dumps, so neither would raise on a lone surrogate. I dropped the sentence, the issue's first direction. The comparison withorigin_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 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, which landed as55c6ba7d: 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 animport yamlreadpasseswhilesitewas on, and now readscrashed before reaching a verdict (exit 1): ModuleNotFoundError: No module named 'yaml', the crash its own CI gets, becausevalidate.ymlinstalls nothing. It calls that row a fair answer and says-Sdoes not ask whether a copy was edited. No code change.tests/test_shape_doctor.py, the decoy test's two comments (the block aboveDECOY_REPO_SHAPEand the inline comment beforereached).run_validatorstarts every child as[sys.executable, "-S", script, ...], so no child imports asitecustomize. The comments now say that, say that replace-not-prepend and the shape-doctor.py: after #238 the doctor runs a root's OWN validator with the operator'sPYTHONPATHstill in the child's environment, so for an operator who exports one that reaches arepo_shape.pythemanifestrow of a root that lost its ownscripts/repo_shape.pysaysok ... passesagain, the false pass #238 removed, where the project's own gate in CI fails onModuleNotFoundError: No module named 'repo_shape'#306 review S1 case are held bytest_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 exportedPYTHONPATH.Fix round
The review of the first two commits approved with nits. Two new commits take S1 and N1:
7f2bb36bmakes both edits, and426877bfrewrites the last sentence of the N1 comment, which did not parse ("...a future removal of-S, whichtest_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(intests/test_doctor_validator_site.py) is the test that holds-S." Both are comments and docstrings only.test_run_validator_gives_the_child_exactly_the_pythonpath_it_is_givensaid that for the callers which pass nopythonpath, "only a probe like this one, or (b)'s decoy, can see that they have none". That is false under-S: arun_validatorthat 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(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). It is the same defect as the issue's, in a place the issue did not name. "Could" holds for themanifestandpinscases: with-Sremoved, 2 of the 3 decoy cases fail, and thefamilycase never caught it.reachedsaid "What this loop still holds is that no row quotes the decoy or says it exited 86." Under-Sthe loop cannot fire. It now says so, says the loop is kept as a tripwire for a future removal of-S, and namestest_run_validator_starts_every_child_with_no_siteintests/test_doctor_validator_site.pyas the test that holds-S. That test is on main.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 were stale (they citedde926142and a conflict that is gone). They are rerun and rewritten below.Evidence
Only comments and docstrings changed.
git diff 8062810d 426877bfhas 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 oftests/test_shape_doctor.pywith docstrings blanked is identical to the one ata2113cff,git diff --checkis clean, and the longest added line is 75 columns (73 in the second commit).What the squash holds.
git merge-tree --write-treeof this head with origin/main20c8873bgives the tree6ead2ffc.git diff 20c8873b 6ead2ffcis 71 changed lines in three files, andshape-doctor.pyhas 8 of them: the newrun_validatorparagraph and nothing else.git diffof the two trees has no hunk that mentionssubmodule_config,surrogate,PRINTSorworking clone. On main,submodule_config's docstring has no "PRINTS" sentence and ends inworking clone.. The same two checks on that tree: 0 lines outside comments and docstrings, ASTs identical. On main2d988200with the head426877bfthe squash is the same: 71 changed lines, 8 of them inshape-doctor.py, 0 outside comments and docstrings, ASTs identical, and no hunk that mentionssubmodule_config.python3 scripts/render-cli-reference.py --check, at426877bf:[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_validatorand ran the two tests (test_an_exported_pythonpath_does_not_reach_a_template_validator, three cases, andtest_run_validator_gives_the_child_exactly_the_pythonpath_it_is_given, six):-S(main)-Sremovedscripts/put in FRONT of the operator's valueSo 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 ona2113cffand got the same counts.The
run_validatorparagraph, measured. A root whose ownvalidate-manifest.pyisimport yamlplus a print, run throughrun_validatorfrom this tree: exit 1 andModuleNotFoundError: No module named 'yaml'. The same call with-Staken out of the child's argv: exit 0,manifest ok.yamlis importable from the machine's site-packages and not withoutsite.Tests
With the real
ghunreachable (a stub first on PATH, a bogus token, an emptyGH_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 driverun_validator,submodule_configor 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 needpowershell.exeon a Windows host.tests/test_shape_doctor.pythere: 405 passed, 3 skipped (512 s). On the predicted merge with main2fac9790it rantest_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.pyandtest_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:test_an_exported_pythonpath_does_not_reach_a_template_validator(3 cases) andtest_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) at7f2bb36b.tests/test_repo_hygiene.py: 77 passed (1.9 s). It also passed (2.0 s) at7f2bb36b.No test fails on the base, because nothing here changes behaviour. The AST comparison above is the proof in their place.
Merge checks
git merge-tree --write-treeof 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 head7f2bb36b(the one before the last comment commit) and main20c8873b: the 41 branches (fix/*,l3-*,wip/*,docs/*andrelease/v1.0) and the 55 PR heads from #630 up. That is 96 refs. I ran #731's headab55c29fthrough the same list. After426877bfI re-ran main, now2d988200, and the six heads that edittests/test_shape_doctor.py, the one file that commit touches (#705, #737, #740,l3-669-members-row,l3-680-doctor-signalsandl3-697-crash-cure-next), and #630: all clean.20c8873b, with the head7f2bb36b, the predicted tree is6ead2ffc. At2d988200(threeadopt-project.pycommits later, with their tests and a change inscripts/shape_materialize.py), with the head426877bf, it is7ee5caf4, and the squash is the same three files (43 added, 28 removed). shape_materialize.py, scaffold-project.py and family.py: the folder refusals andfamily-operation-in-progressname a path asshown_sourcenames it, so an ESC or a line break in a path no longer reaches the terminal (#692) #731's headab55c29fis clean with2d988200too. This head with shape_materialize.py, scaffold-project.py and family.py: the folder refusals andfamily-operation-in-progressname a path asshown_sourcenames it, so an ESC or a line break in a path no longer reaches the terminal (#692) #731's head: clean.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's head6fd33a93: clean. It conflicted with main indocs/handbook.htmlwhen this body was first drafted, and no longer does, with or without this change.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 and 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 have landed (55c6ba7dand20c8873b), and so has 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, and adopt-project.py:planrefuses--id ''and--elected-by ''by name, a derived id's refusal says to change--project, or in place to rename the source first, and an org read from a url is named as not given (#658) #699, adopt-project.py:_default_branchkeeps a branch name's byte that is not UTF-8, so a source whose HEAD ororigin/HEADis oncaf<e9>is refused or adopted past it, and no longer endsplan,checkandexecutein a traceback (#425) #717 and adopt-project.py: a--work-dirthat is a file or cannot be made is refused by name inplan,checkandexecute, and--helpsays what--work-diris and where--orgcomes from (#650) #719 foradopt-project.py. Their heads still merge clean with this head.shape-doctor.py,tests/test_shape_doctor.pyoradopt-project.pymerges 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 (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, adopt-project.py, shape-doctor.py: a plan's answer against a rule is recorded and an empty.gitmodulesasks nothing, sodocs/answeredcodeis not MISPLACED afteradoption verified, nor a.gitmodulesemptied bygit rmasked on every run (#655) #721, shape-doctor.py: an own-copy validator row whose crash is a root's lostscripts/repo_shape.pynamesgit -C <root> checkout HEAD -- scripts/repo_shape.pyas its NEXT (none where HEAD no longer holds it) and the validator in its WHY (#697) #737 and shape-doctor.py and update-shape.py: run from a partial clone of the standard, theshape currencyrow 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 calledboth(#683) #742, and lane 3'sl3-680,l3-683,l3-687,l3-691andl3-697, which were not on origin when this body was first drafted). shape-doctor.py: themembersrow prints a mount url and a stranger's origin raw, so an ESC in either reaches the terminal as a control, wheremake siblingsspells the same values in its WRONG ORIGIN finding #673 has no branch or PR head on origin.docs/release-notes-v1.0.0andrelease/v1.0, and the pre-squash heads of the landed family.py and validate-family.py: where an earlier act left the branch, theswitch -cremedy says to give it another name, or go back only if it holds work not merged yet, and the docs sayfamily/add-<Project>(#607) #637 and bump-leg.py, scaffold-project.py and family.py:git status --porcelainandgit config user.nameare read as bytes, so a file name that is not UTF-8 isbump-leg-root-dirtyor the DIRTY warning and auser.namethat is not UTF-8 is refusedfamily-unwritable-valuenaming--created-by, where each ended in a UnicodeDecodeError traceback (#423, #426) #641. Their conflicts do not come from this change..gitmodulesis read as bytes and a url that is not UTF-8 is replaced, asmake siblingsreads it, so--rootreaches a verdict where a member mounted from a legacy-code-page directory ended in a UnicodeDecodeError traceback, exit 1, with none (#432) #632 conflicts with main on its own. shape-doctor.py: every validator child starts with-S, so no.pthin the user's or a virtualenv's site-packages stands in for therepo_shape.pya root lost, and themanifestrow is the gate's ownModuleNotFoundError(#342) #636 merges clean with main, but its old head conflicts with this head inrun_validator's docstring, next to the text shape-doctor.py: every validator child starts with-S, so no.pthin the user's or a virtualenv's site-packages stands in for therepo_shape.pya root lost, and themanifestrow is the gate's ownModuleNotFoundError(#342) #636 added; main has that text, and this head merges clean with main.--no-membersprints the case-variant move (#648) #682, 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, validate-family.py and validate-pins.py: a staged gitlink removal says to commit it,member-gitlink-absentputs the gitlink back by hand, the variantmvis guarded, and a pin row with nopath:isshape-pin-row(#681) #747,fix/648,fix/681andfix/704conflict with main intemplates/family-root/scripts/validate-family.py; shape-doctor.py and update-shape.py: run from a partial clone of the standard, theshape currencyrow 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 calledboth(#683) #742 andl3-683inshape-doctor.py. Each merges clean with this head.Left out
Nothing from the issue. Its four lines are done. The decoy test's
sitecustomizemachinery is dead code under-Sand I left it, because the issue says comment only. The comment abovereachednow says it is kept as a tripwire.Checklist candidates
sitecustomize.pyand exit-86 trap never run.DECOY_SITECUSTOMIZE,os._exit(86)and the(exit 86)andDECOYclauses inreachedcan 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_sitealready holds-S. Small, tests only.Closes #666
🤖 Generated with Claude Code
Summary by Sourcery
Enhancements: