Skip to content

adopt-project.py: check never reads a plan's elected_on: when the plan has no reference:, so plan ok is followed by an execute that creates both leg repositories and only then refuses election-date-malformed, naming --elected-on, a flag neither command takes #294

Closed

Description

@brettheap

(lane openRepoShape-2, 2026-10-12T00:11:31Z)

Found by this lane's adversarial review of PR #270 at aed9190 (the fix for #255), its follow-up FU3; the PR body's "Left out" names it, and the review's probe confirmed it. It is the same on main d94d155, where it was reproduced again today: #270 neither causes it nor changes it. Not claimed.

What is wrong. A plan with no reference: line and an elected_on: that is not an ISO date passes check (plan ok, exit 0). execute then runs _create_leg_remotes, which creates both leg repositories (empty bare repositories on the local route, two gh repo create calls on the GitHub route), and only afterwards builds the template values. There default_reference asks election_date for the date, and execute ends REFUSED election-date-malformed: --elected-on 'someday' is not a date. Neither check nor execute takes --elected-on, and the remediation it prints, re-run with a zero-padded ISO date, e.g. --elected-on 2026-09-02, is a flag only plan has. The operator has to find the plan file's elected_on: unaided, and the two repositories are already there: a second execute meets REFUSED leg-remote-exists.

# $U: a checkout of openRepoShape at d94d155 (git-filter-repo on PATH). $SRC: a three-file git repository (src/app.py, docs/spec.md, README.md), one commit. Local remotes only; no network.
python3 "$U/adopt-project.py" plan --source "$SRC" --project Northwind --org testorg --elected-by 'T H' --elected-on 2026-09-02 --out "$P"
#   the plan holds:  elected_on: "2026-09-02"   and   reference: "openxFactory docs/project-repo-schema.md"
sed -i -E '/^reference:/d; s/^elected_on: .*/elected_on: someday/' "$P"     # a hand edit: no reference, a word for the date
python3 "$U/adopt-project.py" check --plan "$P"                           # exit 0   plan ok
python3 "$U/adopt-project.py" execute --plan "$P" --yes --local-remote-dir "$R/remotes" --work-dir "$R/work"
#   exit 2
#   REFUSED election-date-malformed: --elected-on 'someday' is not a date; it takes YYYY-MM-DD (and a plan file's `elected_on:` carries the same form)
#   Remediation: re-run with a zero-padded ISO date, e.g. --elected-on 2026-09-02 ...
ls "$R/remotes"                                                           # Northwind-code.git  Northwind-spec.git   (created, empty: no `main` in either)
python3 "$U/adopt-project.py" execute ... (again)                          # exit 2   REFUSED leg-remote-exists: <R>/remotes/Northwind-spec.git already exists
the plan check execute on d94d155
elected_on: someday, no reference: exit 0, plan ok exit 2, election-date-malformed naming --elected-on, after both leg repositories were created; no main in either, no split branch
the same, execute run again exit 2, leg-remote-exists
elected_on: "2026-09-02", no reference: (control) exit 0 exit 0, adoption verified; the reference is derived from the date
elected_on: someday, reference: kept exit 0, plan ok exit 0, adoption verified; project.yaml holds elected_on: someday, and the project's own scripts/validate-manifest.py refuses it: FINDING manifest-elected-on: elected_on is 'someday', expected an ISO date YYYY-MM-DD

Why. election_date (scripts/shape_materialize.py:241-258) is called on a plan's date in exactly one place, and that place is late. plan calls it on --elected-on (adopt-project.py:1417, with the comment at :1414-1416 that says why: "a date the tools cannot parse would reach execute as a manifest field instead of as a question"). On the plan side it is read again only through default_reference(elected_on) (shape_materialize.py:261) in _template_values (adopt-project.py:3094), which cmd_execute calls at :3030, after _confirm (:3020) and _create_leg_remotes (:3023), and which runs only when plan.get("reference") is empty (:3093-3094). check does not read elected_on at all, and neither does _refuse_what_check_finds (:3012), which execute runs before any leg exists for everything check finds. So the rule the tool already has fires, but after the side effect, from a message written for a flag the command does not take.

What it should do.

  1. check reads the plan's elected_on: with election_date and reports a date it cannot read as a FINDING election-date-malformed naming the plan key (elected_on:, not --elected-on), whether or not reference: is present. It is then on the list execute refuses through _refuse_what_check_finds, so execute exits 2 before any leg exists. This is the same early read plan already does for its own flag.
  2. The message names the plan file's key when the date came from a plan: its election_date is shared with plan, so the call site passes where the date came from, and the remediation tells execute and check callers to edit elected_on: in the plan file.

How this differs from #261. #261 is about values the tools ACCEPT and execute writes, so that adoption verified is followed by a red first bootstrap: --elected-on 2026-W41-6, 20261011, a plan's visibility: secret or elected_by: null. Here the tool's own rule REFUSES the value, and the defect is when and how: after two repositories exist, under the wrong flag name, and only when reference: is absent. The last row of the table is #261's class (a bad elected_on the tools let through, with reference: kept) and is not what this issue is about. #261's fix list does include "check applies the same predicates to the plan's values (elected_by, elected_on, reference, visibility, org)"; if that lands as written, point 1 above is covered by it and this issue shrinks to point 2 (the wording) and a test that pins the order. It does not mention that execute creates both repositories before reading the date, or the flag name in the message.

How to test. In tests/test_adopt_execute_refusals.py, with write_edited, check_findings, run_check and no_leg_was_created, beside test_execute_refuses_each_class_and_creates_no_leg (:347):

  • (a) delete the plan's reference: line and set elected_on: someday: check exits 1 with election-date-malformed, the finding names elected_on: and not --elected-on; execute exits 2 with the same code and no_leg_was_created;
  • (b) the same with reference: kept, if the fix makes check read the date whether or not reference: is there;
  • (c) controls: elected_on: "2026-09-02" with no reference: still passes check and execute, and the reference is the derived one.

Reverting the early read fails (a).

Related: #261 (above); #255 and PR #270 (the review that found this); #188 (a failure after the legs exist prints no notice of what exists, and the re-run meets leg-remote-exists); #168 (the shared list execute refuses through); #196 (check admitting what execute refuses, the general class).

🤖 Generated with Claude Code

Activity

  1. brettheap commented on Oct 12, 2026

    @brettheap
    ContributorAuthor

    CLAIMED — lane openRepoShape-2, session 5b7b5f3d-dce7-452d-a33d-ab8537d91db3@Eagle, 2026-10-12T11:01:03Z, for #294

    Logged in lanes/log/openRepoShape-2.md at cac0d57a7258d08bc9f213c9c19e93958b5acb00.

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

    1. existing `CLAIMED —` comments on opensoft/openRepoShape#294:
       none
    2. `gh pr list --repo opensoft/openRepoShape --state all --search "#294"`, kept where the row or its body names `#294`:
       none
    3. `git ls-remote --heads git@github.com:opensoft/openRepoShape` branches naming `294` as a whole token:
       none
    
  2. added 10 commits that reference this issue on Oct 13, 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

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions