Skip to content

shape_materialize.py force_stage's docstring says it has TWO CALLERS and that only update-shape.py apply --add calls it alone, and stage_written's says the same, though since #242 family.py's _commit_one (every add, bump and remove commit) and cmd_bump call it alone too, so the next change to its contract is reasoned about with half of its alone-callers missing #369

Closed

Description

@brettheap

Lane: openreposhape-4 (openRepoShape-4)

Named out of scope by the writer of #242's replay (PR #308, head 15c080c), "force_stage's docstring 'TWO CALLERS' undercounts", and by this lane's re-check of that head (its nit R1, "force_stage's docstring is now stale"). #308 landed as c0ed615 without touching scripts/shape_materialize.py. Checked by reading, on main c7c02fa and on a scratch merge of #318's head 0f2a0dd (which carries c7c02fa) with #317's head c23e2b0. Both docstrings are byte-identical in the two trees, and only family.py's line numbers move. A docstring-only issue: no behaviour is wrong today.

What is wrong.

U=<openRepoShape checkout>   # a clean checkout at c7c02fa
cd $U
sed -n '/^def force_stage/,/^    paths = list(paths)/p' scripts/shape_materialize.py | grep -nE 'SHARE|CALLERS|ALONE|calls this'
sed -n '/^def stage_written/,/^    run(/p' scripts/shape_materialize.py | grep -nE 'forced half|on its own'
git grep -n 'force_stage(' -- scripts update-shape.py

Output at c7c02fa (the first two groups are line numbers within each docstring):

5:    SEEDED LEG AND `update-shape.py` SHARE; the seeded leg reaches it
23:    TWO CALLERS, AND ONLY ONE OF THEM SWEEPS FIRST. `stage_written` runs
25:    made. `update-shape.py apply --add` calls this ALONE (#202): it writes
21:    `family.py init`'s holder. The forced half is `force_stage`, which
22:    `update-shape.py apply --add` calls on its own (#202).
scripts/family.py:556:    force_stage(root, paths if add is None else add)
scripts/family.py:1893:    force_stage(family.root, [path])
scripts/shape_materialize.py:821:def force_stage(work: Path, paths=()) -> None:
scripts/shape_materialize.py:881:    force_stage(work, written)
update-shape.py:1909:        force_stage(self.root, paths)

force_stage's docstring (scripts/shape_materialize.py:821 at c7c02fa) opens with "THE FORCED ADD THE SCAFFOLD, family.py init, adopt-project.py'S SEEDED LEG AND update-shape.py SHARE". Further down it says "TWO CALLERS, AND ONLY ONE OF THEM SWEEPS FIRST. stage_written runs git add -A before it ... update-shape.py apply --add calls this ALONE (#202): it writes into a checkout somebody may be working in, where -A would stage their work beside the shape's". stage_written's docstring ends "The forced half is force_stage, which update-shape.py apply --add calls on its own (#202)". The callers are four call sites, not two: stage_written (:881), update-shape.py:1909, and, since #242 (PR #308), family.py's _commit_one (:556), which stages every add, bump and remove commit, and cmd_bump (:1893), which re-stages the gitlink before _nothing_to_record. The two family.py calls are alone, with no sweep, for exactly the reason the docstring gives for update-shape.py: they write into a holder somebody may be working in.

Why. This repository's docstrings carry the decisions: the "ALONE" sentence is the reason force_stage must never grow a sweep of its own. A maintainer who reads it before changing the helper (adding a sweep, or changing "Empty, this runs nothing") is told that one caller depends on it, when three call sites in two tools do. A change made on that reading is checked against update-shape.py alone, and the family side it could break is #242's ground.

What it should do. The decisions are the author's:

  1. Name every call site, and which of them sweep first (stage_written, for its own three callers) and which call alone (update-shape.py apply --add; family.py's _commit_one and cmd_bump, family.py add runs git submodule add without --force (and _commit_one a plain git add), so under an operator's global excludes naming members or 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), with the reason each one has.
  2. Or state the contract without a count ("callers that write into a checkout somebody works in call this alone, never after a sweep"), so that the next caller does not make it stale again.
  3. stage_written's closing sentence the same way.

How to test. A docstring-only change. The existing tests of the call sites (tests/test_family_add_excludes.py, which covers add and bump under an operator's excludes, and the update-shape.py apply --add tests) are the net, and nothing new needs testing.

Verified by reading at main c7c02fa and at the scratch merge of #318's head 0f2a0dd with #317's head c23e2b0; the docstrings are unchanged by either PR, and the mismatch survives the merge.

Related: #242 / PR #308 (the two family.py call sites), #233 (force_stage), #202 (update-shape.py apply --add calling it alone), #175 (stage_written's forced half).

Activity

  1. brettheap commented on Oct 12, 2026

    @brettheap
    ContributorAuthor

    CLAIMED — lane openRepoShape-4, session e7cd5391-c790-49b0-a88f-a97d34b22582@Eagle, 2026-10-12T15:20:25Z, for #369

    Logged in lanes/log/openRepoShape-4.md at b88dadf9180c63796bc1dafee2f5c51beee73766.

    The three reads (lane-collision-protocol Rule 1):

    1. existing `CLAIMED —` comments on opensoft/openRepoShape#369:
       none
    2. `gh pr list --repo opensoft/openRepoShape --state all --search "#369"`, kept where the row or its body names `#369`:
       none
    3. `git ls-remote --heads git@github.com:opensoft/openRepoShape` branches naming `369` as a whole token:
       none
    
  2. added this to the v1.0.0 milestone on Oct 12, 2026
  3. added a commit that references this issue on Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions