Repository navigation
tests/test_chain_remedy_callers.py: no row holds #980's unchanged --link-source reading at the old first-= split's corners (path =x, blank path, key in capitals), so four gate mutants survive #1054
Description
Goal: three test rows hold what #980 left unchanged in how --link-source reads a value (a keyed path that begins with =, a keyed blank path, a key typed in capitals), so each of rv980's four surviving mutants of scripts/validate-repository-naming.py fails a test.
State
#1044 (#980, landed as 82fc86752) made a --link-source key the longest chain link before an = that leaves a path after it (LinkSources._read_source, scripts/validate-repository-naming.py:401-444). Its body claims that a chain whose links hold no = is read exactly as before. That is true: rv980 compared 800 runs on the base and the head (stdout, stderr and exit code) and none differed. But the claim rests on that probe. tests/test_chain_remedy_callers.py holds the #980 rows for the new reading (:479-653) and none for the corners of the old first-= split.
What happens
Nothing is wrong in the code. rv980 wrote seven mutants of the new reading, and four survive the five closest test files (404 passed under each). Line numbers are on main:
- R10,
:439:at = typed.rfind("=", 0, at)becomestyped.rfind("=", 0, at - 1), so the scan skips an=that sits right before the current one.--link-source openXdox==x(chainopenXdox,openYdox,openInk) printslink-source-unreadable: =x (--link-source openXdox=...), the keyopenXdoxwith the path=x. Under R10 it is a bare PATH, and the run adds a false line: "It was read as a PATH:openXdoxis not a link of a referent chain here". - R1,
:437: inif link is not None and typed[at + 1:]:,typed[at + 1:]becomestyped[at + 1:].strip().--link-source 'openXdox= 'stops being keyed to the path(one blank) and becomes a bare PATH, with the same false line. - R14,
:385:no_pathtestsself._read_source(typed)[1], and R14 tests[1].strip(). The same value'openXdox= 'is then refusedlink-source-no-path, exit 2. On main it exits 0, as before validate-repository-naming.py: the--link-source <link>=<path>the gate offers for a chain link holding=is read as a bare PATH when typed, so it never verifies that link #980. - R5,
:438:return link, typed[at + 1:]becomesreturn typed[:at], typed[at + 1:], so the link is spelled as typed and not as the chain spells it. WithOPEN=Y=<tree>, the chainopenXdox,open=y,openInkand a name that reads no declaration (brett-wip), the NOTE saysno name classified here reads OPEN=Y's own declarationwhere main saysopen=y's.
Each one changes output. R1, R10 and R14 do it for a chain whose links hold no =, and rv980 counts those three against #1044's claim; R5 does too, with a key typed in capitals (OPENXDOX=<tree>). At drafting the gate printed the same bytes before #980 (5b41d44f, the base of #1044) and on main for openXdox==x, 'openXdox= ' and OPENXDOX=<tree>.
Direction
Add three rows to the #980 section of tests/test_chain_remedy_callers.py, which already has THREE (:200), EQUALS (:322), naming and tree. They are rv980's suggestion, and together they kill all four:
- A keyed path that begins with
=.openXdox==xwithTHREE: the WARNING=x (--link-source openXdox=...) could not answer for openXdox: no such file or directory, and no "read as a PATH" line. (open=y==withEQUALSis the same row for a link holding=:= (--link-source open=y=...) could not answer for open=y.) Kills R10. - A keyed blank path.
'openXdox= 'withTHREE: exit 0, noREFUSED, the WARNINGlink-source-unreadable: (--link-source openXdox=...)(the path is one blank), and no "read as a PATH" line. Kills R1 and R14. - A key typed in capitals, in a run that reads no declaration.
OPEN=Y=<tree>withEQUALSand the namebrett-wip: the NOTE endsreads open=y's own declarationand never namesOPEN=Y. Kills R5. (OPENXDOX=<tree>withTHREEkills it too, and prints the same bytes before validate-repository-naming.py: the--link-source <link>=<path>the gate offers for a chain link holding=is read as a bare PATH when typed, so it never verifies that link #980.OPEN=Y=is the row for the new reading.)
rv980's checklist line, if the reviewer checklist takes it: when a PR claims an unchanged reading, at least one test row covers each corner of the old split (a path beginning with =, a blank path, and a key typed in another case).
Optional, and the writer's call: the "It was read as a PATH" line names only the text before the first =. It is LinkSources.read_as_path (:616-626), and the text is typed.partition("=")[0] at :623. rv980's ruling is a NIT for a follow-up, not a regression: under the new reading the line is always true, since a value whose first-= text names a link is always keyed and never bare. It can still mislead, in a chain openXdox,open=y,openInk:
open=z=<p>says "openis not a link of a referent chain here", where the key the person typed wasopen=z.--link-source open=y, with no path, says "openis not a link ... (links: openXdox, open=y, openInk)", where the value is a link's name and names no path.
Both print the same bytes before #980 (checked at drafting), and the list of links makes the mistake recoverable. If the line is changed, it could name each text before an = that _read_source tried, or say that a value that is a link's name names no path. Two rows hold the line's bytes where the first-= text is the only text and must keep passing: test_a_key_is_read_whole (tests/test_chain_remedy_callers.py:632-653) and test_a_path_typed_after_the_equals_sign_is_still_read (tests/test_link_source_chain_defaults.py:344-364). The twin line in validate-pins.py (PinSources.read_as_path, :1547-1561) has the same shape, and is #1053's.
Land the three rows alone: they touch no pinned copy. A change to the line touches scripts/validate-repository-naming.py, a pinned copy (COPIED_FROM_SHAPE, scripts/shape_materialize.py:439-443), so it takes one upgrade row.
Verify
tests/test_chain_remedy_callers.pypasses alone on main with the three rows (rv980 ran it on git 2.43 and 2.47.1).- In a scratch worktree, apply each mutant by its one-line edit above and run that file alone. Each must fail: R10 on row 1, R1 and R14 on row 2, R5 on row 3, and each on the line it changes. At drafting the gate was run on main and on each mutant with these values and each row's output differs from main's in just that way; no test was run.
- The three rows alone leave no new row in a root's
update-shape.py check.
Found by lane 5's independent review of #1044 (#980), rv980 (#1044 issuecomment-6288391970).
Milestone: v1.2.0 (placement is lane 3's call).
Not claimed.
Lane: openreposhape-5 (openRepoShape-5)
Activity
brettheap commentedon Oct 20, 2026
CLAIMED — lane openRepoShape-5, session 50cede29-ab82-4ca3-9f67-d98e1a58c8d2@Eagle, 2026-10-20T10:51:06Z, for #1054
Logged in
lanes/log/openRepoShape-5.mdatd67cf3dcad40bb4350f4b128b4cf66fea2004648.The three reads (lane-collision-protocol Rule 1):
tests/test_chain_remedy_callers.py: the row for a key typed in capita…
tests/test_chain_remedy_callers.py: three rows hold #980's unchanged …
validate-pins.py: a `--pin-source` key is the longest declared pin be…