Repository navigation
adopt-project.py: _pin_row_problem says a pin field whose value is not text as _read_as says what the plan's reader read, "records commit: as the number 7", where it spelled it as Python does, commit: 7 and True, so check and execute name it in the words the plan's other refusals use under the same plan-pin-malformed (#1114) - #1198
brettheap wants to merge 1 commit into
Conversation
…not text as `_read_as` says what the plan's reader read, "records `commit:` as the number 7", where it spelled it as Python does, `commit: 7` and `True`, so `check` and `execute` name it in the words the plan's other refusals use under the same `plan-pin-malformed` (#1114) `_pin_row_problem` held each of a pin's five fields (`product`, `repository`, `commit`, `tree_sha256`, `digest_source`) to text and spelled a value that is not text with `repr`: a number as `commit: 7`, a boolean as `True`, a list as `['a', 'b']` and a mapping as `{'k': 'v'}`. Every other refusal of a plan's value says what the reader read (`_read_as`): "the number 7", "the boolean true", "a list of 2 item(s)", "a mapping of 1 key(s)". It says it that way now, field by field: "records `commit:` as the number 7, which is not text", and for two or more "records `commit:` as the number 7, `tree_sha256:` as the boolean true, which are not text". What stays as it was: the code (`plan-pin-malformed`), the sentence's ending, and every text value's spelling byte for byte (`commit: '7'`, which is not 40 hex). A null or a blank is "records no `commit:`" under the code it has always had, and spells no value. The other `!r` in the pin rows are on a value that is text by then: the later branches of `_pin_row_problem`, a text product in the entry's name, and an entry that is a name. An entry that is neither a name nor a mapping is #1020's, in #1125. tests/test_adopt_pin_row_values.py runs each of the five fields with a number, a boolean, a list and a mapping through `check` and `execute`, with the edges of `_read_as`, two fields at once, null and blank rows, and text controls. tests/test_adopt_pins.py and tests/test_adopt_plan_value_order.py had one row each that pinned the old spelling. Lane: openreposhape-4 (openRepoShape-4) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Reviewer's GuideUpdates malformed pin diagnostics so non-text values are described using Flow diagram for malformed pin value diagnosticsflowchart LR
PinField["Pin field value"] --> Missing{"Null or blank?"}
Missing -->|Yes| NoRecord["records no field"]
Missing -->|No| Text{"Text value?"}
Text -->|Yes| Existing["Existing text validation and spelling"]
Text -->|No| ReadAs["_read_as(value)"]
ReadAs --> Diagnostic["records field as reader description"]
Diagnostic --> Refusal["plan-pin-malformed"]
File-Level Changes
Assessment against linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
|
RV1198: independent review of #1198 at RV1198 started this review and stopped at an account swap with nothing posted. RV1198-cont finished it with RV1198's scripts, and did not redo the measurements RV1198 had already made. This is the one comment. No MUST and no SHOULD. There are three NITs, all for follow-ups. Two predate this PR and are equally true on main: one in the plan's reader and one in What was measured
GateThe gate ran on a scratch merge,
MutantsThere were 32 mutants of this head's
B-float-repr is killed by one row only, the Merge-treesThis head was merged with
Every merged tree keeps the new #1125, looked at closely.
FindingsNIT-1 (predates this PR; in
NIT-2 (predates this PR; in the plan's reader): a plain integer of more than 4300 digits ends
NIT-3 (the PR body only): the release-notes paragraph cites the wrong lines.
Not a finding. Some different plan spellings get the same words, because the reader reads them as the same value. Lane: openreposhape-4 (openRepoShape-4) |



Closes #1114
This PR lands only after the v1.2.0 tag, on Brett's word.
What
_pin_row_problemholds each of a pin's five fields (product,repository,commit,tree_sha256,digest_source) to text. A value that is not text it spelled with Python'srepr: a number ascommit: 7, a boolean asTrue, a list as['a', 'b']and a mapping as{'k': 'v'}. Every other refusal of a plan's value says what the reader read, with_read_as: "the number 7", "the boolean true", "a list of 2 item(s)", "a mapping of 1 key(s)". W1020 found the gap while working on #1020.It says it that way now, field by field, in
adopt-project.py's_pin_row_problem, in thenot_textbranch only:records `commit:` as the number 7, which is not textrecords `commit:` as the number 7, `tree_sha256:` as the boolean true, which are not textWhat stays as it was:
plan-pin-malformed, the remedy, and the sentence's ending,which is not text;commit: '7', which is not 40 hex);commit:" under the code it has always had, and no value is spelled there.Every field takes the one site (
PIN_FIELDS). The docstring and a comment say so. The change is 13 lines added and 4 removed inadopt-project.py.Behaviour change
A pin field that is a number, a boolean, a list or a mapping is named by what it was read as, where it was named as Python spells it. A text value, a null and a blank print as they did.
Rows
tests/test_adopt_pin_row_values.pyis new, ASCII only, with 45 rows. Each runscheckand thenexecute --yes, with a stubghfirst on PATH and--local-remote-dir, and asserts one finding,executerefusing with that same finding, an emptyghlog, no remotes directory made and no Traceback.commit: 7, and a booleandigest_source[],{},[a]commit: "7"and"true", another product, no owner, short digest, source by hand)Every one of the 33 failures is the finding text holding the repr spelling (
records `commit: 7`,True,['a', 'b'],{'k': 'v'},{},[]). There is no crash or other cause. The 12 that pass on main are the controls, which pin what must not change.Two existing rows pinned the old spelling, and no others did. Each now expects the new one, and both pass on this head (2 passed):
tests/test_adopt_pins.py, thea-number-commitrow:`commit:` as the number 1234567;tests/test_adopt_plan_value_order.py, thenot-textrow:`digest_source:` as the number 7.Mutants
19 mutants of this head's
adopt-project.py, all killed. Each was run against the new file (first failure with-x, or a whole run where the table says so), and each run was restored with its sha256 checked.!rinside the new "as" formstr()in place of_read_asmissingtakes any falsy value (an existing guard; the zero, false and empty rows pin it)plan-pin-unrecordedGate
A scratch merge of this head
d38e4e36dwith main961640c68: commit1ef3f0783, treeb12197610, which is this head's own tree. Targeted files only, in the landing gate's environment (a stubghfirst on PATH,GH_TOKEN=bogus, an emptyGH_CONFIG_DIR, an empty global git config). The set is 47 test files: every one that namesplan-pin-malformed,plan-pin-unrecorded,_pin_row_problem,_read_pinsorpins:, the new file, andtest_path_guard_hygiene.py,test_repo_hygiene.pyandtest_scaffold_leg_path_collisions.py; andtest_shape_doctor.py(448 ids, each in exactly one shard, run from a script that reads each list into an array because 25 ids hold spaces). Every chunk exited 0, with 0 failed.test_adopt_pins.pytest_adopt_plan_yaml_quoting.py,test_adopt_plan.pytest_adopt_execute_refusals.py,test_adopt_pin_row_values.py,test_adopt_plan_escapes.py,test_adopt_plan_value_order.py,test_adopt_reencoded_files.py,test_adopt_root_symlinks.py,test_adopt_shape_pin_and_work_dir.py,test_adopt_template_values.pytest_bump_remedies_family_root.py,test_chain_link_fold.py,test_chain_pin_sources.py,test_chain_remedy_callers.py,test_doctor_gitlink_repairs.py,test_doctor_recorded_answers.py,test_family_add_member_id.py,test_family_makefile_siblings.pytest_family_tracking_branch.py,test_legs_not_a_list.py,test_link_source_chain_defaults.py,test_manifest_validator.py,test_naming_policy.py,test_neutral_pin_entry_one_spelling.py,test_neutral_pin_validator.py,test_non_list_project_fields.pytest_path_guard_hygiene.py,test_pin_annotated_tag.py,test_pin_source_env_collisions.py,test_pinned_copy_text.py,test_reader_refusals_named.py,test_repo_hygiene.py,test_scaffold_e2e.py,test_scaffold_leg_path_collisions.pytest_scaffold_pin_and_reuse.py,test_scaffold_pin_collisions.py,test_scaffold_referent_chain_links.py,test_setup_project_py.py,test_template_text_placeholders.py,test_update_shape_add_ignored.py,test_update_shape_landing.py,test_validate_pins_named_and_spelled.pytest_yaml_flow_brackets.py,test_yaml_flow_quotes.py,test_yaml_indicator_openers.py,test_yaml_reader_spaces.pytest_shape_doctor.py, 56 idsThe file chunks hold 4919 passed and 4 skipped (f02:
SHAPE_MEDXEHR_CLONEis unset; f03: the reftable backend needs git 2.45). The doctor shards hold 445 passed and 3 skipped (d08: the PowerShell line is printed only on a Windows host). In all, 5364 passed, 7 skipped, 0 failed.Run on the merge with #1125's head. A scratch merge of this head with #1125's head
9549006fe: commit8a291d8b2, tree88530bb7. The new file (45),test_adopt_pins.py(150),test_adopt_plan_value_order.py(40),test_adopt_execute_refusals.py(181) andtest_adopt_check_plan_name.py(45): 461 passed.Merge-trees
git merge-tree --write-tree, this head against each, all clean (exit 0), at the heads of 2026-10-23T08:20Z:origin/main961640c68;adopt-project.py: adopt-project.py:_github_namereads no owner over 39 characters or repository over 100, soplan --source <50 b's>/Thingnever asksghfor a name GitHub cannot hold, no remedy offers--org <50 b's>, andcheckandexecutenever clone such a record again (#1129) #1194900f77af9, adopt-project.py:planruns withGIT_NO_LAZY_FETCH=1, refuses a partial-clone--sourcethat lacks objects assource-partial-clone, and names a partial--pin-sourceit could read only by fetching and the fetch that makes it whole (#1162) #119000f959c61, adopt-project.py:checknames the case twins the plan keeps in one repository asplan-case-twinson every disk, a one-blob set as a NOTE in a leg and, in the root, two paths in one folder, andexecuterefuses the finding before any leg (#1161) #11894d40ce9fd, adopt-project.py: a--source, or a plan'ssource.local_path, with a part of its repository git reads at mode 000 (the.git, itsHEAD,objects,refsorconfig, the git directory agitdir:line names, or a directory above it) is refusedsource-unreadablenaming that part, nevergit-failedand never cloned again (#1151) #118607486a498, adopt-project.py:checkandexecuterun withGIT_NO_LAZY_FETCH=1and refuse a partial-clone source that lacks an object its branches, tags or HEAD reach assource-partial-clone, so neither fetches into the source any more (#1145) #1180b316f4157, adopt-project.py:plan's table pads each name by the columns a terminal gives it, not the code points it holds, so a wide or combining name'slegcolumn lines up underlegwith every other row's (#1034) #1178c4beba193, adopt-project.py: the--planpath incheckandexecute, and the--local-remote-dirpath inexecute'sbare, leg andsplitlines, are named with_shown, as #1154 names--outand--work-dir, so a bidi control, an escape, a line feed or a byte that is not UTF-8 in either no longer reaches the terminal as it was typed (#1152) #11775208e874e, adopt-project.py and repo_shape.py: a name that holds a default-ignorable character, which a terminal draws as nothing, is spelled by its code point inplan's lines and in theunsafe-valuerefusal, so a branchma<U+034F>inno longer prints asmain(#1128) #11718162b874e, adopt-project.py:checknames each case twin at the shape's copy, above it and at the manifest, before a link there or after it, and at a pin's file whose exact spelling holds nothing, as_KeptTreekeeps every row, not the first (#1138) #117024ee133aa, adopt-project.py:check's rehearsal and_stored_as_writtentake a parent's-csettings,attr.treetoo, and the source's objects,GIT_ATTR_SOURCEis refused by name before any question, and each throwaway reads its environment first (#1136) #1169258051022, adopt-project.py:plan written toandcloning <repository> (read only) intoname the caller's--outand--work-dirwith_shown, as the other lines of the report name a path, so a bidi control, a line feed or a tab in either no longer reaches the terminal as it was typed (#1115) #11548a7828332, adopt-project.py: under a one-byte locale such as Latin-1, a clonecheckmakes again for a plan's clone record that neither spelling names is compared with both, so it is kept and the next run reads it rather than cloning again (#1112) #1153ff33ba12a, adopt-project.py: a--work-dirlink into a loop that Python 3.12 reads past a link that does not loop names the loop, Windows' winerror 1921 counts as one, and a path read as the loop's link says so, with tests for r1065's mutants (#1074) #11437af5fabc3, adopt-project.py: a recorded source whose.gitthis user cannot read is refusedsource-unreadable, naming that.git, socheckandexecuteno longer call a cloneplanmade with its.gitat mode 000 no longer whole and clone it again (#1099) #11417a2711d03, adopt-project.py:checkandexecuteask a plan'sorg:andid:right after its three repository names, so a bad one beside an unanswered entry, a moved source, a refused name or another repository is that one refusal in both, and apins:entry that is no pin is said as_read_assays it (#1020) #11259549006fe, README.md, adopt-project.py and the handbook: a kept directory entrymakefile/is tested, README saysmakeat the root reads a keptGNUmakefileormakefileinstead, and a docstring says the shape's Makefile alone holdsCONTRACTS_DIR(#1061) #11235c3908f8d, adopt-project.py: anorg/repo--sourcetoo long for the disk is refused as a path is, naming no GitHub repository and offering no url, so--source <300 a's>/Thingis no longer offeredhttps://github.com/<300 a's>/Thing, which can never clone (#1003) #1122c01c4d73d, adopt-project.py:execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #11211c5173758, adopt-project.py:plan'ssourceline names the source's branch as_shownnames a path, so a bidi control, a line boundary or a byte that is not UTF-8 in it is spelled and no longer reaches the terminal raw (#1035) #1120c55e55e33, adopt-project.py: check asks the split's own clone of the source in the work directory, so a clone this git will not make is adopt-git-unasked before any leg, and _resolved and _answers make their repositories as check's other throwaways do (#1083) #1119bba168bdd, adopt-project.py, shape_materialize.py and tests: a named bad link left out of the copy and pin findings takes no other path's finding with it, and the docstrings and the materializer's refusal name the #979 exception and what helps it (#1089) #11182307036ab, adopt-project.py: under a one-byte locale such as Latin-1,checkreads a plan written in UTF-8 whose source is there, asking the plan's UTF-8 bytes where the spelling as written names nothing, rather than refusingplan-source-gone(#1078) #1106504a1dd65, shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105b28f40de0;COMMIT_RE,SHA256_REandCOMMIT_40end in\Z, not$, so a pin'scommit:ortree_sha256:that ends in a line break is refused as not 40 or 64 hex by every validator andadopt-project.py(#1017) #11264c1f80cf4, which touchestests/test_adopt_pins.py.This PR needs no #1125
#1125 (for #1020) makes
_read_pinssay an entry that is not a pin as_read_assays it. Itsadopt-project.pyhunks are at the_read_pinsdocstring and at the non-dict entry's{row!r}(about line 625 on main), and they do not touch_pin_row_problem. Its test hunks do not overlap the lines this change edits. The two are textually independent: this PR is based on main, not stacked, the merge-tree with #1125's head is clean, and the run above on the merge with its head passed.An entry that is neither a name nor a mapping stays #1020's, in #1125.
Not in this PR
The other
reprin the pin rows are on a value that is text by then: the later branches of_pin_row_problem(spelled as before), a text product in an entry's name, and an entry that is a name. They are not gaps.docs/release-notes/v1.2.0.mdis left alone. Its lines 297 to 299 mention #901's pins wording, and the release owner may want a line there.Out of scope
Four other places in
adopt-project.pyput a plan value of any type into a refusal with!r, as the pin rows did:plan-wrong-kind,plan-unsupported-mode,plan-bad-legandplan-bad-id. They are not pin rows, so this change leaves them. They were found by reading the code, not by running it. They are filed as #1199, with each site's line and what it would print.🤖 Generated with Claude Code
Lane: openreposhape-4 (openRepoShape-4)