Repository navigation
shape-doctor.py: the members row prints a mount url and a stranger's origin raw, so an ESC in either reaches the terminal as a control, where make siblings spells the same values in its WRONG ORIGIN finding #673
Copy link
Copy link
Closed
Milestone
Description
Goal: no value the members row quotes from a manifest, a disk or git reaches the terminal as a control character.
Filed by lane openRepoShape-3 on Brett Heap's word of 2026-10-16T12:24:41Z ("give #460 to lane 3").
What happens (measured on main d4a7fab9):
- The setup. A holder from the suite's
holderfixture has its member's url in.gitmodulesrewritten to<remotes>/caf\x1b[31m/IRRS.git(mount_throughintests/test_doctor_gitmodules_not_utf8.py). A clone of the member's real remote sits beside it. - The result.
shape-doctor.py --root <holder>exits 0. Its printedmembersrow reads:IRRS: <dir> is a clone of <remotes>/IRRS.git, not of <remotes>/caf, then a raw ESC, then[31m/IRRS.git, so it is not counted as its working clone. - Why it matters. A terminal reads that ESC as a colour change. A CR, a line break or U+202E in the same place would overwrite or reorder the line.
make siblingsalready spells these values. Its WRONG ORIGIN finding names the same directory and the same two urls, and since siblings.py and the family-root README:make siblings,parkandresumeprint the family's name and every member row spelled and never end in a traceback onname: "a\ud83db"or a dash underPYTHONIOENCODING=ascii, and the holder's README names its folder after the repository, so--family Quill --name QuillWorkslays out as its README says (#454, #629) #642 (family-root siblings.py:make siblings,parkandresumeprint the family'snamewith a plainprint, soname: "a\ud83db"ends each in aUnicodeEncodeError, and the literal dash ends every name underPYTHONIOENCODING=ascii#454) it spells each one:templates/family-root/scripts/siblings.py:474-489usesspelled(project),spelled(target),spelled(origin or '(no origin)')andspelled(repository or url).- Pinned shape copies: one bump, so AGENTS-shape.md is true of every root, the scaffold's chain WARNING offers only its own sources and spells
--pin-source, the root's not-used note spells it too, and THE LOCKSTEP RULE'sbumpruns (#610) #634 (Pinned shape copies: AGENTS-shape.md'sCONTRACTS_DIRsentence is false for every scaffolded root, and the chain WARNING offers remedies the scaffold lacks (one shape bump before the v1.1.0 tag) #610, open) does not reach it.- Pinned shape copies: one bump, so AGENTS-shape.md is true of every root, the scaffold's chain WARNING offers only its own sources and spells
--pin-source, the root's not-used note spells it too, and THE LOCKSTEP RULE'sbumpruns (#610) #634 spellsrepo_shape.git_out'sgit-failedrefusal (shown_path(cwd),spelled(stderr)), and some prints invalidate-pins.py, the naming gate, the scaffold andvalidate-family.py. - It touches no line of
shape-doctor.py. - This row's urls come from git's STDOUT, through
submodule_configandorigin_url, never from a refusal.
- Pinned shape copies: one bump, so AGENTS-shape.md is true of every root, the scaffold's chain WARNING offers only its own sources and spells
Where it is (main d4a7fab9), in shape-doctor.py:
:7322-7328(members_verdict). The stranger sentence interpolatesentry['project'],ctx.root.parent / entry['project'],entry['other_origin']andentry['mounted_from']raw.:7186and:7230(working_clone,member_state) apply onlyredacted(...), which keeps controls (scripts/repo_shape.py:2740-2752).:814(Row.__init__) applies onlyascii_text(reason)(:624-636), whoseencode("ascii", "replace")keeps every ASCII control.
The change:
- Spell every quoted value. Spell each value the
membersrow quotes fromfamily.yaml, the disk or git withrepo_shape.spelled: the project, the directory, the origin and the mount url, assiblings.pyspells the same four.spelledhas been on main since templates/assembly-root/scripts/bootstrap.py and templates/family-root/scripts/bootstrap.py:mainprints the manifest'snamewith a plainprintbefore any step runs, soname: "a\ud83db"(a lone surrogate) endsmake bootstrapin aUnicodeEncodeErrortraceback, exit 1 (make: 2), and the validator that names the problem is never reached; a valid name the stdout cannot encode ends the same way #391.- The doctor already imports from its own checkout's
scripts/repo_shape.py, which is not a pinned copy of any project. - A plain value prints byte for byte as before.
--jsonkeeps the raw values. They are data, andjson.dumpsescapes them.- Out of scope:
- other rows that quote a value raw (Pinned shape copies: AGENTS-shape.md's
CONTRACTS_DIRsentence is false for every scaffolded root, and the chain WARNING offers remedies the scaffold lacks (one shape bump before the v1.1.0 tag) #610's class, across the doctor); - a general guard in
Rowforreasonandwhybut nevernext, where an escape would not run as typed. That is a separate decision.
- other rows that quote a value raw (Pinned shape copies: AGENTS-shape.md's
- No dependency on Pinned shape copies: one bump, so AGENTS-shape.md is true of every root, the scaffold's chain WARNING offers only its own sources and spells
--pin-source, the root's not-used note spells it too, and THE LOCKSTEP RULE'sbumpruns (#610) #634. It can land before or after. - Pinned shape copies: none.
shape-doctor.pyis not one.
Tests, in a new file such as tests/test_doctor_members_spelled.py (it can import the fixtures of tests/test_doctor_gitmodules_not_utf8.py):
- A mount url and a stranger's origin, each holding ESC, CR, NEL and U+202E:
- the printed row holds each one as Python's escape and no raw control, on a UTF-8 stdout and under
PYTHONIOENCODING=ascii; - the
--jsondetail holds the raw url.
- the printed row holds each one as Python's escape and no raw control, on a UTF-8 stdout and under
- A plain url leaves the row's text unchanged.
From #460, #460 (comment) (L24)
🤖 Generated with Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
brettheap commentedon Oct 16, 2026
CLAIMED — lane openRepoShape-3, session b30e8b49-f249-4668-adb1-1dbfa93c09e1@Eagle, 2026-10-16T12:58:47Z, for #673
Logged in
lanes/log/openRepoShape-3.mdatf87a172464795ce8f1fd9e800799369039128361.The three reads (lane-collision-protocol Rule 1):
shape-doctor.py: the `members` row reads a folder beside the holder i…
shape-doctor.py: the `members` row says, member by member, what `make…
adopt-project.py, shape-doctor.py and tests/test_shape_doctor.py: the…