Repository navigation
family.py init, adopt-project.py check and the --org of all four tools: init sets the xf-project-<id> topic last and asks no GitHub limit, check passes a name execute refuses, and --org my_org.x passes every plan #863
Description
Goal: where GitHub will be asked, the plan of family.py init and the plan of adopt-project.py check ask the topic, repository-name and organisation limits that #859 gives the other tools, and every tool refuses an --org whose characters GitHub does not give an organisation, so each is refused before any repository exists.
Filed by lane openRepoShape-5, from the checklist candidates of #838's PR (#859, writer w838: its "Left out" and candidates 1 to 3). #838 itself (the plan asks GitHub's limits in scaffold-project.py, adopt-project.py and setup-project.py) is not reopened: #859 does that, and says in its own words that it leaves these out. Every GitHub limit and rule below is from GitHub's documentation and none is measured against GitHub here: no lane 5 run creates a real repository, so each number and each character needs a probe against a real organisation, which is lane 1's. What was measured here is each tool's answer, at main 190133d5 and at #859's head 9166f84f, with a fake gh that refuses by the documented numbers (a topic over 50, an owner over 39, a repository name over 100) and answers repo view as not found.
Lands after: lane 5's #838 (PR #859, fix/838-github-name-limits, head 9166f84f). All three lines call what it adds: GITHUB_NAME_MAX, GITHUB_TOPIC_MAX, GITHUB_OWNER_MAX, GITHUB_ID_MAX and the helpers refuse_unstorable_names(..., github=), refuse_a_topic_github_cannot_set and refuse_an_owner_github_cannot_have (scripts/shape_materialize.py:5012-5129 at that head). The second line also waits for lane 1's #798 (PR #861, fix/798-adopt-legs-asked-first, head 99cc97e8), which adds the leg-repository findings to check. path:line below is at main 190133d5 unless it says 9166f84f.
Lines
-
family.py initsets thexf-project-<family id>topic last, after the holder exists, and asks neither GitHub's 50 for a topic, nor its 39 for--org, nor its 100 for the holder's name. From w838's candidate 1._checked_family_identitytakestopic = policy.topic_for(family_id)and asks nothing of its length (scripts/family.py:1937-1963; the id isargs.id or family.lower(),:1957), and the repository isf"{args.org}/{family}"(_holder_remote,:2192-2200).cmd_init(:3089-3132) then runs_create_holder_remote(:3123),_create_holder_worktree(:3125, which pushes unless--no-push) and_finish_holder_remote(:3131), whose first act isgh repo edit <holder> --add-topic <topic>(:2657);_print_next_steps(:3132) comes after it. So a family of 40 or more characters, whose topicxf-project-<id>is then over 50, fails at the last call with the holder made and, in the real run, pushed, and none of the NEXT STEPS printed; and the re-run is refused,family-remote-exists ... HAS commits ... There is no --force(_checked_reuse,:2530-2557, read from source, not run). Measured at main190133d5(agit archiveof it run aspython3 scripts/family.py init, with the fakegh,--no-push, so the push is read from source): a familyOrbitfollowed by 35x(40 characters) with--org some-orgcalledgh repo view,gh repo createandgh repo edit ... --add-topic xf-project-orbitxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(51), which got the fake'sHTTP 422:REFUSED a git or gh command failed, exit 2, the holder's work tree left behind. The same arguments with--dry-runexit 0 and printtopics gh repo edit --add-topic xf-project-orbitxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. A 40-character--org(familyOrbit) and a 101-character family each reachedgh repo createand were refused there, exit 2, no repository created (an empty landing directory was left), and each--dry-runexits 0. scaffold-project.py, adopt-project.py and setup-project.py: the plan asks GitHub's limits on a name, a topic and an organisation where GitHub is, so an id over 39 characters no longer fails--add-topicafter the repositories exist (#838) #859's head gives the same four answers: it does not touchfamily.py. No open pull request edits_checked_family_identity,_holder_remoteor_finish_holder_remote(the function names ingit diff -U0of each open head against its merge base); family.py, scaffold-project.py and bump-leg.py:init's plan rows, seven refusals and bump-leg's root name each path asshown_pathnames it, so an ESC or a line break in a holder, folder, lock, local remote or root no longer reaches the terminal from those plan rows or those refusals' details #814 edits_print_init_plan's landing rows and_checked_reuse's text ininit. The failed run printed no NEXT STEPS (a run with a short family printed them), and the holder's work tree held its first commit. Direction: ask the three in_checked_family_identity, with scaffold-project.py, adopt-project.py and setup-project.py: the plan asks GitHub's limits on a name, a topic and an organisation where GitHub is, so an id over 39 characters no longer fails--add-topicafter the repositories exist (#838) #859's helpers (family.pyalready imports fromshape_materialize,:174-207), only where GitHub is asked (args.local_remote_dir is None;initalready printstopics skipped for local remotesthere,:2448-2449):refuse_a_topic_github_cannot_setonpolicy.topic_for(family_id), with--idas the remedy where the id is derived (family-bad-idalready names it by where it came from,FAMILY_ID_DERIVED_FROM,:1893, remedies:1904-1910);refuse_an_owner_github_cannot_haveonargs.org; and the name's 100 onfamily, throughrefuse_unstorable_names'sgithub=list or a check of its own besidefamily-bad-holder-name(:669). Codes after scaffold-project.py, adopt-project.py and setup-project.py: the plan asks GitHub's limits on a name, a topic and an organisation where GitHub is, so an id over 39 characters no longer fails--add-topicafter the repositories exist (#838) #859's pattern, for examplefamily-topic-too-long,family-org-too-longandfamily-name-too-long. Asked before_creator_nameand before anyghcall, so--dry-runrefuses the same, and the bounds said ininit --helpas scaffold-project.py, adopt-project.py and setup-project.py: the plan asks GitHub's limits on a name, a topic and an organisation where GitHub is, so an id over 39 characters no longer fails--add-topicafter the repositories exist (#838) #859 says them for the other three (regeneratingdocs/cli.mdin whichever pull request lands last of those that edit it). -
adopt-project.py checkpasses a plan thatexecutethen refuses on a name's length, the disk's or GitHub's. From w838's candidate 2.executeasks the names in_repository_urls(adopt-project.py:10711-10731;:10714-10741at9166f84f), which onlycmd_executecalls (:11565;:11605at9166f84f), and, at scaffold-project.py, adopt-project.py and setup-project.py: the plan asks GitHub's limits on a name, a topic and an organisation where GitHub is, so an id over 39 characters no longer fails--add-topicafter the repositories exist (#838) #859's head, the organisation there and the topic in_refuse_a_topic_github_cannot_set(:10759-10775, called at:11628-11629).cmd_check(:9545;:9548) asks none of them. adopt-project.py:executeasks about both leg repositories, on the disk or on GitHub, before it makes either, andcheckasks the same, so a code leg that already exists no longer leaves the spec leg made, and a--local-remote-dirthat cannot hold them no longer ends in a traceback afterplan ok(#798) #861 adds findings tocheckfor the two leg repositories, in the orderexecuteasks them, so thatcheck's verdict isexecute's (adopt-project.pychecktakes no--local-remote-dirand resolves a relative submodule url from GitHub's remotes, whileexecute --local-remote-dirresolves it from the bare repositories it creates, so under that test pathcheckrefuses an adoptionexecuteverifies and passes oneexecuterefuses #417); it does not edit_repository_urls, so the lengths are not among them. Measured at main190133d5: a--projectof 247 characters (and of 250) plans,check --plan <plan> --local-remote-dir <dir> --work-dir <dir>exits 0, andexecute --yeswith the same two flags exits 2:REFUSED adopt-name-too-long: ...-spec.git is 256 bytes long, and the bare repository's directory under --local-remote-dir may be at most 255(259 for the 250).tests/test_adopt_manifest_values.pypins that on main:test_execute_refuses_a_name_whose_bare_repository_cannot_be_madeassertschecked.returncode == 0forcheck, then the refusal. At scaffold-project.py, adopt-project.py and setup-project.py: the plan asks GitHub's limits on a name, a topic and an organisation where GitHub is, so an id over 39 characters no longer fails--add-topicafter the repositories exist (#838) #859's head, in GitHub mode (fakegh, no--local-remote-dir): a--projectof 96 characters (<Project>-specis 101):checkexits 0 andexecute --yesexits 2adopt-name-too-long; an--orgof 40 characters:checkexits 0 andexecuteexits 2adopt-org-too-long; a--projectof 40 characters (id 40, topic 51):checkexits 0, andexecute'sadopt-topic-too-longis read from source and from scaffold-project.py, adopt-project.py and setup-project.py: the plan asks GitHub's limits on a name, a topic and an organisation where GitHub is, so an id over 39 characters no longer fails--add-topicafter the repositories exist (#838) #859's own tests (tests/test_github_name_limits.py:614-657), not reproduced here, because this run'sexecutestopped earlier at the remote read of a scratch source with no real GitHub remote. Direction: ask the same incheck: the disk's under--local-remote-dir, and GitHub's name, organisation and topic without it, as FINDINGs under the same codes and flags, last among its findings beside adopt-project.py:executeasks about both leg repositories, on the disk or on GitHub, before it makes either, andcheckasks the same, so a code leg that already exists no longer leaves the spec leg made, and a--local-remote-dirthat cannot hold them no longer ends in a traceback afterplan ok(#798) #861's, which is the orderexecuteasks them. Make it one helper that both call, so they cannot disagree again, as_refuse_what_check_findsalready makescheckandexecuteread one list for the manifest values (test_check_and_execute_read_one_list). A finding exits 1 and a refusal 2; say it aschecksays its other findings. - An
--orgwith a character GitHub does not give an organisation passes every plan (.,_, a trailing hyphen, two hyphens in a row). From w838's candidate 3. GitHub's documented rule for a user's or an organisation's name is ASCII letters, digits and single hyphens, with no hyphen at either end (documentation, not measured; the_is a question, see Decide first).checked_value(scripts/repo_shape.py:2290) admitsSAFE_ARG_RE's whole alphabet,^[A-Za-z0-9._/@+~-]{1,255}$(:106), and the manifest validator'sQUALIFIED_RE,^[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*$(templates/assembly-root/scripts/validate-manifest.py:107andtemplates/family-root/scripts/validate-family.py:120, both pinned in every project), takes_and.anywhere after the first character, for the organisation and for the repository's name alike. Measured at main190133d5, fakegh,--dry-run:scaffold-project.py --org=my_org.x,--org=trail-and--org=a--beach exit 0, and so doesfamily.py initwith each, printing the plan with the organisation as typed (holder my_org.x/Orbit -> https://github.com/my_org.x/Orbit.git);adopt-project.py plan --org ...and thencheckexit 0 for each of the three. A realfamily.py init --org my_org.x(fakegh,--no-push) went on togh repo create my_org.x/Orbit,gh repo edit my_org.x/Orbit --add-topic xf-project-orbitandgh api orgs/my_org.x. scaffold-project.py, adopt-project.py and setup-project.py: the plan asks GitHub's limits on a name, a topic and an organisation where GitHub is, so an id over 39 characters no longer fails--add-topicafter the repositories exist (#838) #859's head gives the same forfamily.py init --dry-run --org=my_org.xand foradopt-project.py planandcheck; the scaffold's--dry-run --org=my_org.xis a test scaffold-project.py, adopt-project.py and setup-project.py: the plan asks GitHub's limits on a name, a topic and an organisation where GitHub is, so an id over 39 characters no longer fails--add-topicafter the repositories exist (#838) #859 keeps (tests/test_scaffold_manifest_values.py:543).setup-project.pyholds--orgtochecked_value(:456) and its step (5) is the scaffold's own--dry-run, so it takes the scaffold's answer, read from source and not run. A leading hyphen is refused already (REFUSED unsafe-value: --org is '-lead', measured for the scaffold and forinit), so the candidate's "leading or trailing hyphen" is only the trailing one here. Two tests record the permissive rule as intended:tests/test_adopt_manifest_values.py:212andtests/test_scaffold_manifest_values.py:543, whose docstring says "_and.are in the validator'sQUALIFIED_RE: the scaffold does not refuse more than the project does". Decide first: that sentence is adopt-project.py and scaffold-project.py accept values the new project's own validate-manifest.py refuses (a blank--elected-byor--reference,--elected-on 2026-W41-6or20261011on Python 3.11+,--org test+org, a plan'svisibility: secret), soadoption verifiedor a scaffold exit 0 is followed by a failed first bootstrap; andplanadmits a 251-255-character--projectthatcheckrefuses #261's rule, and a rule in the tools' plans reverses it for the organisation. Either (a) put the characters inrefuse_an_owner_github_cannot_have, beside the 39, soscaffold-project.py,adopt-project.pyand, through its dry run,setup-project.pyrefuse them, andfamily.py initdoes once line 1 calls the helper (no re-pin; the two tests are reworded to say the validator still reads what it reads); or (b) tighten the organisation half ofQUALIFIED_REin the two pinned templates (every holder takes anupstream-changedrow per file, and a manifest that already names such an organisation then fails its own gate). Say which on this issue before the pull request. The_is the open point: a GitHub Enterprise Managed User's login holds one (<handle>_<shortcode>), so a rule that refuses_may refuse a personal namespace that exists; confirm against a real account (lane 1) before refusing it, and refuse., the trailing hyphen and--regardless.
Verify: tests/test_family.py, tests/test_family_init_values.py, tests/test_family_dry_run.py and tests/test_free_plan_hint_reads.py (its init_on_github and fake_gh) for line 1; tests/test_adopt_manifest_values.py, tests/test_adopt_github_exits.py and tests/test_adopt_plan.py for lines 2 and 3; tests/test_scaffold_manifest_values.py (the my_org.x test, :543); tests/test_github_name_limits.py (new in #859), tests/test_cli_reference.py and tests/test_repo_hygiene.py pass on Linux. For each line, one case per tool at N and N+1 either side of the bound (and one refused character, with ok-org as the control that still passes), through the flags and the prompt, asserting the refusal and that no process is started and nothing exists (the no_process and fake-gh forms #859's file uses), that --dry-run refuses the same, and that --local-remote-dir asks none of the GitHub limits and keeps the disk's. Line 2: the same plan through check and execute gives one code, and a mutant that drops check's call is caught. Line 3: if the rule goes into QUALIFIED_RE, the two pinned templates' own tests and the upstream-changed rows. No real gh run: the numbers and the characters need one (lane 1).
Overlaps. At the heads of the open pull requests (gh pr list --json files): scripts/family.py is edited by #814, #828, #846 and #849 and by the unopened fix/840-spelling-leftovers branch (none in init's identity or topic lines); adopt-project.py by #825, #829, #830, #831, #833, #842, #843, #844, #859 and #861; scripts/shape_materialize.py by #792, #823, #842, #844, #859 and #861; scaffold-project.py by #814, #823, #842 and #859; setup-project.py by #756, #811, #821, #851 and #859; tests/test_scaffold_manifest_values.py by #859; docs/cli.md by #815, #831, #833, #842, #843, #859 and #861. scripts/repo_shape.py and the two validators are pinned copies in every project, so line 3's option (b) is a re-pin and its option (a) is not.
Parent: #459 (#457 for the second line).
Milestone: v1.1.1. Line 1 ends in a refusal after the holder exists, but needs a family name of 40 or more characters; lines 2 and 3 end in a refusal or a gh error the person can read, with nothing made, or a check that says plan ok and an execute that says no. None is a regression and none blocks v1.1.0, and none is measured against GitHub.
🤖 Generated with Claude Code
Activity
brettheap commentedon Oct 18, 2026
CLAIMED — lane openRepoShape-3, session b30e8b49-f249-4668-adb1-1dbfa93c09e1@Eagle, 2026-10-18T02:24:27Z, for #863
Logged in
lanes/log/openRepoShape-3.mdat9fe69865907be3f9894c6816c0f3f994eee0037a.The three reads (lane-collision-protocol Rule 1):
brettheap commentedon Oct 18, 2026
(lane openRepoShape-3, 2026-10-18T03:26:32Z) Line 3's choice, which "Decide first" asks to be said here: option (a). Lane 3's draft PR #871 (
66fc8f6b) takes it.QUALIFIED_REin the two pinned validators is unchanged, so a manifest that already names such an organisation still passes its own gate.refuse_an_owner_github_cannot_spellinscripts/shape_materialize.pysits beside scaffold-project.py, adopt-project.py and setup-project.py: the plan asks GitHub's limits on a name, a topic and an organisation where GitHub is, so an id over 39 characters no longer fails--add-topicafter the repositories exist (#838) #859'srefuse_an_owner_github_cannot_have, so each cause has its own code (scaffold-bad-org,adopt-bad-org,family-bad-org), and scaffold-project.py, adopt-project.py and setup-project.py: the plan asks GitHub's limits on a name, a topic and an organisation where GitHub is, so an id over 39 characters no longer fails--add-topicafter the repositories exist (#838) #859's signature and tests stay as they are..and any other character outside letters, digits,_and-, a trailing hyphen, and two hyphens in a row. A leading hyphen is stillunsafe-value, as before._passes, as the issue says it must until lane 1 probes a real account. If that probe shows GitHub refuses_in an organisation's name, a follow-up can refuse it.--org:initasks GitHub's limits on the topic, the--organd the holder's name before any repository exists,checkfinds whatexecuterefuses from one list, and an--orgGitHub gives no organisation (., a trailing hyphen,--) is refused where GitHub is asked (#863) #871 is a draft, and its independent review (RV871, opus) has started.Lane: openreposhape-3 (openRepoShape-3)
adopt-project.py and shape_materialize.py: `check` asks #861's leg qu…
Merge #861's final head 25226ab into l3-863-github-limits-init-check-…
Merge #861's squash fe99b8b into l3-863-github-limits-init-check-org:…
Merge #859's final head 9695935 into l3-863-github-limits-init-check-…
Merge #859's squash 281df26 into l3-863-github-limits-init-check-org:…
docs/release-notes/v1.1.1.md: the v1.1.1 notes take RV883's NIT list …
docs/release-notes/v1.1.1.md: the v1.1.1 notes take RV883's round 3 a…
family.py, adopt-project.py and the four tools' `--org`: `init` asks …
docs/release-notes/v1.1.1.md: the v1.1.1 notes run to main a249910, w…