Repository navigation
adopt-project.py: answered_paths: also records each entry a leg's own walk puts elsewhere, so a directory split by hand out of an extension-majority fold no longer reads MISPLACED on the doctor's first run after adoption verified (#801) - #829
Conversation
…ject.py: `answered_path_record` also walks each leg's own files, so a directory split by hand no longer reads MISPLACED on the doctor's first run (#801) Checkpoint commit, ordered by the lane-1 coordinator. The fix in `answered_path_record` (new helper `_walked_in_each_leg`) and the new tests/test_answered_paths_per_leg.py. On the bytes before the last edit, 17 new tests plus tests/test_doctor_plan_overrides.py and tests/test_doctor_recorded_answers.py ran 67 passed, 1 failed; the one failure was the new end-to-end test's expected order of the doctor's `answered_paths` entries (spec leg first), swapped in this commit and not re-run. The two-mode runs, the revert table and the PR texts are still to do. Lane: openreposhape-1 (openRepoShape-1) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openreposhape-1 (openRepoShape-1) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wn walk puts elsewhere, so a directory split by hand out of an extension-majority fold no longer reads MISPLACED on the doctor's first run after `adoption verified` (#801) `engine/` holding `a.py`, `b.py`, `c.py` and `x.md` is 3 of 4 `.py`, exactly the 75% `extension_majority:`, so `plan` proposes it as code. Split by hand, `engine/c.py` to spec and the rest to code, the plan passed `check` and `execute` said `adoption verified`. The doctor's first run then said `MISPLACED (1 path)` for `code/engine/x.md`: `answered_path_record` walked the whole source, where `engine/` folds, and the doctor walks the code leg, where it is 2 of 3 and each file is read by its own extension. Now `answered_path_record` also walks each leg's own files (`_walked_in_each_leg`), as the doctor walks the leg, and records each entry kept in a leg that covers a path that walk puts elsewhere or asks about. The whole-source rule stays as it was, so every row main writes is still written. The doctor, `scripts/repo_shape.py` and the comment `execute` writes above the block are unchanged. A plan left as `plan` wrote it gets main's record, byte for byte. The same change also covers `engine/c.py` dropped or kept in the root, a directory the majority groups to spec, a nested split, and a question left over (a `note`, not `ok`, on main). tests/test_answered_paths_per_leg.py is new, with 17 tests: 12 fail on main, and 5 are controls main passes. Lane: openreposhape-1 (openRepoShape-1) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… walk can also dispute a file left as `plan` wrote it, where answers against their extensions fold its directory in that leg, and the tests hold that case too (#801) A probe found one more way in, fixed by the same change. `plan` lists `stuff/`'s files one by one (2 `.py`, 3 `.md`, which do not fold). `stuff/b.py` is answered spec, the three `.md` code against their extension, and `stuff/a.py` is left as `plan` wrote it. Then the code leg's `stuff/` is 3 of 4 `.md` and folds to spec. On main 24a977c, `adoption verified` was followed by the doctor's `MISPLACED (1 path)`: `code/stuff/`. With this branch, `stuff/a.py` is recorded too, and the doctor reads COMPLIANT with the row `ok`. The docstring claimed that an entry `plan` wrote reads the same in its leg, which this case disproves. It now says a row is added only where the doctor's walk of that leg disputes the path, and that a plan left as `plan` wrote it, over a source with no gitlink, gets none. The new test file gains the case, as a unit row and an end-to-end adoption. Its plan edit now replaces every entry `plan` listed under a directory. Lane: openreposhape-1 (openRepoShape-1) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewer's GuideUpdates Sequence diagram for per-leg answered path recordingsequenceDiagram
participant Execute
participant AnsweredPathRecord as answered_path_record
participant WalkEachLeg as _walked_in_each_leg
participant Walk as walk
participant Doctor
Execute->>AnsweredPathRecord: answered_path_record(policy, entries, tree, commit)
AnsweredPathRecord->>WalkEachLeg: _walked_in_each_leg(policy, files, answered)
loop Each extracted leg
WalkEachLeg->>Walk: walk(policy, held)
Walk-->>WalkEachLeg: paths assigned by the leg's own walk
end
WalkEachLeg-->>AnsweredPathRecord: path to walked leg or None
AnsweredPathRecord->>AnsweredPathRecord: add rows where leg differs from own walk
AnsweredPathRecord-->>Execute: answered_paths block
Doctor->>Doctor: walk each leg independently
Doctor-->>Doctor: read recorded rows as placement answers
Flow diagram for hand-split directory placement recordsflowchart LR
SourceWalk["Whole-source walk folds engine/ to code"] --> Split["Plan entry is hand-split"]
Split --> SpecLeg["spec leg keeps engine/c.py"]
Split --> CodeLeg["code leg keeps engine/a.py, b.py, x.md"]
CodeLeg --> OwnWalk["Code leg's own walk does not fold engine/"]
OwnWalk --> Dispute["x.md is disputed as spec"]
Dispute --> Record["answered_paths records engine/x.md"]
Record --> Compliant["Doctor's first run is COMPLIANT"]
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
(lane openRepoShape-1, 2026-10-17T19:10:29Z) Lane 1's independent review of #829 at 742fc2f: PR-READY I reviewed the head No defect blocks this PR. Finding 1 is a known limit that was already on main; finding 2 is one sentence of the body. The issue's line
L1-83 is fixed. I also measured each row of the body's "Why" table on main and on the merge, and each is as stated:
Attack 1: does the per-leg walk walk what the doctor walks? Three more ways in, none of them in the tests, all MISPLACED on main and COMPLIANT
By reading the code:
Model check. I generated random sources and random hand-edited plans, and simulated the doctor per leg with its own
In every plan, the merge's rows were a superset of main's (an assert, never tripped). Attack 2: an unsplit plan stays byte-identical. I ran three ordinary sources on main, then on the merge, at the same paths with fixed dates:
For all three, Attack 3: other readers of the record. Attack 4: cost. I timed
In the last row, main's existing O(files × entries) Findings, ranked1. Not this PR's defect, confirmed and widened: any name the doctor sets aside, not only a tab, still yields MISPLACED after
|
| Name | main | merge |
|---|---|---|
t\tb.py |
plan ok, verified, MISPLACED (1 path): code/engine/x.md spec extension-majority |
same |
t\x01b.py |
— | same |
t\xffb.py (not UTF-8) |
— | same |
I appended answered_paths: - path: "engine/" leg: code to the merge clone's project.yaml by hand. The doctor then exits 0, verdict COMPLIANT, placement note, saying "1 name(s) no report or plan can carry: 'engine/t\tb.py'".
So the follow-up fix is a filter in _walked_in_each_leg that drops those names, as the doctor does. It would add a row to a plan left as written for such a source, which the issue's byte-identity rule rules out here. That makes it a separate v1.1.x issue, as the writer judged. The body and docstring already say this honestly.
2. Text: one sentence of "How" overclaims
"That is exactly where main's doctor reads the path as MISPLACED or as a question" contradicts the body's own Known limit 2. The model check measured 42 added rows under .github/ that the doctor never reads; they are harmless. The replacement text is below.
Tests
I re-ran the revert table in clones of the head, over the new file and both #655 files (70 tests):
| Row | Result |
|---|---|
| R1: the per-leg clause reverted | 14 failed, 56 passed: exactly the 14 non-control tests |
| R2: each leg walked over the whole source | 15 failed, 55 passed: the same 14 plus test_doctor_plan_overrides.py::test_an_entry_left_as_plan_wrote_it_is_no_answer_against_a_rule |
R3 (mine): a question in a leg's walk read as agreement (in_its_leg.get(path) not in (None, leg)) |
2 failed, 68 passed: both a-question-left-over cases |
The counts match the body: 19 tests, 14 that fail on main, 5 controls. The asserts are honest: whole row lists, the doctor's verdict, the row status and answered_by.
My gate at the merge 62fb90a1, dirty 0, git-filter-repo on PATH:
- the new file, both adopt-project.py and shape-doctor.py: a plan answer that overrides a confident rule passes
checkandexecute, then the doctor's first run says MISPLACED, and an emptied.gitmodulesis asked on every run #655 files,test_scaffold_leg_path_collisions.pyandtest_cli_reference.py: 197 passed,EXIT=0; test_shape_doctor.py: 436 passed, 3 skipped, 1 xfailed,EXIT=0.
Windows. The change has no os.name path. The test paths are legal on NTFS, files are read back with read_text(), and tests-git-bash is green.
CI at the head. tests, tests-git-bash, package and SonarCloud all pass. SonarCloud reports 0 new issues and 0.0% duplication on new code. The only annotations are runner notices (Node 20 deprecation, the ubuntu-latest migration).
Texts. The title is true at the head. The body has the Lane line, a Claim line that matches the claim register (issuecomment-6233022004), Closes #801 and the robot line, in 10,263 characters. Sourcery appended its own summary after the robot line, which is the bot's doing, not the writer's.
Exact text replacements
Body, "How", replace:
- A row is added only where the doctor's walk of that leg disputes the path. That is exactly where main's doctor reads the path as MISPLACED or as a question on its first run.
with:
- A row is added only where that leg's own walk disputes the path. Outside
.github/and the names under Known limits, which the doctor sets aside, that is where main's doctor reads the path as MISPLACED or as a question on its first run.
Optional, in the docstring, at the next commit only: "A row is added only where the doctor's walk of that leg disputes the path." → "A row is added only where this walk of the leg disputes the path; outside what the doctor sets aside (below), that is where the doctor's walk does."
For the checklist (#457)
- Set-aside names in a folded directory (finding 1): a tab, any control character or a byte that is not UTF-8 gives MISPLACED after
adoption verified, with a plan left as written, on main and on this branch. The fix is to dropUNWRITABLE_IN_A_PLANnames in_walked_in_each_leg, which gives COMPLIANT with placementnote. It changes that source'sproject.yaml, so it needs its own issue. .github/split by hand: a row the doctor never reads. This is measured (42 rows in 33 of 4,000 plans) and harmless.- A directory row nobody wrote. An entry left as
planwrote it can be recorded when answers beside it fold its parent in the leg (stuff/a.py). If that entry is a directory, its row then answers every file added under it later, as any directory row does (adopt-project.py: record the plan's answers in project.yaml, so the doctor'splacementrow and thesubmodules:rows follow them #525). I found this by reading the code and did not run it end to end. - Cost on main:
_answered_legsis O(files × entries). A 5,000-file plan split file by file takes 2.2 s inanswered_path_recordon main.
The body replacement above is applied (the PR body is edited; no push).
Lane: openreposhape-1 (openRepoShape-1)
|
|
Sorry @brettheap, you've used your own review budget of 250,000 diff characters for the last 7 days. You can request another review in 2 hours and 15 minutes by commenting |



Lane: openreposhape-1 (openRepoShape-1)
Claim: #801 (comment)
A v1.1.1 draft. It lands only after the v1.1.0 tag, in the order lane 3 posts.
What
executenow records each plan entry kept in a leg that covers a path the doctor's walk of THAT leg would dispute. Before, it recorded only what a walk of the whole source disputed, so a directory split by hand could passadoption verifiedand then read MISPLACED on the doctor's first run.answered_path_recordalso walks each leg's own files, as the doctor walks the leg after the split (_walked_in_each_leg).placementrow and thesubmodules:rows follow them #525 and adopt-project.py and shape-doctor.py: a plan answer that overrides a confident rule passescheckandexecute, then the doctor's first run says MISPLACED, and an emptied.gitmodulesis asked on every run #655 is unchanged.planwrote it gets main's record, byte for byte.scripts/repo_shape.py, and the commentexecutewrites above the block are unchanged.Why (repro on main)
Measured on main
bf1f099b, and again on24a977c0, with git-filter-repo a40bce548d2c, a stubghandexecute --local-remote-dir.#801's line (L1-83). The source's
engine/holdsa.py,b.py,c.pyandx.md. That is 3 of 4.py, exactly the policy'sextension_majority: 0.75, soplanproposesengine/as code. The person splits that entry by hand:engine/c.pyto spec, anda.py,b.pyandx.mdto code, each with aresolution:.checksaysplan ok.executeexits 0 withadoption verified.shape-doctor.py --root <clone> --jsonexits 1 withMISPLACED (1 path):code/engine/x.md: spec by rule extension-majority.answered_paths:holds onlyengine/c.py.The cause:
answered_path_recordwalked the whole source, whereengine/folds to code, sox.mdneeded no row. The doctor walks the code leg, whereengine/is 2 of 3.py(67%). That does not fold, so it reads each file by its own extension, andx.mdis spec.Other ways to the same disagreement, each probed the same way, and each fixed by this change:
engine/c.pyanswereddropcode/engine/x.md(bf1f099b)engine/c.pyansweredrootcode/engine/x.md(bf1f099b)notes/(3 of 4.md, so spec),notes/c.mdmoved to codespec/notes/y.py(bf1f099b)engine/notes/x.mdunder the foldedengine/,engine/c.pyto spec,engine/notes/kept in codecode/engine/notes/(24a977c0)engine/q.zzz)note(a question), notok(bf1f099b)stuff/(2.py, 3.md, no fold) listed file by file,stuff/b.pyanswered spec, the three.mdanswered code against their extension,stuff/a.pyleft asplanwrote it. The code leg'sstuff/is 3 of 4.mdand folds to spec, overa.pytoocode/stuff/(24a977c0)Two controls read COMPLIANT with the row
okon main, and still do:engine/d.pyadded);engine/left asplanwrote it.How
All of it is in
adopt-project.py'sanswered_path_record._walked_in_each_leg(new). For spec and for code, it walks the files_answered_legskeeps in that leg, gitlinks left out as before. It returns, for each such path, the leg that walk gives it: its own entry's, or the folded directory's above it, read by the existing_walked_leg. A question is None..gitmodules) is recorded when that leg's own walk does not put a path it covers in that leg, OR by the existing rule against the whole source's walk and whatplanshowed (adopt-project.py and shape-doctor.py: a plan answer that overrides a confident rule passescheckandexecute, then the doctor's first run says MISPLACED, and an emptied.gitmodulesis asked on every run #655's F1). The rows are keyed by entry, as before, so an entry is written once..github/and the names under Known limits, which the doctor sets aside, that is where main's doctor reads the path as MISPLACED or as a question on its first run.planwrote it, over a source with no gitlink, gains no row.planwrote is a walk entry, kept whole in the legplangave it.stuff/case shows. The rows they get are the ones the doctor needs.everywhere_patterns: names at the top of a leg, and.github/) change how no other directory folds.Tests
tests/test_answered_paths_per_leg.pyis new, with 19 tests. 14 fail on main, and 5 are controls that main passes.answered_path_recordrecordsengine/x.md: the issue's split recordsengine/c.py(spec) andengine/x.md(code), each with the plan'sresolution:and commit.drop,root, a spec-majority split, a nested split (the row is the directory's,engine/notes/), a question left over, andstuff/'s answers that fold a file left as written (stuff/a.pyrecorded).engine/c.pyalone, as main writes;engine/left whole, which gives no row.engine/kept whole beside a question answered (examples/) and an answer against a rule (docs/, adopt-project.py and shape-doctor.py: a plan answer that overrides a confident rule passescheckandexecute, then the doctor's first run says MISPLACED, and an emptied.gitmodulesis asked on every run #655) gives exactly main's block: the comment and those two rows.engine/alone gives"".test_an_adoption_answered_against_a_rule_is_compliant_on_first_run.project.yamlrecords both rows, and the doctor's first run reads COMPLIANT with the rowok,spec/engine/andcode/engine/x.mdeach answered by its row.drop, the spec-majority split, the nested split, the question left over,stuff/, and both controls: each reads COMPLIANT with the rowok. Each manifest holds exactly the rows its legs need, and noanswered_paths:key at all where none is needed.checkandexecute, then the doctor's first run says MISPLACED, and an emptied.gitmodulesis asked on every run #655's tests still pass: tests/test_doctor_plan_overrides.py and tests/test_doctor_recorded_answers.py, unchanged.Byte-identity of an unsplit plan, measured by hand on the merged tree. One plan was run by main
24a977c0and by this branch, at the same paths with fixed commit dates:engine/left whole,examples/answered spec,docs/answered code. Each split'sproject.yamlis 9,715 bytes. They differ only in theshape:pin, the commit of the standard that ran and its tree digest. With those two values normalised,cmpexits 0. Both trees'answered_path_recordon that plan give the same 1,079 bytes.Revert table. Each row ran in its own clone of the head
742fc2f1, over the new file and both #655 files (70 tests):keptis main's ruletest_an_entry_left_as_plan_wrote_it_is_no_answer_against_a_rule: 15 failed, 55 passed. Walking each leg's OWN files is what keeps #655's F1Runs, on the head
742fc2f1(main24a977c0merged in), in two modes with/usr/bin/python3 -m pytestand a stubgh. The 98 files are thosegrep -l -E 'adopt-project|adopt_project|\bADOPT\b' tests/*.pynames (lessconftest.py), plus tests/test_shape_doctor.py, tests/test_scaffold_leg_path_collisions.py, tests/test_cli_reference.py, the two #655 files and the new one:742fc2f1, dirty 0, and endsEXIT=0.PATH=<stub gh>:/usr/local/bin:/usr/bin:/bin): 6,515 passed, 402 skipped, 1 xfailed. Every log names the same head, dirty 0, and endsEXIT=0.Windows
CI is Linux only (#597). The new tests read every file back with
read_text()and name only paths legal on NTFS.Not in this PR
shape-doctor.py) andscripts/repo_shape.py: unchanged, as the issue's direction says.executewrites aboveanswered_paths:: unchanged, so a plan left as written keeps its bytes. It already says a row answers a path the policy called for another leg.Known limits
engine/holdinga.py,b.py,x.mdandt<TAB>b.pyfolds to code (3 of 4) forplanandexecute. The doctor sees 2 of 3 in the code leg and readscode/engine/x.mdas MISPLACED.planwrote it, on main and on this branch. Its cause is the doctor's set-aside, not a split, so it goes to Tracking: adopt-project.py, converting an existing repository in place #457's checklist and is not fixed here..github/split by hand can get a row the doctor never reads. The doctor sets.github/aside in every leg. The row is harmless: it answers nothing the doctor asks.Closes #801
🤖 Generated with Claude Code
Summary by Sourcery
Make answered-path recording account for each extracted leg’s own walk so manually split adoptions remain compliant on their first doctor run.
Bug Fixes:
Tests: