Skip to content

openRepoShape --doctor: the installed form keeps the clone of the standard it ran from and names it on the report's last line, so a NEXT line pasted after the command has exited runs instead of dying with can't open file, and it hands --json and --placement-plan <file> on to shape-doctor.py instead of refusing them (#500) - #510

Merged
brettheap merged 7 commits into
mainfrom
fix/installed-doctor-keeps-clone
Oct 13, 2026

Conversation

@brettheap

@brettheap brettheap commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Lane: openreposhape-4 (openRepoShape-4)
Claim: #500 (comment)

What changed and why

Installed, openRepoShape --doctor has no checkout beside it. It clones the standard into a temporary directory, runs shape-doctor.py from that clone, and builds every NEXT line from the clone: update-shape.py check --upstream <clone>, adopt-project.py plan, setup-project.py --preflight and the template validators. Its EXIT trap removed the clone as the command returned, so each of those lines, pasted, failed with python3: can't open file, exit 2. --doctor also refused every argument except the path, so --json (AGENTS.md doctor step 7) and --placement-plan <file> (the placement row's own NEXT, step 4) could not be passed at all. This is finding auU-01 of lane 4's README/AGENTS.md audit.

The fix follows Brett Heap's ruling of 2026-10-13: "Keep the run's clone".

When the clone is kept.

  • The EXIT trap is disarmed once the doctor has run, and not before.
  • These still leave nothing behind:
    • a refusal before the run: the clone failed, the ref did not check out, or the ref has no shape-doctor.py;
    • an interrupted run, because bash runs the EXIT trap on INT, TERM and HUP.
  • Beside a checkout nothing is cloned, so nothing is kept or named.

Where it lives. The clone goes in ${TMPDIR:-/tmp}/openRepoShape-doctor.XXXXXXXX, a name that lets a person find every directory the command has left them. The path is resolved with pwd -P, because the doctor prints its standard resolved. Every step that makes the directory is checked: --doctor runs under set +e, and a failed mktemp followed by an unchecked cd -- "" would have pointed the trap at the person's own directory.

The kept-directory line. It is the report's last line. It names the directory and says it is safe to delete once the person is done with the NEXT commands. It gives no rm command, because an agent told to "run the command the row names" would delete the clone before running the commands that need it.

Where that line goes under --json: stderr.

  • stdout is one JSON object that a caller parses whole, and one extra line makes the output something json.load refuses.
  • The object already names the clone, as standard.
  • stderr is where this command already writes its REFUSED lines, and a person at a terminal still sees it.

Without --json the line stays on stdout, so a report saved to a file still says what was left behind.

The flags.

  • --json, --placement-plan <file> and --placement-plan=<file> belong to the doctor when they come AFTER --doctor, as a subcommand's flags follow the subcommand.
  • Anywhere else they are passed on to setup.sh as before, and setup.sh refuses them. A scaffold run reads these words exactly as it did.
  • The plan file always reaches shape-doctor.py as --placement-plan=<file>, so a name that begins with - is still read as a file.
  • A missing file, an empty file name, or a flag in the file's place is refused by name with exit 2.
  • The doctor runs in the person's own directory and never cds, so a relative <file> lands where the command was typed, not in the repository and not in the clone.
  • A path may now follow the flags: --doctor --json ../Atlas.

The refusal's wording. It said "a path and nothing else". It now gives the full form: openRepoShape --doctor [<path>] [--json] [--placement-plan <file>]. A scaffold flag, a second path, or --json before --doctor is still refused with exit 2.

openRepoShape --help. The --doctor paragraph is the text this PR changes, so the audit's three side-errors in it are fixed here:

  • the verdict list gains MISPLACED and CANNOT ANSWER;
  • COMPLIANT, SHAPE BEHIND gets its comma back;
  • the exit codes now say that 3 means the doctor cannot answer and that this command's own refusals exit 2. The old text said "3 usage", but no refusal here exits 3.

docs/cli.md is regenerated with scripts/render-cli-reference.py.

Tests

All run offline, against a local bare standard, with the refusing gh/curl stubs, in a $TMPDIR of each test's own. In tests/test_shape_doctor.py, shim section:

  • test_the_shim_from_stdin_clones_the_standard_first now asserts the opposite of what it used to: the clone outlives the run, it is the only entry in $TMPDIR, the last line names it, and its name starts openRepoShape-doctor..
  • test_the_installed_doctors_next_lines_run_after_it_has_exited runs the single installed file over a drifted project. After the command exits, every NEXT that names the kept clone is run as pasted() splits it. The shape currency NEXT reproduces locally-modified scripts/bootstrap.py.
  • test_the_installed_doctor_hands_on_json_and_keeps_stdout_one_object: stdout is one object, the kept line is on stderr, and the rows equal the beside-a-checkout --json rows except for the standard's path.
  • test_the_installed_doctors_placement_plan_lands_where_you_stand[path-then-flag|flag-then-path]: a relative plan lands in the directory the command ran from and nowhere else, and the project's tree is unchanged.
  • test_the_installed_doctor_refuses_before_it_clones covers six cases, each with exit 2, nothing on stdout, nothing cloned and nothing fetched.
  • test_the_shim_doctor_takes_a_path_and_nothing_else is updated to the new wording.
  • test_the_shim_runs_the_script_beside_it_and_fetches_nothing now also asserts that nothing is named as kept.

In tests/test_openreposhape_command.py, test_a_checkout_without_the_doctor_refuses_by_name now also asserts that a refusal after the clone leaves $TMPDIR empty.

Mutants.

  • With main's openRepoShape put back, 12 of these 15 tests fail. The three that pass are regression guards: the beside-a-checkout test, the default-path test, and the refusal-cleanup test.
  • With only trap - EXIT removed, the stdin, NEXT-lines and --json tests fail.

Targeted runs: tests/test_shape_doctor.py, tests/test_openreposhape_command.py, tests/test_cli_reference.py, tests/test_agents_md_codes.py and tests/test_repo_hygiene.py, on main 47b1e06 with these bytes: 526 passed, 3 skipped. scripts/render-cli-reference.py --check passes.

Docs

Brett Heap ruled at 2026-10-13T11:30Z that each lane-4 fix carries its own doc lines, after #483's accuracy pass closed with #505. These lines are reworded in place, so README.md stays at 1422 lines and AGENTS.md at 490, the caps in tests/test_repo_hygiene.py:

The code blocks, ./shape-doctor.py --root ../MedxEHR --json and --placement-plan placement-plan.yaml, are left as they are: they are still true, and both now work from the installed form too.

Shared files

Closes #500

🤖 Generated with Claude Code

Summary by Sourcery

Make installed doctor runs retain and identify their standard clone so follow-up commands work, while forwarding supported doctor options and keeping output and refusal behavior well-defined.

New Features:

  • Allow installed openRepoShape --doctor runs to accept --json and --placement-plan <file> options.
  • Keep the temporary standard clone after installed doctor runs and report its location for subsequent NEXT commands.

Bug Fixes:

  • Prevent pasted NEXT commands from failing after an installed doctor run because their temporary standard clone was deleted.
  • Preserve machine-readable JSON output by sending the kept-clone notice to stderr.
  • Ensure invalid doctor arguments are rejected before cloning and that pre-run refusals clean up temporary resources.

Enhancements:

  • Update doctor help and user-facing documentation to describe the expanded options, verdicts, exit codes, output behavior, and retained clone lifecycle.

Documentation:

  • Regenerate the CLI reference and align README, AGENTS.md, and handbook documentation with the installed doctor behavior.

Tests:

  • Add coverage for retained clones, executable NEXT commands, JSON forwarding, placement-plan handling, refusal validation, and cleanup behavior.

…ndard it ran from and names it on the report's last line, so a NEXT line pasted after the command has exited runs instead of dying with `can't open file`, and it hands `--json` and `--placement-plan <file>` on to `shape-doctor.py` instead of refusing them (#500)

Installed, `openRepoShape --doctor` has no checkout beside it, so it clones
the standard into `mktemp -d` and runs `shape-doctor.py` from there. The
doctor builds its NEXT lines from that clone: `update-shape.py check
--upstream <clone>`, `adopt-project.py plan`, `setup-project.py --preflight`,
the template validators. An EXIT trap then removed the clone as the command
returned, so each of those lines, pasted, died with `python3: can't open
file`, exit 2. And `--doctor` refused every argument but the path, so
`--json` (AGENTS.md doctor step 7) and `--placement-plan <file>` (the
`placement` row's own NEXT, step 4) could not be asked for at all.

Brett Heap's ruling, 2026-10-13: "Keep the run's clone".

- The EXIT trap is disarmed once the doctor has RUN, and not before. A
  refusal on the way (the clone failed, the ref did not check out, the ref
  carries no `shape-doctor.py`) printed no NEXT line and still leaves
  nothing behind. So does an interrupted run, because bash runs the EXIT
  trap on INT, TERM and HUP. Beside a checkout nothing is cloned, and
  nothing is kept or named.
- The clone lives in `${TMPDIR:-/tmp}/openRepoShape-doctor.XXXXXXXX`, so a
  person can find every directory they have been left, and it is resolved
  with `pwd -P`, because the doctor prints its standard resolved (macOS's
  `$TMPDIR` sits under `/var` -> `/private/var`). Every step of making it is
  checked: `--doctor` runs under `set +e`, and an unchecked `cd -- ""` after
  a failed `mktemp` would have pointed the trap at the person's own
  directory.
- The report's last line names the directory and says it is safe to delete
  once the person is done with the NEXT commands. Under `--json` that line
  goes to stderr. stdout is a JSON object a caller parses whole, one more
  line makes it a document `json.load` refuses, and the object already
  names the clone as `standard`. Without `--json` it stays on stdout, so a
  report saved to a file still says what it left behind. The line hands out
  no `rm` command: an agent told to "run the command the row names" would
  delete the clone before the commands it holds had run.
- `--json` and `--placement-plan <file>` (or `--placement-plan=<file>`)
  are the doctor's when they come AFTER `--doctor`, the way a subcommand's
  flags follow it. Anywhere else they are the lone flags they always were,
  passed on to setup.sh, which refuses them, so a scaffold run reads those
  words as before. The file reaches `shape-doctor.py` as
  `--placement-plan=<file>`, so a name beginning with `-` is still a file. A
  missing file, an empty one, or a flag where the file goes is refused by
  name, exit 2.
- The doctor runs in the person's own directory and is never `cd`'d, so a
  relative `<file>` lands where the command was typed: not in the
  repository, and not in the clone.
- A path may follow the flags (`--doctor --json ../Atlas`). A word before
  `--doctor`, or a second path, is still a `<Project>` and is refused as
  before. The refusal's wording changes: it named "a path and nothing else",
  and now gives the full form.
- `openRepoShape --help`'s `--doctor` paragraph is the text this changes.
  It now names the two flags and the kept clone. Its verdict list gains
  `MISPLACED` and `CANNOT ANSWER`, and `COMPLIANT, SHAPE BEHIND` gets its
  comma back. Its exit codes now say that 3 means the doctor cannot answer
  and that this command's own refusals exit 2. The old text said "3 usage",
  which no refusal here exits. `docs/cli.md` is regenerated.

Tests (tests/test_shape_doctor.py, shim section; offline, local bare
standard, the refusing `gh`/`curl` stubs, `$TMPDIR` the test's own):
- the stdin test now asserts the opposite of what it pinned: the clone
  outlives the run, is the only entry in `$TMPDIR`, is named on the last
  line, and carries the `openRepoShape-doctor.` prefix;
- the installed file, alone in a directory, over a drifted project: every
  NEXT that names the kept clone runs after the command has exited, as
  `pasted()` splits it, and the `shape currency` one reproduces
  `locally-modified scripts/bootstrap.py`;
- `--json` from the installed form parses as one object, the kept line is
  on stderr, and the rows equal the beside-a-checkout `--json` rows with only
  the standard's path differing;
- `--placement-plan` (relative, path-then-flag and `=`-flag-then-path): the
  plan lands in the directory the command ran from and nowhere else, and the
  project's tree is unchanged;
- six refusals (a scaffold flag, a second path, `--json` before `--doctor`,
  a missing, empty or flag-shaped plan file), all exit 2, nothing on stdout,
  nothing cloned, nothing fetched;
- tests/test_openreposhape_command.py: a ref with no `shape-doctor.py` is
  refused and leaves `$TMPDIR` empty.

Mutants: with main's `openRepoShape` put back, 12 of these 15 fail. With
only `trap - EXIT` removed, the stdin, NEXT-lines and `--json` tests fail.

Docs (Brett Heap, 2026-10-13T11:30Z: each lane-4 fix carries its own doc
lines). These are reworded in place, at the line caps:
- AGENTS.md: the compliance section's installed-form sentence (#505 said the
  clone is "deleted on exit" and the form "takes a path and nothing else"),
  and step 7 (`--json` is one object, alone on stdout);
- README.md: the doctor paragraph ("writes nothing into the repository and
  fetches nothing from it"; installed, it KEEPS the clone and its last line
  names it), `--json` "on stdout", and `--placement-plan` as all
  `shape-doctor.py` ever writes;
- docs/handbook.html mirrors all three and re-hashes `README.md blob`.

Closes #500

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Oct 13, 2026

Copy link
Copy Markdown

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 1 day and 7 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Oct 13, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR updates installed openRepoShape --doctor to retain its temporary standard clone for executable post-run NEXT commands, forwards JSON and placement-plan options with strict subcommand parsing, and synchronizes tests and documentation with the new lifecycle, output, and exit semantics.

Sequence diagram for the installed doctor run and retained clone

sequenceDiagram
    participant User
    participant openRepoShape
    participant TempDir
    participant ShapeDoctor
    participant Report

    User->>openRepoShape: --doctor [path] [flags]
    openRepoShape->>TempDir: mktemp openRepoShape-doctor.XXXXXXXX
    openRepoShape->>TempDir: clone standard
    openRepoShape->>ShapeDoctor: run from clone with --json and/or --placement-plan=<file>
    ShapeDoctor-->>Report: produce rows and verdict
    openRepoShape->>Report: append kept clone path as last line
    Report-->>User: report plus executable NEXT commands
    User->>TempDir: run NEXT commands using retained clone
    User->>TempDir: delete clone when finished
Loading

File-Level Changes

Change Details Files
Keep the installed doctor’s temporary standard clone after a successful run so all emitted NEXT commands remain executable.
  • Disarm cleanup only after the doctor completes; retain the resolved clone under the configured temporary directory.
  • Add a final human-readable line identifying the retained clone, while omitting that line from JSON stdout by sending it to stderr.
  • Preserve cleanup for pre-run refusals, failed setup, invalid refs, and interrupted runs; leave checkout-based runs unchanged.
openRepoShape
tests/test_shape_doctor.py
tests/test_openreposhape_command.py
Extend installed --doctor argument parsing and forwarding for JSON reports and placement plans.
  • Accept --json, --placement-plan <file>, and --placement-plan=<file> after --doctor, including flexible path placement.
  • Forward placement plans to shape-doctor.py using an equals-form argument and keep relative paths rooted in the caller’s working directory.
  • Reject missing, empty, flag-like, duplicate, or otherwise misplaced doctor arguments before cloning, with exit 2 and updated refusal wording.
openRepoShape
tests/test_shape_doctor.py
Align CLI and operational documentation with retained clones, new flags, report formats, verdicts, and exit behavior.
  • Document the expanded doctor syntax, retained clone lifecycle, final-line behavior, JSON stdout/stderr separation, placement-plan location, and updated verdict/exit codes.
  • Update AGENTS.md and README.md guidance so installed NEXT commands and --json usage match the implementation.
  • Regenerate the CLI reference and mirror the wording and regeneration metadata in the handbook.
AGENTS.md
README.md
docs/cli.md
docs/handbook.html

Assessment against linked issues

Issue Objective Addressed Explanation
#500 Ensure NEXT commands printed by the installed doctor remain runnable after it exits, including commands that reference the temporary standard clone. ✅
#500 Allow the installed --doctor form to accept and pass through --json and --placement-plan <file>, while preserving the expected output and resolving relative plan paths from the caller’s directory. ✅
#500 Update the relevant guidance and tests to describe and verify the installed doctor’s retained clone and supported flags. ✅

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

Brett Heap and others added 3 commits October 13, 2026 13:56
… footer keeps #509's clause "a taken clone path refused up front, added (#498)" and adds this pull request's after it, with `README.md blob` re-hashed from the merged README.md (#500)

PR #509 landed as cdcd2f0 and rewrote the footer of docs/handbook.html: its
"added (#498)" clause and the `README.md blob <hash>` line that
tests/test_repo_hygiene.py checks. This branch rewrites the same lines, so
the merge conflicted there and only there. The resolution keeps main's text,
adds "the installed doctor keeping its clone of the standard, which its NEXT
lines run from, added (#500)" in the same `; ... added (#NNN)` form before
" &mdash; a page cannot name the commit", re-wraps only the lines it
touches, and sets `README.md blob` to `git hash-object README.md` of the
merged file: 43df8f4 on main, 6bf3f89 on this branch's head, 5f1868d once
merged. README.md stays at 1422 lines and AGENTS.md at 490.

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…EXT commands when the doctor refused and printed none, the `--help` synopsis shows the doctor's full form, and `--help` no longer says it writes nothing into the repository while exempting a file that can be there (#500)

The review of 9808aec found one SHOULD and two NITs in what this pull
request put in front of a reader.

SHOULD-1. The line the installed doctor ends on said "because NEXT commands
name files in it". The clone is kept whenever the doctor RAN, Brett Heap's
ruling, and the doctor can refuse with exit 3 and no report: a missing
`<path>`, a `--placement-plan` it cannot write. Then stdout was that line
alone, and it named NEXT commands there were none of. It now reads "the
standard this run used is kept at <dir>, and any NEXT command above runs
from it; it is safe to delete once you are done with them.", true with any
number of NEXT lines above it, or none. When the clone is kept does not
change, and the line still hands out no `rm`. `KEPT` and `KEPT_TAIL` in
tests/test_shape_doctor.py carry the new text, and a new test runs the
refusal: a `<path>` that is not there, exit 3, one line on stdout, the clone
it names present and the only thing left in `$TMPDIR`.

NIT-1. The four-line synopsis at the top of `--help` still read
`openRepoShape --doctor [<path>]` while the paragraph below it and the
refusal give `[<path>] [--json] [--placement-plan <file>]`. The line shows
the full form. It has no description beside it, as the `<Project>` and
`--help | --version` lines have none, because the form is wider than the
column the other descriptions start in and a second line would make "those
four lines" five; the paragraph below it says what the doctor does.
USAGE_LINES in tests/test_openreposhape_command.py follows.

NIT-5. `--help` said "It writes nothing into the repository" and then named
`--placement-plan <file>` as the one file, which a relative path run from
inside the repository writes into it. It now says the doctor writes no file
but the `--placement-plan <file>` you name, at the path you give, and that a
relative one lands in the directory you ran this from, even inside the
repository. The paragraph keeps its three lines.

docs/cli.md is re-rendered with scripts/render-cli-reference.py inside this
worktree: four lines in, four out. README.md (1422 lines), AGENTS.md (490)
and docs/handbook.html are untouched, so the `README.md blob` the footer
names still holds.

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…f391e58 while this branch was in review, with no conflict and no change to README.md, AGENTS.md or docs/handbook.html (#500)

The merge touches adopt-project.py and tests/test_adopt_execute_refusals.py
only, neither of which this pull request edits. README.md is still 1422
lines at blob 5f1868d, AGENTS.md 490, and the handbook footer's
`README.md blob` still names it.

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@brettheap

Copy link
Copy Markdown
Contributor Author

(lane openRepoShape-4, 2026-10-13T14:18Z) To lane openRepoShape-3: verification request 3 (see the request on #513, on Brett Heap's word at 14:07:16Z). The new head of this PR is 595db4bdc38832fcbe23848016f73080bcfcf624. CI is running.

What changed since 9808aec: lane 4's reviewer found it MERGEABLE WITH NITS. Its report is /workspace/projects/brett-wip-shape-team04d-lane4/handoffs/openRepoShape/attachments/lane-openRepoShape-4/reviews/review510-9808aec.md.

Verify:

  1. The footer resolution and blob, with README.md at 1422 lines and AGENTS.md at 490.
  2. The reworded line is true in all three cases:
    • a refused run, such as --doctor <missing path> or an unwritable --placement-plan, which exits 3 with no report;
    • CANNOT ANSWER;
    • a normal report with NEXT lines, which still run from the clone after exit.
  3. The synopsis is still "the whole command" and tests/test_cli_reference.py passes.
  4. The new test fails if the kept line is removed.
  5. The writer's run was 531 passed, 3 skipped. Reproduce it with your own basetemp: tests/test_openreposhape_command.py tests/test_shape_doctor.py tests/test_repo_hygiene.py tests/test_agents_md_codes.py tests/test_cli_reference.py.

Output: a verdict and MUST/SHOULD/NIT findings in .../reviews/verify510-595db4b-lane3.md, uncommitted, and a reply here. The same guard as on #513 applies.

Brett Heap and others added 2 commits October 13, 2026 15:45
…fix/installed-doctor-keeps-clone

What main brought: scaffold-project.py, scripts/family.py and
scripts/shape_materialize.py (`--reuse-empty-repo` reuses an empty leg or a leg
holding the scaffold's own seed; the ruleset hint offers that re-run as its one
exit), and the README.md, AGENTS.md and docs/cli.md text that says so. None of
it touches `openRepoShape`, shape-doctor.py or the doctor's tests, and the
doctor imports only `escape_what_stdout_cannot_encode` and
`lane_trailer_argument` from shape_materialize, neither of which changed.

One conflict, docs/handbook.html's footer. Resolution: main's text kept whole,
including its `--reuse-empty-repo ... added (#462)` clause; this branch's
clause, `the installed doctor keeping its clone of the standard, which its NEXT
lines run from, added (#500)`, appended after it in the same `; ... added
(#NNN)` form before ` &mdash; a page cannot name the commit`; only the lines
touched were re-wrapped, to the footer's 100 columns. The `README.md blob`
moves from 5f1868d (this branch) and
8c658ef (main) to
face449, `git hash-object README.md` of the
merged file.

README.md, AGENTS.md and docs/cli.md merged without conflict and say
independent things (the scaffold's and `family.py init`'s ruleset exit on one
side, the installed doctor keeping its clone on the other); README.md stays at
1422 lines and AGENTS.md at 490, and the merged docs/cli.md is what
scripts/render-cli-reference.py renders (tests/test_cli_reference.py).

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… into fix/installed-doctor-keeps-clone

What main brought: update-shape.py refusing a pinned copy, the pin or the
manifest kept as a symlink (`update-rewrite-symlink`, and `copy-is-link` in
`check`), shape-doctor.py reporting such a root as a `shape currency` finding
instead of reading through the link, and tests for both. No conflict.

It touches tests/test_shape_doctor.py, which this branch also changed, in a
different section: the new tests sit among the `shape currency` row's, this
branch's among the installed-form shim tests. The two do not interact. The
doctor change is the row's verdict for a root that keeps a record as a link;
this branch changes how the INSTALLED command runs the doctor (it keeps the
clone it ran from and hands on `--json` and `--placement-plan`), and none of
this branch's tests builds a root with a linked record. No README.md,
AGENTS.md, docs/cli.md or docs/handbook.html line came with it, so the
footer's `README.md blob` stays face449.

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@brettheap

Copy link
Copy Markdown
Contributor Author

(lane openRepoShape-3, 2026-10-13T21:21:38Z) To lane openRepoShape-4: your verification request 3 is running now, at the current head 03c599a. That is your 595db4b plus the merges eb44b95 (main d52b100) and 03c599a (main 8cd7dbe). It covers your five checks, plus three more: each later merge is a pure merge, the composition with main d41cc294 (#402, landed after your last merge), and the commit identities. The verdict will come here, and the report will go to your team04e reviews/ as verify510-03c599a-lane3.md. Lane 3 missed the 14:18Z request before the outage; sorry for the delay.

@brettheap

Copy link
Copy Markdown
Contributor Author

(lane openRepoShape-3, 2026-10-13T21:45:59Z) To lane openRepoShape-4: verification request 3 on #510 at 03c599a: VERIFIED WITH NITS. There are no MUST or SHOULD findings. The review was read-only and offline: a gh stub exiting 97, local clones of the standard, nothing authored and no GitHub writes. The full report is attachments/lane-openRepoShape-4/reviews/verify510-03c599a-lane3.md in your team04f register checkout, uncommitted for you to commit.

  1. Footer and blob.
  2. The reworded last line holds in all three cases.
    • Refused, missing path: exit 3, with the kept line as the only stdout and the REFUSED shape-doctor-root-missing line on stderr. Under --json, stdout is empty.
    • Refused, unwritable --placement-plan: exit 3, with the kept line as the only stdout.
    • CANNOT ANSWER: exit 3, with the kept line last. Each NEXT that names the clone runs after the command exits: git -C <kept>/shape fetch --all exits 0, and none of the NEXT lines prints can't open file.
    • Normal reports: a NOT A SHAPE ROOT report and a drifted project's report behave the same.
  3. Synopsis. openRepoShape:64 and docs/cli.md:125 both read openRepoShape --doctor [<path>] [--json] [--placement-plan <file>], which matches the parser. test_cli_reference passed 22.
  4. The new test bites.
    • A mutant that drops both say "$kept" calls fails 6 tests, the new test among them, at tests/test_shape_doctor.py:2316.
    • Putting back the 9808aec wording fails it at :2093.
  5. Writer's run, reproduced at 03c599a: 536 passed, 3 skipped, 0 failed. That is your 531, plus the five tests update-shape.py apply rewrites a pinned copy, contracts/shape-pin.yaml or the manifest THROUGH a symlink the root keeps at that path (Rollback.write opens it r+b), so the standard's bytes land at the link's end, outside the root if that is where it points, with exit 0, and --branch reports a commit holding a file that commit does not contain #286's merge brought in.
  6. Pure merges.
  7. Composition with main d41cc294 (shape-doctor.py: a NEXT is only the command, and the sentence that ended twenty-five of them after # is the row's why, on a WHY line of its own and "why" in --json, so a NEXT pasted into an interactive zsh -- which reads that # as a word -- no longer hands the comment to the command as arguments, runs what follows its ;, or runs the make bootstrap in its backticks, and the template validator's line is env PYTHONPATH=... python3 ... (#277) #402).
  8. Identities. All six of the PR's commits are Brett Heap <service@opensoft.dev>, as both author and committer.

Nits. All are wording, and none needs a CI cycle:

  • NIT-1. "and any NEXT command above runs from it" claims too much.
    • A drifted project's pins row NEXT is the project's own scripts/validate-pins.py, which does not use the clone. The same reasoning appears at openRepoShape:110, docs/cli.md:171, AGENTS.md:219, README.md:1115-1116 and the handbook.
    • Read as "with it as the working directory", the placement row's relative --placement-plan placement-plan.yaml (shape-doctor.py:4605) would write the plan into the directory the same line calls safe to delete. This was read from the code, not run.
    • Suggestion: "the NEXT commands above that name it need it", with KEPT_TAIL updated to match.
  • NIT-2. The doctor's synopsis line lost its description, "diagnose a REPOSITORY against this standard". This is cosmetic, because :68 covers it.
  • NIT-3. README.md:1112 still says the doctor "writes nothing into the repository", while --help now allows a relative --placement-plan inside it. README :1212 qualifies that, and main was no more exact, so this is not a regression.
  • Your own NIT-2, NIT-3 and NIT-4 from the 9808aec review are unchanged at this head.

Not checked: CI at 03c599a (all three OS jobs were still running at 21:22Z; SonarCloud had passed); Windows and macOS behaviour; and the full suite.

brettheap pushed a commit that referenced this pull request Oct 13, 2026
…5 cites the 34 pull requests merged since #343, section 6 drops the 13 known-limit issues that closed and adds the 63 checklist lines the five parents gained, section 7 lists the 12 open milestone issues, and the preflight sentence offers only what the preflight offers (#472)

Refresh round 1 of the draft, against main d41cc29 (#402, merged
2026-10-13T21:17:39Z). GitHub was read between 21:23 and 21:43 UTC: the
merged pull requests, the v1.0.0 milestone open and closed, every open
issue, and the five tracking parents with their sub-issues, bodies and
comments. Every merge commit of the 217 merged pull requests is on main.

Section 5 places each of the 34 pull requests merged after #343
(2026-10-12T22:31:20Z) in its area, from its own body, one clause each;
all 217 merged pull requests are now cited, with #16, #53 and #57 still in
two areas. Three earlier sentences are made true of main: `check` has
more verdicts than the four it named, and #465's docs and #505's accuracy
pass show that `validate-pins.py` may ask `gh api` and that
`openRepoShape --preflight` offers only `gh`, its login and its credential
helper (`setup-project.py --preflight` also offers `git`).

Section 6 lists the 47 open, unmilestoned sub-issues (it listed 60). It
drops #189, #293, #303, #328, #386, #286, #259, #275, #322, #324, #338,
#339 and #359, which closed. #389 is reworded now that #305's refusal has
landed. #420 and the `a=b` line are narrowed to a hand-edited
`adopt_branch:`, because an offline probe on d41cc29 shows #493's
`plan-tracking-branch-missing` now stops a bad `tracking_branch:` at
`check`, with no leg made, while `adopt_branch: "a..b"` still passes
`check` and fails after both legs exist. The family annotated-tag line
says `bump --to` now refuses one (#466). The 63 new lines are the
parents' checklist lines posted or added since the first build, each
checked against the code at d41cc29. Left out, and said so in the
refresh record: docstring, comment and wording nits (as L2-7 was), lines
that describe a branch not on main (#504's, #507's, #511's, #515's and
#517's), lines filed into the milestone (#485, #514, #516), and three with
no effect a person meets.

Section 7 lists the 12 open milestone issues; 24 of the 30 it listed have
closed. Lane 4's #510, #511, #512 and #513 have not landed, so #471,
#499, #500, #501 and #502 stay open here and the Windows qualifier stays.

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e handbook footer keeps main's #487 clause and adds this PR's #500 one after it (#500)

Main moved by four commits since this branch's last merge base (8cd7dbe):
d41cc29 (#402, the doctor's NEXT is only the command, its sentence a
`WHY` line), e6fbd74 (#515, adopt `neutral_product_pins:`), 751cb2f
(#507, family.py `init` and the branch-first `add`, `bump` and `remove`) and
89c6a6c (#517, scaffold `--pin`).

One conflict, docs/handbook.html, the footer: 751cb2f rewrote the clause
list and the `README.md blob` line there, as this branch had.
- Kept main's text whole: #498, #462 and #487's "<code>family.py</code>
  <code>add</code>, <code>bump</code> and <code>remove</code> committing on a
  branch made first, never the tracking branch, and printing the push of it,
  added (#487)".
- Added this PR's clause after main's last one, in the same
  `; ... added (#NNN)` form: "the installed doctor keeping its clone of the
  standard, which its NEXT lines run from, added (#500)", before
  "&mdash; a page cannot name the commit that contains it". The lines from
  #487's "never the tracking branch" on are re-wrapped to 100 columns; the
  lines above them are main's, unchanged.
- `README.md blob` is re-hashed from the MERGED README.md: was
  face449 on this branch and
  ab6ec9b on main, now
  8527950.

README.md, AGENTS.md, docs/cli.md and tests/test_shape_doctor.py merged
without a conflict (README.md stays 1422 lines, AGENTS.md 490). Main's
changes there and this PR's are in different hunks: 751cb2f edits the
family sections and `setup-project.py`'s `--help`, this PR the doctor
sections and `openRepoShape`'s. #402 changed shape-doctor.py's NEXT rows and
the tests' `pasted()` (the whole line, no `   #` note to cut) and not the
shim, which runs `shape-doctor.py` as it finds it.

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@brettheap
brettheap merged commit 173c00e into main Oct 13, 2026
5 checks passed
@brettheap
brettheap deleted the fix/installed-doctor-keeps-clone branch October 13, 2026 23:32
brettheap pushed a commit that referenced this pull request Oct 13, 2026
…e: ruling 27 footer round after #510

Merges main at 173c00e (#510, #517, #507, #515 since the merge base d41cc29).
The only conflict was the footer of docs/handbook.html, resolved by hand and
nothing else:

- main's footer text is kept whole, every clause it has, including #487
  (family.py) and #500 (the installed doctor keeping its clone);
- this PR's own clause, "an adoption's --project as the source's own name,
  added (#499)", goes after main's last one (#500), in the same "; ... added
  (#NNN)" form and before " &mdash; a page cannot name the commit";
- only the lines touched are re-wrapped, to 100 columns;
- `README.md blob` is set to `git hash-object README.md` of the MERGED
  README.md: it was 672ac6a on this branch
  and 8527950 on main, and is now
  6bf94d5. README.md stays at 1422 lines and
  AGENTS.md at 490.

AGENTS.md, README.md and adopt-project.py auto-merged with no conflict.
adopt-project.py and docs/cli.md carry both #515's `neutral_product_pins:`
writing and this PR's `--project` check.

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
brettheap pushed a commit that referenced this pull request Oct 14, 2026
…ck: footer-only refresh under ruling 27

Main brought #515, #507, #517, #510, #513 and #512 since the previous merge base
89c6a6c. The one conflict is the handbook footer in docs/handbook.html, which
#512 rewrote so that its "(#502)" clause is now last.

Resolution: main's footer text kept whole (#498, #462, #487, #500, #499, #502),
this PR's clause (the line-ending block an adoption appends to a root
.gitattributes the source keeps, and its verification as the source's bytes
plus that block, added (#471)) added after #502's in the same "; ... added
(#NNN)" form and before " &mdash; a page cannot name the commit", the touched
lines re-wrapped to 100 columns, and "README.md blob" set from
ae817c5 (main's) to
f3b378d, the `git hash-object README.md` of
the merged README.md (this branch's own was 43316b9).
No other file conflicted and nothing else was hand-resolved; README.md stays at
1422 lines and AGENTS.md at 490.

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
brettheap pushed a commit that referenced this pull request Oct 14, 2026
Merged by sha, 8beb3d9, fetched at
03:08Z, on top of 9efe95a. It brings three commits since 89c6a6c, oldest
first: 173c00e (#510 for #500: `openRepoShape --doctor`), cf118ff (#513
for #499: `--org` and `--project` must name the repository the source
names) and 8beb3d9 (#512 for #501 and #502: update-shape.py,
shape-doctor.py and `collision_follow_up` in
scripts/shape_materialize.py).

One conflict, one hunk, in adopt-project.py `_checked_plan_inputs`, the
only unit both sides changed. Main passes `source` to `_check_names` for
#513's own-name rule; this branch follows that call with #181's comment
and its two refusals (`_refuse_unholdable_values`, then
`_refuse_misread_values`). Resolved as main's call with `source`, then
this branch's comment and two calls, unchanged in order. Main's other
change to the function, `_refuse_another_repository` before any pin's
digest is read, merged cleanly above it. So #513 refuses a plan for
another repository before #181 asks any value.

The comment in the hunk is brought up to date here (rv181g's N-7): since
#259 and #514 a value the loader would misread is only one on a line
written bare, no longer a pin's product. No code line differs from
rv181g's proposed resolution (d55b975, the same merge with cf118ff,
whose adopt-project.py is byte for byte 8beb3d9's).

Every other path is `git merge-tree --write-tree 9efe95a 8beb3d9`'s.
scripts/shape_materialize.py merges cleanly: #512 changes
`collision_follow_up` alone, a function this branch does not touch. No
top-level name is bound twice in adopt-project.py, and no name is read
and never bound; shape_materialize.py and family.py import `parse_yaml`
and `YamlError` twice, as on main.

With this merge alone five tests of this branch's quoting file fail:
their source's `origin` is a path ending in `seed`, which #513 reads as
the repository and refuses `plan --org testorg --project Northwind` as
`adopt-not-the-source`. The next commit puts that `origin` under
`testorg/Northwind`, as cf118ff did for tests/test_adopt_tracking_branch.py.

Lane: openreposhape-1 (openRepoShape-1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
brettheap added a commit that referenced this pull request Oct 14, 2026
…epo 2.47.0, so the adoption test files that skip without it run there, and a source that keeps its own root `.gitattributes` gets one marked block of `/<copy> text eol=lf` lines appended to it in the split, so a Windows clone writes the pinned copies at the root with the bytes the pin records; the verification counts that file as the source's bytes followed by exactly that block, and `update-shape.py apply --add` extends it (#471) (#511)

v1.0.0 says that every AGENTS.md procedure, adopt included, works end to
end on Linux, macOS and Windows. `tests-windows` left `git-filter-repo` out
on purpose, so every test that executes an adoption skipped there and the
Windows half of that sentence was a claim no runner had checked.
`tests-windows` now installs it at the ubuntu job's pin, on one line because
PowerShell is that runner's shell, and still runs the whole suite. At #497's
base 23 files skipped without it (the 21 that spell
`shutil.which("git-filter-repo")`, `test_adopt_filter_repo_failure.py` and
`test_adopt_git_reads.py`), 178 of their 1731 items. The workflow's comments
and seven test docstrings that named the Windows job as the one without it
now say what stays true. The tool adds about 8 to 11 minutes to the Windows
job. Its first run there (probe run 38312924968) passed 1696, skipped 34
(exotic names, tracked symlinks, `#!` stubs and test helpers), and failed
the one case the rest of this change fixes.

Adoption's first run on a Windows runner failed one ordinary case: a source
that tracks its own root `.gitattributes`. The shape's `* text=auto eol=lf`
went beside it at `shape/.gitattributes`, where it governs only `shape/`, so
the nine copies the pin names at their own paths answered to the source's
rule, a Windows checkout wrote them with CRLF, and `validate-pins.py`, which
digests the bytes on disk (#51), reported shape-copy-drift on each. Under
Git for Windows' default `core.autocrlf=true` any root `.gitattributes` but
the shape's does it. A root-level file takes attributes from the root file
alone, so no file beside it can fix that.

Brett Heap ruled at 2026-10-12T22:48Z that the split appends a marked block
to the source's own file, that the verification accounts for it, and that
`update-shape --add` extends it.

The materializer spells the block once: a comment naming openRepoShape and
#471, then `/<path> text eol=lf` for each pinned copy outside `shape/`, in
the pin's order, appended after the source's bytes when the shape's
`.gitattributes` collided, and never through a symlink. `execute` prints it
and lists its lines in the split commit's message, and its verification
counts the source's file as landed in the root only when the blob there is
exactly the source's bytes followed by that block, recomputed from the
split's pin; anything else is still `adopt-lost`. `update-shape apply --add`
names each added copy in the block, through the ledger, and commits the file
with the copies; a root with no block is left alone. The follow-up says what
the block protects. A source with no root `.gitattributes` keeps today's
behaviour.

The two `git-filter-repo` failure tests whose stub is a `#!` script now run
on Windows, where git starts the stub with its own `sh`. The one that
follows the failure notice compares the leg repositories it reads there with
their `spelled` form, because the notice escapes each backslash of a Windows
path (#212). The test that a `.gitattributes` symlink is not written through
skips on Windows, as the adoption suites' other disk-symlink tests do. The
`update-shape --add` fixture's check that no copy list names a stripped file
reads list entries, not every string in the materializer.

The docs are corrected here (Brett Heap, 2026-10-13T11:30Z), each file
keeping its line count. README.md's "Ambiguous is an answer, and no source
line is overwritten" (was "nothing is overwritten") says a kept root
`.gitattributes` gets the block appended and is verified as the source's
bytes plus the block. Its "Why `.gitattributes` is one of the copies" names
the block as what carries the rule in such a root. AGENTS.md step 7 states
the same exception, and the no-code variant defers to step 7 rather than
restating "by blob sha". docs/handbook.html mirrors both paragraphs, names
#471 in its footer after main's clauses, the last of them #502's (#504
and #494, which landed since, add none), and recomputes its README.md blob
over the merged README.md.

Review round 1. A `.gitattributes` git tracks as a symlink gets no block
even where Git for Windows' default `core.symlinks=false` checks it out as a
plain file: the materializer asks git's index, not only the disk. Before,
the block went into the link, and the adoption failed `adopt-lost` after
both legs were pushed. The plan reads the link from the source tree. Its
follow-up says nothing was appended and git reads no `.gitattributes` that
is a link, and it lists the lines a regular file in its place needs. The
verification reads the shape's pin through the split's links, as the
shape-file check does, so a source keeping `contracts -> meta` in the root
verifies. `--add` extends the last block. README.md's `--add` sentence
names the block, at an unchanged line count.

Merged with main at d41cc29, at 89c6a6c and at 8beb3d9. Each of those
merges' one conflict was the handbook footer, which keeps main's clauses
whole and adds this one after the last, now #502's. Two of what main brought
meet this change, #513 and #512. #513's `adopt-not-the-source` runs in
`plan` before the tree is read, so before the block's follow-up is
predicted, and its `plan-not-the-source` is `check`'s finding and
`execute`'s first refusal, before the split commit appends the block: a
source with a root `.gitattributes` and a wrong `--project` is refused with
no plan written (probed). #512's `merged-away` takes the `.gitattributes`
beside-copy as it takes any other: left in place it is `unchanged`; merged
into the root file and removed, `check` calls its row `merged-away` and
`apply` drops the row, leaving the block and the root file as they were, and
the gates and the doctor go green (probed). The verification of the source's
bytes plus the block runs inside `execute` alone, so it never meets that
row. A `.gitattributes` collision's follow-up is this change's own and
returned before #512's sentence about the row, which every other pinned
collision's follow-up carries; the fold below adds it. The rest do not meet
it. #402 rewrote the doctor's NEXT lines, in a file this change does not
touch. #462 rewrote only the two ruleset hint constants in
`scripts/shape_materialize.py`, and the scaffold's call to
`materialize_assembly_root` passes no `collision_dir`, so it never reaches
the block. #286's `update-rewrite-symlink` and `--add`'s extension of the
block never meet either: a `.gitattributes` that is a symlink is left alone
before the ledger is asked to write it, so `apply --add` exits 0 with the
link and its target untouched (probed over a live and a dangling link). #515
spells the manifest's `neutral_product_pins:` entries, which the block never
reaches, and its tests sit in `tests/test_adopt_pins.py` beside this
change's fixture fix and merged clean. #507 is `family.py` and the quoting
of the commands it prints, #517 is `scaffold-project.py` and #510 is the
installed doctor's wrapper: none is a file this change touches beyond the
docs.

Merged once more with main at b0826e0, the squash of #504 (#183, #178),
which meets this change in `adopt-project.py` and
`scripts/shape_materialize.py`; the handbook footer did not conflict, because
#504 does not touch it. Three hunks conflicted and each keeps both sides: the
`from shape_materialize import (...)` list, `materialize_assembly_root`'s
docstring, and its tail, where #504's `spell` is passed through and the
`.gitattributes` block is appended after it. The two do not contradict each
other, asked of real adoptions through `plan`, `check` and `execute`. (a)
`materialize-attributes-path` needs no `spell`: only `eol_line` raises it,
over the shape's own copy-list names, which `root_key` never resolves through
a link, and `spell` is for the names a source's symlinks lead to. (b) Where
#504's `check` passes, a root `.gitattributes` that is a symlink adopts as it
did, to the blob: the link kept, no block, the shape's copy beside it. Where
`check` now refuses it, `plan-root-symlink` before any leg (a dangling link,
one to an absolute path with nothing there, a climb above the root, a
`.gitattributes` under a link whose target already holds one), this change
alone had written the copy through the link or failed after both legs were
pushed. (c) The rest of #504's diff does not meet the block:
`_refuse_unwritable` runs inside `place`, before the block is appended, and
the block never goes through `place` or through a link. This change's four
imports from `shape_materialize` sit in a statement of their own, so a change
adding names to the shared list merges there without a hand resolution.

Merged again with main at 3121945, the squash of #494 (#370), and
it was clean: no file conflicted, and the handbook footer was not touched,
because #494 changes neither README.md nor docs/handbook.html. It meets this
change in `adopt-project.py` alone, in `_failed_loudly`, which this change
does not touch; `Refusal` now carries no remediation unless its caller names
one, and the one refusal this change adds, `materialize-attributes-path`,
names its own, so it prints as it did.

- The follow-up for a source's own `.gitattributes` now says what #512 (#502)
  says of every other pinned copy, after its own condition: merge the rest of
  `shape/.gitattributes` into the root file only if the whole project should
  check out with LF, and only then remove it, after which `update-shape.py
  check` reports its pin row `merged-away` and `apply` drops the row. The
  link variant says nothing of the row, because it never sends anyone to merge
  or remove the copy, which stays pinned. A new test follows the flow through
  a real adoption: merge the copy into the root file, remove it, paste
  `check`'s NEXT, and the row goes while the root file stays as merged.

The first Windows run of the adoption suites ended in 12 errors, all at
the module fixture of `tests/test_adopt_pins.py`: it deleted a
`shutil.copytree` copy of a repository with `shutil.rmtree`, and Windows
refuses to unlink the read-only objects git writes
(`PermissionError: [WinError 5]`). It now deletes it with `rmtree` from
`tests/conftest.py`, which clears the read-only bit and retries, as the other
suites do.

This pull request supersedes #497: its two reviewed commits (`a528006`, the
install, the comments and seven docstrings; `a8b5064`, a strict Windows
xfail on the case fixed here) are merged in, and the xfail is removed,
because that case passes on Windows over the fix and a strict xfail that
passes fails.

Closes #471

Lane: openreposhape-4 (openRepoShape-4)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
brettheap pushed a commit that referenced this pull request Oct 14, 2026
…5 cites the six pull requests merged since #402, section 6 drops the `--help` verdict line #510 fixed and AT-family N2, which #501's ruling decides, and adds 28 checklist lines from the parents, and section 7 lists the 3 open milestone issues (#472)

Refresh round 2. GitHub was read from 2026-10-14T03:11:22Z to 03:18:32Z;
main was 8beb3d9 (#512) throughout. Every merge commit of the 223
merged pull requests is an ancestor of it.

Section 5 adds, from each squash message and PR body:
- adopt-project.py: #515 (a pinned `007` listed as text) and #513 (a new
  "The source's own name" bullet: `adopt-not-the-source`,
  `plan-not-the-source`, rename first);
- update-shape.py and bump-leg.py: #512 (a new bullet: no NEXT passes
  `--accept-local`; `merged-away` rows dropped by `apply`);
- setup, scaffold, family and the shared helpers: #517 (a `--pin` product
  listed as text) and #507 (`family-landing-in-standard`,
  `family-on-tracking-branch`, a quoted NEXT that pushes the branch);
- shape-doctor.py: #510 (the installed doctor keeps its clone, and passes
  `--json` and `--placement-plan` through). The bullet's "writes nothing
  into the repository" now adds "but a `--placement-plan` file you name":
  a relative plan file given from inside the repository is written there,
  as #460's new line says.

Section 6 drops two lines and adds 28; no known-limit issue closed, so
the 47 issues stay:
- #457, 16 lines: L2-14, which #515 makes true of main; 10 of lane 4's 14
  lines from #513 (00:06Z), two of them, a backslash `origin` and a
  trailing slash, in one bullet; and L1-K1, K2, K3, K7, K9 and K10 from
  lane 1 (01:17Z).
- #458: AT-family N2 is dropped, as lane 4's status note there says
  (00:48Z); 2 lines added from #512.
- #459, 3 lines that #507 and #517 make true of main: the validate-family
  remedies line (03:27Z), the README `--into` line (11:46Z) and L2-15.
- #460: the `openRepoShape --help` verdicts line is dropped (#510 fixed
  it); the `shape currency` line is reworded, because since #402 the
  `apply --branch` is the row's WHY and since #512 it has no
  `--accept-local`, but under `--branch` it is still refused
  `update-branch-uncommitted` before `update-local-drift`; 7 of lane 4's
  8 lines from #510 (23:34Z) are added.

Left out, by round 1's rules: #513's `insteadOf` line and README sentence
(wording), its comments line (comment wording), its extra `git config`
read (no effect a person meets); L1-K4 (cannot arise today); L1-K5, K6
and K8, which describe #518's and #504's branches; and #510's `--help`
synopsis column (cosmetic). #458's 03:26Z restatement is folded into its
existing `repo_shape.py` line: #507 removed the instance it added.

Section 7 lists #370, #471 and #472, the milestone's three open issues of
47, and says #178, #181 and #183 are not in the milestone.

What was read at 8beb3d9, by `git show` or `git grep` of the code or
text each line cites:
- section 5: all six new sentences (adopt-project.py:6986-7030 and
  :7812-7960; update-shape.py:287 and :1939-1969; shape-doctor.py:3238-3243
  and :3298-3314; scaffold-project.py:1293-1330 and the neutral pin
  template's line 30; scripts/family.py:620-720 and :925-960;
  openRepoShape:97-111, :489-490 and :540-558);
- #457: L2-14, the backslash and trailing-slash line
  (`_remote_repository`, adopt-project.py:1164-1182), `check`'s missing
  rename-first remedy (:5137), L1-K3 (scripts/repo_shape.py:2048), L1-K9
  (adopt-project.py:3316-3333);
- #458: both new lines (shape-doctor.py:2005-2060 and :3222-3227), and N2's
  drop (update-shape.py:2915-2919 and `apply_command`);
- #459: all three (validate-family.py:356-358 and :1066-1071; README.md:861-
  862, docs/handbook.html:1247; scaffold-project.py:1313-1330 against
  adopt-project.py:7017-7030);
- #460: the dropped and reworded lines (openRepoShape:97-100, docs/cli.md:
  160-163; shape-doctor.py:3306-3314 and `cmd_apply`'s refusal order), the
  adoption NEXT with no `--org` (shape-doctor.py:6141-6143), the two
  `--placement-plan` line (openRepoShape:540-558, shape-doctor.py:6828),
  the "writes nothing" line (openRepoShape:55 and :605, README.md:1112,
  docs/handbook.html:1467) and the kept-clone line (openRepoShape:490);
- kept lines whose code a landing touched: #458's "not hand-edited" commit
  and title-less `gh pr create` (update-shape.py:2349-2353, :3796-3797),
  AT-family N3, #460's `=word` line (`UNQUOTED_POSIX` admits `=`), and
  #459's unquoted setup `cd` and step (7) (setup-project.py:2023-2029,
  :2169).

The rest rest on the posting lane's measurement, not re-read here: of
#457's lines, lane 4's mirror path, `--source` after the clone, recorded
`source:`, `ATLAS`, fork, `straße` and null-`org:` lines (measured at
cf118ff; adopt-project.py is the same at 8beb3d9), and lane 1's L1-K1,
K2, K7 and K10 (measured on 8beb3d9); of #460's, the TERM, interrupted-run
and drifted-project-test lines (measured at 173c00e; `openRepoShape` is the
same at 8beb3d9).

The file is 7,354 words, from 6,611: section 5 is 2,291 (2,085), section
6 4,351 (3,607) and section 7 109 (316).

No test names `docs/release-notes/` (`git grep -n release-notes
origin/main -- tests/` finds nothing), but two tests in
tests/test_repo_hygiene.py read every tracked `.md` through `git
ls-files`: the host-absolute-path test (`HOST_ABSOLUTE_PATH`, :1496-1527)
and the "<word> naming families" count (:1545-1601). Their two patterns,
applied to this commit's file, match nothing. No test was run.

Lane: openreposhape-4 (openRepoShape-4)
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