Skip to content

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

Merged
brettheap merged 5 commits into
mainfrom
fix/666-stale-comments
Oct 17, 2026

Conversation

@brettheap

@brettheap brettheap commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

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 --help text, no pinned copy, so no README, handbook or docs/cli.md change.

What changed

Fix round

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.

Evidence

Only comments and docstrings changed. git diff 8062810d 426877bf 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 20c8873b 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.

Tests

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.

Merge checks

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.

Left out

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.

Checklist candidates

  • 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.

Closes #666

🤖 Generated with Claude Code

Summary by Sourcery

Enhancements:

  • Align comments and docstrings with the validator execution model, including isolated child processes and the actual verification output.

Brett Heap and others added 2 commits October 16, 2026 13:58
… 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>
@brettheap

Copy link
Copy Markdown
Contributor Author

(lane openRepoShape-5, 2026-10-16T17:22Z) @codex review

@sourcery-ai

sourcery-ai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

This documentation-only PR updates stale comments and docstrings to describe the current verification output and validator isolation accurately, including -S, missing dependencies, exported PYTHONPATH, and the decoy test’s actual coverage. Runtime behavior, CLI help, generated documentation, and ASTs remain unchanged.

Sequence diagram for isolated validator execution and dependency failure

sequenceDiagram
    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
Loading

File-Level Changes

Change Details Files
Correct documentation of the seeded verification row to match the output format.
  • Removed the stale colon from the documented code row.
  • Kept the description aligned with the existing seeded-template wording.
adopt-project.py
Document validator behavior under isolated child execution and missing validator dependencies.
  • Removed the misleading rationale from the submodule configuration docstring.
  • Explained that edited validators can crash under -S when CI dependencies such as yaml are unavailable.
  • Clarified that -S enforces execution isolation rather than detecting edited copies.
shape-doctor.py
Align decoy-test comments and docstrings with actual -S behavior and test coverage.
  • Explained that sitecustomize is inert because validator children are launched with -S.
  • Identified the direct PYTHONPATH probe as the coverage for replace-not-prepend and S1 regressions.
  • Reframed the decoy assertions as a tripwire for any future removal of -S and identified the dedicated isolation test.
  • Corrected the claim about detecting absent PYTHONPATH for callers that pass no value.
tests/test_shape_doctor.py

Assessment against linked issues

Issue Objective Addressed Explanation
#666 Make the adopt-project.py verification-row docstring and the submodule_config docstring accurately describe current behavior. ✅
#666 Clarify in run_validator's docstring that the no-import claim applies only to unedited validator copies and that edited copies can fail when their own CI dependencies are unavailable. ✅
#666 Correct the decoy test's comments to reflect that -S prevents sitecustomize from running and identify the test that now guards the relevant PYTHONPATH behavior. ✅

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T17:24:15.112013Z a2113cf Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: a2113cffb5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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>
@brettheap brettheap changed the title adopt-project.py, shape-doctor.py and tests/test_shape_doctor.py: the 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 (#666) 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) Oct 16, 2026
@sonarqubecloud

Copy link
Copy Markdown

@brettheap
brettheap marked this pull request as ready for review October 17, 2026 11:43

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Approved.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@brettheap
brettheap merged commit 974d482 into main Oct 17, 2026
5 checks passed
@brettheap
brettheap deleted the fix/666-stale-comments branch October 17, 2026 11:45
brettheap pushed a commit that referenced this pull request Oct 17, 2026
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>
brettheap pushed a commit that referenced this pull request Oct 17, 2026
…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>
brettheap added a commit that referenced this pull request Oct 17, 2026
…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>
brettheap pushed a commit that referenced this pull request Oct 17, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant