Skip to content

scaffold-project.py: --project NUL and --project Con are taken and the three repositories and their folders are made, where family.py init refuses the same names as family-bad-holder-name #989

Closed

Description

@brettheap

Goal: scaffold-project.py refuses, before anything exists and under --dry-run alike, a --project that is a name no Windows disk can make a file or folder of (CON, PRN, AUX, NUL, COM1 to COM9, LPT1 to LPT9, in any case), by the question family.py init already asks of --family.

Filed by lane openRepoShape-3, from RV972's review of #972, its N5 (comment 6254722026), on #972. Lane 3 ruled that N5 predates #972 and goes to a follow-up issue; this is it.

State. Read at origin/main ae63d450. scaffold-project.py, scripts/family.py and scripts/shape_materialize.py are unchanged since c4dd19dc, so every line below is the same there.

  • family.py init asks the question. _checked_family_identity calls _classify_family_name and then _refuse_an_unholdable_holder_name(family) (scripts/family.py:2232-2233; the function is scripts/family.py:733-760). That asks _unmountable_reason (scripts/shape_materialize.py:4481, which reads WINDOWS_DEVICE_RE at :4420) and refuses as family-bad-holder-name. family.py init: --created-by and GIT_AUTHOR_NAME are never asked whether the manifest can hold them, a whitespace-only GIT_AUTHOR_NAME fails after the remote exists, and a --family a Windows disk cannot hold exactly is accepted #688 added it for init.
  • scaffold-project.py never asks it of --project. The value goes through checked_value("--project", ...) (scaffold-project.py:1953), the three names are built (:2000) and judged by the naming policy alone (_refuse_bad_id at :2022, _check_declared_names at :2048). The one question about a Windows-unmakeable name that the scaffold does ask is about the two leg PATHS (refuse_bad_leg_paths, called at :1967, which reaches _unmountable_reason too).
  • NUL and Con are each one CamelCase token, which is all the naming policy asks of a project name, so nothing else stops them.

What happens. Measured at cf66102f (the NUL and Con dry runs and the init refusals again at ae63d450, with the same results) with a stub gh (exit 97) first on PATH, GH_TOKEN=bogus, an empty GH_CONFIG_DIR, GIT_SSH_COMMAND=false, and --local-remote-dir so no network is asked.

scaffold-project.py --org acme --project NUL --dry-run --local-remote-dir <dir>/lr --work-dir <dir>/out --elected-by X
  assembly  acme/NUL      -> <dir>/lr/NUL.git
  spec      acme/NUL-spec -> <dir>/lr/NUL-spec.git
  code      acme/NUL-code -> <dir>/lr/NUL-code.git
--dry-run: nothing was created.            exit 0

--project Con   --dry-run   exit 0      (the same plan, acme/Con and <dir>/lr/Con.git)
--project Nul, com1, Lpt9, COM9, Aux, Prn   --dry-run   exit 0 each

--project NUL and --project Con, without --dry-run          exit 0 each
  <dir>/out : NUL  NUL-code  NUL-spec          <dir>/lr : NUL-code.git  NUL-spec.git  NUL.git

family.py init --org acme --family NUL --dry-run --local-remote-dir <dir>/lr --work-dir <dir>/out2 --created-by X
REFUSED family-bad-holder-name: --family is 'NUL', which names the holder and the folders `init` makes for it, and `NUL` is a Windows device name (with or without an extension), which cannot be created there.     exit 2
--family Con     the same refusal, exit 2

The device-name rule is a whole-name rule: NUL-spec and NUL-code are not device names (WINDOWS_DEVICE_RE.fullmatch needs the whole segment), but the assembly root's folder NUL and, under --local-remote-dir, its bare repository NUL.git (a device name with an extension) are. The root is the repository every engineer clones, into a folder of that name. I ran no Windows machine; the claim that a Windows disk cannot make NUL or NUL.git is HOLDER_NAME_REMEDIATION's (scripts/family.py:721-730), the rule #688 settled for holders.

adopt-project.py plan takes the same names for --project too, measured on a one-commit local repository: plan --source <dir>/src --project NUL --org acme --elected-by X exits 0 and writes a plan (project NUL (nul) in acme); Con the same. execute was not run.

Evidence.

Direction.

Verify.

  • scaffold-project.py --project NUL, Con, Nul, com1, Lpt9, COM9, Aux and Prn, with and without --dry-run, exit 2 with the new code; no gh call is made, and no work folder and no bare repository exist afterwards. Nullable, Console and Auxo still scaffold, as they did at cf66102f (a device name is the whole name only).
  • Rows for the scaffold beside init's, in both modes, each holding that nothing was made.
  • One test over a list of names that BOTH tools must refuse, so the two cannot part again.
  • tests/test_family_init_asks_every_value.py, tests/test_scaffold_e2e.py, tests/test_dry_run_parity.py, and the docs guards tests/test_agents_md_codes.py, tests/test_cli_reference.py, tests/test_repo_hygiene.py and tests/test_no_auto_maintenance.py pass, one file at a time under a stub gh.

Size: S.

Lane: openreposhape-3 (openRepoShape-3)

Activity

  1. added this to the v1.2.0 milestone on Oct 19, 2026
  2. brettheap commented on Oct 19, 2026

    @brettheap
    ContributorAuthor

    CLAIMED — lane openRepoShape-3, session b30e8b49-f249-4668-adb1-1dbfa93c09e1@Eagle, 2026-10-19T18:33:38Z, for #989

    Logged in lanes/log/openRepoShape-3.md at 83bfb56ef8c2463acb3679deea6ba9904049b462.

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

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

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions