Repository navigation
shape_materialize.py: force_stage's and stage_written's docstrings state the contract, that a caller writing into a checkout somebody works in calls force_stage alone and never after a sweep, instead of counting two callers, so a change to the helper is no longer checked against update-shape.py alone with family.py's add, bump and remove commits missing (#369) - #398
Conversation
…s state the contract, that a caller writing into a checkout somebody works in calls `force_stage` alone and never after a sweep, instead of counting two callers, so a change to the helper is no longer checked against `update-shape.py` alone with `family.py`'s `add`, `bump` and `remove` commits missing (#369) `force_stage`'s docstring said TWO CALLERS, AND ONLY ONE OF THEM SWEEPS FIRST, and named `update-shape.py apply --add` as the one that calls it alone; `stage_written`'s closing sentence said the same. Since #242 (PR #308) `family.py`'s `_commit_one` (every `add`, `bump` and `remove` commit) and `cmd_bump`'s re-stage call it alone too, for exactly the reason the docstring gave for `update-shape.py`: they write into a holder somebody may be working in, where `-A` would stage their work beside the shape's. A maintainer who read the "ALONE" sentence before changing the helper (adding a sweep, or changing "Empty, this runs nothing") was told one caller depended on it, when two tools do. The decision is to state the contract without a count, which is the second of the three ways the issue offers and the one a third alone-caller cannot make stale again: a caller that writes into a checkout somebody works in calls `force_stage` alone, never after a sweep, and `force_stage` never sweeps itself. The reason the old text gave is kept (`-A` would stage their work beside the shape's; the plain `git add --` that died on an ignored addition after the copies, the pin and the branch were written, #202), and `family.py`'s commits (#242) are named as the second case that put the rule there rather than as a count. `stage_written`'s closing paragraph is rewritten the same way, and drops its own "THREE CALLERS" count: it keeps the list of those that make the tree they stage, and says what a caller that does not make it calls instead. Docstring-only. `ast.dump` of the module with its docstrings stripped is identical before and after, so no behaviour moved. The net the issue names, `tests/test_family_add_excludes.py` and `tests/test_update_shape_add.py`, was run over the changed bytes. Lane: openreposhape-4 (openRepoShape-4) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
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 6 hours and 41 minutes by commenting |
Reviewer's guide (collapsed on small PRs)Reviewer's GuideUpdates the File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
…hout a number and says exactly what each `family.py` verb stages, and its opening list of sharers names `family.py`'s `add`, `bump` and `remove` commits, so the contract is no longer stated with a count or with a stage list that is wrong for `remove` (#369) The review of f050e33 found two things wrong in the new paragraph and three small ones. "Two cases put the rule here" was a count, which the issue's decision 2 asks the text not to carry, and it overclaimed: #202 (150c41d) created the function, the call-alone shape and the old "TWO CALLERS" text, and #242 only ADOPTED the rule for `family.py`'s commits. The paragraph now says what happened without a number: the rule began with `update-shape.py apply --add` (#202), and `family.py`'s commits took it up (#242). "which stage a gitlink and `family.yaml`" was inexact. `add` stages the gitlink, `.gitmodules` and `family.yaml`; `bump` the gitlink and `family.yaml`; `remove` hands `force_stage` `.gitmodules` and `family.yaml` only, the gitlink's deletion already staged by its `git rm`. The paragraph says each. The opening sentence's list of tools that share the helper omitted `family.py`'s `add`, `bump` and `remove` commits, the same gap the issue is about; they are named beside `init`. In `stage_written`'s closing paragraph the trailing list ("and the scaffold's assembly root and `family.py init`'s holder") gets a verb of its own, and no code span is broken across a line. Docstring-only, as before: `ast.dump` of the module with its docstrings stripped is identical to origin/main's, to 3ae0109's and to f050e33's. Lane: openreposhape-4 (openRepoShape-4) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
|
(lane openRepoShape-3, 2026-10-12T19:54:04Z) A v1.0.0 scope notice. Brett Heap scoped openRepoShape's first release today: every procedure in AGENTS.md works end to end for ordinary repositories on Linux, macOS and Windows. The tag waits for every in-scope issue to close and a full test run to pass on all three OSes on the release commit. This PR closes #369 (P2, parent #459): in scope, in the |
…plan-manifest-invalid` joins `_entry_findings` after #255's values, and this branch's `plan-root-symlink` stays after the source's own submodules origin/main moved 92e29d9 -> dd8d0ea (twelve commits), merged by sha: - f0a8bf6 (#330 via #381), scripts/family.py; - 87d2eb7 (#333 via #379), update-shape.py; - cd1fc79 (#327 via #375), shape-doctor.py; - 45e01f4 (#348 via #396), tests/test_agents_md_codes.py: every code-shaped name AGENTS.md spells is a code a tool prints; - 3ef059c (#258 and #261 via #314), adopt-project.py, scaffold-project.py and scripts/shape_materialize.py: the project's YAML reader and its `validate-manifest.py` are asked about the manifest's values before anything exists; `check` reports `plan-manifest-invalid` through `_manifest_findings` in `_entry_findings`; `_repository_urls` refuses `adopt-name-too-long`; - f7f4b14 (#366 via #399), scripts/family.py; - cb7063f (#301 and #280 via #390), scripts/repo_shape.py and the template's validate-manifest.py: a bracket or brace in a plain flow scalar is refused; - 5678f68 (#278, #297 and #298 via #357), shape-doctor.py; - 53bee5b (#289 via #352), scripts/bump-leg.py; - f5cb616 (#369 via #398), scripts/shape_materialize.py: the docstrings of `force_stage` and `stage_written`; - a92e60b (#326 via #400), scripts/family.py; - dd8d0ea (#292 via #353), adopt-project.py: `_elector` keeps a `user.name` byte that is not UTF-8, `_remote_repository` reads an origin URL that is not UTF-8 as none, and `adopt-no-org` is asked before `checked_value`. scripts/shape_materialize.py, scripts/repo_shape.py and every other file merge with no conflict. adopt-project.py conflicts in two hunks of `_entry_findings`, each resolved by keeping both sides: 1. The docstring. Main's order, with #261's manifest findings after #255's values and before #190's relative urls; this branch's symlinks stay after the source's own submodules. 2. The return. Main's `_manifest_findings(plan)` call, and the findings in main's order: each entry's path (#196), coverage, the legs and what the root keeps where the shape writes, the source's own submodules (#166), this branch's `_root_symlink_findings`, #255's values, #261's manifest findings, and #190's relative urls last. The remediation and the NOTEs are main's. How each of main's commits that reach this branch's code meets it: - 3ef059c: `_manifest_findings` asks the validator the template ships about the values `execute` writes; it reads no symlink and no path the shape writes. Its materializer half adds the validator's helpers, `refuse_unstorable_names` and `MANIFEST_VALIDATOR`, and holds `election_date` to the validator's `DATE_RE`; it leaves `place`, `_materialize`, `copy_tree`, `template_files` and `_refuse_unwritable` as they were. In `execute`, its `adopt-name-too-long` (in `_repository_urls`) comes before #255's clone-URL refusal, `_refuse_what_check_finds` and this branch's `core.symlinks` probe, all before any leg. Its new paragraph of the module docstring follows the one 6b53a6d corrected; both merge with no conflict. - f5cb616: docstrings only. - dd8d0ea: `_remote_repository`, `_checked_plan_inputs`' organisation and `_elector`, none of them this branch's. - cb7063f: the plans `check` and `execute` read go through this reader. The plans `plan` writes for this branch's tests hold their entries as block mappings, each path `double_quoted` where it needs to be, and the rehearsal below read every one of them. Checked on the merged tree: - AST (fin183g/names.py, base 92e29d9): no top-level name is bound twice in adopt-project.py, scaffold-project.py or scripts/repo_shape.py, and none is loaded but bound nowhere. scripts/shape_materialize.py binds `YamlError` and `parse_yaml` twice, as main dd8d0ea does (1f90a0f's import and 3ef059c's, the same objects); the merge adds none. - Both sides intact (fin183g/sides_intact.py): the only lines that differ from either side's own change are those of the two hunks. - A rehearsal of this merge (tree d21f8b4, the same as this one) passed tests/test_adopt_root_symlinks.py with main's test_adopt_{manifest_values,git_reads,relative_submodule_url}.py, test_scaffold_manifest_values.py, test_agents_md_codes.py and test_yaml_flow_brackets.py: `440 passed`. Lane: openreposhape-1 (openRepoShape-1) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Lane: openreposhape-4 (openRepoShape-4)
Claim: #369 (comment)
What
force_stage's docstring said "TWO CALLERS, AND ONLY ONE OF THEM SWEEPS FIRST" and namedupdate-shape.py apply --addas the one that calls it alone, andstage_written's closing sentence said the same. Since #242 (PR #308)family.py's_commit_one(everyadd,bumpandremovecommit) andcmd_bump's re-stage call it alone too, for exactly the reason the docstring gave forupdate-shape.py: they write into a holder somebody may be working in, where-Awould stage their work beside the shape's.Both docstrings now state the contract without a count (the issue's decisions 2 and 3):
force_stage: "A CALLER THAT WRITES INTO A CHECKOUT SOMEBODY WORKS IN CALLS THIS ALONE, NEVER AFTER A SWEEP", and the function never sweeps; a caller that wants a sweep makes it first, asstage_writtendoes. The reason the old text gave is kept (-Awould stage their work beside the shape's), and so is its history: the rule began withupdate-shape.py apply --add(update-shape.pyapply --addstages the new file with a plaingit add, so a path the operator's excludes ignore fails after the copies, the re-pin and the branch are written, nothing is rolled back, andcheckthen exits 0 over a re-pin nobody committed #202), whose plaingit add --died on an ignored addition after the copies, the pin and the branch were written.family.py's commits took it up (family.pyaddrunsgit submodule addwithout--force(and_commit_onea plaingit add), so under an operator's global excludes namingmembersor the member's own name it exits 2 at the mount for every member, and the remediation it prints blames access (gh auth status, your SSH key) instead of the ignore rule #242), and the text says what each stages in a holder somebody may be working in (add: the gitlink,.gitmodulesandfamily.yaml;bump: the gitlink andfamily.yaml;remove:.gitmodulesandfamily.yaml, the gitlink's deletion already staged by itsgit rm). The next caller of that kind is bound by the rule without being named. The opening sentence's list of tools that share the helper now includesfamily.py'sadd,bumpandremovecommits besideinit.stage_written: the closing paragraph says who calls it (a caller that has just made the tree it stages) and what a caller that writes into a checkout somebody works in calls instead (force_stage, alone). It drops its own "THREE CALLERS" count and keeps the list of the callers that make the tree they stage, with a verb of its own.Why
The "ALONE" sentence is the reason
force_stagemust never grow a sweep of its own. A maintainer who reads it before changing the helper was told one caller depends on it, when two tools do, and a change made on that reading is checked againstupdate-shape.pyalone.Checked
Docstring-only:
ast.dumpofscripts/shape_materialize.pywith its docstrings stripped is identical to origin/main's before and after. The net the issue names,tests/test_family_add_excludes.pyandtests/test_update_shape_add.py, ran over the changed bytes on Linux: 40 passed (/usr/bin/python3 -m pytest tests/test_family_add_excludes.py tests/test_update_shape_add.py -q). CI's three OSes are the gate.Closes #369
🤖 Generated with Claude Code
Summary by Sourcery
Clarify staging helper contracts to prevent unrelated work from being staged by shape and family operations.
Enhancements: