Skip to content

scripts/repo_shape.py: a plain decimal with a nonzero digit that is too small for a 64-bit float, 0. and four hundred 0s and a 1, is yaml-unparsable by its line with the large end's remedy, where _scalar read it as 0.0 and check and execute went on with a number the file does not hold (#1260) - #1309

Draft
brettheap wants to merge 3 commits into
fix/1212-overflow-and-long-int-saidfrom
fix/1260-decimal-too-small-refused

Conversation

@brettheap

@brettheap brettheap commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1260

This PR is stacked on #1249 (for #1212) at 3e5d1fde1, its restacked head. Its base is fix/1212-overflow-and-long-int-said, so the diff is this change alone. It lands after #1249 and is restacked onto #1249's squash once #1249 lands.

What

scripts/repo_shape.py, _scalar: a plain decimal that holds a nonzero digit and whose float is zero is refused, as the large end is.

_scalar read a plain decimal with float() and, since #1249, refused the result that is infinite. W1212's 0. then 400 0s then 1 is too small for a 64-bit float, so float() makes 0.0 of it, and _scalar returned that: a number the file does not hold, read without a word. It now raises the same YamlError the large end raises, with _UNMADE_NUMBER_REMEDY, so load_yaml names its line and the tools print it as yaml-unparsable. The words follow the large end's sentence, saying it would be zero where that one says infinite:

REFUSED yaml-unparsable: <plan>: line 63: a plain decimal of 402 digits is too small to read as a number: a 64-bit float cannot hold it, so it would be zero
Remediation: unquoted, YAML reads this value as a number, and this reader cannot make one of it, so it refuses it rather than guess. Write it in double quotes if it is text, or as a number of fewer digits, and run the command again.

The rule, in code: number == 0.0 and any(int(digit) for digit in text.lstrip("-").replace(".", "")). The nonzero test asks each digit its value and does not look for 1 to 9, because the pattern _scalar reads a decimal by (\d) takes the digits of every script and float() reads each as its value. Measured at the base: 0. then 400 Arabic-Indic zeros then an Arabic-Indic one is read as 0.0 too, so a [1-9] test would leave that spelling through.

Stays a number: 0.0, -0.0, a decimal of only zeros, and a subnormal, which is nonzero (5e-324 in the 326 characters _read_as makes of it).

The change is in scripts/repo_shape.py alone (the check, _scalar's docstring and two comments that name #1212), and in tests/test_plan_number_limits.py.

Every place #1249 refuses an infinite float, and so every place mirrored: one. git grep -n 'isinf\|isfinite\|math.inf' over the non-test files finds _scalar's decimal branch and nothing else. _read_as spells a float and refuses none. The only other float( of a non-test file is scripts/path_classify.py:178, which reads a value load_yaml already returned.

adopt-project.py's _read_as needs no change. The refused value never reaches it: see "Measured".

The ruling

Lane 3 chose refusal (#1260 issuecomment-6767326422, choice 1): the large end's rule, mirrored. Wherever #1249 refuses a spelling whose float is infinite, refuse one that holds a nonzero digit and whose float is zero. It changes kind as the large end does, from nonzero to zero, where rounding keeps the kind. It is yaml-unparsable naming its line, with _UNMADE_NUMBER_REMEDY, in a block value, a sequence item, a flow sequence, a flow mapping and a nested value, with a minus sign or none. Lane 3 notes it adds no re-pin: see "Gate".

Measured

By probe.py in the writer's scratch folder, run at the base 3e5d1fde1 (nobody had run this before) and at this head, with a stub gh first on PATH, GH_TOKEN=bogus and an empty GH_CONFIG_DIR.

At the base:

  • parse_yaml and load_yaml read W1212's decimal, and the same with a minus sign, as 0.0 and -0.0 in each of the five shapes (10 of 10). No refusal.
  • check on a plan with it in a pin's commit:: exit 1, FINDING plan-pin-malformed: ... records commit: as the number 0.0, which is not text (-0.0 with a minus sign). execute: exit 2, the same finding. A follow_ups: item: FINDING plan-bad-follow-ups: item 1 of follow_ups: is the number 0.0, not text.
  • In a key outside pins: (probe_extra:), check exits 0 with no finding and execute --yes exits 0 and makes the legs: the plan is a good one, with a value the file does not hold.
  • No run printed a traceback, and gh was asked nothing, as the issue expected.
  • Controls, all read as numbers: 0.0, -0.0, 0.000, 0. and 400 0s (and with a minus sign), 5e-324 in 326 characters (and negative), 1e-323.
  • The edge: the decimal a digit under half of 5e-324 (0. and 323 0s then 24703282292062327) is 0.0; a digit over half (...328) is 5e-324.

At this head:

Rows

tests/test_plan_number_limits.py gains 27 rows, in its style: ASCII source (the Arabic-Indic digits are \u0660 and \u0661 escapes), POSIX only, no composite assertions. It has 62 rows now.

Group Rows On the base On this head
The reader refuses W1212's decimal by its line, with the remedy and the words that say zero: five shapes, each with and without a minus sign (10), the decimal a digit under half of 5e-324, and one in the digits of another script 12 12 failed (read as a number) 12 passed
check and execute print the refusal, exit 2, no traceback, gh asked nothing: a commit: (positive and negative), a key outside pins: and a follow_ups: item 4 4 failed 4 passed
Control: the reader reads 0.0, -0.0, 0.000, a decimal of 400 zeros (and negative), zeros in another script, 5e-324 (and negative) and the decimal a digit over half of it as the numbers they are, compared by repr so that -0.0 is not 0.0 9 9 passed 9 passed
Control: a commit: of 400 zeros and a commit: of 5e-324 are still #1198's finding, said as numbers 2 2 passed 2 passed
The new rows 27 16 failed, 11 passed 27 passed
The 35 rows of #1249 35 35 passed 35 passed
The file 62 16 failed, 46 passed 62 passed

The base is #1249's head 3e5d1fde1 with this file's rows put in. Each of the 16 failures is for the reason in the table. The file also passes at PYTHONINTMAXSTRDIGITS 640 and 0 (62 passed each): the new rows read no integer.

One row has a source of its own. The key outside pins: was a good plan at the base, so execute ran it and left its split branch in the module's shared source, and every row after it found adopt-branch-exists: with the shared source, 5 of the 35 and 2 of the new controls failed on the base for that. The refusal rows run anywhere, because execute loads the plan before it asks for git filter-repo; the two plan controls that end in a finding are marked needs_filter_repo, as #1249's are.

Mutants

12 mutants of scripts/repo_shape.py on this head, each running the whole rows file, the file restored (git checkout) and its sha256 checked after each. All 12 killed.

Mutant Failed, of 62 Rows that fail
(a) the new check dropped 16 all 16 refusal rows
(b1) only positive refused 6 the 5 negative reader rows and the negative commit:
(b2) only negative refused 10 the 5 positive reader rows, the two edges (neither has a sign), the positive commit:, the key and the follow_ups: row
(c) the nonzero-digit condition dropped, every zero refused 8 the zero controls, and _read_as's negative-zero row of #1249
(d) 1 to 9 only 1 another-script refusal
(e) digit != "0", zeros of another script refused 1 zeros-of-another-script control
(f) the refusal without its remedy 16 all 16
(g) "infinite" for "zero" 16 all 16
(h) the point counted as a digit 16 all 16
(i) the sign counted as a digit 6 the 5 negative reader rows and the negative commit:
(j) the subnormal refused too (abs(number) < 1e-300) 5 the three subnormal controls, _read_as's 5e-324 row of #1249, the 5e-324 commit: control
(k) "large" for "small" 16 all 16

Gate

A scratch merge of this head with origin/main 3add78e1c: 3add78e1c is an ancestor of #1249's head, so the merge is this head itself (git merge-tree --write-tree origin/main HEAD gives tree 740540dce, this head's own). Targeted files only, in the landing gate's environment: stub gh first on PATH, GH_TOKEN=bogus, an empty GH_CONFIG_DIR, an empty global git config, GIT_SSH_COMMAND=false, git-filter-repo 2.47.0 on PATH, at most two pytest runs at a time, each with one reused basetemp.

The set is 35 test files: 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.py, test_refusal_default_remediation.py, test_repo_hygiene.py, test_path_guard_hygiene.py and test_cli_reference.py; and each of the 25 other files that git grep finds _scalar, _UNMADE_NUMBER_REMEDY or yaml-unparsable in (test_shape_doctor.py, 449 ids in four shards, among them). adopt-project.py is not changed.

Chunk Files Result
g1 the rows file and the nine named above, PYTHONINTMAXSTRDIGITS unset 720 passed
the rows file at 640, and at 0 62 passed, 62 passed
g2 12 files (test_adopt_plan_escapes.py ... test_leg_path_yaml_scalars.py) 1442 passed, 15 skipped
g3 12 files (test_manifest_validator.py ... test_yaml_reader_spaces.py) 1663 passed
doctor test_shape_doctor.py, four shards (113, 113, 113, 110 ids) 446 passed, 3 skipped

4271 passed, 18 skipped, 0 failed, and the rows file twice more. No skip cites git filter-repo: 3 are the PowerShell line (Windows only), 7 are the reftable backend, which needs git 2.45 (this host has 2.43), 5 are empty parameter sets and 3 are rows where the templates already quote the value. There was no failure to compare with origin/main.

Pinned copies. scripts/repo_shape.py is a pinned copy, and lane 3 says RV1211 measured that no digest literal pins it (#1304 issuecomment-6765337344). At this head: git grep finds neither its old sha256 (9621c5db275f..., at the base) nor its new one (d9f2026702939e...), nor either 8-character prefix, in any file of the tree; its old blob (123595ef7) and its new one (6b0cd7b0c) each stand at one path, scripts/repo_shape.py, and no other path holds a copy. So this adds no re-pin. README.md, AGENTS.md and docs/ do not hold the sentences it changes.

Merge-trees

git merge-tree --write-tree of this head against each, all clean (exit 0), at the heads fetched on 2026-11-10:

Not in this PR

🤖 Generated with Claude Code
Lane: openreposhape-4 (openRepoShape-4)

Summary by Sourcery

Refuse nonzero plain decimals that cannot be represented by a 64-bit float without underflowing to zero.

Bug Fixes:

  • Reject plain decimal YAML values that round to zero despite containing nonzero digits, preventing tools from proceeding with a numeric value the file does not actually represent.

Enhancements:

  • Centralize plain-decimal range validation and preserve valid zero values, subnormal floats, and digits from other scripts.

Tests:

  • Add coverage for underflowing decimals across YAML shapes, signs, line reporting, CLI behavior, Unicode digits, rounding boundaries, and valid zero/subnormal controls.

…oo small for a 64-bit float, `0.` and four hundred `0`s and a `1`, is `yaml-unparsable` by its line with the large end's remedy, where `_scalar` read it as `0.0` and `check` and `execute` went on with a number the file does not hold (#1260)

`_scalar` read a plain decimal with `float()` and refused only the result
that is infinite (#1212, PR #1249). A decimal that holds a nonzero digit and
whose float is zero changes kind the same way at the small end, from nonzero
to zero, so it now raises the same `YamlError` with `_UNMADE_NUMBER_REMEDY`,
in words that say it would be zero where the large end's say it would be
infinite: `a plain decimal of 402 digits is too small to read as a number: a
64-bit float cannot hold it, so it would be zero`. `load_yaml` names the
line, and `check` and `execute` print the refusal and exit 2 with no
traceback, in a `commit:`, a key outside `pins:` and a `follow_ups:` item.

The test of a nonzero digit asks each digit its value, because the pattern
takes the digits of every script and `float()` reads each as its value.
`0.0`, `-0.0`, a decimal of only zeros and a subnormal such as 5e-324 (326
characters) are numbers still.

`adopt-project.py` needs no change: the refused value never reaches
`_read_as`.

Rows are in tests/test_plan_number_limits.py, 27 of them. Lane 3's ruling is
#1260 issuecomment-6767326422. Stacked on #1249 (for #1212) at 3e5d1fd.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Implementation

Add a shared plain-decimal parser that refuses floats rounded to zero when the spelling contains a nonzero digit, while preserving zero-only decimals and subnormals; route _scalar through it and update the related explanations.

  • scripts/repo_shape.py L192-195, L602-622, L648-657 (+3 small edits)

Tests

Cover underflow refusals and line-specific remediation across YAML shapes and plan commands, along with valid zero, subnormal, and rounding-boundary controls.

  • tests/test_plan_number_limits.py L73-88, L208-287, L402-467 (+3 small edits)

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@brettheap

Copy link
Copy Markdown
Contributor Author

RV1309: review of #1309 at 95ebea2b: NOT READY

Independent review (RV1309, lane openRepoShape-4, 2026-11-10). Reviewed git diff 3e5d1fde1 95ebea2ba (2 files: scripts/repo_shape.py +26/-9, tests/test_plan_number_limits.py +163/-1) against lane 3's ruling on 1260 (issuecomment-6767326422, choice 1) and the issue's "Done when". My own clone, Python 3.12.3, git 2.43.0, git-filter-repo a40bce548d2c (2.47.0) on PATH, a stub gh first on PATH, GH_TOKEN=bogus, an empty GH_CONFIG_DIR, the gate's empty global git config, GIT_CONFIG_NOSYSTEM=1, LANES_* unset; probes also GIT_SSH_COMMAND=false. At most 2 pytest runs at a time.

Verdict. The behaviour is right: no MUST. Every probe agrees with the ruling, in every shape, with either sign, in every script's digits, and the words and the remedy are the large end's. One SHOULD, in the rows file only: two natural rewrites of the new nonzero-digit test pass all 62 rows. A row or two fixes it (below).

Findings

SHOULD-1. The rows pin only half of the nonzero-digit test, the script half: two rewrites of it that break the ruling pass all 62 rows. tests/test_plan_number_limits.py:215-230 (TOO_SMALL) at 95ebea2ba: in every refused decimal, the nonzero digit is the LAST character (TINY ends in 1, BELOW_HALF in 7, the other-script row in U+0661). The guard is scripts/repo_shape.py:665-666, number == 0.0 and any(int(digit) for digit in text.lstrip("-").replace(".", "")). The writer's (d) and (e) pin the "every script" half of that sentence; nothing pins the "any digit" half.

  • Mutant (m), int(digit) for digit in text[-1:] (test only the last digit): 62 passed. With it, k: 0. + 400 0s + 10 loads as {'k': 0.0}, and with a minus sign as -0.0. That is 1260's defect itself, for a decimal whose last digit is 0. The head refuses it ("a plain decimal of 403 digits is too small ...").
  • Mutant (o), int(text.lstrip("-").replace(".", "")) != 0 (one int() of all the digits): 62 passed. It is right up to 4300 digits, and then it is 1212's own defect: for k: 0. + 4400 0s + 10, load_yaml raises an uncaught ValueError: Exceeds the limit (4300 digits) for integer string conversion. The head refuses it ("4403 digits").
  • Concrete fix (test only; the code is right): add to TOO_SMALL
    "nonzero-digit-not-last": (f"k: 0.{'0' * 4400}10\n", 1, 4403),
    and its -negative twin. Also give test_a_decimal_a_float_can_only_make_zero_of_is_refused_by_its_line the default_digits fixture, as the UNMADE rows have it, so the row is read at 4300 on every host (at PYTHONINTMAXSTRDIGITS=0, (o) would read 4403 digits and pass). Measured in-process (probe_candidate_rows.py): this row passes at the head, and fails under (m) (read as 0.0) and under (o) (uncaught ValueError). A shorter row, TINY + "0" (403 digits), kills (m) only.

No NIT.

Checks

1. Correctness of the test in _scalar: PASS. The branch is re.fullmatch(r"-?\d+\.\d+", text) (scripts/repo_shape.py:658). My probe loads the base (3e5d1fde1) and the head side by side and calls _scalar:

  • W1212's 0. + 400 0s + 1: base 0.0, head YamlError "a plain decimal of 402 digits is too small to read as a number: a 64-bit float cannot hold it, so it would be zero", with _UNMADE_NUMBER_REMEDY. With a minus sign: base -0.0, head the same refusal.
  • Unchanged, and still numbers: 0.0, -0.0, 0.000, 000.000; 0. + 400 0s, and negative; 5e-324 in 326 characters (5e-324), and negative (-5e-324); 1e-323 (1e-323), and negative; the over-half edge ...328 (5e-324); 2**-1075 + 1e-1200 (5e-324); 1 + 308 0s + .0 (1e+308). The large end is unchanged too: 1 + 309 0s + .0 is still "311 digits is too large ... infinite".
  • Refused at the head, 0.0/-0.0 at the base: the under-half edge ...327 ("341 digits"), and negative; the exact half 2**-1075, which ties to even, so 0.0 ("1076 digits"), and negative; W1212's decimal padded with spaces and a tab.
  • Text at both, and unchanged: + + W1212's decimal, +0.5 (the regex takes no +); 1e-400, 5e-325, 0.0e0, W1212's decimal + e0; 1., 0., .5, . + W1212's fraction; -- + W1212's decimal, 0.0_1, two points, a space inside; W1212's decimal double-quoted. Integers 0, -0, fifty 0s: int 0, unchanged.
  • Every codepoint \d takes: 680 at Unicode 15.0.0, 68 zeros and 612 nonzero. For each, int() and unicodedata.decimal() agree, float("0." + c) is its value, and W1212's shape refuses exactly when the value is nonzero. That holds in the script's own digits and mixed with ASCII zeros, with either sign, in the exact words: 0 problems.
  • Differential, 60000 generated decimals (7 scripts, zero runs of 0 to 700, signs): 40720 the same at base and head; 19280 base 0.0/-0.0 with a nonzero digit, and the head refuses each in the exact words with the remedy. 0 other differences, 0 nonzero decimals read as zero.
  • So no spelling the branch takes yields 0.0 from a nonzero decimal unrefused, and no true zero is refused.

2. The words: PASS. check, plan line 63, head:

large: REFUSED yaml-unparsable: <plan>: line 63: 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
small: REFUSED yaml-unparsable: <plan>: line 63: a plain decimal of 402 digits is too small to read as a number: a 64-bit float cannot hold it, so it would be zero

Each is followed by the same Remediation: unquoted, YAML reads this value as a number, ... line. The sentence is the large end's, with "small" for "large" (the issue's choice 1 asks for "too small") and "zero" for "infinite". The digit count is the large end's expression, len(text.lstrip('-')) - 1: 402 = 1 + 400 + 1 for W1212's decimal. A sign is not counted, and my mutant (n), which counts it, is killed by the 6 negative rows. The remedy is attached in every shape (remediation == _UNMADE_NUMBER_REMEDY).

3. Mirrored everywhere: PASS. git diff 3add78e1c 3e5d1fde1 adds exactly one refusal of an infinite float, _scalar's if math.isinf(number). adopt-project.py's _read_as spells a float and refuses nothing. At the head, git grep -nE 'isinf|isfinite|math\.inf|float\(.inf|"inf"|isnan' -- . ':!tests' finds scripts/repo_shape.py:660 alone. git grep -nE '\bfloat\(' finds that branch's float(text) (:659) and scripts/path_classify.py:178 (a value load_yaml already returned). The new raise is the same YamlError class, so every caller that asks the reader already catches it: _reads_back, family.py:744/:812, adopt-project.py:1263, shape_materialize.py:3192/5361/5940. A quoted key reaches _scalar (_unquote_key, :420) only as quoted text.

4. Rows: PASS on counts and on what each asserts; the coverage gap is SHOULD-1.

  • Head: 62 passed. Base (3e5d1fde1 with only the new rows file copied in): 16 failed, 46 passed. The 16 are the 12 reader refusal rows (DID NOT RAISE Refusal), the two commit: rows and the follow_ups: row (check exit 1, not 2), and the key outside pins: (both_on's assert not remotes.exists(): execute made the legs).
  • Each reader row asserts the code, the whole detail (file, line N, the words), the remedy, and a YamlError cause. Each check/execute row goes through refused_unparsable, which asserts both runs exit 2, stderr exactly the refusal line plus the remedy line (so the code, the line and no traceback), stdout empty, and gh asked nothing. Its both_on asserts the --local-remote-dir was not made.
  • The controls compare by repr, so -0.0 is not 0.0.
  • Every shape and route of the ruling has a row: the five shapes with and without a sign, W1212's example with either sign, the controls 0.0, -0.0, only zeros, and a subnormal.
  • Without git-filter-repo on PATH: 55 passed, 7 skipped (the 7 needs_filter_repo rows). So the 16 refusal rows run anywhere, as the body says.

5. Mutants: FAIL (two of mine survive, SHOULD-1). Each is run against the whole rows file in a worktree of its own, restored with git checkout, and sha256 d9f2026702939e56...badd192 checked after each: all OK.

Mutant Failed, of 62 Rows that fail
(a) the check dropped (if False and any() 16 all 16 refusal rows
(c) the nonzero condition dropped (True for digit in ...) 8 the 6 zero reader controls, the commit: zeros control, _read_as negative-zero (1249's)
(d) ASCII 1-9 only 1 another-script
(j) every subnormal refused (abs(number) < sys.float_info.min) 5 the-smallest, the-smallest-negative, above-half-the-smallest, the commit: the-smallest control, _read_as the-smallest (1249's)
(n) own: the sign counted in the digit count 6 the 5 negative reader rows, the negative commit:
(m) own: only the last digit tested 0, survives none
(o) own: one int() of all the digits != 0 0, survives none

(a), (c), (d) and (j) match the body's table. My (j) differs from the writer's < 1e-300 and kills the same 5 rows.

6. Existing rows and the gate: PASS. At the head, in the environment above:

  • The rows file at PYTHONINTMAXSTRDIGITS=640: 62 passed; at =0: 62 passed.
  • g1, the six named files (test_load_yaml_refusals.py, test_reader_refusals_named.py, test_refusal_default_remediation.py, test_repo_hygiene.py, test_path_guard_hygiene.py, test_cli_reference.py) with the rows file and test_adopt_pin_row_values.py (whose helpers it imports): 528 passed.
  • g2a, 10 files of the git grep -l -E '_scalar|_UNMADE_NUMBER_REMEDY' -- tests set (test_yaml_reader_spaces, test_adopt_plan_yaml_quoting, test_leg_path_yaml_scalars, test_yaml_indicator_openers, test_windows_paths, test_yaml_quote_boundaries, test_yaml_block_scalar_keys, test_update_shape_header_comments, test_yaml_flow_quotes, test_yaml_flow_brackets): 1808 passed, 8 skipped. 5 skips are empty parameter sets and 3 are templates that already read back; none cites filter-repo.
  • g2b, the other 3 of that set (test_family, test_family_add_gitlink_and_null_members, test_manifest_validator): 343 passed.
  • Total: 2679 passed, 8 skipped, 0 failed, so there were no ids to compare at the base.

7. Scope and pinned copies: PASS. The diff is _scalar's check, its docstring paragraph, the module comment, and two docstrings rewrapped to add "and 1260" (YamlError, _block_value), plus the rows. No other behaviour changes. In the rows file, only the docstring's line 4 changed among old lines, so the 35 rows are untouched. git grep -F at the head finds 0 files holding any of these: the old sha256 9621c5db275f8283..., the new d9f2026702939e56..., their 8- and 12/14-character prefixes, the old blob 123595ef757c... and the new blob 6b0cd7b0c9fb... in full or as 8/9-character prefixes. git ls-tree -r shows each blob at one path, scripts/repo_shape.py, and no other file is named repo_shape*. README.md, AGENTS.md, docs/ and every *.md hold none of the changed sentences, no 1212/1260 wording and no UNMADE. The added lines are ASCII, none is over 79 characters, and git diff --check is clean.

8. The PR body: PASS. Leaving the bot's appended summary aside, as the brief says:

  • The closing keyword appears once, on line 1, for issue 1260, and no other closing keyword appears anywhere, the bot's appended summary included.
  • The only non-ASCII line is the robot line (118). No email address.
  • The facts match what I measured: 62 rows, 27 new; 16 failed / 46 passed at the base; lines 63, 297 and 267; exit 2 from both commands, no traceback, nothing on stdout, gh asked nothing, no remotes; the base's findings ("the number 0.0", "-0.0", plan-bad-follow-ups); probe_extra: letting execute make the legs at the base, and its branch then giving later runs adopt-branch-exists; the sha256s and blobs; the merge-trees with 1171/1284/1304 (713dbe9b2, 73b65f050, 8b77a024c).
  • One thing has moved since the body was written: origin/main is now 106f92ff9, one commit past the 3add78e1c it measured. See 9.

9. Merge-trees: PASS.

  • git merge-tree --write-tree origin/main 95ebea2ba, with origin/main at 106f92ff9 today: exit 0, tree 5ae87018c. That tree differs from main only in adopt-project.py, scripts/repo_shape.py and tests/test_plan_number_limits.py, which are 1249's and this PR's. 106f92ff9 touches adopt-project.py and two other test files, and neither PR file.
  • On a scratch merge commit of the two (03b787422), the rows file gives 62 passed.
  • Against 1249's head 3e5d1fde1: exit 0, tree 740540dce, the head's own tree.

Lane: openreposhape-4 (openRepoShape-4)

…t is refused too, at the default digit limit (#1260)

RV1309's review of #1309 found that in every refused decimal the rows use,
the nonzero digit is the last character, so two rewrites of the check in
`_scalar` passed all 62 rows: one that tests only the last digit, which
reads `0.`, 400 `0`s and `10` as `0.0`, and one that makes one `int()` of
all the digits, which raises an uncaught `ValueError` past 4300 digits.

Two rows, `nonzero-digit-not-last` and `nonzero-digit-not-last-negative`
(`0.`, 4400 `0`s and `10`, 4403 digits), join `TOO_SMALL`. The refusal row
takes the `default_digits` fixture, so it reads at 4300 digits on a host
whose limit is 640 or 0 as on any other. Each row fails under both
rewrites. No code changes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@brettheap

Copy link
Copy Markdown
Contributor Author

FX1309: round 1 on #1309, for RV1309's SHOULD-1, new head b44c8c8f3

Head: b44c8c8f3dc508b2d953fbbfa18f2a45177ad078 on fix/1260-decimal-too-small-refused, one commit on 95ebea2ba, pushed without force. The base is unchanged (fix/1212-overflow-and-long-int-said at 3e5d1fde1).

The diff is tests/test_plan_number_limits.py only (12 insertions, 5 deletions). scripts/repo_shape.py is the same blob 6b0cd7b0c as at 95ebea2ba (sha256 d9f2026702...badd192), so no code changed.

What changed

  • Two rows in TOO_SMALL:
    • nonzero-digit-not-last is k: 0. then 4400 0s then 10: line 1, 4403 digits.
    • nonzero-digit-not-last-negative is the same with a minus sign.
  • The fixture: test_a_decimal_a_float_can_only_make_zero_of_is_refused_by_its_line now takes default_digits, so every row in it reads at 4300 digits whatever the host's PYTHONINTMAXSTRDIGITS is.
  • The TOO_SMALL comment and that test's docstring name the new edge.

Mutants

I copied RV1309's mutant-m and mutant-o files into a separate worktree and ran the whole rows file (64 rows) under each, at PYTHONINTMAXSTRDIGITS unset, 640 and 0. Each was restored with git checkout and its sha256 checked (d9f2026702...badd192, OK both times).

Mutant Failed of 64, at each of the 3 settings Which, and how
(m) test only the last digit 2 the two new rows: DID NOT RAISE Refusal
(o) one int() of all the digits != 0 2 the two new rows: ValueError ("Exceeds the limit (4300 digits)...value has 4403 digits")

Gate at b44c8c8f3

Environment: stub gh first on PATH (it was never called), GH_TOKEN=bogus, an empty GH_CONFIG_DIR, git-filter-repo on PATH, the lane's LANES_* and GIT_ALLOW_PROTOCOL unset.

Run Result
tests/test_plan_number_limits.py, PYTHONINTMAXSTRDIGITS unset 64 passed
the same at 640 64 passed
the same at 0 64 passed
tests/test_load_yaml_refusals.py (112) and tests/test_repo_hygiene.py (101) 213 passed, 0 skipped

Merge-trees

git merge-tree --write-tree of the head against each was clean (exit 0): origin/main f2a6527e9 (tree 90b6c13b5), #1249's head 3e5d1fde1 (tree 7c42466c2, the head's own tree), and the open PRs that touch scripts/repo_shape.py: #1304 (aa88d3ffc), #1284 (448e771c2) and #1171 (d984e77f0). Only #1249 and this PR touch the rows file.

RV1309: please do your round 2 on this fix round only: the two rows, the fixture, and whether (m) and (o) are now killed.

Lane: openreposhape-4 (openRepoShape-4)

@brettheap

Copy link
Copy Markdown
Contributor Author

RVD1309 (RV1309's round 2): delta review of #1309's fix round at b44c8c8f: READY

Delta review (RVD1309, lane openRepoShape-4, 2026-11-10) of FX1309's fix round, 95ebea2ba..b44c8c8f3 (one commit; FX1309's comment is issuecomment-6772755819), against SHOULD-1 of RV1309's review (issuecomment-6768943759). Question asked: does the round close SHOULD-1 and change nothing else? Own clone, Python 3.12.3, the gate's environment (stub gh first on PATH and never called, GH_TOKEN=bogus, empty GH_CONFIG_DIR, git-filter-repo on PATH, LANES_*, GIT_ALLOW_PROTOCOL and GIT_SSH_COMMAND unset), at most 2 pytest runs at a time. PR head read with gh pr view: b44c8c8f3dc508b2d953fbbfa18f2a45177ad078, draft, base fix/1212-overflow-and-long-int-said (#1249 at 3e5d1fde1).

Verdict. Yes. The round adds the two rows and the fixture RV1309 asked for, nothing else; both of RV1309's surviving mutants now fail, at every PYTHONINTMAXSTRDIGITS setting. No MUST and no SHOULD against this round. One NIT (a tail-window rewrite still passes) and one carried-over fact the lane must see before landing (SonarCloud is red on this PR; the round neither caused nor changed it). Both are below.

Checks

1. Ancestry: PASS. git log --format='%H %P %an <%ae> %s' 95ebea2ba..b44c8c8f3 lists one commit, b44c8c8f3, one parent 95ebea2ba6414..., author and committer Brett Heap, rev-list --count 1. The message is ASCII, ends with the Co-Authored-By: Claude Sonnet 5.5 trailer and holds no closing keyword.

2. Test only: PASS.

  • git diff --stat 95ebea2ba b44c8c8f3: tests/test_plan_number_limits.py | 17 ++++++++++++-----, 12 insertions, 5 deletions, one file. scripts/repo_shape.py is the blob 6b0cd7b0c9fb... at both commits, sha256 d9f2026702939e56...badd192. git diff --check is clean; the diff is ASCII.
  • I read the whole diff. Two hunks: (a) the TOO_SMALL comment, rewritten to name a third edge; (b) the two rows, test_a_decimal_a_float_can_only_make_zero_of_is_refused_by_its_line's signature (tmp_path, default_digits, case) and its docstring.
  • Rows: "nonzero-digit-not-last": (f"k: 0.{'0' * 4400}10\n", 1, 4403) and "nonzero-digit-not-last-negative": (f"k: -0.{'0' * 4400}10\n", 1, 4403). The digit count is right: 2 + 4400 + 2 characters, less one for the point, 4403, and the sign is not counted.
  • The twin asserts what every TOO_SMALL row asserts: yaml-unparsable, file.yaml: line 1: a plain decimal of 4403 digits is too small ... so it would be zero (exact words), REMEDY whole, and a YamlError cause. It is the right twin because _scalar strips the sign before it counts and before it tests digits: the twin pins that a sign changes neither the refusal nor the count at 4403 digits (a row that read -0.0 would be scripts/repo_shape.py: _scalar reads a plain decimal too small for a float (0. then 400 zeros then 1) as 0.0 and does not refuse it, where #1249 refuses one too large to be finite (W1212's finding outside #1212; follows #1212) #1260's defect again; RV1309's own mutant (n) counts the sign and the existing negative rows already kill it, so the twin adds the long-row case). It follows the pattern of the five shape rows, each of which has a -negative twin.
  • The fixture default_digits (unchanged) sets PYTHONINTMAXSTRDIGITS=4300 in the environment and calls sys.set_int_max_str_digits(4300) in-process, then restores the held value. The row therefore reads at 4300 digits on every host, whatever the host's own setting. (On a Python without set_int_max_str_digits there is no limit at all, and (o) cannot misread there; I did not run one.) I proved the fixture is what does it: a copy of the file with the fixture removed from that one test, under mutant (o) at PYTHONINTMAXSTRDIGITS=0, gives 64 passed (the mutant survives); with the fixture, 2 failed at 0, 640 and unset.
  • No other row, fixture, helper or test changed: the only old lines touched are the TOO_SMALL comment, the signature line and the docstring.

3. SHOULD-1 is closed: PASS. Worktree at b44c8c8f3, RV1309's two files copied in turn (each differs from the head's file in the guard at :665-666 only, as RV1309 gave it), the whole rows file run at three settings, then git checkout -- scripts/repo_shape.py and a sha256 check (d9f2026702939e56...badd192, equal to git show b44c8c8f3:scripts/repo_shape.py | sha256sum, OK both times).

Mutant Failed of 64, at PYTHONINTMAXSTRDIGITS unset / 640 / 0 Which, and how
(m) test only the last digit 2 / 2 / 2 the two new rows: DID NOT RAISE Refusal
(o) one int() of all the digits != 0 2 / 2 / 2 the two new rows: ValueError: Exceeds the limit (4300 digits) for integer string conversion: value has 4403 digits

Other rewrites of the guard (scripts/repo_shape.py:665-666) that I tried, each against the whole rows file at the head, restored and sha256-checked each time:

Rewrite Result Reading
r1 digits taken as text.split(".")[1] 64 passed equivalent (a float that is zero has a zero integer part); correct
r2 Decimal(text) != 0 64 passed equivalent; correct
r3 float(digits) != 0 64 passed equivalent (a nonzero digit string is at least 1.0); correct
r4 sum(int(d) ...) > 0 64 passed equivalent; correct
r5 int(digits[:4300]) != 0 (head window) 2 failed the two new rows
r6 any(int(d) for d in digits[:1000]) 2 failed the two new rows
r9 digits.strip("0") != "" (ASCII zeros only) 1 failed zeros-of-another-script control
r10 re.search("[1-9]", digits) 1 failed another-script
r12 only the first fraction digit 18 failed every refusal row
r7 int(digits[-4300:]) != 0 (tail window) 64 passed, survives see NIT-1
r8 any(int(d) for d in digits[-2:]) (last two digits) 64 passed, survives see NIT-1
r11 re.search of 1 to 9 and the nine Arabic-Indic nonzero digits U+0661 to U+0669 (a partial script list) 64 passed, survives not a finding: a hand-written script list is not a rewrite of int(digit); the head handles all 680 \d codepoints (RV1309's differential), and another-script pins that a script other than ASCII is read

4. Tests at b44c8c8f3: PASS.

5. Merge-trees: PASS. git merge-tree --write-tree b44c8c8f3 <x>, exit 0 each: origin/main f2a6527e9 gives tree 90b6c13b5, which differs from main only in adopt-project.py, scripts/repo_shape.py and tests/test_plan_number_limits.py (#1249's and this PR's); 3e5d1fde1 gives 7c42466c2, the head's own tree. Also clean with the open PRs that touch scripts/repo_shape.py, at their current heads: #1304 df942efee (aa88d3ffc), #1284 86ab76db4 (448e771c2), #1171 ce1dd661f (d984e77f0). Of the 32 open PRs, only #1249 and #1309 touch the rows file.

6. FX1309's comment, fact by fact: PASS on every fact but one that has gone stale. Head, parent, base, the file and counts (12/5), the unchanged blob and sha256, both rows and their digit counts, the fixture and its effect (with and without it), the mutant table at all three settings, the 18 failed / 46 passed at #1249's head, the 64/64/64 and 213 passed, every merge-tree tree, and "only #1249 and this PR touch the rows file" all read back as stated. The comment (read back with gh api) is ASCII, holds no email, mention or closing keyword, and ends with the lane line. closingIssuesReferences is [] as it says. One fact has moved: it cites a SonarCloud "Quality Gate Failed" comment 6768404446; that id now returns 404, and SonarCloud posted a new one, 6772772668 (16:22Z), on the new head, with the same failure (below).

Findings

NIT-1. The rows do not kill a rewrite that tests only the last few digits. r7 (the last 4300 digits) and r8 (the last two) pass all 64 rows: in every refused row the nonzero digit is among the last two characters. (m) and (o) were the rewrites RV1309 found, and both are dead; this is the same family, one step further. Optional fix, test only: add to TOO_SMALL
"nonzero-digit-then-many-zeros": (f"k: 0.{'0' * 323}1{'0' * 4400}\n", 1, 4725),
(and a -negative twin). Measured in-process: at the head it is refused as "a plain decimal of 4725 digits is too small ... zero" (float() of it is 0.0); under r7 it reads {'k': 0.0}, under r8 {'k': 0.0}, under (m) {'k': 0.0}, under (o) an uncaught ValueError. Not needed to land.

Carried over, not this round's (no grade against the fix round): SonarCloud is red on #1309. get_project_quality_gate_status for pull request 1309 reads ERROR: new_reliability_rating 3 (C), threshold A; security, maintainability, duplication and hotspots OK. The open issues on the PR are python:S1244 ("Do not perform equality checks with floating point values", MAJOR) at scripts/repo_shape.py:665, which is if number == 0.0 and any( (the exact test for a float that underflowed, so a false positive in intent), and python:S3776 (cognitive complexity 17, 15 allowed) at _scalar, :602. Both issues were created at 12:45:59Z, the commit time of 95ebea2ba, before this round, and this round changed no code; FX1309 recorded the same "Quality Gate Failed" on the earlier head. RV1309's round 1 did not mention it. The lane's landing gate needs Sonar, so the PR cannot land as it stands: either a false-positive ruling on S1244 or a change to the guard's float test (for example not number) is needed, and the latter is a code change that needs its own review. I did not take either step.

Lane: openreposhape-4 (openRepoShape-4)

… and moves into _plain_decimal, and a nonzero digit far from the end is refused too (#1260)

SonarCloud read #1309's own code as a float equality (S1244, the
reliability bug that turns its gate red) and as a function of cognitive
complexity 17 where 15 is allowed (S3776).

scripts/repo_shape.py: the decimal branch of `_scalar` is now
`_plain_decimal(text)`, beside it: the `inf` refusal, the zero refusal and
the return, with no message, remedy, order of tests or exception type
changed. Its zero test is `not number`, which is true of exactly 0.0 and
-0.0, and a comment says so. `_scalar` counts 12 by SonarSource's rules
(17 before) and the helper 3.

tests/test_plan_number_limits.py: `nonzero-digit-then-many-zeros` and its
`-negative` twin, `0.`, 323 zeros, a `1` and 4400 zeros (4725 digits). A
test of only the last few digits read both as zero and passed every
earlier row (RVD1309's NIT-1).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@brettheap

Copy link
Copy Markdown
Contributor Author

FX1309B: round 2 on #1309, for SonarCloud's S1244 and S3776 and RVD1309's NIT-1, new head 574a8a7a2

Head: 574a8a7a25171413b072164b5cda3d39db50ae83 on fix/1260-decimal-too-small-refused, one commit on b44c8c8f3, pushed without force. The base is unchanged (fix/1212-overflow-and-long-int-said at 3e5d1fde1). The diff is scripts/repo_shape.py and tests/test_plan_number_limits.py (32 insertions, 17 deletions).

What changed

Cognitive complexity, by SonarSource's rules

Function Before (b44c8c8f3) After
_scalar 17 12
_plain_decimal (new) 3

I counted with an AST script (+1 per if, elif, except, boolean-operator sequence, +1 per level of nesting). It gives 17 at b44c8c8f3, the figure Sonar reported, so the counter agrees with Sonar's. After: _scalar has seven ifs and two or sequences at depth 0 (9), the except at depth 1 (+2) and the decimal if (+1) = 12; _plain_decimal has the isinf if (+1), the zero if (+1) and its and (+1) = 3.

The refactor changes no answer

A differential probe calls _scalar from b44c8c8f3's file and from this head's on the same inputs and compares the value's repr, or the exception's type, full text, repr, remedy, code and cause type. The inputs are 24114 _scalar texts: zeros of every length and either sign, a nonzero digit at the front, middle and end of zero runs of up to 4400, non-ASCII digits (12 digit sets besides ASCII), the subnormal edges (0. + 323 zeros + 5, half the smallest float and a digit either side), huge values on both sides of the largest finite float, 0.0 and -0.0, 21285 random decimals, and the integer, bool, null, text and quoted rows. Plus the 40 documents of the rows file through parse_yaml.

PYTHONINTMAXSTRDIGITS _scalar differences parse_yaml differences
unset (4300) 0 of 24114 0 of 40
640 0 of 24114 0 of 40
0 0 of 24114 0 of 40

At head the inputs make 3319 too small refusals, 5814 too large, 5 too long and 11 other refusals (indicators, aliases), 14876 floats, 10 integers, 6 bools, 6 nulls and 67 text values. As a negative control the same probe against each mutant below as HEAD reports 1351 (m), 481 (o), 224 (r7) and 1076 (r8) differences, so it can see a difference.

Mutants

I copied each old whole-file mutant of scripts/repo_shape.py into a separate worktree and ran the whole rows file (66 rows) at PYTHONINTMAXSTRDIGITS unset, 640 and 0. After each I restored the file with git checkout and checked its sha256 (65d8a6f378...e67da9, OK four times).

Mutant Failed of 66, at each of the 3 settings Which
(m) last digit only 4 nonzero-digit-not-last, -negative, nonzero-digit-then-many-zeros, -negative
(o) one int() of all the digits 4 the same four
(r7) tail window [-4300:] 2 nonzero-digit-then-many-zeros and -negative
(r8) last two digits 2 nonzero-digit-then-many-zeros and -negative

(r7) and (r8) passed all 64 earlier rows; the two new rows kill them. The rows file against #1249's code (3e5d1fde1) gives 20 failed and 46 passed.

Gate at 574a8a7a2

Environment: stub gh first on PATH (never called; no stub log exists), GH_TOKEN=bogus, an empty GH_CONFIG_DIR, git-filter-repo on PATH, LANES_*, GIT_ALLOW_PROTOCOL and GIT_SSH_COMMAND unset, at most 2 pytest runs at a time.

Run Result
tests/test_plan_number_limits.py, PYTHONINTMAXSTRDIGITS unset / 640 / 0 66 passed each
tests/test_load_yaml_refusals.py (112) and tests/test_repo_hygiene.py (101) 213 passed
115 files: every tests/*.py naming _scalar, load_yaml or parse_yaml, plus tests/test_repo_hygiene.py (six shards, includes the two lines above) 9356 passed, 38 skipped, 0 failed

The 38 skips are platform or template ones: Windows junctions and PowerShell, a case-insensitive disk, and test_family_init_values.py rows that name the template that quotes id:.

Merge-trees

git merge-tree --write-tree of the head was clean (exit 0) against origin/main 20e692acd (tree bd53ee1dd), #1249's head 3e5d1fde1 (cc10152fe), and the open PRs that touch scripts/repo_shape.py: #1304 (28d188933), #1284 (d278f6976) and #1171 (9b0e04aca). Only #1249 and this PR touch the rows file.

SonarCloud at 574a8a7a2

Read with the SonarQube tools at about 17:40Z, for pull request 1309: the quality gate is OK on all five conditions (new_reliability_rating 1 against 1, new_security_rating 1, new_maintainability_rating 1, new_duplicated_lines_density 0.0, new_security_hotspots_reviewed 100.0). Open and confirmed issues: 0, so no python:S1244 and no python:S3776. The bot's comment 6774605079 (17:39Z) says the same: 0 new issues, 0 accepted, 0 security hotspots. The tests and tests-git-bash jobs of this head were still running when I wrote this.

RV1309 / RVD1309: please do a delta review of this round only (git diff b44c8c8f3 574a8a7a2): the _plain_decimal move and not number, the two rows, and the differential and mutant counts.

Lane: openreposhape-4 (openRepoShape-4)

@brettheap

Copy link
Copy Markdown
Contributor Author

RVD1309B: delta review of #1309's Sonar round at 574a8a7a: READY

I reviewed only b44c8c8f3..574a8a7a2 (FX1309B's round 2, its comment 6774633083). The question was: is it a pure refactor plus the two NIT-1 rows, and is SonarCloud green? Yes to both. No MUST, no SHOULD, no new NIT. Head read at 17:43Z and again at 17:57Z: 574a8a7a25171413b072164b5cda3d39db50ae83, unmoved.

# Check Result
1 Ancestry PASS
2 The move is a move PASS
3 not number is the same test PASS
4 Independent differential PASS (0 of 12169, at three limits; control sees 1083)
5 The rows under four mutants PASS (each mutant fails at least 2)
6 Tests at H PASS (3124 passed in 22 files, plus 66 x 3, 0 failed)
7 CI and SonarCloud PASS (tests still pending, see below)
8 Merge-trees PASS (clean against #1249 and against origin/main, old and new)
9 FX1309B's comment PASS (every fact I could check holds; one head figure has drifted, see below)

1. Ancestry: PASS

git log --format='%H %P %an <%ae> %s' b44c8c8f3..574a8a7a2 lists exactly one commit: 574a8a7a2 with the one parent b44c8c8f3dc508b2d953fbbfa18f2a45177ad078, author Brett Heap at the estate service address. git rev-list --count is 1 and merge-base --is-ancestor b44c8c8f3 H holds, so the push was a fast-forward. The message is ASCII with the Co-Authored-By: Claude Sonnet 5.5 trailer and no closing keyword. git diff --stat: 2 files, 32 insertions, 17 deletions (scripts/repo_shape.py, tests/test_plan_number_limits.py). git diff --check is clean, no added line is over 79 characters, and the diff names neither Sonar nor a rule id.

2. The move is a move: PASS

  • A stripped-line diff of the 13 lines that left _scalar against the 18-line body of _plain_decimal shows only the docstring (3 lines), the comment (2 lines), and if number == 0.0 and any( becoming if not number and any(. Every other statement is the same text.
  • A stronger proof, tools/run/rvd1309b/ast_inline.py: parse both whole files; inline _plain_decimal's body (docstring dropped, not number mapped back to number == 0.0) into _scalar at its one call site; drop the helper; compare ast.dump of the two modules. Output: helper args: (text: str) -> float, not-number sites mapped back: 1, inlined call sites: 1, module AST equal after inline: True. So nothing else in the file moved: not a message, a remedy, an exception type, the order of tests, or _scalar's docstring.
  • _scalar reads if re.fullmatch(r"-?\d+\.\d+", text): return _plain_decimal(text): the same pattern, in the same place (after the integer branch), then return text. The helper is module-level, after _UNMADE_NUMBER_REMEDY, and git grep _plain_decimal at H finds only its definition and that one call.

3. not number is the same test: PASS

CPython's float.__bool__ is ob_fval != 0.0, so not x is x == 0.0 for every non-NaN float and, for a NaN, both are False. For the text this pattern admits (-?\d+\.\d+, digits of any script) float() makes no NaN, and inf is refused by the isinf test above it, so the two tests agree on every float that can reach it. Probe (check3.py): 89 floats, among them 0.0, -0.0, NaN, both infinities, the smallest subnormal 5e-324 and its neighbours (bit patterns 1 to 63), the largest subnormal 2.225073858507201e-308, the smallest normal, and values just either side: 0 mismatches of x == 0.0 against not x. Twenty plain-decimal texts through both files' _scalar: 0 differences; the round-to-zero edge reads as the old code did (0.<323 zeros>2 and the exact half of 5e-324 are refused as zero, 0.<323 zeros>3 reads as 5e-324, -0.0 stays -0.0, the largest subnormal and the smallest normal stay numbers).

4. Independent differential: PASS

diff_probe.py (mine, seed 1309) calls _scalar from b44c8c8f3's file and from H's on 12169 inputs and compares the value's type and repr, or the exception's type, full text, remediation, line, cause type and context. Inputs: structured decimals (zero runs of 0 to 9000 in 25 boundary lengths around 323, 4300, 4301, nonzero digit at front, after the run, in the middle, at the end, two of them; 8 digit scripts mixed in); 2600 random digit strings with zero density from 0 to 1; 1500 decimal expansions of random subnormal, normal and near-overflow floats, some nudged; the eighths of the smallest subnormal; overflow edges and the exact largest-float neighbours; integers of 1 to 9000 digits, nulls, bools, quoted, indicator openers, nan, .inf, 1e5, 1_0.5; 8 whitespace kinds around six values (U+00A0, \x0b and U+3000 are not stripped); and 2400 fuzzed strings. At H the outcomes were 9487 values and 2682 refusals (1527 too small, 810 too large).

PYTHONINTMAXSTRDIGITS sys.get_int_max_str_digits() seen Differences, b44c8c8f3 against H
unset 4300 0 of 12169
640 640 0 of 12169 (25 more too long refusals)
0 0 0 of 12169

Negative control (mutant as H, same probe, unset): (m) 1083 differences, (o) 1225, (r7) 199, (r8) 1015. (m) at 640 and at 0: 1083 each. So the probe can see a difference.

5. The rows under four mutants: PASS

The two new rows assert k: 0.<323 zeros>1<4400 zeros> and its minus twin at line 1 with 4725 digits (the leading 0, 323 zeros, the 1 and 4400 zeros; the point is not counted), by yaml-unparsable, the remedy and a YamlError cause. Whole file (66 rows), in the worktree rvd1309b-mut-wt, each old whole-file mutant copied over scripts/repo_shape.py, the file restored with git checkout and its sha256 checked each time (65d8a6f37819ea8f...de67da9, restore-OK four times):

Mutant Result Rows that fail
(m) last digit only 4 failed, 62 passed nonzero-digit-not-last, -negative, nonzero-digit-then-many-zeros, -negative (DID NOT RAISE)
(o) one int() of all digits 4 failed, 62 passed the same four (ValueError: Exceeds the limit (4300 digits))
(r7) tail window [-4300:] 2 failed, 64 passed nonzero-digit-then-many-zeros and -negative
(r8) last two digits 2 failed, 64 passed the same two

(r7) and (r8) pass every earlier row, so the two new rows are what kill them; every mutant fails at least two.

6. Tests at H: PASS

Environment: the reviewer rules' (stub gh first on PATH, GH_TOKEN=bogus, an empty GH_CONFIG_DIR, git-filter-repo on PATH, empty GIT_CONFIG_GLOBAL, LANES_*, GIT_ALLOW_PROTOCOL, GIT_SSH_COMMAND unset). At most 2 pytest runs at a time. The stub gh was never called (it leaves no log).

Run Result
tests/test_plan_number_limits.py, PYTHONINTMAXSTRDIGITS unset / 640 / 0 66 passed / 66 passed / 66 passed
tests/test_load_yaml_refusals.py 112 passed
tests/test_repo_hygiene.py 101 passed
10 more files (shard 0, listed below) 1795 passed, 8 skipped
10 more files (shard 1, listed below) 1116 passed

The 20 files I chose, from the 14 that name _scalar and the readers' own: test_family_add_gitlink_and_null_members, test_family, test_leg_path_yaml_scalars, test_manifest_validator, test_adopt_plan_yaml_quoting, test_windows_paths, test_yaml_reader_spaces, test_yaml_block_scalar_keys, test_yaml_flow_quotes, test_update_shape_header_comments, test_yaml_quote_boundaries, test_yaml_flow_brackets, test_yaml_indicator_openers, test_yaml_flow_mappings, test_reader_refusals_named, test_bom_reads, test_adopt_plan_escapes, test_adopt_pins, test_validate_pins_named_and_spelled, test_update_shape. The 8 skips are all in test_leg_path_yaml_scalars.py: four got empty parameter set and four the templates read ... back (#259 quotes the leg-path lines), so the rule has nothing to refuse, both computed from the templates and not from the change. I did not rerun FX1309B's 115-file shards; my 22 files overlap them.

7. CI and SonarCloud at H: PASS

gh pr checks 1309 (17:57Z):

tests	pending
SonarCloud Code Analysis	pass	47s
package	pass	31s
tests-git-bash	pass	3m10s

The check-runs API for 574a8a7a2 agrees (tests in_progress, the other three completed/success). tests is the long job and is still pending, which does not fail this check: lane 4's landing pilot reads it on the head itself. No job has failed.

The newest sonarqubecloud[bot] comment is 6774605079 (17:39:28Z, created and never edited): ## Quality Gate passed, 0 New issues, 0 Accepted issues, 0 Security Hotspots, 0.0% Duplication on New Code. Cross-checked against SonarCloud's public API, not the bot alone: the pull request's analysis is of commit 574a8a7a25171413b072164b5cda3d39db50ae83 (analysis 17:38:37Z), qualityGateStatus OK, bugs 0, codeSmells 0; the gate's five conditions are all OK (new_reliability_rating 1, new_security_rating 1, new_maintainability_rating 1, new_duplicated_lines_density 0.0, new_security_hotspots_reviewed 100.0); open issues: 0; python:S1244 and python:S3776 on this pull request are CLOSED, resolution FIXED. My own count of _scalar by SonarSource's rules is 12 (seven if, two or, except at depth 1 for +2, the decimal if) and _plain_decimal 3 (two if, one and), as FX1309B says, and the old 17 (12 plus 5 for the branch at depth 1) is the figure Sonar reported.

8. Merge-trees: PASS

git merge-tree --write-tree of H, all exit 0:

Against Tree Differs from it in
#1249 3e5d1fde1 cc10152fe scripts/repo_shape.py, tests/test_plan_number_limits.py only
origin/main 20e692acd bd53ee1dd adopt-project.py, scripts/repo_shape.py, tests/test_plan_number_limits.py
origin/main f39c6707a (it moved after FX1309B, #1316: shape-doctor.py and two doctor tests) 2aeec27f8 the same three files

adopt-project.py is #1249's file, which #1309 is stacked on. Against the other open PRs that touch scripts/repo_shape.py: #1284 86ab76db4 (d278f6976) and #1171 ce1dd661f (9b0e04aca) are clean and match FX1309B's trees; #1304 is clean at its current head ec240265c (8ab392587). Of the 31 open PRs only #1249 and #1309 touch the rows file.

9. FX1309B's comment against what I verified: PASS

Findings

  • MUST: none.
  • SHOULD: none.
  • NIT: none new.

Left, as FX1309B says, outside this round: #1309 is still a draft stacked on #1249 and needs restacking onto #1249's squash once that lands; its landing is the pilot's, with tests read on the head itself.

Scratch: /workspace/projects/openRepoShape-worktrees/_lane4-scratch/tools/run/rvd1309b/ (probes, logs, scripts), clone rvd1309b-clone, worktrees rvd1309b-wt and rvd1309b-mut-wt (both at H, clean, scripts/repo_shape.py sha256 65d8a6f37819ea8f...de67da9), basetemps /tmp/lane4-rvd1309b-bt/.

Lane: openreposhape-4 (openRepoShape-4)

@brettheap brettheap added this to the v1.2.1 milestone Nov 10, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant