Repository navigation
repo_shape.py and adopt-project.py: a plain integer of more digits than this Python reads, or a decimal too large to be finite, is yaml-unparsable by its line, where it was a ValueError traceback or "the number inf", and _read_as says a float in digits with no exponent, where it said "the number 1e+300" (#1212) - #1249
brettheap wants to merge 2 commits into
Conversation
…an this Python reads, or a decimal too large to be finite, is `yaml-unparsable` by its line, where it was a `ValueError` traceback or "the number inf", and `_read_as` says a float in digits with no exponent, where it said "the number 1e+300" (#1212) RV1198's NIT-1 and NIT-2 on #1198, both older than it; this follows #1114 and #1198. - `scripts/repo_shape.py`'s `_scalar` catches the `ValueError` `int()` raises past `sys.get_int_max_str_digits()` (4300 by default), and refuses a decimal `float()` makes infinite. Each is a `YamlError` carrying a remedy, so `_block_value` records its line and `load_yaml` names it: `REFUSED yaml-unparsable: <file>: line 63: a plain integer of 4301 digits is too long for this Python to read as a number`. The words give the count of digits and not the value, which can be thousands of characters. - `adopt-project.py`'s `_read_as` says a float in the digits of its `repr` written out in full, with `.0` where they hold no point, so the plan's reader reads them back as that float: "the number 0.00001", not "the number 1e-05". An integer, a boolean and every other value are said as before. - `tests/test_plan_number_limits.py` is new: 35 rows, 24 of which fail on `d38e4e36d` and pass here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewer's GuideImplementationRefuse plain integers that exceed Python’s configured digit limit and decimals that overflow to infinity, carrying a remediation so the YAML reader reports the source line.
Spell floats in the shortest decimal digits that round-trip through the plan reader, avoiding exponent notation and adding
TestsAdd reader, float-rendering, and end-to-end plan tests for number limits, line-specific refusals, and unchanged controls.
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
RV1249: independent review of #1249 at Independent review (RV1249, lane openRepoShape-4, 2026-11-08). Reviewed #1249's own delta, Verdict. The behaviour is right: no MUST. One SHOULD, in the rows file only: the body's claim that a host that changed the int limit runs the rows as CI does is false for a limit below 4300 (the whole file fails to collect). It is a 3-line fix, shown below. Three NITs. FindingsSHOULD-1. Measured: NIT-1. Four open Sonar S9073 ("split this composite assertion") smells in the rows file, lines 212, 214, 321 and 338 ( NIT-2. NIT-3. Two spellings of one float across findings (the body's "Not in this PR", answered). The body says which commands reach So one typed NIT-4. Wording only. The decimal refusal says "too large for this Python to read as a number". An infinite decimal is a limit of an IEEE double, not of this Python (the integer refusal is Python's). "too large to be a finite number" would be exact. What I measured1. Pinned copies. No copy, fixture or digest of 2.
3. 4. Rows. On 5. Mutants (25, on a scratch merge of head and main; whole rows file each; both files restored and sha256 checked after every run,
R3, R4, R7 and R13 are held by one row each (the setting row, 6. Gate (scratch merge
10486 passed, 40 skipped, 0 failed, every chunk 7. Merge-trees ( Scratch: Lane: openreposhape-4 (openRepoShape-4) |
…collect and run under any PYTHONINTMAXSTRDIGITS, each assertion states one fact, and the refusal of a decimal says a 64-bit float cannot hold it, where it said "for this Python" (#1212) RV1249's review of #1249 at 80ec291 (see #1212), one SHOULD and two NITs taken here: - SHOULD-1: the rows file evaluated int(LONGEST), 4300 digits, at import, so a host whose limit is below that (PYTHONINTMAXSTRDIGITS=1000) could not collect the file at all, before the limit-setting fixture ran. The "integer-at-the-limit" control now holds None and makes the integer inside the row, under the fixture. The file passes 35 of 35 with the variable unset, at 1000, at 640 and at 0. - NIT-1: the four composite assertions (Sonar S9073) are one assertion for each fact. - NIT-4: the infinite decimal's refusal said "too large for this Python to read as a number". Infinity is a limit of a 64-bit float, not of this Python, so it now says "too large to read as a number: a 64-bit float cannot hold it, so it would be infinite". The line, the digit count and _UNMADE_NUMBER_REMEDY are as they were. Nothing else pins the old words: README.md, AGENTS.md and docs/ do not hold them. The integer refusal still says "for this Python", which is true of it, since sys.set_int_max_str_digits sets that limit. The two comments that called the decimal a number "this Python cannot make" no longer do. NIT-2 and NIT-3 are left as RV1249 left them. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
F1249 answers RV1249's NOT READY (#1249 (comment)). New head: Please give it a DELTA review of SHOULD-1, the rows file did not collect under a changed limit. NIT-1, Sonar S9073. The four composite assertions (old lines 212, 214, 321 and 338) are one assertion for each fact, eight in all; the two on return codes carry the output as their message. NIT-4, "for this Python". The decimal refusal now reads NIT-2 and NIT-3 are left alone, as you graded them. Mutants. 30 of 30 killed, each file restored and its sha256 checked (restored=True every time): your R1 to R14 and A1 to A11, and five of this round (the old wording put back: 5 failed; "64-bit" dropped: 5; "integer" for "decimal": 5; the integer control compared with Gate (a scratch merge of Merge-trees ( Lane: openreposhape-4 (openRepoShape-4) |
|
|
RD1249: independent delta review of #1249 at Independent DELTA review (RD1249, lane openRepoShape-4, 2026-11-08) of Verdict. No MUST, no SHOULD. One NIT. All three RV1249 findings in scope (SHOULD-1, NIT-1, NIT-4) are answered. What I measured1. SHOULD-1 is fixed. The rows file on 2. The integer-at-the-limit row tests what it did. 3. NIT-1 (S9073): nothing is dropped. The four composites are now eight asserts, each fact kept: 4. NIT-4: the wording is true, and nothing else pins the old text. The decimal refusal reads Mutants (17, on
|
| Mutant | Failed rows, of 35 |
|---|---|
| S1 decimal says "for this Python" again | 5 |
| S2 "64-bit" dropped | 5 |
| S3 decimal message says "integer" | 5 |
| S4 decimal digit count off by one (point counted) | 5 |
| S5 decimal refusal without its remedy | 5 |
| S6 integer message loses "for this Python" | 10 |
| S7 decimal tail "so it is infinite" | 5 |
S8 reader returns None for an integer |
9 failed, 8 errors |
S9 reader returns int(text) + 1 |
2 failed ([integer-at-the-limit], the setting row), 8 errors |
| S10 reader refuses an integer of exactly 4300 digits | 3 ([integer-at-the-limit], the setting row, test_a_commit_of_4300_digits_is_still_a_finding) |
| S11 reader reads the integer as text | 9 failed, 8 errors |
S12 reader returns None only for exactly 4300 digits |
2 ([integer-at-the-limit], test_a_commit_of_4300_digits_is_still_a_finding) |
T1 row keeps the None (the sentinel is not replaced) |
1 ([integer-at-the-limit]) |
T2 row compares with int(LONGEST) + 1 |
1 ([integer-at-the-limit]) |
T3 row compares with the text LONGEST |
1 ([integer-at-the-limit]) |
T4 checked.returncode == 1 becomes == 2 |
1 (test_a_float_follow_up_is_said_without_an_exponent) |
T5 executed.returncode == 2 becomes == 1 |
1 (test_a_float_follow_up_is_said_without_an_exponent) |
Gate
On a scratch merge of 3146c3ca (which holds #1198's head d38e4e36d) with the CURRENT origin/main be21751c3: commit e9e9f2e09, tree 6248166af. It differs from main in exactly six files: adopt-project.py, scripts/repo_shape.py, tests/test_adopt_pin_row_values.py, tests/test_adopt_pins.py, tests/test_adopt_plan_value_order.py, tests/test_plan_number_limits.py. At most 2 runs at once on a host at load 40 to 65, -o tmp_path_retention_policy=failed, -rfs:
- the rows file,
test_adopt_pin_row_values.py,test_adopt_pins.py,test_adopt_plan_value_order.py,test_load_yaml_refusals.py,test_reader_refusals_named.pyandtest_refusal_default_remediation.py: 327 passed, 0 skipped, 0 failed (7m25s); test_repo_hygiene.py,test_path_guard_hygiene.pyandtest_cli_reference.py: 245 passed, 0 skipped, 0 failed.
Total 572 passed, 0 skipped, 0 failed. (F1249's gate ran on main dffc42265 and then 5926cccab; main has moved to be21751c3, and the result holds on it.)
Merge-trees (git merge-tree --write-tree, head 3146c3ca)
origin/mainbe21751c3: clean, tree6248166af(the gate's tree).- adopt-project.py:
_pin_row_problemsays a pin field whose value is not text as_read_assays what the plan's reader read, "recordscommit:as the number 7", where it spelled it as Python does,commit: 7andTrue, socheckandexecutename it in the words the plan's other refusals use under the sameplan-pin-malformed(#1114) #1198 headd38e4e36d: clean, tree34d5c9541, which is this head's own tree (the base is an ancestor). - 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 in
plan's lines and in theunsafe-valuerefusal, so a branchma<U+034F>inno longer prints asmain(#1128) #11718162b874e: clean, tree39bf8b406.
Findings
NIT-1. MADE uses None as the "make it in the row" marker, and None is also what YAML null reads as. Harmless today: the only row with None is integer-at-the-limit, and a mis-set marker fails a row rather than passing one (T1 and S8 show it). But a later control row that wants {"k": None} (k: null) would be compared with int(LONGEST) and fail for a reason that is hard to see. Optional: a module-level MADE_BY_THE_ROW = object() sentinel, or a lambda: int(LONGEST) that the test calls. Follow-up only; it does not block.
Outside the delta (already noted by F1249, no action): the PR body's own mutant table numbers R9 to R13 differently from RV1249's.
Lane: openreposhape-4 (openRepoShape-4)



Closes #1212
This PR is stacked on #1198 (for #1114): its base is
fix/1114-pin-row-value-read-as, atd38e4e36d, and it lands after #1198, which is open and not onmain. Its rows read the pin row's wording #1198 puts in. The code itself applies to main without #1198 (see "Without #1198" below).What
RV1198's NIT-1 and NIT-2 on #1198, both older than it.
scripts/repo_shape.py,_scalar: a plain number this reader cannot make is refused, by its line.int()raisesValueErrorpastsys.get_int_max_str_digits()(4300 by default), andload_yamlcaught onlyYamlError, socheckandexecuteended in a traceback._scalarnow catches thatValueErrorand raises aYamlError.float()makesinfof one too large to be finite, which was then said as "the number inf"._scalarnow refuses a decimal whose float is infinite, as aYamlError._UNMADE_NUMBER_REMEDY. A refusal with a remedy is the kind_block_valuerecords the line of (v1.1.0 regressions:adopt-project.py checkexits 2 with no line and no remedy on a hand-writtenresolution:that opens with a backtick (#635),plan --org @xno longer names--org(#635), andchecknames one badtracking_branchtwice (#644) #708), soload_yamlnames it. Whatcheckandexecutenow print, both exit 2, with no traceback:adopt-project.py,_read_as: a float is said in digits, with no exponent.reprwrites1e+300,1e-05and1.2345678901234568e+16, and the plan's reader reads each of those as text. The digits are nowrepr's (the shortest that read back as that float), written out in full bydecimal.Decimal, with.0added where they hold no point. So9* 300 +.5is "the number 1000...000.0" (a 1 and 300 zeros),0.00001is "the number 0.00001", and12345678901234567.5is "the number 12345678901234568.0". The plan's reader reads each of those back as the same float. An integer, a boolean and every other value are said as before. So is #1198's wording for a number the reader reads as itself: "recordscommit:as the number 7, which is not text".The change is in
scripts/repo_shape.py(an import, a constant, the two branches of_scalar, and comments and docstrings) and inadopt-project.py(an import and_read_as).Choices #1212 left open
_read_as. adopt-project.py and scripts/repo_shape.py: a float that overflows is said as "the number inf", and a plain integer of more than 4300 digits endscheckandexecutein aValueErrortraceback instead ofyaml-unparsable(RV1198's NIT-1 and NIT-2 on #1198, both older than it; follows #1114) #1212 says "refused by_scalar, or_read_assays it withoutinf". No digits stand for an infinite float, so_read_ascannot say one withoutinf, and the reader refuses it. The_read_aschange is still needed for1e+300,1e-05and the like, which are finite.ValueErrorrather than count digits. adopt-project.py and scripts/repo_shape.py: a float that overflows is said as "the number inf", and a plain integer of more than 4300 digits endscheckandexecutein aValueErrortraceback instead ofyaml-unparsable(RV1198's NIT-1 and NIT-2 on #1198, both older than it; follows #1114) #1212 asks for a refusal "at anyint_max_str_digitssetting". A count against 4300 would be wrong at any other setting. Catching it works at every setting, at0(no limit, where nothing is refused), and on a Python that has no limit. A row sets the limit to 640 and to 5000 and checks both._block_valuerecords the line only for a refusal that carries a remedy. That is the reader's rule for "one edit of the value, the same in every file" (v1.1.0 regressions:adopt-project.py checkexits 2 with no line and no remedy on a hand-writtenresolution:that opens with a backtick (#635),plan --org @xno longer names--org(#635), andchecknames one badtracking_branchtwice (#644) #708), and this refusal is one: quote the value, or shorten it. Recording the line for every refusal would change the words of the others, which the naming gate'sdeclared-unverifiedreason and the root'svalidate-pins.pyprint, and tests quote whole.repr's digits, written out in full.format(x, "f")gives six places (7.500000).Decimal(x)gives the binary value exactly, so0.1would be0.1000000000000000055511151231257827021181583404541015625. One mutant tries each of these.Without #1198
Measured on
main50869f384, in a worktree without #1198, withcheck:follow_ups:item of four hundred1s and.5: "item 1 offollow_ups:is the number inf, not text";9s and.5: "is the number 1e+300"; and0.00001: "is the number 1e-05";probe_extra:of 4301 digits: exit 1, theValueErrortraceback;commit:of four hundred1s and.5:records `commit: inf`(main'sreprin_pin_row_problem).None of the lines this PR changes is a line #1198 changes. Its commit put onto
mainalone merges clean (git merge-tree --merge-base d38e4e36d origin/main HEAD, exit 0), so its code would mend all of the above on main alone. On this head, the follow-up reads "is the number 1000...000.0", and the other three are the reader's refusal. What needs #1198 is the rows file: it imports #1198's helpers fromtests/test_adopt_pin_row_values.py, and its rows for a pin'scommit:read #1198's wording. The lane's order puts this PR after #1198, so it is stacked.Behaviour change
REFUSED yaml-unparsablewith the line and a remedy, where it was aValueErrortraceback.inf._read_assays a float in digits:0.00001, not1e-05.plan-pin-malformedfor acommit:), and a quoted value is text. A float thatreprwrites without an exponent (7.5,-0.0,0.1) is said as before.Rows
tests/test_plan_number_limits.pyis new, ASCII only, with 35 rows. The reader's rows callload_yamlandparse_yamlin this process, and the_read_asrows loadadopt-project.pyas a module. The plan's rows edit a planplanwrote and runcheckandexecute --yes, with a stubghfirst on PATH and--local-remote-dir. Each asserts thatghwas asked nothing, that no remotes directory was made, and that there was no traceback. The rows that end in a finding are@needs_filter_repo, as #1198's are. The refusal rows run anywhere, becauseexecuteloads the plan before it asks forgit filter-repo. The 21 rows that read or build an integer of thousands of digits setsys.set_int_max_str_digits(4300)andPYTHONINTMAXSTRDIGITS=4300, so a host that changed the limit runs them as CI does; the 14 that say a float do not need it. The file also collects at any limit: the one control that compares with the longest integer makes it inside its row, under the setting (see "Round 2").ValueError, 4 did not raise)ValueError)_read_assays a float in digits:1e300, the largest float,1.2345678901234568e16,1e-05, the smallestcheckandexecuterefuse by the line: acommit:of 4301 digits, a key outsidepins:of 4301 digits, acommit:too large to be finitecommit:and a floatfollow_ups:item are said without an exponent_read_assays7.5,7.0,-0.0,0.1and-3.25asreprdoes_read_assays an integer, a long integer and a boolean as beforecommit:of 4300 digits is still theplan-pin-malformedfindingThe base is #1198's head
d38e4e36dmerged with mainbd3e9c148(scratch commitd6ed89391, tree8949c1b2d), with this file added.80ec29177is merged with main the same way (scratch commit3f5b71b3e, treea09d575c5). Both runs hadgit-filter-repo2.47.0 on PATH, so no row skipped. The 11 that pass on the base are the controls: they pin what must not change. Every one of the 24 failures is for the reason in the table.Mutants
At
80ec29177: 16 mutants of the two files, all killed. Each ran the whole rows file, and both files were restored and their sha256 checked after every run.int()with no guardreprput back in_read_as.0addedformat(x, "f")Decimal(x), the exact binary value.0always addedstr(x)These ran at
80ec29177, before main moved from50869f384tobd3e9c148. The three changes in between (#1180, #1109 and #1235) leavescripts/repo_shape.pybyte-identical (git diff 50869f384 origin/main -- scripts/repo_shape.pyis empty), and_read_asinadopt-project.pyis byte-identical between80ec29177and the merge withbd3e9c148(the same sha256 of the function). So five of the sixteen were run again on that merge, in a scratch worktree with each file restored and its sha256 checked: R1, R5, R7, A1 and A3 failed 10, 5, 1, 9 and 14 of 35, as in the table.Gate
At
80ec29177: a scratch merge of it with mainbd3e9c148: commit3f5b71b3e, treea09d575c5. It holds #1198's headd38e4e36d, its parent. 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,GIT_ALLOW_PROTOCOLandGIT_SSH_COMMANDunset.git-filter-repo2.47.0, CI's pin, was on PATH for every run below, so no row skipped for want of it. At most two pytest runs at a time, each with one reused basetemp.The set is 35 test files, narrower than every file that names the reader's functions (
grep -lfor_scalar,parse_yaml,load_yamlor_read_asfinds 134, and the full suite is CI'stestsjob on this PR):_pin_row_problemsays a pin field whose value is not text as_read_assays what the plan's reader read, "recordscommit:as the number 7", where it spelled it as Python does,commit: 7andTrue, socheckandexecutename it in the words the plan's other refusals use under the sameplan-pin-malformed(#1114) #1198 changes (test_adopt_pin_row_values.py,test_adopt_pins.py,test_adopt_plan_value_order.py);_scalar(thetest_yaml_*files,test_adopt_plan_yaml_quoting.py,test_leg_path_yaml_scalars.py,test_windows_paths.py,test_update_shape_header_comments.py,test_family_add_gitlink_and_null_members.py),test_yaml_flow_mappings.py, and the reader's refusal files (test_load_yaml_refusals.py,test_reader_refusals_named.py,test_refusal_default_remediation.py);test_adopt_plan_escapes.py,test_adopt_execute_refusals.py,test_adopt_values_as_typed.py,test_adopt_manifest_values.py,test_neutral_pin_entry_one_spelling.py,test_scaffold_manifest_values.py,test_family_init_values.pyandtest_template_text_placeholders.py;test_repo_hygiene.pyandtest_path_guard_hygiene.py;test_bootstrap_spelling.py,test_pinned_copy_text.py,test_readme_windows_quoting_sentence.py,test_git_output_decoding.py,test_shape_advisory.pyandtest_bootstrap_pasteable_lines.py;test_shape_doctor.py, 449 ids, each in exactly one of four shards, run from a script that reads each shard's ids, one per line, into an array because 25 hold spaces.test_adopt_pin_row_values.py,test_adopt_pins.py,test_adopt_plan_value_order.py,test_adopt_plan_yaml_quoting.py,test_family_add_gitlink_and_null_members.py,test_leg_path_yaml_scalars.py,test_update_shape_header_comments.py,test_windows_paths.py,test_yaml_block_scalar_keys.pytest_yaml_flow_brackets.py,test_yaml_flow_quotes.py,test_yaml_indicator_openers.py,test_yaml_quote_boundaries.py,test_yaml_reader_spaces.py,test_yaml_flow_mappings.py,test_load_yaml_refusals.py,test_reader_refusals_named.py,test_refusal_default_remediation.py,test_adopt_plan_escapes.pytest_adopt_execute_refusals.py,test_adopt_values_as_typed.py,test_adopt_manifest_values.py,test_neutral_pin_entry_one_spelling.py,test_scaffold_manifest_values.py,test_family_init_values.py,test_template_text_placeholders.py,test_repo_hygiene.py,test_path_guard_hygiene.pytest_shape_doctor.py, 112, 113, 112 and 112 idsEvery chunk exited 0. In all, 4289 passed, 30 skipped, 0 failed. Every skip is one the files declare and none cites
git filter-repo: 8 in c1 (test_leg_path_yaml_scalars.py: five empty parameter sets and three where the templates already read the value back), 19 in c3 (test_family_init_values.py: templates that quote the value), and 3 in the doctor shards (the PowerShell line is printed only on a Windows host).The rows file ran by itself on the merge: 35 passed. With no
git-filter-repoon PATH it is 30 passed and 5 skipped, which are the five rows that end in a finding.Main then moved to
b1f45fa76(#1144, which editsshape-doctor.py,scripts/shape_advisory.py,tests/test_path_guard_hygiene.pyand adds a test file). It touches neither file this PR changes.80ec29177merged with it (scratch commit05f5e65c8, tree3e3962f43) is clean, and on that merge the rows file,test_path_guard_hygiene.py,test_shape_advisory.pyandtest_repo_hygiene.pyran again: 304 passed.Merge-trees
At
80ec29177:git merge-tree --write-treeagainst each, all clean (exit 0), at the heads fetched on 2026-11-08 (main at 14:01Z, #1169 and #1237 at their heads of 14:04Z):origin/mainb1f45fa76: tree3e3962f43;_pin_row_problemsays a pin field whose value is not text as_read_assays what the plan's reader read, "recordscommit:as the number 7", where it spelled it as Python does,commit: 7andTrue, socheckandexecutename it in the words the plan's other refusals use under the sameplan-pin-malformed(#1114) #1198's headd38e4e36d: clean, tree89a4e55c0, which is this head's own tree;adopt-project.py(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) #1171 changesscripts/repo_shape.pytoo): 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, 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, 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: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: 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, 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: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, 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: 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: 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: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: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) #1169989295be3, 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 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: 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: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: 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: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) #118958aa9d2ba, 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) #1190e42134e10, 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, shape_materialize.py and the assembly-root template: a keptGNUmakefile/is a directory GNU make stops at,python3 scripts/bootstrap.pynamespythonon Windows, and the template says what to run wheremakereads another file #12076fa1edd56, adopt-project.py:checkandexecuteread one list of a plan's problems against its source, in the order a person mends them (another repository, a refused name, a moved source, an unanswered entry), socheck's first finding isexecute's refusal for each pair (#1113) #1210791106c2b, adopt-project.py: a refused command's REFUSED block spells each character a terminal acts on in the command, its directory and what it printed, as_first_saidspells gh's, so--local-remote-dirno longer reaches the terminal raw there; a NOTE beforeNEXT:says when the source's path in its clone command holds a character a terminal does not show as itself; and rows pin six sites #1177's 148 left to chance (#1195) #122573c9f57e8, adopt-project.py: the mount removes a path a case twin is at or under withgit rm -fand writes the twins the root keeps back from the index, so on a disk that ignores caseexecutekeeps a set the plan splits across repositories or drops (#1183) #123763c527185.None of the 24 touches
tests/test_plan_number_limits.py. #1210 and #1125 add new_read_ascallers: they benefit from the digits and do not conflict with them.Round 2: RV1249's review,
3146c3ca5on top of80ec29177RV1249 (#1249 (comment)) graded
80ec29177NOT READY: no MUST, one SHOULD and four NITs, with the behaviour right. One more commit,3146c3ca5, answers the SHOULD and two NITs, intests/test_plan_number_limits.pyandscripts/repo_shape.pyand no other file. NIT-2 (_read_asofinfandnan, which the reader never makes) and NIT-3 (the helpers left alone still spell1e-05, which pairs withstr(value), the textexecutewrites) are left as RV1249 left them.MADEheldint(LONGEST), 4300 digits, which was evaluated at import, soPYTHONINTMAXSTRDIGITS=1000ended in "1 error, no tests collected" before the limit-setting fixture ran.integer-at-the-limitnow holdsNone, and the row makesint(LONGEST)itself, under the fixture. The 35 rows pass with the variable unset, at 1000, at 640 and at 0 (on80ec29177, at 1000: the collection error).a plain decimal of 401 digits is too large to read as a number: a 64-bit float cannot hold it, so it would be infinite. The line it names, the digit count and_UNMADE_NUMBER_REMEDYare as they were. The integer's refusal still says "for this Python", which is true of it (sys.set_int_max_str_digitssets that limit). Onlytoo_largein the rows pinned the old words: README.md, AGENTS.md anddocs/do not hold them. Two comments inscripts/repo_shape.pythat called the decimal a number "this Python cannot make" no longer do.PYTHONINTMAXSTRDIGITSunset, 1000, 640, 080ec29177at 1000int(LONGEST) + 1or never made)3146c3ca5with maindffc42265(commit83698e6a3, treeeda7be55f; it holds #1198's headd38e4e36d): the rows file, #1198's three test files, both hygiene files,test_cli_reference.py, the reader's three refusal files, the six files that read the changed file's source, andtest_shape_doctor.pyin four shards of 449 ids5926cccab(adopt-project.py,docs/cli.mdand a new test file). A second scratch merge of3146c3ca5with it (commit41e904e86, tree55fcaf8bb): the rows file (also atPYTHONINTMAXSTRDIGITS1000 and 0), #1198's three test files, both hygiene files,test_cli_reference.py, the reader's three refusal files and the newtest_adopt_plan_partial_clone.pygit merge-tree --write-treeof3146c3ca5againstorigin/mainat bothdffc42265and5926cccab, #1198's head, #11718162b874eand the 24 other open PRs that changeadopt-project.py34d5c9541, this head's ownNot in this PR
repr:adopt-project.py's_the_loader_made, andscripts/shape_materialize.py's_read_asand_reading_in_words. Called in this process, each says1e300as "the number 1e+300" and1e-05as "the number 1e-05". adopt-project.py and scripts/repo_shape.py: a float that overflows is said as "the number inf", and a plain integer of more than 4300 digits endscheckandexecutein aValueErrortraceback instead ofyaml-unparsable(RV1198's NIT-1 and NIT-2 on #1198, both older than it; follows #1114) #1212 names_read_asalone, so they are left as they are. None of them can be handedinffrom a file any more, because the reader refuses it. Which commands reach them with a float was not run.0.and four hundred0s and a1) is read as0.0, the nearest float, as any decimal is rounded. adopt-project.py and scripts/repo_shape.py: a float that overflows is said as "the number inf", and a plain integer of more than 4300 digits endscheckandexecutein aValueErrortraceback instead ofyaml-unparsable(RV1198's NIT-1 and NIT-2 on #1198, both older than it; follows #1114) #1212 names only the infinite, so it is not refused.docs/release-notes/v1.2.0.mdis left alone. Its known limits do not name either fault.🤖 Generated with Claude Code
Lane: openreposhape-4 (openRepoShape-4)
Summary by Sourcery
Make YAML number handling fail safely and describe floating-point values in forms the plan reader can preserve.
Bug Fixes:
Tests: