Repository navigation
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
Description
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+8A9Eis 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 coleis 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'sstatecolumn 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 thatsiblings.pymust also run beside an older keptrepo_shape.py(its comment at:1520-1524), so the writer decides once, and the PR says where the rule lives. -
:795and:919also padfamily['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-266already runs this script asrun_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 ascodexGlass'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_scripttakesenv), 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 withcmp.
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
brettheap commentedon Oct 23, 2026
CLAIMED — lane openRepoShape-3, session b30e8b49-f249-4668-adb1-1dbfa93c09e1@Eagle, 2026-10-23T18:38:43Z, for #1217
Logged in
lanes/log/openRepoShape-3.mdat309ecbd5e2c3e035c592afdbc4e8c50a571c1c3b.The three reads (lane-collision-protocol Rule 1):