Skip to content

scripts/validate-repository-naming.py: the plain listing pads each name from the command line or stdin by code points, not by the columns a terminal gives it, so a wide or combining name's label column stands out of line (twin of #1034) #1217

Open

Description

@brettheap

Goal: the plain listing of validate-repository-naming.py pads each name by the columns a terminal gives it, so a wide or combining name's label column starts where every other row's does, and an ASCII name prints byte for byte as it does today.

Filed by lane openRepoShape-3, from RV1178's independent review of #1178 (#1034) at fa56168a (#1178 issuecomment-6351653129), its follow-up for scripts/validate-repository-naming.py:1297; the delta review at c4beba19 (#1178 issuecomment-6353960809) is READY and takes the follow-up no further. It did not hold the landing. #1178 is open at c4beba19, and its diff against main ef619c74 leaves this script, templates/family-root/scripts/siblings.py and scripts/repo_shape.py alone, so the defect is on main now. Line numbers are main's at ef619c74.

The listing pads a name by code points

State. _print_classification (scripts/validate-repository-naming.py:1280) prints f" {name:<32} {label}{also}" (:1297). A format width counts code points. The name is a target's: a command-line name or a line of stdin, both through repo_basename (:1258, :1465), printed as it is. _classify_targets prints one such line per target unless --explain or --quiet is given, a name no family classifies as NO FAMILY (:1290-1291). Two existing rows pin the width for ASCII: tests/test_chain_link_fold.py:175 and :266 assert f"{'codexGlass':<32} ...".

What happens. Arithmetic from the code and the standard library's unicodedata, not a run of the tool: RV1178 measured adopt-project.py's table and listed this one as a follow-up without a measurement. Under the rule #1178 uses (no column for categories Mn, Me and Cf, two for East Asian width W or F, one otherwise):

  • a name of the three characters U+65E5 U+672C U+8A9E is 3 code points, so the pad adds 29 spaces and the field is 35 columns wide, 3 more than an ASCII name's 32: its label starts 3 columns to the right of every other row's;
  • e U+0301 cole is 6 code points and 5 columns, so its field is 31 columns wide and its label starts 1 column to the left.

On a stdout that cannot hold a character, _escape_what_stdout_cannot_encode (:1262, called at :1452) makes the handler backslashreplace, so U+65E5 reaches the terminal as \u65e5: six columns for one code point that the pad counted once (by reading that function's docstring; not run).

Direction. Pad by display columns, as #1178 does for adopt-project.py's plan table (_columns at adopt-project.py:6437 and _padded at :6460 at c4beba19, with ZERO_COLUMN_CATEGORIES, TWO_COLUMN_WIDTHS and the two Hangul jamo sets), and measure the text as stdout will write it. An ASCII name keeps its width exactly; a name wider than 32 columns is left as it is. No command and no flag.

  • This script already imports from scripts/repo_shape.py (:146), the library the roots carry, so one helper there could serve this script, siblings.py (templates/family-root/scripts/siblings.py: the layout table pads each member's name by code points, not by the columns a terminal gives it, so a wide or combining name's state column stands out of line (the family-root twin of #1034) #1216, for its layout table) and, later, adopt-project.py's _columns. The cost is that siblings.py must also run beside an older kept repo_shape.py (its comment at :1520-1524), so the writer decides once, and the PR says where the rule lives.

  • :795 and :919 also pad family['id'] to 18 code points. A family id is a policy's word, and whether a policy can name one outside ASCII was not read for this issue: the writer reads that before leaving them.

  • The test is tests/test_chain_link_fold.py, whose row at :262-266 already runs this script as run_script(REPO / "scripts" / "validate-repository-naming.py", "--role", "assembly", "--pins", pin, "codexGlass", cwd=tmp_path) and compares the whole stdout. The new rows give it a wide name and a combining one and read the line raw.

  • A name of U+65E5 U+672C U+8A9E: its label starts at the same display column as codexGlass's, on a UTF-8 stdout. The row fails before and passes after.

  • The same for a name holding e U+0301.

  • The same two rows with env={"PYTHONIOENCODING": "ascii:strict"} added to the run (run_script takes env), so the escaped form is counted as stdout writes it.

  • An ASCII name prints byte for byte as before: the two existing rows pass unchanged.

  • One mutant, the pad back to len, fails a new row; each mutant run is restored and checked with cmp.

Related: #1178, #1034 (adopt-project.py's plan table, the same defect), and #459 (the tracker for setup, scaffold, family and the shared helpers).

Size: S.

Lane: openreposhape-3 (openRepoShape-3)

Activity

  1. added this to the v1.2.1 milestone on Oct 23, 2026
  2. brettheap commented on Oct 23, 2026

    @brettheap
    ContributorAuthor

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

    Logged in lanes/log/openRepoShape-3.md at 309ecbd5e2c3e035c592afdbc4e8c50a571c1c3b.

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

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