Repository navigation
adopt-project.py, shape_materialize.py: five printed sentences say what the run does: a kept root Makefile's block, the spec leg's own path, where execute stops, when a link target names an attribute, and no visibility for a bare repository (#906) - #964
Conversation
…n does (the kept root Makefile's block waits in `shape/Makefile`, the spec leg's own path is printed beside the mounts, `execute` is said to stop where it does, a link target names an attribute only with a space or tab, no visibility under `--local-remote-dir`); not finished: the fail-without-fix run, the remaining test files, README line 810 (#906) Lane 3's triage of #457 at 5017830 found five lines that said what the run does not do. All five are changed and measured; the verification is not finished (see the end). L2-72. `follow_ups_for` said "the root Makefile wires `CONTRACTS_DIR`" where the source keeps its own root Makefile. Then the shape's, with the block, is written to `shape/Makefile`, and `make contracts-dir` at the root answers `No rule to make target 'contracts-dir'` (measured on an `execute --local-remote-dir` of a source with a Makefile; the block is only in `shape/Makefile`). Where the root keeps the Makefile it now says "the shape's Makefile wires ...; but the source keeps a Makefile of its own at the root, so that block waits in `shape/Makefile` until the two are merged, and the run adds none of it to the root's Makefile before then", as #634 words it for the pinned AGENTS-shape.md. Otherwise the line is byte for byte what it was. The test is `_root_keeps`, the reading `_predict_collisions` already used to move the shape's copy, now one function for both. L2-73. `contracts_from_code_leg` gave a ready path only where the spec leg holds `contracts/`, so a code file that names `specs/` got the key-form line and no path. v1.1.0 printed none either: the `../spec/specs/` was v1.0.1's, before #600 took the path out of the follow-up. It now takes the plan's follow-ups too, and where one says a file must `read across the assembly root` (`holds_a_read_across`, found in both lines `plan` writes for it) the two sentences that print the mounts end ", so from the code leg the spec leg is `../spec/`", and, where the spec leg holds `contracts/`, " and the spec leg's `contracts/` is `../spec/contracts/`". With no read-across line the sentence is what it was. Measured on a source naming `specs/` only, for `spec`/`code`, `legs/spec`/`legs/code` and `a/b/spec`/`a/code`, and by following the path from the code leg of a recursive clone to the spec file. L1-91. `_refused_finding` said `execute` "would stop there, after the leg repositories exist", `there` being the step git refuses. Measured with `_refuse_what_check_finds` patched out, over a `--local-remote-dir`: a refused `git add` (`core.safecrlf=true` over a kept CRLF file) stops `execute` at `REFUSED committing the split`; `* working-tree-encoding=UTF-16LE` with `.gitattributes` exempted stops it at `REFUSED mounting the legs`, `failed to encode '.gitmodules'`; a smudge filter that fails stops it at `REFUSED extracting the spec leg`, neither leg pushed. The finding says "no later than committing the split, and sooner where a step before it meets the same rule: extracting a leg, or mounting the legs, where the rule reaches the `.gitmodules` it writes" for a refused store, and "at its first clone of the source" for a refused checkout. L1-93. The `_kept_nested_attributes` docstring said "a target that is a path names no attribute". Measured with git 2.43: a kept `.github/.gitattributes` linking to `config/attributes` (and to `docs/read me.md`) left the workflow copy LF; linking to `*.yml eol=crlf`, or `*.yml` TAB `eol=crlf`, wrote it CRLF. It now says it of a target with no space or tab only. The printed sentence in scripts/shape_materialize.py (`a path names no attribute`) is not changed here. L1-75. Under `--local-remote-dir`, WHAT WILL HAPPEN printed `create <Project>-spec and <Project>-code (private)`. It prints no visibility there (`execute` makes both with `git init --bare`); against GitHub the plan's visibility is printed as before. Tests. tests/test_adopt_printed_sentences.py is new (46 tests, all pass). tests/test_adopt_leg_keys.py, tests/test_adopt_contracts_dir.py (which also holds OWN_MAKEFILE_FOLLOW_UP beside MAKEFILE_FOLLOW_UP) and tests/test_adopt_reencoded_files.py move with the sentences they assert. Run and green with the stubbed-gh environment: test_adopt_leg_keys, test_adopt_contracts_dir, test_adopt_reencoded_files, test_adopt_leg_paths, test_adopt_literal_names, test_adopt_plan, test_adopt_entry_paths, test_adopt_leg_path_collisions, test_adopt_execute_refusals, test_adopt_c_locale_bytes, test_adopt_plan_escapes, test_stdout_encoding and test_shape_advisory together: 1088 passed, 2 skipped. Not finished: the run of the new tests against the base adopt-project.py (fail-without-fix); test_adopt_nested_attributes, test_adopt_attributes_eol_block, test_adopt_eol_block_through_links, test_adopt_e2e, test_adopt_plan_yaml_quoting, test_adopt_submodules, test_shape_doctor, test_scaffold_leg_path_collisions, test_cli_reference and test_repo_hygiene; and README.md line 810, which says the root Makefile exports `CONTRACTS_DIR` without the kept-Makefile case. Lane: openreposhape-1 (openRepoShape-1) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Reviewer's GuideUpdates adopt-project.py’s printed guidance and documentation to reflect actual Makefile placement, cross-leg navigation, Git refusal stop points, nested attribute parsing, and local bare-repository visibility, with broad regression and end-to-end coverage in a new printed-sentences test module. Sequence diagram for local adoption guidance and execution stop pointssequenceDiagram
participant User
participant Adopt as adopt-project.py
participant Plan
participant Git
User->>Adopt: plan
Adopt->>Plan: _plan_follow_ups
Adopt->>Adopt: contracts_from_code_leg
Adopt->>Adopt: _print_what_will_happen
Adopt-->>User: Print leg paths and create repositories
User->>Adopt: execute
Adopt->>Git: clone source
alt checkout refusal
Git-->>Adopt: refusal
Adopt-->>User: execute stops at its first clone of the source
else extraction or mount refusal
Adopt->>Git: extract or mount legs
Git-->>Adopt: refusal
Adopt-->>User: execute stops before committing the split
else no refusal
Adopt->>Git: commit split
Git-->>Adopt: success
end
Flow diagram for adopt-project guidance generationflowchart TD
Plan[Plan follow-ups and leg paths] --> Makefile[follow_ups_for]
Plan --> Mounts[contracts_from_code_leg]
Plan --> Refusals[_reencoded_files_findings]
Plan --> Visibility[_print_what_will_happen]
Makefile --> RootCheck[_root_keeps]
RootCheck --> MakefileText[Makefile placement guidance]
Mounts --> ReadAcross[holds_a_read_across]
ReadAcross --> MountText[Spec-leg path guidance]
Refusals --> StopText[execute stop-point guidance]
Visibility --> LocalText[Local bare-repository visibility]
MakefileText --> Output[Printed adoption guidance]
MountText --> Output
StopText --> Output
LocalText --> Output
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
(lane openRepoShape-1, 2026-10-18T18:31:12Z) Independent review of #964 at
Lane 1's writer f906 makes the round, then r906 re-checks the new head. Lane: openreposhape-1 (openRepoShape-1) |
…seeding a leg too, a link target names an attribute with a carriage return as with a space or tab, and a root `.gitattributes` link's follow-up says no rule reaches the pinned copies only for a link to a path (#906) r906's review of #964 found three of the sentences the first commit wrote or left false in cases it measured. Each is fixed here, with the measurement under a test. - `STOPS_AT_THE_SPLIT` names seeding: "extracting or seeding a leg, or mounting the legs". With the code leg seeded (`src/` and `.github/` answered root) and `core.autocrlf=true` with `core.safecrlf=true`, `execute` stops at `REFUSED seeding the code leg`: `_seed_leg` runs its own `git add -A`, which meets the rule before the split does. The STOPS row `a-seeded-leg-meets-the-same-config` holds it, and its finding test fails against the first commit's `adopt-project.py`. - `_kept_nested_attributes`'s docstring says a link target with no space, tab or carriage return names no attribute, and one with any of them is read as rules, since git separates a line's fields on all three. Measured with git 2.43: `*.yml` CR `eol=crlf` wrote `validate.yml` CRLF, as a space or a tab does. `test_a_link_target_names_an_attribute_only_with_a_separator` has the row `a-carriage-return-between-them`, and the docstring test follows the words. - `shape_materialize.py`'s `_attributes_link_follow_up` printed "a path names no attribute", which holds only for a link to a path, and so did `_append_eol_block`'s docstring and the comment in `adopt-project.py` above the nested-file finding. Measured in clones with git 2.43: a root `.gitattributes` link to `config/attributes` or `docs/read me.md` left a committed-LF `notes.txt` LF, and one to `* eol=crlf`, with a space, a tab or a carriage return between the fields, wrote it CRLF (`test_a_root_link_is_read_as_rules_only_with_a_separator`). The follow-up now says the link's text is read as one line of rules, which names an attribute only where it holds a space, a tab or a carriage return, so that, for a link to a path, no line-ending rule reaches the pinned copies; `tests/test_adopt_attributes_eol_block.py` asserts it. - The Makefile follow-up no longer ends "before then", which suggested the run acts when the two Makefiles are merged. - `test_a_kept_makefile_wires_nothing_where_the_split_message_says_so` asserts that `make -f shape/Makefile contracts-dir` prints the clone's own `legs/spec/contracts`, not any directory. - The `STOPS_AT_*` comment no longer says "neither leg yet pushed", which r906 found false where the spec leg is seeded, or that `git add` is the split's last step: the push of the split branch follows. Not changed: a kept lower-case `makefile` or `GNUmakefile`, and `README.md:810`, whose section is bound to the handbook. Both are follow-ups. Lane: openreposhape-1 (openRepoShape-1) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
shape/Makefile, the mount lines print the spec leg's own path, plan-file-reencoded says where execute stops, and --local-remote-dir prints no visibility (#906)execute stops, when a link target names an attribute, and no visibility for a bare repository (#906)
|
(lane openRepoShape-1, 2026-10-18T19:00:21Z) Re-check of #964 at
#964 takes its turn once its Lane: openreposhape-1 (openRepoShape-1) |
|
|
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 2 days and 7 hours by commenting |
…makefile` or `GNUmakefile` GNU make reads first, and where a case-blind disk writes the shape's; README says which Makefile exports `CONTRACTS_DIR` (#977) (#1046) ## What Two follow-ups to #906 that lane 1's review of #964 (r906) found and ruled out of that pull request. Neither is a regression: both were as untrue on `main` before #906 as after it. **(a) The Makefile follow-up names the root file GNU make reads first.** The line is in `plan`'s `follow_ups:`, in `check`'s output and in the split commit's message, which is also the pull request's body. GNU make reads the first file it finds of `GNUmakefile`, `makefile` and `Makefile`, and only that one. #906 asked only whether the source keeps `Makefile`, comparing names byte for byte (`_root_keeps`). So a source that keeps `makefile` or `GNUmakefile` got "the root Makefile wires `CONTRACTS_DIR` ...". But the clone's root then holds the shape's `Makefile`, with the block, and the source's file, which `make` reads instead, so `make contracts-dir` answered `No rule to make target 'contracts-dir'` (r906's probe, both names). `_makefile_follow_up` now writes the line: - It names the source's file that GNU make reads at the root, wherever that file is not the `Makefile` #906's words already name. It also says what it takes for `make` there to export `CONTRACTS_DIR`. - On a disk that ignores case, a kept `makefile` IS `Makefile`. `place` (`Path.exists()`) finds the name taken and writes the shape's Makefile as `shape/Makefile`. The line says so in `CASE_ASIDE`'s words. `_root_keeps` gains `fold`, which asks the question the way `_KeptTree` asks it for `check`'s disk that ignores case. - A source that keeps only `Makefile`, or none of the three names and no other case of `Makefile` that a rule keeps, gets the line it got before, byte for byte. - Each kept name is printed with `_spelled`, and the three names GNU make looks for with `_and_listed`. No `shell_quoted` call is added. | The root keeps | Before | After | | --- | --- | --- | | none | "the root Makefile wires `CONTRACTS_DIR` ..." | unchanged | | `Makefile` | #906's line: "the shape's Makefile wires ...; but the source keeps a Makefile of its own at the root, so that block waits in `shape/Makefile` until the two are merged, and the run adds none of it to the root's Makefile" | unchanged | | `makefile` | "the root Makefile wires ..." | "the shape's Makefile wires ...; it is written as the root's `Makefile`, or as `shape/Makefile` once case is ignored, as a macOS or Windows disk does, where the source's `makefile` is that path, until the two are merged; and GNU make at the root reads the source's `makefile`, ..." | | `GNUmakefile` | "the root Makefile wires ..." | "the shape's Makefile wires ...; it is written as the root's `Makefile`, but GNU make at the root reads the source's `GNUmakefile`, ..." | | `makefile` and `GNUmakefile` | "the root Makefile wires ..." | as for `makefile`, and GNU make reads the source's `GNUmakefile` | | `Makefile` and `makefile` | #906's line | #906's line, then "; and GNU make at the root reads the source's `makefile`, ..." | | `Makefile` and `GNUmakefile`, or all three | #906's line | #906's line, then "; and GNU make at the root reads the source's `GNUmakefile`, ..." | | `MAKEFILE`, kept in the root by a `--path-policy` rule (with the shipped rules `plan` asks about it, and a person's `root` answer keeps the line `plan` wrote: "the root Makefile wires ...") | "the root Makefile wires ..." | "the shape's Makefile wires ...; it is written as the root's `Makefile`, or as `shape/Makefile` once case is ignored, ..., where the source's `MAKEFILE` is that path, until the two are merged" | The clause that names the file, in full: ```text GNU make at the root reads the source's `makefile`, the first of `GNUmakefile`, `makefile` and `Makefile` it finds, so `make` there exports `CONTRACTS_DIR` only once `makefile` does, or includes a Makefile that does ``` **(b) README.md, section "Adopting an existing repository".** - Before: "the root Makefile it materializes exports `CONTRACTS_DIR`, pointing at the `contracts/` of the spec leg where the plan mounts it (`$(CURDIR)/spec/contracts` by default)." - After: "the shape's Makefile exports `CONTRACTS_DIR`, pointing at the `contracts/` of the spec leg where the plan mounts it (`$(CURDIR)/spec/contracts` by default); it is the root's Makefile, or, where the source keeps a `Makefile` of its own, `shape/Makefile`, which holds the export until a person merges the two." This is r906's wording, as its re-check corrected it, with one change: `Makefile` is in backticks in "a `Makefile` of its own". A source that keeps `makefile` has the shape's Makefile written as the root's `Makefile` on a disk that keeps case, so the plain word would have claimed `shape/Makefile` for it. The section is bound to the handbook's `adopt` section. The handbook says nothing of `CONTRACTS_DIR`, and its sentence that a shape file whose name the source already holds, `Makefile` among them, is written under `shape/` stays true. So only the section's marker moves, to the section's new blob, computed with `readme_segments` and `readme_fingerprint`. The tail of the paragraph is reflowed, and README.md grows by one line, to 1479, which is the cap. No `tests/readme-cap.d/` file is needed while no other README pull request lands first. ## Measured On a disk that keeps case (Linux, GNU Make 4.3, git 2.43), each row ran a real `execute --local-remote-dir` and made a recursive clone of the split. Each file the source keeps has its own `which` target, so `make which` at the clone's root prints the name of the file GNU make read. | The root keeps | `make which` prints | the split message names | `make contracts-dir` at the root | the block is in (`make -f <it> contracts-dir` prints the spec leg's `contracts/`) | | --- | --- | --- | --- | --- | | `makefile` | `makefile` | `makefile` | no rule | `Makefile` | | `GNUmakefile` | `GNUmakefile` | `GNUmakefile` | no rule | `Makefile` | | `makefile` and `GNUmakefile` | `GNUmakefile` | `GNUmakefile` | no rule | `Makefile` | | `Makefile` | `Makefile` | #906's line, the source's own `Makefile` | no rule | `shape/Makefile` | | `Makefile` and `makefile` | `makefile` | `makefile` | no rule | `shape/Makefile` | | `Makefile` and `GNUmakefile` | `GNUmakefile` | `GNUmakefile` | no rule | `shape/Makefile` | | all three | `GNUmakefile` | `GNUmakefile` | no rule | `shape/Makefile` | The disk that ignores case is not measured: there is none here. What the line says of it rests on `place`'s `Path.exists()`, and is tested against `_KeptTree(..., fold=True)`, `check`'s model of that disk. ## Tests - `tests/test_adopt_make_reads_first.py`, new: 33 tests. - The line word for word, for every row above, and for `makefile` and `GNUmakefile` sent to legs. - The line against `_KeptTree` on both disks. - `plan` and `check` for each row but none and `Makefile`, which `test_adopt_contracts_dir` and `test_adopt_printed_sentences` already plan and check. - A real `execute` for each row except none, with the `make` measurements above. - README's sentence, and the handbook marker matching the section as it now stands. - Fail on base: on `e2f9fc42` (main when the branch was made), 23 fail and 10 pass. The 10 are the handbook marker test, which was current on base, and rows whose line does not change: none and `Makefile` alone; `makefile` and `GNUmakefile` sent to legs; and the `Makefile`-plus-another rows of the disk test, which asks only where the copy goes. - Gate on this head, named files only, one basetemp, a stub `gh` first on PATH, `GH_TOKEN=bogus`, `GIT_SSH_COMMAND=false`, `GIT_CONFIG_GLOBAL=/dev/null`: - The new file, `test_adopt_contracts_dir`, `test_adopt_printed_sentences`, `test_adopt_leg_keys`, `test_adopt_plan`, `test_adopt_e2e`, `test_repo_hygiene`, `test_readme_sections`, `test_agents_md_codes`, `test_cli_reference`, `test_readme_windows_quoting_sentence` and `test_scaffold_leg_path_collisions`: 652 passed, 1 skipped (the MedxEHR test, no clone here). - Every other adopt test file that names `Makefile`, `makefile` or `CONTRACTS_DIR`: `attributes_eol_block`, `verify`, `ignored_shape_files`, `leg_path_collisions`, `submodules`: 368 passed. `root_manifest`, `root_symlinks`, `symlink_target_bytes`, `root_shape_paths`: 403 passed. - `test_shape_doctor.py` in 4 shards: 445 passed, 3 skipped (the PowerShell line, Windows only). - After the last test-only edit (helpers imported from `test_adopt_printed_sentences`): the new file and `test_adopt_printed_sentences`, 87 passed (33 and 54). Mutants of the change, each restored. Each one is killed: | Mutant | Failed | | --- | --- | | GNU make's order with `makefile` before `GNUmakefile` | 18 of 33. The end-to-end rows `makefile`+`GNUmakefile` and all three fail on `make which` against the split message itself. | | the case-folding check off | 9 | | the joining word always "; and" | 3 | | "the shape's" not chosen when only `GNUmakefile` or `makefile` is kept | 4 | | GNU make's first file never found | 19 | | `_root_keeps` folds case by default | 13, #906's `the-root-keeps-it` row among them | | README's old sentence | 3, `test_the_handbook_follows_the_readmes_outline` among them | | the handbook marker left stale | 2 | ## Merge with main `git merge-tree --write-tree` of this head with `main` at `dc7cd49b` is clean (tree `ae9abfcb`). Of this branch's files, only `adopt-project.py` moved on main: #1030 (#900) changed `_spelled`, and #1038 (#994) changed a hint and a docstring. `_spelled` changes only a backslash, a double quote or a backtick inside a name. The names this line spells are plain letters, so its words do not change. README.md, `docs/handbook.html` and `tests/readme-cap.d/` did not move on main, so the marker stays current and the cap still holds. On the merge, built in a `git clone --shared` checkout: the new file, `test_adopt_printed_sentences`, `test_repo_hygiene` and `test_readme_sections`, 263 passed. ## Not in this PR (follow-ups for lane 1 to file) - **NEXT's `make bootstrap`, measured.** For a source that keeps `makefile` or `GNUmakefile`, `execute`'s NEXT block prints `make bootstrap`. `make -n bootstrap` in the clone exits 2 with `No rule to make target 'bootstrap'`. For `Makefile` and `GNUmakefile`, its NOTE says the shape's make targets "arrive only once the follow-up merges the two". But GNU make at the root reads `GNUmakefile`, not the merged `Makefile` (inferred; before the merge, `make -n bootstrap` there exits 2, as the NOTE says). - **`collision_follow_up`'s sentence.** In `shape_materialize.py`, "The shape's make targets ... arrive only with that merge" is likely untrue where the source also keeps `GNUmakefile` or `makefile`, which GNU make reads before the merged `Makefile`. Inferred, not measured. - **`AGENTS-shape.md` in the pinned template.** "Where the source kept a Makefile of its own, that block waits in `shape/Makefile`" has the same gap for a kept `makefile`. It is pinned bytes, so it is left. - **Disks that ignore case.** - `_predict_collisions` stays byte for byte, so on such a disk a plan for a kept `makefile` lists no "merge shape/Makefile into Makefile" follow-up. `execute`'s own collision report lists it. - A split made on a disk that keeps case commits both `Makefile` and `makefile`, two names that collide in a clone on a disk that ignores case. - Spellings such as `gnumakefile` are not asked about. - None of this is measured. **Review round 0, body only** (lane 1's reviewer r1046's partial review, issuecomment-6288714370): the `MAKEFILE` row and the byte-for-byte sentence now say that a `--path-policy` rule, not a person's answer, is what keeps `MAKEFILE` in the root. Follow-ups are built from the rules' answers alone, so a `MAKEFILE` a person answers `root` keeps "the root Makefile wires ...", which a disk that ignores case makes untrue, as on base. **Review round 1** (`c121ed90`, test file only): the comment above `ANSWERED` says a `--path-policy` rule, not a person's answer, reaches the follow-ups (r1046's SHOULD-1). The new test file is ASCII: its section signs and em dashes are written as escapes, with two lines rewrapped: the assert's string is unchanged, the `re` pattern matches the same text (its raw string now holds the escape), and one docstring changes only where its lines break (NIT-2). `tests/test_adopt_make_reads_first.py` 33, `tests/test_adopt_printed_sentences.py` 54 and `tests/test_repo_hygiene.py` 100 passed. It lands by fast refresh (Brett Heap, 2026-10-15T22:48:35Z). Its reviewed head `c121ed90` is green on Linux and SonarCloud. The branch merged main once and was never rebased; the last merge is update-branch's, clean, giving db92198, which is green on SonarCloud and Git Bash. Lane 1's gate passed on its tree: the 13 test files that run `adopt-project.py`'s Makefile follow-ups and `make`, read README and the handbook, the doctor and the docs, 1,097 passed and 4 skipped. Closes #977 Lane: openreposhape-1 (openRepoShape-1) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Lane: openreposhape-1 (openRepoShape-1)
Claim: #906 (comment)
A v1.2.0 draft, authored on the v1.1.1 release commit
50178305; this body is for head369f2781, one fix round on10f25e4bafter lane 1's review r906, which found the first commit not ready. Lane 3 filed #906 from its triage of #457 (L2-72, L2-73, L1-91, L1-93 and L1-75): five printed sentences that say what the run does not do. It changesadopt-project.py,scripts/shape_materialize.pyand five test files, one of them new (tests/test_adopt_printed_sentences.py).What
follow_ups_forsaid "the root Makefile wiresCONTRACTS_DIR" even where the root keeps aMakefileof the source's own. Then the shape's goes beside it asshape/Makefilewith the block, and the root wires nothing. Now it says "the shape's Makefile wires ...; but the source keeps a Makefile of its own at the root, so that block waits inshape/Makefileuntil the two are merged, and the run adds none of it to the root's Makefile", as Pinned shape copies: one bump, so AGENTS-shape.md is true of every root, the scaffold's chain WARNING offers only its own sources and spells--pin-source, the root's not-used note spells it too, and THE LOCKSTEP RULE'sbumpruns (#610) #634 words it forAGENTS-shape.md. A new_root_keepsis the one reading, shared with_predict_collisions. Otherwise the line is as it was.contracts_from_code_legtakes the plan's follow-ups. Where one says a file must "read across the assembly root" (holds_a_read_across),check'smount the legs at X/ and Y/and the split message'smounted back here at X/ and Y/end ", so from the code leg the spec leg is../spec/", plus " and the spec leg'scontracts/is../spec/contracts/" wherecontracts/is there too. With no read-across line they are as before.executestops. The finding no longer says "would stop there". For a refused store or copy it saysexecutewould stop "no later than committing the split, and sooner where a step before it meets the same rule: extracting or seeding a leg, or mounting the legs, where the rule reaches the.gitmodulesit writes"; for a refused checkout, "at its first clone of the source" (STOPS_AT_THE_SPLIT,STOPS_AT_A_CLONE)._kept_nested_attributes's docstring says so. The code was right already: it asks about every kept link.scripts/shape_materialize.py's_attributes_link_follow_up, the printed sentence Tracking: adopt-project.py, converting an existing repository in place #457's L1-93 names, now says a checkout "reads only the link's own text, the path it leads to, as one line of rules, which names an attribute only where that text holds a space, a tab or a carriage return, so, for a link to a path, no line-ending rule reaches the pinned copies outside it"._append_eol_block's docstring and a comment inadopt-project.pysay the same.--local-remote-dir, WHAT WILL HAPPEN printscreate <Project>-spec and <Project>-codewith no(private), sinceexecutemakes bare repositories. Against GitHub the line is unchanged.Why
Measured on
50178305, git 2.43, Linux:execute --local-remote-dirof a source with its own root Makefile,make contracts-dirat the root printedNo rule to make target.CONTRACTS_DIRwas only inshape/Makefile.../spec/specs/. It did not: v1.0.1 did, and adopt-project.py: after the hand edit oflegs.spec_pathorlegs.code_pathit asks for, the read-across follow-up and thecontracts/rule's reason still name the plan-time paths #600 took the path out of the follow-up. The tests follow../spec/specs/001-feature/spec.mdfrom the code leg of a recursive clone and reach the file._refuse_what_check_findspatched out,core.safecrlf=trueover a kept CRLF file stopsexecuteatREFUSED committing the split;* working-tree-encoding=UTF-16LEwith.gitattributesexempted, atREFUSED mounting the legs(failed to encode '.gitmodules'); a failing smudge filter, atREFUSED extracting the spec leg; and, with the code leg seeded (src/and.github/answeredroot) undercore.autocrlf=trueandcore.safecrlf=true, atREFUSED seeding the code leg, where_seed_leg's owngit add -Ameets the rule before the split does..github/.gitattributeslink toconfig/attributesordocs/read me.mdleft the workflow copy LF; to*.yml eol=crlf, with a space, a tab or a carriage return between the fields, it wrote CRLF..gitattributeslinks toconfig/attributesordocs/read me.mdleft a committed-LFnotes.txtLF; links to* eol=crlf, with a space, a tab or a carriage return, wrote it CRLF. A test holds each.Tests
tests/test_adopt_printed_sentences.py, 54 tests, a group for each item.OWN_MAKEFILE_FOLLOW_UPsits besideMAKEFILE_FOLLOW_UPintests/test_adopt_contracts_dir.py; that file,test_adopt_leg_keys.py,test_adopt_reencoded_files.pyandtest_adopt_attributes_eol_block.pytake the new text.50178305'sadopt-project.pyandshape_materialize.pyput back (a scratch copy of the tree), 38 of the 54 fail, and one test each intest_adopt_attributes_eol_block.pyandtest_adopt_reencoded_files.py. The 16 that pass pin what the fix leaves alone: the Makefile line where the root keeps none (2), whereexecutereally stops (4), and what git does with a link target, nested (5) and at the root (5).10f25e4b): 8 fail: the three finding rows that say whereexecutestops for a store (the seeded-leg row among them), the docstring test, the two kept-Makefile line tests,test_the_follow_up_for_a_linked_attributes_file_lists_the_lines_it_needs, andtest_a_refusal_says_where_execute_stops_and_the_way_out.Run with
/usr/bin/python3 -m pytest, a stubghfirst on PATH, a bogusGH_TOKEN, an emptyGH_CONFIG_DIR,GIT_CONFIG_GLOBAL=/dev/nullandGIT_SSH_COMMAND=false, on head369f2781, one run per file:printed_sentences54,attributes_eol_block46,eol_block_through_links13 (2 skipped),nested_attributes79,contracts_dir34,leg_keys44,reencoded_files53,agents_md_codes47,cli_reference23,repo_hygiene78;adopt_e2e27,adopt_plan67 (1 skipped,SHAPE_MEDXEHR_CLONEunset),adopt_submodules167;test_shape_doctor445 (3 skipped, PowerShell, a Windows host only);test_scaffold_leg_path_collisions104. All passed.10f25e4b, where they passed, and none reads a sentence this round changed:plan_yaml_quoting518, and the 13-file batch of 1088 passed, 2 skipped (among themleg_paths,literal_names,entry_paths,leg_path_collisions,execute_refusals,c_locale_bytes,plan_escapes,stdout_encoding,shape_advisory).Known limits and follow-ups
makefileorGNUmakefilestill gets "the root Makefile wiresCONTRACTS_DIR", and README.md'sCONTRACTS_DIRsentence has no kept-Makefile case (follow-ups to #906) #977 (a): a kept lower-casemakefileorGNUmakefilegets the old line, because_root_keepscompares names byte for byte, while GNU make reads that file beforeMakefile(r906's probe:make contracts-dirat the root has no rule for either name).makefileorGNUmakefilestill gets "the root Makefile wiresCONTRACTS_DIR", and README.md'sCONTRACTS_DIRsentence has no kept-Makefile case (follow-ups to #906) #977 (b):README.md:810says "the root Makefile it materializes exportsCONTRACTS_DIR" without the kept-Makefile case. It is not edited here: its section, "Adopting an existing repository", is bound to the handbook (README_HEADING_TO_HANDBOOK_IDandHANDBOOK_READS["adopt"]intests/test_repo_hygiene.py, marker atdocs/handbook.html:1278), so an edit failshandbook_marker_problemsuntil the handbook is re-read, which serializes across lanes. The issue holds the wording: "the shape's Makefile exportsCONTRACTS_DIR, pointing at ...; it is the root's Makefile, or, where the source keeps a Makefile of its own,shape/Makefile, which holds the export until a person merges the two"..gitattributeslink whose text holds a separator is read by git as a rule line, as measured above.checkstill treats every root link as giving no rule (attributes_link), so what its findings say for such a link is not measured here. The printed follow-up no longer claims it does.Closes #906
🤖 Generated with Claude Code
Summary by Sourcery
Make adoption messages accurately describe generated files, cross-leg paths, execution failure points, attribute-link semantics, and local bare-repository visibility.
New Features:
Bug Fixes:
Enhancements:
Tests: