Repository navigation
adopt-project.py, shape_materialize.py and the assembly-root template: a kept GNUmakefile/ is a directory GNU make stops at, python3 scripts/bootstrap.py names python on Windows, and the template says what to run where make reads another file - #1207
brettheap wants to merge 7 commits into
Conversation
…: a kept `GNUmakefile/` is a directory GNU make stops at, `python3 scripts/bootstrap.py` names `python` on Windows, and the template says what to run where `make` reads another file RV1105's and RV1121's follow-ups (#1132) that hold on main, measured on main 961640c and with GNU make 4.3: 1. The template's AGENTS-shape.md ("Work from here" and the five-commands table) and README.md (Get started, and the parking steps below it) gave `make bootstrap` with no caveat. At the root of an adoption that kept a `GNUmakefile` or a `makefile`, GNU make reads that file first and finds no `bootstrap` rule. Each now says to run `python3 scripts/bootstrap.py` (`python` on Windows) there, which is what the shape's `make bootstrap` runs. 2. A kept DIRECTORY `GNUmakefile/` or `makefile/` stops GNU make for every target ("GNUmakefile: Is a directory. Stop.", exit 2). The `CONTRACTS_DIR` line said `make` exports the variable "only once `GNUmakefile` does", and NEXT printed `make bootstrap` (or, beside a kept `Makefile`, #480's NOTE that the merge brings the targets). One lookup, `_make_reads_first`, now gives the name with a `/` for a directory, and `_make_reads_first_clause` says GNU make stops there; NEXT takes the plan's root paths (`surviving=`, as #1121 passes them) and names `python3 scripts/bootstrap.py` there. A kept FILE in NEXT stays #1047's (#1121). 3. Every sentence that names `python3 scripts/bootstrap.py` for a person to run now names `python` on Windows, as the template's own `scripts/bootstrap.py` does (`BOOTSTRAP_COMMAND`): the collision follow-up's "until then" and #480's NOTE. Pasted command lines stay as they were. NIT-2 (#1105's second review): where `scripts/bootstrap.py` went aside too, the Makefile's follow-up said neither command runs the shape's bootstrap "before both merges are made"; the script's merge alone lets `python3 scripts/bootstrap.py` run it. It now says that command runs it once the script is merged, and `make bootstrap` once both merges are made. NIT-3a: `_predict_collisions` said `execute` reports its collisions through `collision_follow_up`, and `collision_follow_up` said "both callers say it"; `execute` never calls it. Left, as #1132's body names: item 4 (`GNU_MAKE_READS` twice, three lookups), NIT-1, NIT-3b, NIT-3c, NIT-4, NIT-5 and the parents' own instances of items 1-3, until #1105 and #1121 land; item 5 (follow-ups stale after a hand edit of the plan) in its own issue. Closes #1132 Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewer's GuideImplementationDefine the shared bootstrap command and update collision follow-ups to describe accurately which command works after each merge, including the script-only case.
Detect the first GNU make precedence name retained at the root, distinguish directories from files, and use that distinction in the CONTRACTS_DIR follow-up.
Correct the collision-prediction comment to describe how planned follow-ups are stored and carried into the split commit.
UIMake NEXT choose a runnable bootstrap command and explain GNU make’s behavior when a retained precedence name is a file or directory.
DocumentationExplain in the assembly-root guidance when to run the bootstrap script instead of make, and when the shape’s make targets are reachable.
TestsUpdate existing adoption expectations for the revised follow-up wording and Windows interpreter guidance.
Add coverage for template instructions, GNU make file and directory precedence, NEXT and collision follow-ups, Windows command wording, and real adoption scenarios.
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
…ure GNU make against the template's `Makefile` each assert the sentence they back, so they fail on main too, and #480's NOTE row asks `_next_steps` as main's signature can Five rows of the new file measured GNU make 4.3 against the template's own `Makefile`, and nothing tied them to the words they back, so they passed on main 961640c as they pass here (#1132): - the four `test_make_reads_the_template_makefile_only_where_nothing_comes_first` rows now assert AGENTS-shape.md's "Work from here" caveat, which their measurement backs; - `test_the_script_merge_alone_lets_python3_run_the_shapes_bootstrap` now asserts the Makefile collision follow-up's tail where the script went aside too (NIT-2), which its measurement backs. `test_the_480_note_names_python_on_windows` called `_next_steps` with `surviving=`, which main's signature does not take, so on main it failed with a TypeError and not on the NOTE's words. `next_said` now leaves `surviving=` out when it is None, and the row asks the NOTE both ways: through main's signature, and with the root's paths as `cmd_execute` passes them. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Independent review of #1207 (#1132) for lane openRepoShape-5 NOT READY There is no MUST. On every path I measured, the code does what the title and body say. Three SHOULDs need action before landing. SHOULD-1 needs one new test row, so the head moves. SHOULD-2 is a body or issue edit. SHOULD-3 is a landing-order question. With those done, and CI green, I would call it READY. FindingsSHOULD-1: the script-only-aside branch with a kept directory has no row (mutant X1 survives)
SHOULD-2:
|
| run | git | files | result |
|---|---|---|---|
| g243 | 2.43.0 | the two changed test files | 59 passed |
| g247 | 2.47.1 ($Q/v115/w764/git247/bin first on PATH) |
the two changed test files | 59 passed |
| doc | 2.43.0 | test_shape_doctor.py, test_scaffold_leg_path_collisions.py |
549 passed, 3 skipped (the PowerShell rows, Windows host only) |
| hyg | 2.43.0 | 11 files (below) | 766 passed |
| tpl | 2.43.0 | 4 files (below) | 197 passed |
- hyg:
test_repo_hygiene.py,test_agents_md_codes.py,test_cli_reference.py,test_template_text_placeholders.py,test_pinned_copy_text.py,test_bootstrap_placement_texts.py,test_park_resume_targets.py,test_adopt_make_reads_first.py,test_adopt_contracts_dir.py,test_template_quoted_values.py,test_template_values_single_pass.py. - tpl:
test_scaffold_e2e.py,test_scaffold_free_text_values.py,test_free_plan_hint.py,test_update_shape_hardlink.py.
My mutants (in wtm, each alone, against 92 rows: the new file, test_adopt_e2e.py and test_adopt_make_reads_first.py; unmutated, all 92 pass; each restored, sha256 4/4 OK):
| id | mutant | result |
|---|---|---|
| X1 | script-only-aside NOTE says make bootstrap |
SURVIVED (SHOULD-1) |
| X6 | NEXT gets every leg's paths | SURVIVED (NIT-4) |
| X7 | stops = first, so a kept FILE takes the directory path |
SURVIVED; expected, since that case is #1121's and main's |
| X8 | the after-table sentence loses (python on Windows) |
killed, 1 row |
| X9 | README loses "here and below" | killed, 1 row |
| X10 | the directory clause drops "the first of ... it finds" | killed, 10 rows |
Template pins
- I grepped tests/ for every changed line, and for nearby phrases ("Work from here", "run
make bootstrap", "They are the shape", "here and below", "includes a Makefile that", "Where this root keeps", the five-commands table). Only the PR's own rows pin the changed lines. - No test or file stores a digest or byte size of either file. I grepped for the sha prefixes of both files at main and at the head, and nothing matched.
test_scaffold_e2e.py's rule list still finds "make bootstrap".- The README line-count check in
test_scaffold_free_text_values.pycounts against the template, and it passes.
Merge-tree
- Against current main: origin/main
e04826db4, fetched at 20:40Z with-c gc.auto=0 -c maintenance.auto=false fetch --no-write-fetch-head, is 16 commits past961640c68.- The merge is clean, tree
672c2178. - Two of main's commits touch this PR's files:
b7edd8816(adopt-project.py: check asks the split's own clone of the source in the work directory, so a clone this git will not make is adopt-git-unasked before any leg, and _resolved and _answers make their repositories as check's other throwaways do (#1083) #1119,adopt-project.py) and0d76e4c59(shape_materialize.py and bump-leg.py: the fetch for a branch's answer leaves out a pattern likerefs/heads*that puts a branch under another name, its clauses move into_left_out, and the docstrings name the clashes left and the way back (#1100) #1157,scripts/shape_materialize.py). - The newest commit,
e04826db4(test_validate_family_index_gitmodules.py and validate-family.py: a row pins path-twice's wording of whose file it puts back, the index's or HEAD's as the index holds none, a row pins the value check's reading of HEAD's where the deletion of.gitmodulesis staged, and_listed_as_git_reads's docstring says it returns nothing where the work tree's file is on disk (#1181) #1208), touches neither. - That merged tree, run on 2.43.0 against the same 92 rows: 92 passed.
- The merge is clean, tree
- Against the parents: the shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps a
GNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105 and adopt-project.py:execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121 conflicts are as the body says (SHOULD-3).
Not checked
- The body's M1-M18. I ran my own mutants instead.
- The body's gates A-D at
1c7ca5c6d. - The 25 "clean" merges of other open PRs. I merged only shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps a
GNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105 and adopt-project.py:execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121. test_path_guard_hygiene.py, and the full suite.- A disk that ignores case, GNU make other than 4.3, and Windows.
- CI:
testswas still IN_PROGRESS at 20:51Z.tests-git-bash,packageand SonarCloud were SUCCESS.
(Posted by lane openRepoShape-5's coordinator. rv1207 is lane 5's independent opus reviewer; it wrote none of #1207. Lane 5 takes the three SHOULDs as a fix round: SHOULD-1's row, SHOULD-2's open issue for the Left items, and SHOULD-3's landing order with lane 4 for #1105 and #1121. #1207 lands only after a re-check is READY.)
Lane: openreposhape-5 (openRepoShape-5)
… kept `Makefile` and `GNUmakefile/` says the merge comes first too, README.md names `make park` and `make resume`, and rows pin the script-only aside and a directory sent to a leg #1207's independent review (issuecomment-6374516382), the code items: - SHOULD-1: no row pinned NEXT where only `scripts/bootstrap.py` went aside beside a kept `GNUmakefile/`, so its mutant X1 (`if stops and makefile`, which names `make bootstrap` after the merge) survived. A row now asserts the whole NOTE there. - NIT-1: `AGENTS-shape.md`'s sentence after the five-commands table said "(above)" of a Makefile that includes another, which nothing above names. The pointer is gone. - NIT-2: README.md's caveat covered `make bootstrap` only. It now says `make park` and `make resume` below work there only where the file GNU make reads first holds them, or includes a Makefile that does. - NIT-3: beside a kept `Makefile`, NEXT's directory NOTE said only that the targets run once the root keeps no directory of that name. The root's `Makefile` is the source's own until the merge, so the NOTE now says the targets run there once the follow-up merges the two, and only once the directory is gone. - NIT-4: no row showed that NEXT reads only the root's paths (mutant X6, every leg's paths, survived). An adoption now answers `plan`'s question for `GNUmakefile/` with `code`; NEXT names `make bootstrap`, and that command runs in the pasted clone. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…teps` asks `_make_reads_first` once for a kept file or directory, words both through `_make_reads_first_clause`, and #1121's NOTEs name `python` on Windows #1121 (#1047) and this branch both changed `_next_steps`, and git stopped on four hunks of adopt-project.py (84 lines). The resolution: - execute's comment names both: a kept `GNUmakefile` or `makefile` is what GNU make reads first (#1047), and a directory of either name stops it (#1132). - The docstring keeps #1121's paragraph and this branch's two. - One lookup, `_make_reads_first`, in place of #1121's own: it gives the kept name, with a `/` for a directory. The command line is `python3 scripts/bootstrap.py` where a `Makefile` went aside or `first` is set, as #1121 had it. - One clause, `_make_reads_first_clause(first, ..., "has them")`. For a file it gives #1121's `reads` byte for byte; for a directory it gives this branch's words, and beside a kept `Makefile` it names the merge (#1207's review, NIT-3). - The NOTEs end in `BOOTSTRAP_COMMAND`, so #1121's file NOTE and its script-aside NOTE name `python` on Windows, as #480's NOTE does on this branch. tests/test_adopt_next_make_reads_first.py moves three pins to that: OWN_MAKEFILE_NOTE, RUNS and script_aside. Without them, its rows fail on #480's NOTE, which merged with no textual conflict. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Independent review of #1207 (#1132) for lane openRepoShape-5, by rv1207b (opus), at 6fa1edd: READY on what is measured so far, PARTIAL This review is partial because the coordinator sent LAST STEP at 22:06Z. So far there is no MUST and no SHOULD. Two gates are still running (see "Left"). What I checked and measuredSetup. I made two detached worktrees at
The notes are in 1. The first review's findings are fixed as claimed
2. The merge resolution of #1121I wrote a probe that renders NEXT and the
3. Mutants at
|
| id | mutant | rows failing |
|---|---|---|
| X1a | script-only NOTE names make bootstrap unless a Makefile went aside |
5 of 61 |
| X1b | the same, for a directory only | 1 (SHOULD-1's row) |
| N1 | merged = "" |
2 |
| N2 | merge named even where the script went aside | 1 |
| N3 | merge named without a kept Makefile |
2 |
| K1 | merge named for a kept FILE too (75c's condition) | 3 |
| K2 | clause given only for a directory (75c's gate) | 18 |
| K3 | command test makefile or stops (75c's) |
3 |
| K4 | the elif first NOTE back to plain python3 |
10 |
| K5 | the script-aside NOTE back to plain python3 |
5 |
| K6 | M18: the file clause says does |
9 |
| K7 | _make_reads_first drops the / of a directory |
14 |
| T1 | "(above)" put back | 1 |
| T2 | the README's park/resume sentence removed | 1 |
| X6 | NEXT is handed every leg's paths | 2 of 5 |
All 15 mutants are killed. M18 (K6) is no longer equivalent, which confirms #1240's item J.
4. Gates, all through run9.sh
-
The PR's test files plus
test_adopt_make_reads_first.py(135 rows):- 135 passed on git 2.43.0 (
logs/rv1207b-g243pr.log); - 135 passed on git 2.47.1 (
logs/rv1207b-g247pr.log).
- 135 passed on git 2.43.0 (
-
Rows on main (
mut/ONMAIN.log): I checked out main's four production files over the head. 53 failed and 22 passed:- the new file: 34 fail, and 1 passes (NIT-4's row, as the body says);
- adopt-project.py:
execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121's file: 19 fail and 21 pass.
Restored afterwards, 4/4 OK.
5. Template pins
I grepped tests/ for 18 phrases from the changed lines. Only tests/test_adopt_make_bootstrap_followups.py pins the changed text. The other hits are unrelated:
- a sentence in the doctor test;
- a comment in
test_ruleset_hint_tracking_branch.py; - park/resume text in the family-root tests;
os.nametext intest_setup_project_py.py.
6. The body
- The new file has 35 rows and adopt-project.py:
execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121's file has 40, as the body says. - The rows-on-main counts (34/1 and 19/21) are true.
Closes #1132is the only closing keyword, andbody-guard.pyexits 0.- The sq.sh awk cut, run on the live body, keeps
Closes #1132and the Lane line, and leaves no "For the squash message" text.
7. Merge-trees
- Main + head: clean, tree
cb8962c9, which is the head's own tree. - Head and shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps a
GNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105 (b28f40de0): conflicts inscripts/shape_materialize.pyonly, in both orders. It is 3 hunks: 65 lines without markers, 74 with them. This matches the body.adopt-project.pyandAGENTS-shape.mdmerge without conflict.- The merged
AGENTS-shape.mdadds shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105's paragraph and repeats no sentence.
- Main + shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps a
GNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105: clean.
Findings
MUST: none so far.
SHOULD: none so far.
NIT-A: a stale comment.
- Where:
tests/test_adopt_next_make_reads_first.py:64. - What it says: "adopt-project.py: a source with its own Makefile keeps it, so
execute's NEXTmake bootstrap(and every shape make target) fails in the adopted root until a human merges shape/Makefile #480's NOTE, for a root that keeps only its ownMakefile: unchanged." - Why it is wrong: the merge moved that pin to
(python on Windows), so "unchanged" is no longer true. - Fix: drop the word, or say it changed for adopt-project.py and the assembly-root template: follow-ups from RV1105's and RV1121's reviews of #1105 and #1121 (
make bootstrapin the template, a keptGNUmakefile/directory,python3on Windows,GNU_MAKE_READStwice, stale follow-ups) #1132.
NIT-B: a contrived corner, inherited from 75c90b6db and not new in the merge. I did not measure it with make; it follows from GNU make's order.
- The root:
Makefile, amakefilefile and aGNUmakefile/directory, on a disk that keeps case. - What the NOTE says: the targets run "once the follow-up merges the two, and only once the root keeps no directory of that name".
- What actually happens: with the directory gone, GNU make reads the source's
makefile, not the mergedMakefile. - Suggestion: record it in adopt-project.py:
planwrites its follow-ups once, so after a hand edit of the plancheckand the split commit name aGNUmakefilethe root no longer keeps, or say nothing of one it now keeps #1206 or adopt-project.py, shape_materialize.py and the assembly-root template: after #1121 and #1105, oneGNU_MAKE_READSand one lookup, their NEXT NOTE and collision line as true as #1207's, and the NITs 1, 3b, 3c, 4 and 5 of #1105's second review #1240. It is not worth a fix round.
Left (not done because of LAST STEP)
- Two gates still running (the
gates.shchain, PID 4193513):rv1207b-g243rest: run9 PID 415764, pytest PID 415799,logs/rv1207b-g243rest.log;- then
rv1207b-g247rest:logs/rv1207b-g247rest.log. - Together they cover
test_shape_doctor.py,test_scaffold_leg_path_collisions.pyand the hygiene five, on 2.43 and on 2.47.1. - Results land in
$Q/v130/rv1207b/logs/gates.summary. READY depends on both ending with rc=0.
- The template's
scripts/bootstrap.pywording, checked againstBOOTSTRAP_COMMAND. - The body's 26 clean merges with other open PRs, re-run against today's heads.
- A grep of
tests/for a stored digest of either template file. - NIT-B measured with GNU make.
All paths above are under $Q/v130/rv1207b/, where $Q is /tmp/claude-1000/-workspace-projects-openRepoShape/50cede29-ab82-4ca3-9f67-d98e1a58c8d2/scratchpad.
Lane: openreposhape-5 (openRepoShape-5)
|
(lane openRepoShape-5, 2026-11-08T14:18:07Z) Independent review of #1207 (#1132) for lane openRepoShape-5, by rv1207b, rv1207c and rv1207d, at 6fa1edd: READY No MUST and no SHOULD. Both rest gates ended rc=0 and the merge-tree with main is clean. I wrote nothing: no commit, push or GitHub write, and the review worktree stayed clean at Earlier findings (rv1207b and rv1207c)Their posted review is issuecomment-6385544168. It found no MUST and no SHOULD, with three NITs. Everything it measured was READY.
Step 1: head and main
Step 2: the rest gates at
|
| Gate | git | Result |
|---|---|---|
rv1207d-g243 |
2.43.0 | 929 passed, 3 skipped, 13m17s, rc=0 |
rv1207d-g247 |
2.47.1 | 929 passed, 3 skipped, 13m22s, rc=0 |
- Skips: the same 3 on both legs,
test_shape_doctor.py:10516("powershell.exe exists, only on a Windows host"). - git per leg: each log prints
git --version, and the 2.47.1 leg resolvestools/git247/bin/git. - filter-repo: both runs used 2.45.0, because they started at 13:34Z and 13:47Z, before
run10.shchanged at 14:09Z. - filter-repo rows re-run on 2.47.0: only 4 rows in these 7 files execute
git filter-repo, theneeds_filter_reporows intest_shape_doctor.py. I re-ran them on 2.47.0 (CI's pin), and also the PR's adoption files (test_adopt_e2e.py,test_adopt_make_bootstrap_followups.py,test_adopt_next_make_reads_first.py,test_adopt_make_reads_first.py), at the head.
| Gate | git | filter-repo | Result |
|---|---|---|---|
rv1207d-fr247-A-243 |
2.43.0 | 2.47.0 | 4 passed |
rv1207d-fr247-A-247 |
2.47.1 | 2.47.0 | 4 passed |
rv1207d-fr247-B-243 |
2.43.0 | 2.47.0 | 135 passed |
rv1207d-fr247-B-247 |
2.47.1 | 2.47.0 | 135 passed |
The earlier review's "about 1035 rows" was loose; the real count is 932.
Step 3: merge-tree with main
- With
bd3e9c148:git merge-tree --write-tree bd3e9c148 6fa1edd56is clean (rc=0) on both 2.43.0 and 2.47.1, tree84d7b62560c2377289d3b49940cef51a56c38a38. It differs from the head only in main's 8 files. - With
93d293141, re-run after main moved: clean (rc=0) on both versions, tree42ccfd3e191fb2d2d81f2c95b2f76ff258bf9abc.
Extra: the merged trees, gated in scratch repos
I extracted each predicted merge into its own repo under L/work/rv1207d/ (merged-main/, merged-main2/). Nothing was written to the shared repo.
| Merged tree | git | Files | Result | filter-repo |
|---|---|---|---|---|
84d7b6256 (main bd3e9c148 + head) |
2.43.0 | test_adopt_e2e.py, test_adopt_make_bootstrap_followups.py, test_adopt_next_make_reads_first.py, test_adopt_make_reads_first.py, test_adopt_partial_clone_source.py, test_path_guard_hygiene.py |
294 passed | 2.45.0 |
84d7b6256 |
2.47.1 | the same 6 | 294 passed | 2.45.0 |
84d7b6256 |
2.43.0 | the other 6 of the 7 rest-gate files | 808 passed, 3 skipped (the same PowerShell skips) | 2.45.0 |
42ccfd3e1 (main 93d293141 + head) |
2.43.0 | the 6 above plus main's test_adopt_check_throwaway_repos.py, test_adopt_nested_attributes.py, test_adopt_reencoded_files.py, test_command_scopes_built_at_the_test.py |
573 passed, 1 skipped | 2.45.0 |
- The one skip:
test_adopt_check_throwaway_repos.py:482, which needs a case-insensitive disk. - Not run on the newest merge: the full 7-file gate on 2.47.1, or any of these on filter-repo 2.47.0. Landing should gate the head against current main as usual.
Verdict
READY. No finding changes the earlier review's three NITs, and nothing in the gates or the merges contradicts it. For the coordinator at landing: re-check the head against main (now 93d293141), and add NIT-B to #1240.
Logs and scripts are in /workspace/projects/.lane-worktrees/openRepoShape-5/work/rv1207d/, with notes in STATE.md there.
- Logs (
logs/):rv1207d-g243.log,rv1207d-g247.log,rv1207d-fr247-{A,B}-{243,247}.log,rv1207d-merged243.log,rv1207d-merged243b.log,rv1207d-merged247.log,rv1207d-merged2-243.log,mt-main.txt,mt-main2.txt,collect.txt,gates.summary. - Scripts (the folder itself):
gates.sh,merged-gate.sh,merged-gate2.sh,merged-gate3.sh,fr247-gate.sh.
Lane: openreposhape-5 (openRepoShape-5)
…on_follow_up` keeps #1105's `reads_first` lines and #1207's script-aside tail, each naming `python` on Windows, and four pins in #1105's test file move with them Lane 4's #1105 (#1048) landed as 1212295, and its `collision_follow_up` conflicted with this branch's, as the body's "Landing order" said it would. `adopt-project.py` and `templates/assembly-root/AGENTS-shape.md` merged with no conflict. The resolution keeps both sides' behaviour and does none of #1240's unification: #1105's second `GNU_MAKE_READS`, its `_predict_collisions` lookup and its collision line stay, and so do this branch's `_make_reads_first`, `_make_reads_first_clause` and NEXT. scripts/shape_materialize.py, three hunks, all in `collision_follow_up`: - Docstring, the NIT-4 sentence: both sides rewrote the same sentence for the same finding. Main's is kept, since it also names `Materialized.follow_ups()`, which #1240 item G changes. - Docstring, the Makefile paragraphs: main's heading and its "BUT GNU MAKE READS" paragraph, with this branch's `BOOTSTRAP_COMMAND` and NIT-2 sentences in the first, and one sentence in the second saying both of its commands are named as `BOOTSTRAP_COMMAND` names them. - The returns: #1105's per-branch `arrive`, `joint` and `meanwhile` stay, and its `until` becomes a per-branch `then`. With no `reads_first`, the line is this branch's, byte for byte. With one, it is #1105's, byte for byte, but the command a person runs is `BOOTSTRAP_COMMAND` in `meanwhile` and in "and then ... runs it" (#1240 item C, for #1105's line). tests/test_adopt_collision_make_reads.py (#1105's): `MERGE_IS_ENOUGH`, `MEANWHILE`, `BOTH_MERGES` and `SCRIPT_MERGED` move to those words, through a new `COMMAND`. Before the move exactly the 11 rows that use them failed, and the other 242 rows of the six adopt and pin files passed. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…LE_NOTE` no longer calls #480's NOTE unchanged, since #1132 adds `python` on Windows to it (rv1207b's NIT-A) The merge of #1121 moved that pin to "(`python` on Windows)", and the comment above it still said "unchanged" (#1207's review, NIT-A, at `tests/test_adopt_next_make_reads_first.py:64`). Comment only. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…`makefile-directory` row in `tests/test_adopt_make_reads_first.py` expects the line that says GNU make stops at a kept `makefile/`, and still guards `twins` Lane 1's #1123 (#1061) landed after this branch merged main 46fe6ac, and the merge with it is clean by text. By meaning it is not: #1123 adds a row, `test_a_name_only_a_disk_that_ignores_case_takes_for_makefile[makefile-directory]`, that expects the `CONTRACTS_DIR` line a kept `makefile` FILE gets for a kept `makefile/` DIRECTORY ("only once `makefile` does"). #1123's own message says that line is not true for a directory, since GNU make 4.3 stops there with `makefile: Is a directory.`, and that the row works as a crash guard for `twins` in `_makefile_follow_up`. This branch changes exactly that line (#1132, RV1121's NIT-1): a kept directory is one GNU make stops at. On the predicted merge the row was the one failure in 254 rows. The row now expects `SHAPES + written_as("makefile")`, as #1123 wrote it, which is what guards `twins`, followed by this branch's directory clause, through a new `stops_at` helper beside `reads`. The comment above `ANSWERED` and the row's docstring say so. Nothing else changes, and #1118's merge (9ec0dc7, also in this main) is clean by text and by its rows. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
(lane openRepoShape-5, 2026-11-08T19:27Z) Delta check of #1207's main merges, Delta check of #1207 (#1132) for lane openRepoShape-5, by rv1207e (opus), 6fa1edd..01e93b6: READY The delta is clean. Neither merge carries a hidden change (no "evil merge"): each differs from git's own merge only where the body says. Hunk 3 renders as promised on every branch. The four moved pins and #1123's moved row change only what they should, and all gates pass. I found no MUST and no SHOULD, and three NITs. CI's Linux PR head FindingsNIT-1: one docstring sentence kept from #1105 is now untrue. In
NIT-2: one line number in the body is off by one. "Main merge after #1105" says hunk 2 sits at lines 1033-1070. It starts at 1032, the heading line, which is main's side of the conflict. NIT-3: the body's "Merges" section is one landing behind. It stops at main Checks, by measurement
Both worktrees are clean and detached at Files are in
Lane: openreposhape-5 (openRepoShape-5) |
…says a full name that is no pattern takes the one ref git completes it to, which may be a branch, where it said any other source names no branch (#1238) (#1244) #1238 is a wording NIT that the review of #1235 (#1230) found in the code: NIT 4 of rv1235's first review, and NIT 2 of its re-check. The docstring of `gives_a_branch_another_name` in `scripts/shape_materialize.py` ended "ANY OTHER SOURCE NAMES NO BRANCH", but git completes a source that is a full name and no pattern, and completes `refs/h` to the branch `refs/heads/refs/h` where the remote has one. The sentence now says what git does with such a source, as an open list ("such as"), and where the clash is. A reader of the docstring is no longer told that a source outside `refs/heads/` is never a branch. Wording only, in one docstring of one file: 9 lines added, 3 removed. No code, no row, no other file. The file's syntax tree with every docstring dropped is the same as main's. The sentence is at `scripts/shape_materialize.py:1720-1723`, the end of the docstring of `gives_a_branch_another_name` (line 1671): ``` 1720: BRANCH REACHES). A shorter start, such as `refs/*` or `*`, can name a 1721: tag, and that clause has left it out first. ANY OTHER SOURCE NAMES NO 1722: BRANCH, though a refspec from one can still put a ref on a branch's 1723: name: `origin_fetch_refspecs` says where (WHAT CAN STILL CLASH). ``` It is true of a source in another namespace such as `refs/pull/7/head`. It is not true of every other source. A source that is a full name and no pattern takes the one ref git completes the name to on the remote: for `refs/h`, `refs/h` itself, the branch `refs/heads/refs/h`, the tag `refs/tags/refs/h`, `refs/refs/h` or `refs/remotes/refs/h`, and where several exist git takes the exact ref over a tag over a branch. Where the remote has the branch, the source is a branch. The code is right: `gives_a_branch_another_name("refs/h", ...)` is False, because the source has no `*` and does not start with `refs/heads/`, so the refspec is carried. What fails afterwards is the clash the docstring's own next clause names. Only the words were untrue. Measured on this branch's base, with git 2.43.0 (`/usr/bin/git`) and git 2.47.1, which gave the same answers on every row. Local bare remotes, `GIT_CONFIG_GLOBAL=/dev/null`, `GIT_CONFIG_NOSYSTEM=1`, `GIT_SSH_COMMAND=false`. rv1235's probe scripts were run again here (copied unchanged, new output folders), and their logs are identical to rv1235's. The fetch was `+refs/heads/*:refs/remotes/origin/*` plus the refspec of the row, and the remote had `main` and `hy`: ``` the remote has refspec result branch refs/heads/refs/h +refs/h:refs/remotes/origin/hy 128 Cannot fetch both refs/heads/hy and refs/heads/refs/h to refs/remotes/origin/hy tag refs/tags/refs/h +refs/h:refs/remotes/origin/hy 128 Cannot fetch both refs/heads/hy and refs/tags/refs/h to refs/remotes/origin/hy exact ref refs/h (update-ref) +refs/h:refs/remotes/origin/hy 128 Cannot fetch both refs/heads/hy and refs/h to refs/remotes/origin/hy refs/refs/h or refs/remotes/refs/h +refs/h:refs/remotes/origin/hy 128, the same message naming that ref each of those five refs, alone onto origin/not-a-branch 0, holds that ref's commit branch refs/heads/refs/h onto origin/refs/h 0 (the branch's own name: no clash) refs/pull/7/head onto origin/main 128 Cannot fetch both refs/heads/main and refs/pull/7/head to refs/remotes/origin/main branch refs/heads/main onto origin/main 0 ``` So a name with no `*` can be a branch that its spelling does not show, and the clash is a ref that is not that branch put on a branch's name, which is what the second half of the sentence has to say. "ANY OTHER" was wrong in a second way: a carried refspec from a source that IS the branch does not clash onto that branch's own name. The docstring's last sentence, now lines 1721-1729: ``` tag, and that clause has left it out first. ANY OTHER SOURCE TAKES NO BRANCH BY A PATTERN, and a full name that is no pattern, such as `refs/h`, takes the one ref git completes it to on the remote: that ref itself, or one such as the branch `refs/heads/refs/h` or the tag `refs/tags/refs/h` (measured, git 2.43 and 2.47.1). Such a name can stand for a branch its spelling does not show, so it is not left out here. A refspec from any such source can still put a ref on a branch's name, if the ref is not that branch itself: `origin_fetch_refspecs` says where (WHAT CAN STILL CLASH). ``` - **"Takes no branch by a pattern"** holds for every source this sentence covers. Git matches a pattern against each ref's whole name, and a ref under `refs/heads/` starts with the part before the `*` only where that part is a start of `refs/heads/` or is under it, the two cases the function reads before this sentence. - **The list is open** ("one such as"): it names the exact ref, the branch and the tag, and the rows above show two more completions (`refs/refs/h`, `refs/remotes/refs/h`), so no reader takes the three as all. - **"So it is not left out here"** is what the code does: `gives_a_branch_another_name` is False for `refs/h` onto `origin/hy`, onto `origin/refs/h`, for `refs/pull/7/head` onto `origin/main`, and for the pattern `refs/pull/*/head`, and `origin_fetch_refspecs(["+refs/h:refs/remotes/origin/hy"])` returns it carried. It is True for `refs/heads/main` onto `origin/hy`, as before. - **"If the ref is not that branch itself"** is the condition the rows show: the clash is two different refs on one name, a branch's. The checks the issue's Verify lists: - **The diff is only that docstring.** The diff has one hunk, inside the docstring, which spans lines 1672-1724 on main and 1672-1730 here. The file's tree with every docstring dropped (module, class and function: 168 each side) is equal on main (`50869f384`) and at this head under `python3 -I`, `ast.dump`: 380120 characters of dump on both sides. A control that renames `gives_a_branch_another_name` on the head side gives 380121 and DIFFERENT, and the same trees with the docstrings kept differ (520956 against 521366), so the check can fail. Python 3.12.3. The check compares two dumps made by one interpreter and asserts no text that depends on the version. - **`git grep -n 'ANY OTHER SOURCE NAMES NO$' -- scripts/`** finds nothing at this head. On main it finds `shape_materialize.py:1721`. With any case and no line end, `git grep -n -i 'other source names no'` also finds nothing here, and nothing but that line on main. - **No added line is over 79 columns or holds a non-ASCII character.** 9 lines are added, the longest is 75 columns, and none has a tab or trailing space. The file's own width is unchanged: 20 lines over 79 columns (longest 118) and 90 lines with a non-ASCII character, as on main, none of them mine. - **No test, `README.md`, `docs/` page or `AGENTS.md` line pins the sentence.** The issue's grep holds at this head. The issue asks whether `shape_materialize.py:1874` (now 1880, in the docstring of `origin_fetch_refspecs`) and `bump-leg.py:1165` (in `_leg_fetch_refspecs`) want the same change. Both paragraphs were read, and both are left as they are: ``` shape_materialize.py:1880: WHAT CAN STILL CLASH is a refspec carried whose source names no branch, bump-leg.py:1165: whose source names no branch, onto a name a branch of the remote has ``` 1. **They define a shape by its examples and say nothing about what git completes a name to.** Each goes on at once to the pull requests (`origin/pr/` where a branch `pr/7` is, and `+refs/pull/7/head:refs/remotes/origin/main` beside a branch `main`), and neither names `refs/h`. They were not the sentence that told a reader a source is never a branch. 2. **"Names no branch" is spelling there, as it is in the sentence the function's docstring opens with.** "A SOURCE UNDER `refs/heads/` NAMES BRANCHES" is true by spelling too: `can_name_a_tag`'s docstring measures that `+refs/heads/zz` took the tag `refs/tags/refs/heads/zz` where the remote had no branch `zz`. The sentence changed here now says outright that the spelling of a name with no `*` does not show what it stands for, so the docstring that defines the class carries the caveat the two borrowers need. 3. **The mechanism they state is the one that fails `refs/h`:** "wherever a name it writes is a branch's". The `origin_fetch_refspecs` paragraph ends with why such a refspec is carried at all: "Which names the remote's branches have is not known from its refspecs, and left out, what such a refspec keeps would be pruned on every run". That holds for `refs/h` word for word. 4. **The cost of leaving them is one reading:** a reader who takes "names no branch" in git's sense meets the single case `refs/h` beside a remote branch `refs/heads/refs/h`. If the review wants a word there, it is a few words in each place, and no open PR touches either paragraph (merge-trees below), so it can be a fix round. None of either. No row is added or changed and no behaviour moved: the syntax tree outside the docstring is main's, so there is nothing for main to fail and nothing to mutate. `gives_a_branch_another_name` returns what it returned for every case in the table above (called in process at this head; the syntax tree outside the docstrings is main's). All through the lane's runner `run9.sh` (stub `gh` first on PATH, `GIT_SSH_COMMAND=false`, `GIT_CONFIG_GLOBAL=/dev/null`), on the committed head `36ec589a6` with the tree clean (`dirty=0`), as one run of seven files at a time: `tests/test_pinned_copy_text.py`, `tests/test_path_guard_hygiene.py`, `tests/test_repo_hygiene.py`, `tests/test_agents_md_codes.py`, `tests/test_cli_reference.py` (the hygiene five), `tests/test_family_bump_fetch_refspecs.py` and `tests/test_bump_leg_fetch_refspecs.py`. - **The seven files, git 2.43.0** (`/usr/bin/git`): 504 passed in 469.44s (47 `test_agents_md_codes.py`, 68 `test_bump_leg_fetch_refspecs.py`, 23 `test_cli_reference.py`, 57 `test_family_bump_fetch_refspecs.py`, 121 `test_path_guard_hygiene.py`, 87 `test_pinned_copy_text.py`, 101 `test_repo_hygiene.py`; the counts are from `--collect-only -q` on the same head and add up to 504). Log `v131/n1238/gate-g243.log`. - **The seven files, git 2.47.1** (first on PATH, `git --version` printed into the log): 504 passed in 714.00s. Log `v131/n1238/gate-g247.log`. - **`-k carried-refs-h-not-a-pattern`** over `tests/test_family_bump_fetch_refspecs.py` and `tests/test_bump_leg_fetch_refspecs.py`: 2 passed, 123 deselected, on 2.43.0 and on 2.47.1 (`run-k-g243.log`, `run-k-g247.log`). - Both runs start with `dirty=0`. Python 3.12.3 (CI runs 3.14); nothing asserts text that depends on the version. The measured git behaviour above comes from the probe scripts, not the test files. `-k carried-refs-h-not-a-pattern` over the two fetch-refspec files is part of those runs. `git merge-tree --write-tree origin/main HEAD` exits 0, with tree `9d874bcf2caf`, equal to this head's tree, against main `50869f384` (the merge base). Against the head of each open PR that touches `scripts/shape_materialize.py` or `scripts/bump-leg.py` (read from `gh pr list --state open --limit 100 --json number,headRefName,headRefOid,files`, 52 open PRs at the last read, 7 of them touch one of the two files), `git merge-tree --write-tree HEAD <head>` exits 0 and the merged tree still holds the new sentence and not the old one: ``` #1223 f50b472 exit 0 #1207 6fa1edd exit 0 #1160 0068f5a exit 0 #1131 55c30f2 exit 0 #1118 2307036 exit 0 #1105 b28f40d exit 0 #1104 de89aa8 exit 0 ``` Main moved once while this was gated, to `4829418f0` (`adopt-project.py`, `docs/cli.md` and a new test file: none of the files this change or its runs touch), and `git merge-tree --write-tree origin/main HEAD` against it also exits 0. None of their hunks is within 100 lines of the sentence changed here. Review: rv1244 and rv1244b, lane 5's independent sonnet reviewers, which wrote none of #1244: READY at `36ec589a6`, H0 of this landing (issuecomment-6723280477), with no MUST or SHOULD; its four NITs are optional (two wordings, a body note and a follow-up). CI (Brett Heap's ruling 27): H0 is the head 473959f itself, which passed tests, tests-git-bash and SonarCloud; main has touched none of its files since its base 9729315; and the local gate passed on its predicted squash tree fb798f3 over main 9252ef2: the repo_hygiene, agents_md_codes, cli_reference sets, 171 passed. Landed on Brett Heap's word of 2026-10-23T13:10:26Z, relayed to every lane by lane 3 (#473 issuecomment-6365697123): "merge v1.2.1 PRs once reviewed and green". Closes #1238 Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Goal
#1132, the parts that hold on main: the assembly-root template says what to run where GNU make reads a kept
GNUmakefileormakefilefirst; a kept DIRECTORY of either name is named as one GNU make stops at, in theCONTRACTS_DIRline and inexecute's NEXT; every sentence that namespython3 scripts/bootstrap.pyfor a person to run namespythonon Windows too; and two follow-up texts no longer say more than is true (RV1105b's NIT-2 and NIT-3a).This PR was built on main
961640c6. Lane 4's #1121 (#1047) landed as0ed3e57f8at 21:37Z, and this round merged it in (6fa1edd56): NEXT now words a kept file (#1121's) and a kept directory (this PR's) through one lookup and one clause. #1105 landed as12122952bon 2026-11-08, and this PR merges it in (see "Main merge after #1105"). The items that live only in #1105's code, and the parts of #1121's that this merge does not do, are in their own issue, #1240 (see "Left"). Item 5 is #1206.Main merge after #1105
Lane 4's #1105 (#1048) landed as
12122952bat 16:45Z. This round merges main into the branch withgit merge origin/main, never a rebase, and does it twice:46fe6ac19as merge7b0192bde;e5e077940;9729315f1as merge01e93b6d1, the head. Lane 1's README.md, adopt-project.py and the handbook: a kept directory entrymakefile/is tested, README saysmakeat the root reads a keptGNUmakefileormakefileinstead, and a docstring says the shape's Makefile alone holdsCONTRACTS_DIR(#1061) #1123 had landed meanwhile, and one of its rows meets this PR's directory line (see "The second merge, after README.md, adopt-project.py and the handbook: a kept directory entrymakefile/is tested, README saysmakeat the root reads a keptGNUmakefileormakefileinstead, and a docstring says the shape's Makefile alone holdsCONTRACTS_DIR(#1061) #1123").The first merge conflicted in
scripts/shape_materialize.pyonly: 3 hunks, all incollision_follow_up, as "Landing order" said.adopt-project.pyandtemplates/assembly-root/AGENTS-shape.mdmerged with no conflict.Both sides' behaviour stays: #1105's second
GNU_MAKE_READS, its_predict_collisionslookup and its collision line, and this PR's_make_reads_first,_make_reads_first_clauseand NEXT. None of #1240's unification is done here (one tuple, one lookup).The three hunks
6fa1edd56)46fe6ac19, #1105)executecalls it nowhere"Materialized.follow_ups()would say this of them, and nothing calls it"Materialized.follow_ups(), which #1240's item G changes. So this PR no longer touches that sentence, and the lastscripts/shape_materialize.pybullet under "What changed" is #1105's text now.BOOTSTRAP_COMMANDsentence and NIT-2's tailmakeREADS THE MERGED FILE", and the "BUT GNU MAKE READS" paragraphBOOTSTRAP_COMMANDand on NIT-2's tail go in the first paragraph, and one new sentence goes in the second: "Both name that command asBOOTSTRAP_COMMANDdoes,pythonon Windows as well (#1132)."returns, each one sentencearrive,joint,meanwhileanduntilset per branch, then one pair ofreturnsthenin place ofuntil. With noreads_first, the line is this PR's, byte for byte. With one, it is #1105's, byte for byte, except that the command a person runs isBOOTSTRAP_COMMAND, both inmeanwhileand in "and then ... runs it".collision_follow_up's docstring (lines 1014-1084).6fa1edd56, from main, and from the merge, and rendered eachreads_first(none,GNUmakefile,makefile) with and withoutscripts/bootstrap.pyaside.reads_first, the merge equals6fa1edd56(2 of 2).pythonon Windows)" afterpython3 scripts/bootstrap.pyin those two places (4 of 4). For a root that keepsMakefileandGNUmakefile, the line now ends "...; until thenpython3 scripts/bootstrap.py(pythonon Windows) is what the shape'smake bootstrapruns".makereads another file stays shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105's own: "neithermake bootstrapnorpython3 scripts/bootstrap.pyruns the shape's bootstrap until then, and thenpython3 scripts/bootstrap.py(pythonon Windows) runs it". shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105's review fixed that branch for the same finding, so it needs nothing more.GNU_MAKE_READSand one lookup, their NEXT NOTE and collision line as true as #1207's, and the NITs 1, 3b, 3c, 4 and 5 of #1105's second review #1240's list, this round does item C for shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105's collision line, as adopt-project.py, shape_materialize.py and the assembly-root template: after #1121 and #1105, oneGNU_MAKE_READSand one lookup, their NEXT NOTE and collision line as true as #1207's, and the NITs 1, 3b, 3c, 4 and 5 of #1105's second review #1240 asks a resolution to say. So the "withpython3" part of "Left"'s second bullet is done. Item B, the kept directory, stays: shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105's lookup asks_root_keeps, so a root that keepsMakefileandGNUmakefile/is told GNU make "reads the source'sGNUmakefile". Mutant U3 below shows that no row pins this line for a directory.#1105's test pins
tests/test_adopt_collision_make_reads.pyis #1105's file, and it pins the texts this PR changes, as "Landing order" expected.Four pins move.
MERGE_IS_ENOUGHandBOTH_MERGES(noreads_first) move to this PR's words.MEANWHILEandSCRIPT_MERGED(with one) move topythonon Windows. All four go through a newCOMMAND.One comment changes. The comment on the
Makefile+scriptsrow now says what NIT-2's tail says.Measured: before the move, the six adopt and pin files gave 11 failed and 242 passed, and the 11 are exactly the rows that use those four pins. After the move, 253 passed.
On main's code: main
46fe6ac19's four production files (adopt-project.py,scripts/shape_materialize.py,templates/assembly-root/AGENTS-shape.mdandREADME.md) were swapped into the mutant worktree ate5e077940. 64 of the three files' 106 rows fail:tests/test_adopt_next_make_reads_first.py, 19 of 40, as before.The four files were then restored, each matched the head by sha256 (4 of 4), and the tree was clean.
NIT-A
tests/test_adopt_next_make_reads_first.py:64called #480's NOTE "unchanged", but the merge of #1121 moved that pin topythonon Windows. The comment now says the NOTE "namespythonon Windows too since #1132". The change is a comment only, in its own commit.The second merge, after #1123
Lane 1's #1118 and #1123 landed while the first merge was being gated:
9ec0dc79cat 17:30Z and9729315f1at 17:47Z. Both merge withe5e077940with no conflict in the text. The predicted merge with9ec0dc79cpassed (gate P below). The predicted merge with9729315f1failed 1 row of 254 (gate P2):makefile/is tested, README saysmakeat the root reads a keptGNUmakefileormakefileinstead, and a docstring says the shape's Makefile alone holdsCONTRACTS_DIR(#1061) #1123 addstest_a_name_only_a_disk_that_ignores_case_takes_for_makefile[makefile-directory]totests/test_adopt_make_reads_first.py. For a kept DIRECTORYmakefile/, it expects theCONTRACTS_DIRline a keptmakefileFILE gets ("only oncemakefiledoes"). README.md, adopt-project.py and the handbook: a kept directory entrymakefile/is tested, README saysmakeat the root reads a keptGNUmakefileormakefileinstead, and a docstring says the shape's Makefile alone holdsCONTRACTS_DIR(#1061) #1123's own message says that line is not true for a directory, and that the row works as a crash guard fortwinsin_makefile_follow_up. This PR changes exactly that line: a kept directory is one GNU make stops at.01e93b6d1: the row now expectsSHAPES + written_as("makefile"), as README.md, adopt-project.py and the handbook: a kept directory entrymakefile/is tested, README saysmakeat the root reads a keptGNUmakefileormakefileinstead, and a docstring says the shape's Makefile alone holdsCONTRACTS_DIR(#1061) #1123 wrote it, which is the part that guardstwins. This PR's directory clause follows, through a newstops_athelper besidereads. The comment aboveANSWEREDand the row's docstring now say so. Nothing else changes in the merge.01e93b6d1againsttests/test_adopt_make_reads_first.py(34 rows). Each was restored withgit checkoutand matched by sha256 (adopt-project.py3c2cb5f5bea5), and the tree was clean after each._make_reads_firstdrops a directory's/, so the line is the one #1123's row pinnedtwinsreads the entry with its slashIndexErrorMutants on the resolution
H3a-H3g and U1-U3b are the first merge's. All ran in the mutant worktree at
e5e077940.git checkout. Each restore matched by sha256 (shape_materialize.pyb18f09d7c396,adopt-project.py2055a81acdc6), and the tree was clean after each.tests/test_adopt_collision_make_reads.py(31), the new file (35) andtests/test_adopt_e2e.py(27). U1 ran against the new file,tests/test_adopt_make_reads_first.py(33) andtests/test_adopt_collision_make_reads.py, 99 rows. U2 ran against the new file andtests/test_adopt_next_make_reads_first.py(40), 75 rows.reads_first:meanwhileback to main's plainpython3reads_first: the script tail back to main's "before both merges are made"reads_first:meanwhilewithoutBOOTSTRAP_COMMAND(main's)reads_first: "and then ... runs it" withoutBOOTSTRAP_COMMAND(main's)reads_first: this PR's tail in place of #1105'sreads_firstignored, so the resolution is this PR's side wholereads_first: #1105'sjoint("; and") lost_makefile_follow_updrops_make_reads_first(first = None)_next_stepsdrops_make_reads_first(first = None)_predict_collisionsasks_make_reads_firstin place of #1105's lookup_predict_collisionspasses noreads_first, so #1105's lookup is lost in the mergeMEANWHILEandSCRIPT_MERGED. Those pins are what holdBOOTSTRAP_COMMANDin shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105's branch.GNU_MAKE_READSand one lookup, their NEXT NOTE and collision line as true as #1207's, and the NITs 1, 3b, 3c, 4 and 5 of #1105's second review #1240's item B. For a kept file, both lookups give the same name. They differ only for a kept directory, where_make_reads_firstadds the/, and no row runs_predict_collisionson a root that keepsMakefileandGNUmakefile/. A row now would pin the line adopt-project.py, shape_materialize.py and the assembly-root template: after #1121 and #1105, oneGNU_MAKE_READSand one lookup, their NEXT NOTE and collision line as true as #1207's, and the NITs 1, 3b, 3c, 4 and 5 of #1105's second review #1240 is to correct, so this round adds none.Runs
Each run went through the lane's runner, with git-filter-repo 2.47.0 (CI's pin) on PATH, on a commit with a clean tree.
01e93b6d1, the head: the 12 files belowtest_shape_doctor.py:10516), which run only on a Windows host01e93b6d1: the same 12 filese5e077940, after the first merge: the 12 files belowe5e077940: the same 12 filese5e077940with main9ec0dc79c(#1118; treeba3f3c1f3, a local commit object, not pushed): the six adopt and pin files, plus #1118'stests/test_adopt_root_shape_paths.pyandtests/test_adopt_symlink_target_bytes.pye5e077940with main9729315f1(#1123; tree0eb290ae2, a local commit object): the six adopt and pin filesmakefile-directoryrow, which the second merge moves01e93b6d1with main801a7d6d0(#1106; tree25bc27d39, a local commit object): the six adopt and pin files, plus #1106'stests/test_adopt_one_byte_locale.pyandtests/test_adopt_unenterable_source_and_locale.pyThe files are the six adopt and pin files (
tests/test_adopt_collision_make_reads.py,tests/test_pinned_copy_text.py, the new file,tests/test_adopt_next_make_reads_first.py,tests/test_adopt_e2e.pyandtests/test_adopt_make_reads_first.py, 253 rows), plustests/test_shape_doctor.pyandtests/test_scaffold_leg_path_collisions.py, which adopt changes need, plus the hygiene five (test_path_guard_hygiene.py,test_repo_hygiene.py,test_agents_md_codes.py,test_cli_reference.pyandtest_pinned_copy_text.py). That is 1098 rows in one run ate5e077940, and 1099 at01e93b6d1, where #1123 adds one row.What held on main, before the change
All of this was measured on main
961640c68with GNU make 4.3, offline.AGENTS-shape.md(the "Work from here" paragraph and the five-commands table) andREADME.md(Get started, and the parking steps) givemake bootstrapwith no caveat. With the template's ownMakefilebeside a plainGNUmakefileormakefile,make -n bootstrapexits 2,No rule to make target 'bootstrap'.GNUmakefile/ormakefile/besideMakefile,make bootstrapexits 2 withmake: *** GNUmakefile: Is a directory. Stop., or the same withmakefile. It does this for every target, and for each directory alone too. Main'sCONTRACTS_DIRline says "makethere exportsCONTRACTS_DIRonly onceGNUmakefiledoes". NEXT printsmake bootstrapfor a root that keeps onlyGNUmakefile/. Beside a keptMakefile, it prints #480's NOTE that the targets "arrive only once the follow-up merges the two". Rendered by the lane'sprobe_texts.pyon main.python3scripts/bootstrap.pysayspython3 scripts/bootstrap.py (python on Windows). #480's NOTE and the Makefile collision follow-up's "until then" namepython3alone.reads_firstscript-aside tail says "neithermake bootstrapnorpython3 scripts/bootstrap.pyruns the shape's bootstrap before both merges are made". In a root that keeps its ownMakefileandscripts/bootstrap.py, merging the script alone makespython3 scripts/bootstrap.pyprint the shape'sSHAPE-BOOT, whilemake bootstrapstill exits 2. Measured again by a row below._predict_collisionssays the wording comes from "the same functionexecutereports its actual collisions through", andcollision_follow_upsays "Both callers say it".executenever callscollision_follow_up: it carries the plan's storedfollow_ups:into the split message.What changed
adopt-project.py:_make_reads_first(surviving)gives the first ofGNUmakefileandmakefilethe root keeps. It readsGNU_MAKE_READS' order, asks the way_root_keepsasks, and adds a/for a DIRECTORY._make_reads_first_clausewords the clause. For a file, the words are main's, byte for byte. For a directory, it says: "GNU make at the root stops at the source's directoryGNUmakefile/, the first ofGNUmakefile,makefileandMakefileit finds (GNUmakefile: Is a directory.), so ... only once the root keeps no directory of that name"._makefile_follow_up(theCONTRACTS_DIRline) asks both. A kept file's line is unchanged:tests/test_adopt_make_reads_first.pypasses as it is._next_stepstakessurviving=, the plan's root paths, whichcmd_executepasses aspaths_for["root"], as adopt-project.py:execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121 does.python3 scripts/bootstrap.py. The NOTE says GNU make stops there. Beside a keptMakefile, it also says the targets run there once the follow-up merges the two, and only once the directory is gone. Where the script went aside too, alone or with theMakefile, the NOTE names that command after the merges.execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121, a kept FILE goes through the same lookup and the same clause. For a file the clause gives adopt-project.py:execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121's words byte for byte, and its NOTEs end inBOOTSTRAP_COMMANDtoo.BOOTSTRAP_COMMANDis in every NOTE: adopt-project.py: a source with its own Makefile keeps it, soexecute's NEXTmake bootstrap(and every shape make target) fails in the adopted root until a human merges shape/Makefile #480's, adopt-project.py:execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121's and the directory's. Each command line a person pastes stayspython3 scripts/bootstrap.py._predict_collisions' docstring says what the plan stores and whatexecutecarries (NIT-3a).scripts/shape_materialize.py:BOOTSTRAP_COMMAND= "python3 scripts/bootstrap.py(pythonon Windows)", as the template's script names it.python3 scripts/bootstrap.py(pythonon Windows) is whatmake bootstrapruns".python3 scripts/bootstrap.py(pythonon Windows) runs the shape's bootstrap once the script is merged, andmake bootstraponce both merges are made" (NIT-2).GNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105's review NIT-4). shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105 made the same fix, and the merge keeps main's text (see "Main merge after shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105").templates/assembly-root/:AGENTS-shape.md: the "Work from here" paragraph adds "; where the root keeps aGNUmakefileor amakefile, which GNU make reads beforeMakefile, runpython3 scripts/bootstrap.py(pythonon Windows), which is what the shape'smake bootstrapruns." A sentence after the five-commands table says they are the shape's Makefile's targets, whichmakeat the root reaches only where the file it reads first holds them, or includes a Makefile that does.README.md: one sentence after Get started coversmake bootstrap"here and below". A second saysmake parkandmake resumebelow work there only where that file holds them, or includes a Makefile that does.tests/was grepped for every changed line, and only this PR's own rows pin them (see "Template pins").Tests:
tests/test_adopt_e2e.py: two pins move to the new words, at :312 (the "until then" sentence) and at :447-450 (NIT-2's tail).tests/test_adopt_next_make_reads_first.py(adopt-project.py:execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121's): the merge moves three pins,OWN_MAKEFILE_NOTE,RUNSandscript_aside, topythonon Windows. adopt-project.py: a source with its own Makefile keeps it, soexecute's NEXTmake bootstrap(and every shape make target) fails in the adopted root until a human merges shape/Makefile #480's NOTE merged with no textual conflict, so without them its rows fail.tests/test_adopt_make_bootstrap_followups.pyhas 35 rows:Makefile(PYTHON ?= python3,bootstrap:runs$(PYTHON) scripts/bootstrap.py) and toscripts/bootstrap.py's own words;make -n bootstrapagainst the template'sMakefilebeside each kept name, each row asserting theAGENTS-shape.mdcaveat that measurement backs;_make_reads_first(10 roots);CONTRACTS_DIRline for 4 directory roots;Makefile(both names), after both merges, and after the script's merge alone;execute's NEXTmake bootstrap(and every shape make target) fails in the adopted root until a human merges shape/Makefile #480's NOTE, called both as main's signature allows and withsurviving=;Makefileand stand-in scripts, and tied to the follow-up's new tail;GNUmakefile/rules.mk. One is kept by a--path-policyrule, soplanwrites the line,checkprints it and the split message carries it. One is answeredroot. In both, NEXT is asserted,make -n bootstrapin the pasted clone exits 2 withGNUmakefile: Is a directory., and the printed command exits 0. In the third, the question is answeredcode: NEXT namesmake bootstrap, and that command runs in the pasted clone.This round (#1207's review, issuecomment-6374516382)
scripts/bootstrap.pywent aside beside a keptGNUmakefile/(test_next_after_the_script_merge_names_python3_where_make_stops). It fails under the review's mutant X1.AGENTS-shape.md's sentence after the table loses "(above)": nothing above names a Makefile that includes another.README.mdnamesmake parkandmake resume.Makefile, the directory NOTE names the merge as well as the directory. Its row is parametrized overGNUmakefile/andmakefile/.GNUmakefile/to the code leg, and NEXT namesmake bootstrap. It fails under the review's mutant X6.Rows that fail on main
Measured at the merge head
6fa1edd56, in a scratch worktree:0ed3e57f8's bytes of the four production files (adopt-project.py,scripts/shape_materialize.py,templates/assembly-root/AGENTS-shape.md,templates/assembly-root/README.md) were checked out over the head;tests/test_adopt_next_make_reads_first.py(40 rows) ran through the lane's runner;git checkout, and each matched the head by sha256 (c94bd19b,12555f39,8660bafb,b3f9409b).test_an_adoption_sending_a_gnumakefile_directory_to_a_legtests/test_adopt_next_make_reads_first.pyMain now has #1121, so its
_next_stepstakessurviving=. The NEXT rows for a kept directory therefore fail on their words, not on aTypeError. Main readsGNUmakefile/as a file: "then runpython3 scripts/bootstrap.py; GNU make at the root reads the source'sGNUmakefile, ...". This is the case for the SHOULD-1 row, the after-the-merges row, both directory rows, and NIT-3'smakefile/row.The new file's other rows fail on main for these reasons:
AGENTS-shape.mdandREADME.mdlack the sentences;_make_reads_first: main has no such helper;CONTRACTS_DIRline: "only onceGNUmakefiledoes";python3, and NIT-2's old tail;The one new row that passes on main is NIT-4's. It sends
GNUmakefile/to the code leg, and there main's NEXT is alreadymake bootstrap. It guards what main has: under the review's mutant X6, which hands NEXT every leg's paths, it is the row that fails.The 19 rows of #1121's file that fail on main are exactly the rows that use the three pins this merge moved (
OWN_MAKEFILE_NOTE,RUNS,script_aside). The 21 that pass use none of them.Earlier heads, on main
961640c68and with the same method:1c7ca5c6dfailed 29 of 35 rows, and8b499842ffailed 34 of 35 (the new file plus the threetests/test_adopt_e2e.pyrows the mutants use).Mutants
This round, at
75c90b6db, in a scratch worktree. Each mutant was applied alone and restored, and each file's sha256 was checked against the commit (4/4 every time). Each ran against 95 rows: the new file (35),tests/test_adopt_e2e.py(27) andtests/test_adopt_make_reads_first.py(33). Unmutated, all 95 pass.make bootstrapafter the merge (if stops and makefile)cmd_executepasses every leg's pathsMakefile, no merge namedMakefilewas keptmake park/make resumesentence removedThe merge with #1121 rewrote the clause code that N1-N3 mutate (
stoppedbecamereads, and the merge condition gainedstops). The mutants were not run again at6fa1edd56.Earlier, 18 mutants at
1c7ca5c6dagainst 43 rows, each applied alone in a scratch worktree and restored with its sha256 checked:_make_reads_firstdrops the/of a directorystops = None)make bootstrapfor a directorycmd_executepassessurviving=()BOOTSTRAP_COMMANDwithout(python on Windows)AGENTS-shape.md's "Work from here" caveat removedREADME.md's sentence removedpython3python3make bootstrapwhere a directory stops makereversed)Makefilefold=True)GNUmakefile: Is a directory.)doeswhateverhasisM18 was equivalent before the merge: the file clause's only caller was the
CONTRACTS_DIRline. Since the merge, #1121's NOTE calls it withhas them, andtests/test_adopt_next_make_reads_first.pypins that wording. M18 was not run again.Runs
Each run went through the lane's runner:
ghstubbed first on PATH with a bogus token,GIT_SSH_COMMAND=false,GIT_CONFIG_GLOBAL=/dev/null,EMAILset,-p no:cacheprovider, andtmp_path_retention_policy=failed. Each run is on a commit, with a clean tree.6fa1edd56, the mergetest_adopt_next_make_reads_first.py,test_adopt_e2e.py,test_adopt_make_reads_first.py,test_path_guard_hygiene.py,test_repo_hygiene.py,test_agents_md_codes.py,test_cli_reference.py,test_pinned_copy_text.py,test_scaffold_leg_path_collisions.py6fa1edd56test_adopt_next_make_reads_first.py(75), thentest_adopt_e2e.py(27), run one after the other6fa1edd5675c90b6dbtest_adopt_e2e.py, the hygiene five (test_path_guard_hygiene.py,test_repo_hygiene.py,test_agents_md_codes.py,test_cli_reference.py,test_pinned_copy_text.py),test_adopt_make_reads_first.py,test_adopt_contracts_dir.py,test_adopt_printed_sentences.py, and the template's readers:test_scaffold_e2e.py,test_scaffold_free_text_values.py,test_free_plan_hint.py,test_template_quoted_values.py,test_template_values_single_pass.py,test_template_text_placeholders.py,test_bootstrap_placement_texts.py,test_park_resume_targets.py,test_update_shape_hardlink.py1c7ca5c6dtest_adopt_e2e.py, the hygiene five,test_scaffold_leg_path_collisions.py,test_adopt_make_reads_first.py,test_adopt_contracts_dir.py,test_adopt_printed_sentences.py,test_adopt_attributes_eol_block.py,test_adopt_leg_path_collisions.py,test_scaffold_e2e.py,test_bootstrap_placement_texts.py,test_park_resume_targets.py,test_template_text_placeholders.py)1c7ca5c6dtest_adopt_e2e.py,test_path_guard_hygiene.py,test_repo_hygiene.py1c7ca5c6dtest_shape_doctor.py,test_scaffold_leg_path_collisions.pyTemplate pins
tests/was grepped for every line this PR changes intemplates/assembly-root/("They are the shape", "reads first holds", "includes a Makefile that", "(above)", "here and below", "Where this root keeps", "it is what the shape", "beforeMakefile", "pythonon Windows"). Onlytests/test_adopt_make_bootstrap_followups.pypins them. Four other files read the README as a whole, and each passes in gate A2:test_scaffold_free_text_values.pycounts its lines against the template;test_free_plan_hint.pylooks for "Free plan" and--repo;test_template_quoted_values.pyandtest_template_values_single_pass.pyrender it.Merges
git merge-tree --write-treeof the head01e93b6d1, on git 2.43.0, at 18:11Z.9729315f1, fetched again at 18:11Z, is the main this round merged last. The merge-tree is clean, and its tree is the head's own,f6488542f.801a7d6d0at 18:14Z, when lane 3's adopt-project.py: under a one-byte locale such as Latin-1,checkreads a plan written in UTF-8 whose source is there, asking the plan's UTF-8 bytes where the spelling as written names nothing, rather than refusingplan-source-gone(#1078) #1106 landed (adopt-project.pyand two locale test files). The merge with it is clean, tree25bc27d39, and gate P4 passed on it. It was not merged in: it touches none of the code this round resolves, and landing refreshes the branch anyway.gh pr list --state open --limit 100 --json number,headRefName,headRefOid,filesread at 18:11Z returned 51 open PRs. 26 of them touch one of this PR's paths. That includestests/test_adopt_collision_make_reads.pyandtests/test_adopt_make_reads_first.py, which this PR now changes. 25 merge cleanly: adopt-project.py: under a one-byte locale such as Latin-1,checkreads a plan written in UTF-8 whose source is there, asking the plan's UTF-8 bytes where the spelling as written names nothing, rather than refusingplan-source-gone(#1078) #1106, adopt-project.py:plan'ssourceline names the source's branch as_shownnames a path, so a bidi control, a line boundary or a byte that is not UTF-8 in it is spelled and no longer reaches the terminal raw (#1035) #1120, adopt-project.py: anorg/repo--sourcetoo long for the disk is refused as a path is, naming no GitHub repository and offering no url, so--source <300 a's>/Thingis no longer offeredhttps://github.com/<300 a's>/Thing, which can never clone (#1003) #1122, adopt-project.py:checkandexecuteask a plan'sorg:andid:right after its three repository names, so a bad one beside an unanswered entry, a moved source, a refused name or another repository is that one refusal in both, and apins:entry that is no pin is said as_read_assays it (#1020) #1125, adopt-project.py: a recorded source whose.gitthis user cannot read is refusedsource-unreadable, naming that.git, socheckandexecuteno longer call a cloneplanmade with its.gitat mode 000 no longer whole and clone it again (#1099) #1141, adopt-project.py: a--work-dirlink into a loop that Python 3.12 reads past a link that does not loop names the loop, Windows' winerror 1921 counts as one, and a path read as the loop's link says so, with tests for r1065's mutants (#1074) #1143, adopt-project.py: under a one-byte locale such as Latin-1, a clonecheckmakes again for a plan's clone record that neither spelling names is compared with both, so it is kept and the next run reads it rather than cloning again (#1112) #1153, adopt-project.py:plan written toandcloning <repository> (read only) intoname the caller's--outand--work-dirwith_shown, as the other lines of the report name a path, so a bidi control, a line feed or a tab in either no longer reaches the terminal as it was typed (#1115) #1154, adopt-project.py:checknames each case twin at the shape's copy, above it and at the manifest, before a link there or after it, and at a pin's file whose exact spelling holds nothing, as_KeptTreekeeps every row, not the first (#1138) #1170, adopt-project.py and repo_shape.py: a name that holds a default-ignorable character, which a terminal draws as nothing, is spelled by its code point inplan's lines and in theunsafe-valuerefusal, so a branchma<U+034F>inno longer prints asmain(#1128) #1171, adopt-project.py: the--planpath incheckandexecute, and the--local-remote-dirpath inexecute'sbare, leg andsplitlines, are named with_shown, as #1154 names--outand--work-dir, so a bidi control, an escape, a line feed or a byte that is not UTF-8 in either no longer reaches the terminal as it was typed (#1152) #1177, adopt-project.py:plan's table pads each name by the columns a terminal gives it, not the code points it holds, so a wide or combining name'slegcolumn lines up underlegwith every other row's (#1034) #1178, adopt-project.py: a--source, or a plan'ssource.local_path, with a part of its repository git reads at mode 000 (the.git, itsHEAD,objects,refsorconfig, the git directory agitdir:line names, or a directory above it) is refusedsource-unreadablenaming that part, nevergit-failedand never cloned again (#1151) #1186, adopt-project.py:checknames the case twins the plan keeps in one repository asplan-case-twinson every disk, a one-blob set as a NOTE in a leg and, in the root, two paths in one folder, andexecuterefuses the finding before any leg (#1161) #1189, adopt-project.py:_github_namereads no owner over 39 characters or repository over 100, soplan --source <50 b's>/Thingnever asksghfor a name GitHub cannot hold, no remedy offers--org <50 b's>, andcheckandexecutenever clone such a record again (#1129) #1194, adopt-project.py:_pin_row_problemsays a pin field whose value is not text as_read_assays what the plan's reader read, "recordscommit:as the number 7", where it spelled it as Python does,commit: 7andTrue, socheckandexecutename it in the words the plan's other refusals use under the sameplan-pin-malformed(#1114) #1198, adopt-project.py:checkandexecuteread one list of a plan's problems against its source, in the order a person mends them (another repository, a refused name, a moved source, an unanswered entry), socheck's first finding isexecute's refusal for each pair (#1113) #1210, adopt-project.py: a refused command's REFUSED block spells each character a terminal acts on in the command, its directory and what it printed, as_first_saidspells gh's, so--local-remote-dirno longer reaches the terminal raw there; a NOTE beforeNEXT:says when the source's path in its clone command holds a character a terminal does not show as itself; and rows pin six sites #1177's 148 left to chance (#1195) #1225, shape_materialize.py: the docstring ofgives_a_branch_another_namesays a full name that is no pattern takes the one ref git completes it to, which may be a branch, where it said any other source names no branch (#1238) #1244, repo_shape.py and adopt-project.py: a plain integer of more digits than this Python reads, or a decimal too large to be finite, isyaml-unparsableby its line, where it was aValueErrortraceback or "the number inf", and_read_assays a float in digits with no exponent, where it said "the number 1e+300" (#1212) #1249, adopt-project.py:executeunsets the leg clone'sremote.origin.urlbeforegit filter-repo, so under a Latin-1 locale a source under a directory named with the byte 0xE9 is extracted, where filter-repo died printing that url as U+FFFD, and every branch of the source is still rewritten as before (#1247) #1251, adopt-project.py: a source whoserefsthis user cannot list is refusedsource-unreadablenaming the directory, neversource-default-branch-not-local"(its branches: none)" (#1219) #1252, adopt-project.py:check's compare for the mount'sgit rmskips the.gitattributesit leaves and reads its exit code, so the root's failing filter isplan-attributes-reencodedalone, and a refused compare is named in git's words (#1192) #1253, adopt-project.py: a stale split branch in a source refs directory this user cannot list is refusedsource-unreadableby name, neverplan okfromcheckor two legs made byexecute(#1257) #1265 and adopt-project.py: each cloneexecutemakes names its remoteorigin, whateverclone.defaultRemoteNamesays, soexecuteno longer ends inREFUSED mounting the legs("No such remote 'origin'") after both legs are pushed (#1261) #1268. adopt-project.py: under a one-byte locale such as Latin-1,checkreads a plan written in UTF-8 whose source is there, asking the plan's UTF-8 bytes where the spelling as written names nothing, rather than refusingplan-source-gone(#1078) #1106 has landed since (above).checknames the case twins the plan keeps in one repository asplan-case-twinson every disk, a one-blob set as a NOTE in a leg and, in the root, two paths in one folder, andexecuterefuses the finding before any leg (#1161) #1189 (472944b5d, read fresh at 18:11Z) edits three test files that this round changes too:tests/test_adopt_next_make_reads_first.py,tests/test_adopt_collision_make_reads.pyandtests/test_adopt_make_reads_first.py. The merge is clean, tree7fd030b29. adopt-project.py:checknames the case twins the plan keeps in one repository asplan-case-twinson every disk, a one-blob set as a NOTE in a leg and, in the root, two paths in one folder, andexecuterefuses the finding before any leg (#1161) #1189's hunks are in the imports, in the clone rows' parameter lists and docstrings, and in a new refusal row, away from the moved pins, themakefile-directoryrow and NIT-A's comment. On that predicted merge, a local commit object, the three shared files pass on git 2.43.0:tests/test_adopt_make_reads_first.pyandtests/test_adopt_collision_make_reads.pygive 62 passed, andtests/test_adopt_next_make_reads_first.pygives 38 passed. There are fewer rows than at this head because adopt-project.py:checknames the case twins the plan keeps in one repository asplan-case-twinson every disk, a one-blob set as a NOTE in a leg and, in the root, two paths in one folder, andexecuterefuses the finding before any leg (#1161) #1189 leaves out the clone rows that keep case twins.git rm -fand writes the twins the root keeps back from the index, so on a disk that ignores caseexecutekeeps a set the plan splits across repositories or drops (#1183) #1237 (b557859fd) conflicts intests/test_adopt_check_throwaway_repos.py, a file this PR does not change. Main conflicts with adopt-project.py: the mount removes a path a case twin is at or under withgit rm -fand writes the twins the root keeps back from the index, so on a disk that ignores caseexecutekeeps a set the plan splits across repositories or drops (#1183) #1237 in that file too, while6fa1edd56did not, so the conflict is main's, carried in by the merge.--work-dirlink into a loop that Python 3.12 reads past a link that does not loop names the loop, Windows' winerror 1921 counts as one, and a path read as the loop's link says so, with tests for r1065's mutants (#1074) #1143 landed as81eaf757c(adopt-project.py) and lane 4's family.py: theremovethat bothmember-duplicate-idremedies name and theaddthatbump'smember-unknownnames carry--family-root <holder>, quoted for the host, so each runs as printed (#1005) #1117 as9252ef208(README, the handbook andscripts/family.py). The head merges clean with both (treese40373967and279f8c6ce), and rv1207e's gate P passed on the predicted merge with9252ef208(359 passed). At 19:22Z, 48 PRs were open, 24 touch this PR's files, and 23 merge clean; adopt-project.py: the mount removes a path a case twin is at or under withgit rm -fand writes the twins the root keeps back from the index, so on a disk that ignores caseexecutekeeps a set the plan splits across repositories or drops (#1183) #1237's conflict is main's, as above.GNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105, adopt-project.py:execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121, adopt-project.py, shape_materialize.py and tests: a named bad link left out of the copy and pin findings takes no other path's finding with it, and the docstrings and the materializer's refusal name the #979 exception and what helps it (#1089) #1118 and README.md, adopt-project.py and the handbook: a kept directory entrymakefile/is tested, README saysmakeat the root reads a keptGNUmakefileormakefileinstead, and a docstring says the shape's Makefile alone holdsCONTRACTS_DIR(#1061) #1123 are on main. Since6fa1edd56, shape_materialize.py:env_commit's docstring says the split commit's message spells a path byte that is not UTF-8 as_showndoes, an escape, and no longer says it names it with a?in its place, which #900 replaced (#1018) #1104, scripts/shape_materialize.py:adopt_makefile_block's docstring says the block lands whereplacewrites the shape'sMakefile, the root's orshape/Makefilewhere the source keeps one, not the root's alone (#1135) #1160, adopt-project.py:check's rehearsal and_stored_as_writtentake a parent's-csettings,attr.treetoo, and the source's objects,GIT_ATTR_SOURCEis refused by name before any question, and each throwaway reads its environment first (#1136) #1169, adopt-project.py:checkandexecuterun withGIT_NO_LAZY_FETCH=1and refuse a partial-clone source that lacks an object its branches, tags or HEAD reach assource-partial-clone, so neither fetches into the source any more (#1145) #1180, adopt-project.py:planruns withGIT_NO_LAZY_FETCH=1, refuses a partial-clone--sourcethat lacks objects assource-partial-clone, and names a partial--pin-sourceit could read only by fetching and the fetch that makes it whole (#1162) #1190 and scaffold-project.py: a partial-clone--pin-sourceshort of the pinned commit or its trees ispin-source-unreadable, named a partial clone withgit fetch --refetch --no-filter <remote> <commit>, and no longer fetched into (#1182) #1223 landed too.Landing order
The conflicts are the same in every order, measured offline both ways round and with predicted squashes:
execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121: 4 hunks, 84 lines, inadopt-project.py's_next_stepsandcmd_execute's comment.GNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105: 3 hunks, 65 lines, inscripts/shape_materialize.py'scollision_follow_up: its docstring's NIT-4 sentence, its paragraph on the Makefile's merge, and its tworeturns.execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121 and shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105 merge with each other cleanly, and so do shape_materialize.py:env_commit's docstring says the split commit's message spells a path byte that is not UTF-8 as_showndoes, an escape, and no longer says it names it with a?in its place, which #900 replaced (#1018) #1104 and this PR.So the order decides only who resolves them. Both have landed, and lane 5 resolved both on this branch:
execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121 (merge6fa1edd56). The resolution is one lookup and one clause,BOOTSTRAP_COMMANDin adopt-project.py:execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121's NOTEs, and adopt-project.py:execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121's three test pins moved.GNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105 (merge7b0192bde, see "Main merge after shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105"). The resolution keeps shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105'sreads_firstbranch and runsBOOTSTRAP_COMMANDthrough it. NIT-2's tail is this PR's wheremakereads the mergedMakefile, and shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105's wheremakereads another file. Four of shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105's test pins moved:MERGE_IS_ENOUGH,BOTH_MERGES,MEANWHILEandSCRIPT_MERGED.Main was merged in once more after lane 1's #1123 (merge
01e93b6d1): one of #1123's rows pinned the line this PR changes for a keptmakefile/directory, and it moved (see "The second merge, after #1123").No other PR has to land first now.
6fa1edd56was re-checked READY (rv1207b, rv1207c and rv1207d, issuecomment-6722602375). The head,01e93b6d1, needs a check of its delta since then: the two merges' resolutions, the four moved pins in #1105's file, #1123's moved row, and NIT-A.Left
#1240 tracks what this PR leaves:
make bootstrapin the template, a keptGNUmakefile/directory,python3on Windows,GNU_MAKE_READStwice, stale follow-ups) #1132's item 4 (oneGNU_MAKE_READS, one lookup);GNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105's collision line, for a kept directory (itspython3part is done here: see "Main merge after shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105");execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121's file NOTE beside a keptMakefile, which does not name the merge (as this PR's directory NOTE now does);GNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105's second review's NIT-1, NIT-3b, NIT-3c, NIT-4 and NIT-5;_make_reads_first_clause'shasargument, now live;scripts/shape_materialize.pyabout :1067), kept from shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105, is no longer true, since this PR changes the line with noreads_first. It sits beside adopt-project.py, shape_materialize.py and the assembly-root template: after #1121 and #1105, oneGNU_MAKE_READSand one lookup, their NEXT NOTE and collision line as true as #1207's, and the NITs 1, 3b, 3c, 4 and 5 of #1105's second review #1240's items F and G, which reword the same docstring.The local branch
fix/1132-template-bootstrap-stacked(9eb5cce0b, never pushed and never tested) is a model of the end state on #1105 + #1121 + main.For the squash message at landing
1c7ca5c6d, says "Left, as adopt-project.py and the assembly-root template: follow-ups from RV1105's and RV1121's reviews of #1105 and #1121 (make bootstrapin the template, a keptGNUmakefile/directory,python3on Windows,GNU_MAKE_READStwice, stale follow-ups) #1132's body names". It is this PR's body that names them, and they are now adopt-project.py, shape_materialize.py and the assembly-root template: after #1121 and #1105, oneGNU_MAKE_READSand one lookup, their NEXT NOTE and collision line as true as #1207's, and the NITs 1, 3b, 3c, 4 and 5 of #1105's second review #1240. The squash message should say "Left: adopt-project.py, shape_materialize.py and the assembly-root template: after #1121 and #1105, oneGNU_MAKE_READSand one lookup, their NEXT NOTE and collision line as true as #1207's, and the NITs 1, 3b, 3c, 4 and 5 of #1105's second review #1240".BOOTSTRAP_COMMAND). GNU make's order is still in two tuples once shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105 lands, which is item 4, left to adopt-project.py, shape_materialize.py and the assembly-root template: after #1121 and #1105, oneGNU_MAKE_READSand one lookup, their NEXT NOTE and collision line as true as #1207's, and the NITs 1, 3b, 3c, 4 and 5 of #1105's second review #1240. The squash message should not say "centralize" of it.execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121 was merged in, and thattests/test_adopt_next_make_reads_first.py's three pins moved topythonon Windows.GNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105 and after README.md, adopt-project.py and the handbook: a kept directory entrymakefile/is tested, README saysmakeat the root reads a keptGNUmakefileormakefileinstead, and a docstring says the shape's Makefile alone holdsCONTRACTS_DIR(#1061) #1123, thatcollision_follow_upkeeps shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105'sreads_firstlines withBOOTSTRAP_COMMANDin them, that four pins intests/test_adopt_collision_make_reads.pymoved with them, and that README.md, adopt-project.py and the handbook: a kept directory entrymakefile/is tested, README saysmakeat the root reads a keptGNUmakefileormakefileinstead, and a docstring says the shape's Makefile alone holdsCONTRACTS_DIR(#1061) #1123'smakefile-directoryrow now expects the line that says GNU make stops at a keptmakefile/.Limits
planwrites its follow-ups once, so after a hand edit of the plancheckand the split commit name aGNUmakefilethe root no longer keeps, or say nothing of one it now keeps #1206. It also holds the three related cases this work found:makefile/directory gets "until the two are merged";_root_keeps;Makefile/directory is treated as a Makefile.answered-rootrow meets item 5 too.planasks aboutGNUmakefile/, and its storedCONTRACTS_DIRline, written before the answer, names no directory. The row asserts what NEXT andmakedo there, and not that line.Closes #1132
Lane: openreposhape-5 (openRepoShape-5)
🤖 Generated with Claude Code
Summary by Sourcery
Clarify bootstrap and GNU make behavior across assembly-root templates and adoption workflows, including kept GNUmakefile/makefile directories and Windows command guidance.
New Features:
Bug Fixes:
Enhancements:
Documentation:
Tests: