Repository navigation
Description
The root's validate-manifest.py, and setup's step (4) through the naming gate, should offer only the sources each reads, as the scaffold does since #634, and the gate should spell every value it prints.
From the checklist triage of 2026-10-16, batches 4 and 5; Brett Heap approved its recommendations at 2026-10-16T12:14:51Z. One pull request covers the lines below.
Lands after: #634 (and #638, #623 and #631, all landed). Before the v1.1.0 tag.
Decision applied: DB8 (option 3) and DB9 (option b), plus D6: one re-pin for v1.1.0.
Lines
Line numbers are at the commits named; main has moved since.
- L2-68: the root's
validate-manifest.pyprints a WARNING that offers--link-source, a flag it does not take. Where:templates/assembly-root/scripts/validate-manifest.py_chain_and_links(:128-141, the call at:141), the WARNING (:173-174), the parser (:869-871); the text,scripts/repo_shape.py:1456-1463. Effort S; all. On main4cf5fb07: a scaffolded root whose manifest records[openXdox, openDox]makesvalidate-manifest.pyexit 0 with "(a sibling checkout, SHAPE_PIN_SOURCE_OPENXDOX, or --link-source openXdox=<path> would let it be read)", and--link-source openXdox=/nowheregivesunrecognized arguments. Main's library refusesremedies={}withTypeError. - L2-75: setup's step (4) shows the naming gate's
--link-sourceoffer and(--link-source)label for a value typed as--pin-source. Where:setup-project.pynaming_declarations(:1936-1957on main,:2036-2085at setup-project.py: step (3) refuses a parent nobody can write in and a drive that is not there, step (4) verifies a chain from--pin-source,--pinno longer takes a flag as its value, and step (5) says a printed plan was refused (#608) #623's 400965b) andcheck_names(:1964-1975);scripts/repo_shape.py:1456-1463(the offer) and:2826(the bare source's label);scripts/validate-repository-naming.py:330. Effort M; all. On main4cf5fb07: with-- --pin openXdox@<commit> --referent-chain openXdox,openDox, step (4) prints[declared-unverified]and the--link-source openXdox=<path>offer, even when--pin-sourcenames a tree that declares openDox and step (5) reads it. A three-link chain prints one offer per holder. Typing the offer ends step (5) withscaffold-project.py: error: unrecognized arguments, exit 2. At setup-project.py: step (3) refuses a parent nobody can write in and a drive that is not there, step (4) verifies a chain from--pin-source,--pinno longer takes a flag as its value, and step (5) says a printed plan was refused (#608) #623's head, a blank or missing--pin-sourceprintsWARNING link-source-unreadable: ... (--link-source) could not answer, and a later link keeps its offer.
Rides along (backlog; tick it here if the same change covers it)
- L2-69: the naming gate prints
--link-sourcevalues and paths raw, so an ESC reaches the terminal. Where:scripts/validate-repository-naming.pyread_as_path(:303-306),_also_a_directory(:315),unread_lines(:330,:336),no_path_refusal(:345-349) andunused_lines(:385,:395-397). Effort S; all. On main4cf5fb07: four of these prints were measured raw with an ESC, and so was:385's replaced value. 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 spells:330's path alone.
Notes for whoever takes it.
- Skew.
validate-manifest.pyruns in a project against whateverscripts/repo_shape.pythat root holds, and main'slink_pins_from_treestakes noremedies(TypeError, measured). There are three skew-safe forms:- pass
remedies=only where the function takes it; - word the validator's own remedy after the call;
- hand the library a mapping that carries
remediesas an attribute. 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's_chain_link_findingsreads it bygetattr(link_pins, "remedies", None)(:1457at 6dad64b), and main's never asks for it. This form was read, not run. - Test it beside main's
repo_shape.py, as rv610'sskew_run.shdid.
- pass
- What the validator reads.
validate-manifest.pypassesroot, so it reads a sibling checkout andSHAPE_PIN_SOURCE_<LINK>(rules 2 and 3 ofresolve_link_source,scripts/repo_shape.py:2791-2792,:2817-2824). Its words are those two. - Keying. 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 keysremediesbycasefold()(:1478,_link_remedies:956-963at 6dad64b), while repo_shape.py and validate-repository-naming.py: a chain link, a declared pin and a--link-sourcekey are one product bypin_product_key, the pin file's own fold, so a tree declaringopenssno longer verifies a chain that saysopenß, a chain naming both is two links and not a cycle, and--link-source openss=no longer answers foropenß(#444) #638 keys the chain readers bypin_product_key. rv610's fix-list item 7 suggests keyingremediesthe same way, and this issue inherits that if it extendsremedies. - Setup's side (DB9 b). Setup passes the gate its label and remedy where setup-project.py: step (3) refuses a parent nobody can write in and a drive that is not there, step (4) verifies a chain from
--pin-source,--pinno longer takes a flag as its value, and step (5) says a printed plan was refused (#608) #623 builds the bare--link-source=(setup-project.py:2084-2085at 400965b). Then the helper'sre.subintests/conftest.py:1789-1790goes. - Spelling. Use the gate's own
_shownthat 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 adds (:110-120at 6dad64b). Add one test row with an ESC for each print. - The re-pin. Both the gate and
validate-manifest.pyalready differ from v1.0.1 at main, so this issue adds no file to a project's v1.1.0 update.
Not a duplicate: #610 is the scaffold's half (576/2) and the spelling in repo_shape.py and validate-pins.py (L2-30, L2-31); #608 is L2-25; #443 and #444 are other faults in the same files.
Each line above is marked → this issue on its tracking issue. Tick it there too when this closes.
The lines as written on the tracking issues
L2-68 (P3; templates/assembly-root/scripts/validate-manifest.py, #634 review): the root's
validate-manifest.pyprints a WARNING that offers--link-source, a flag it does not take, and any fix has to work beside an olderrepo_shape.py.
- At 4cf5fb0
_chain_and_linkscallslink_pins_from_trees(chain, root)(templates/assembly-root/scripts/validate-manifest.py:128-141), and_naming_classification_findingsprints each text infound.referent.warningsasWARNING naming-referent-chain: ...(:173-174). The text is built inscripts/repo_shape.py:1458-1463and ends "or --link-source <link>=<path> would let it be read" (:1461-1462). The validator's parser takes--root,--policyand--quietand nothing else (:869-871). The wording is right for the naming gate, which takes the flag.- Measured on a scratch export of main: a scaffolded root whose manifest records the chain
[openXdox, openDox](the chainas_a_descendant_by_chainwrites,tests/test_manifest_validator.py:418) makesscripts/validate-manifest.pyexit 0 and print "... openXdox declaring a pin on openDox is a fact in openXdox's own tree, which is not reachable here (a sibling checkout, SHAPE_PIN_SOURCE_OPENXDOX, or --link-source openXdox=<path> would let it be read)." Typing the offer,validate-manifest.py --link-source openXdox=/nowhere, givesvalidate-manifest.py: error: unrecognized arguments: --link-source openXdox=/nowhere.- 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 (head 030fde0) giveslink_pins_from_treesaremedies=argument so the scaffold offers only the sources it reads (scripts/repo_shape.py:1461-1465and:2902at 030fde0). It does not touchvalidate-manifest.py, which passes none, so the validator still gets the naming gate's default text. rv610 saw that and noted that a fix which passesremedies=must still work where the root'srepo_shape.pyis older. Measured on a scratch export of main, which has noremedies=:link_pins_from_trees(['openXdox', 'openDox'], None, remedies={})raisesTypeError: link_pins_from_trees() got an unexpected keyword argument 'remedies'. A root'svalidate-manifest.pycan be newer than itsscripts/repo_shape.py(a half-applied update,--accept-local), and then an unguardedremedies=would end the validator in a traceback.- Direction: a skew-safe form. For example, pass
remedies=only wherelink_pins_from_treestakes it, or word the validator's own sentence after the call, and test it beside an olderrepo_shape.py.validate-manifest.pyis a pinned copy, so a change re-pins every project, and it should ride with this file's next change. rv610 names adopt-project.py, shape-doctor.py, validate-manifest.py:executerecords the plan's answers underanswered_paths:and a moved submodule names its row, so an answeredexamples/is not asked again and a deliberate move names no plan (#525) #617 (on main) and validate-repository-naming.py, validate-manifest.py and validate-pins.py: a project's ownneutral_product_pins:or a leg'snaming.referent_chain:that is not a list isvalidate-manifest.py's finding for that field in every gate that reads it, so5no longer endsmake validatein aTypeErrorand a scalaropenXdoxis no longer read as its characters (#443) #631 as other edits to it. Landing it before the v1.1.0 tag keeps that release's re-pin one.
L2-75 (P3; setup-project.py, #623 review): setup's step (4) shows the naming validator's own
--link-sourcewording for a value the person typed as--pin-sourceafter--, and setup takes no--link-source.
- On main. At 4cf5fb0
naming_declarationspasses the validator--pinsand--referent-chainand no source (setup-project.py:1936-1957), andcheck_namesruns it and nothing else (:1964-1975).runhands the child's output straight to the terminal (:275-278). So a chain the validator cannot read shows[declared-unverified]and one WARNING for each holder it cannot read. Each WARNING offers--link-source <link>=<path>as the way to let that tree be read (scripts/repo_shape.py:1459-1463, in the loop at:1440). The person never typed that flag, and setup does not take it.- Measured on a detached checkout of main, with
-- --pin openXdox@<commit> --referent-chain openXdox,openDox --pin-source '': step (4) printsCHAIN openXdox → openDox [declared-unverified]andWARNING declared-unverified: openXdox declaring a pin on openDox is a fact in openXdox's own tree, which is not reachable here (a sibling checkout, SHAPE_PIN_SOURCE_OPENXDOX, or --link-source openXdox=<path> would let it be read). A tree that does declare openDox, given as--pin-source, prints the same, though step (5) reads that tree (itspinline ends(local-clone)). A three-link chain,openXdox,openYdox,openDox, prints that WARNING once for openXdox and once for openYdox. Typing the offer,-- ... --link-source openYdox=<tree>, ends step (5) withscaffold-project.py: error: unrecognized arguments: --link-source openYdox=<tree>andREFUSED: the plan could not be produced (see above)., exit 2.- The plan speaks in
--pin-source's own words. For--pin-source ''it saysREFUSED pin-source-no-path: `--pin-source ''` names no path. An empty path would be read as the directory this runs in.(scripts/shape_materialize.py:2727-2731). For a source that cannot answer it saysREFUSED pin-source-unreadable: <path> could not answer for opensoft/openXdox @ <commit>: no such directory, with a Remediation that begins "point --pin-source at a clone of that repository that HAS the pinned commit" (:2512-2519).- On setup-project.py: step (3) refuses a parent nobody can write in and a drive that is not there, step (4) verifies a chain from
--pin-source,--pinno longer takes a flag as its value, and step (5) says a printed plan was refused (#608) #623's head (400965b, not on main). The PR passes the last non-empty--pin-sourceto the validator as a bare--link-source=(setup-project.py:2036-2085:names_a_sourceat:2081, the append at:2084-2085). That is L2-25's fix, so a tree that verifies the chain shows[verified](rv623g measured it). A source the validator cannot read now also names the flag in a label. The sentence is built atscripts/validate-repository-naming.py:330and its(--link-source)label comes fromscripts/repo_shape.py:2826. setup-project.py: step (3) refuses a parent nobody can write in and a drive that is not there, step (4) verifies a chain from--pin-source,--pinno longer takes a flag as its value, and step (5) says a printed plan was refused (#608) #623 changes neither file.- Measured on a detached checkout of 400965b:
--pin-source ' '(blank) prints on stderrWARNING link-source-unreadable: (--link-source) could not answer for openXdox: no such file or directory, and a--pin-sourcefolder that is not there prints the same line with that path. Step (5) then refusespin-source-unreadablein--pin-source's words. With the three-link chain and the first tree given, one hint is left, for openYdox,or --link-source openYdox=<path> would let it be read. Setup has no flag for a later link at all:--pin-sourceis the first link's tree alone (scripts/repo_shape.pyresolve_link_source(:2401-2402) and scripts/validate-repository-naming.py_link_sources_from_args(:408): a bare--link-source <path>answers for EVERY chain link that has no more specific source, so in a chain of three or more links one tree is read as two links' declarations and a correct chain is reported broken, a FINDING (exit 1) for a name that holds no direct pin on its referent #441), and onlySHAPE_PIN_SOURCE_OPENYDOXreaches the others. Typing the offer fails as on main.- rv623g saw the blank case and judged it no action: "a blank value goes as typed" is the setup-project.py: step (3) passes an unwritable parent or a missing drive, and step (4) shows a chain the plan verifies as
[declared-unverified]#608 L2-25 design, and it is identical at be44452. f623g saw the hint and left it, because it is the validator's text and outside that task's files. Its test helper strips that one spelling (assert_an_empty_pin_source_is_the_plans_to_refuse,tests/conftest.py:1789-1790at 400965b).- 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 (head 6dad64b) shows what the right words are. The scaffold's own_link_remediesoffers only the sources the scaffold reads (scaffold-project.py:931-965at 6dad64b, issue 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). Measured on a detached checkout of 6dad64b, which has no setup-project.py: step (3) refuses a parent nobody can write in and a drive that is not there, step (4) verifies a chain from--pin-source,--pinno longer takes a flag as its value, and step (5) says a printed plan was refused (#608) #623: the plan's WARNING for openYdox ends "(SHAPE_PIN_SOURCE_OPENYDOX would let it be read)", while step (4) of the same run still says--link-source openYdox=<path>for the same holder. After 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 one run says one fact two ways.- Severity is P3 for the reason L2-68 is: an offer, typed as printed, is refused. The
(--link-source)label alone would be a nit. The hint is advice, and every refusal in these runs comes at step (5), before anything is created, with the right exit.- Direction: one of two. (a) Setup re-words step (4)'s report: it captures the validator's output (
run(..., capture=True)) and prints it with--link-sourcereplaced by--pin-source. A plain swap is right for the first link only, and a later link needs the scaffold's words (SHAPE_PIN_SOURCE_<LINK>, as_link_remediessays it). Swapping text in a pinned tool's output also breaks without a sound when the gate's wording moves. (b) The naming gate takes a label for the flag it was given, and its hint takes the caller's remedy, as 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 does for the scaffold (remedies=, issue 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). That touchesscripts/validate-repository-naming.py:330andscripts/repo_shape.py:1459-1463and:2826, all pinned copies, so a change re-pins every project and should ride with the gate's next change, repo_shape.py and validate-repository-naming.py: a chain link, a declared pin and a--link-sourcekey are one product bypin_product_key, the pin file's own fold, so a tree declaringopenssno longer verifies a chain that saysopenß, a chain naming both is two links and not a cycle, and--link-source openss=no longer answers foropenß(#444) #638 (L2-69). It must still work beside an olderrepo_shape.py(L2-68's rule). (b) is the cleaner one: it is one place, and the test helper'sre.subgoes.
L2-69 (P3; scripts/validate-repository-naming.py, #634 review): the naming gate prints
--link-sourcevalues as typed, so an ESC in a value or a path reaches the terminal, in the "not used" NOTE, the unreadable-source WARNING and the "read as a PATH" line.
- At 4cf5fb0 the raw prints are
typedin the NOTE (scripts/validate-repository-naming.py:395-397,unused_lines),keyin the "read as a PATH" sentence (:303-306,read_as_path),typedtwice in_also_a_directory(:315),pathin the unreadable-source WARNING (:330, and:336for a source the gate did not take from the command line), andtypedin the no-path refusal (:345-349).- Measured on a scratch export of main with a value holding ESC
[31m(cat -vshows the raw byte as^[):--link-source x^[[31mwith no chain recorded printsNOTE --link-source x^[[31m: not used. With a chain,--link-source a^[[31m=b/openXdoxprints "It was read as a PATH:a^[[31mis not a link of a referent chain here (links: openXdox, openDox)." A tree directory namedtree^[[31mthat this user cannot read printsWARNING link-source-unreadable: .../tree^[[31m (--link-source openXdox=...) could not answer for openXdox: its project.yaml: Permission denied. A directoryopenXdox=y^[[31mpassed whole prints "openXdox=y^[[31mis also a directory;--link-source ./openXdox=y^[[31mreads it as one." Each of those four runs exits 0. The:336and:345-349prints were read, not run.- 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 (head 030fde0) spells the{path}at:330with a local_shown(rv610's F6) and leaves the rest. It writes_showninto this file rather than importingshown_path, because a root's olderrepo_shape.pyhas none. L2-30 and L2-31 above are the same class in the scaffold'srepo_shape.pytext and invalidate-pins.py, which 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 also spells.- Direction: spell the other prints with that
_shown, one test row per print with an ESC in it. The naming gate is a pinned copy, so a change re-pins every project. rv610 notes that repo_shape.py and validate-repository-naming.py: a chain link, a declared pin and a--link-sourcekey are one product bypin_product_key, the pin file's own fold, so a tree declaringopenssno longer verifies a chain that saysopenß, a chain naming both is two links and not a cycle, and--link-source openss=no longer answers foropenß(#444) #638 edits the neighbouringLinkSourceshunks, so do it after repo_shape.py and validate-repository-naming.py: a chain link, a declared pin and a--link-sourcekey are one product bypin_product_key, the pin file's own fold, so a tree declaringopenssno longer verifies a chain that saysopenß, a chain naming both is two links and not a cycle, and--link-source openss=no longer answers foropenß(#444) #638 lands and before the v1.1.0 tag, and with 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's_shownalready in the file.
Activity
brettheap commentedon Oct 16, 2026
CLAIMED — lane openRepoShape-2, session 81650e29-c906-4fe8-96c9-55580bfe0c44@Eagle, 2026-10-16T12:45:21Z, for #661
Logged in
lanes/log/openRepoShape-2.mdat1f1d87eba1df44269647ec3cd9084b6568944a06.The three reads (lane-collision-protocol Rule 1):
#661 round 2 (rv661): one assert per condition, the gate's docstring …
validate-manifest.py, the naming gate and setup-project.py: a chain l…
shape_materialize.py: `readable_branch` and `UNSEEN` move out of the …