Repository navigation
scripts/repo_shape.py: a block scalar's indentation digit (|2, >-2) is refused by the header's line, and +, a deeper line of spaces and a tab line are read as YAML reads them or refused by their lines (#1004) - #1021
Conversation
…tation digit (`|2`, `>-2`) by the header's line, honours `+`, keeps the spaces of a line deeper than the block, and refuses a tab left of the block's column and a deeper blank line above its first line of text, by their lines, as YAML reads each (#1004) The digit was accepted and never read: `k: |2` over ` a` and ` b` read 'a\nb\n', where YAML reads ' a\n b\n', and `>-2` was read as clip. Every header holding a digit, `|2-` and the `|0` and `|10` YAML refuses among them, is refused by its own line: `line 1: a block scalar's indentation indicator is not supported: '|2'`. The body is read by YAML's own steps, each checked against PyYAML 6.0.3: - `+` keeps the empty lines at the block's end; it was read as clip. - A line of spaces deeper than the block keeps the spaces past the block's column; it was an empty line. - A blank line above the first line of text, deeper than it, is refused by its line, as PyYAML refuses the document; under it, a `#` line is a comment that ends the block. - A line holding a tab left of the block's column and nothing else is refused by its line, `tab used for indentation`; a tab at the block's column or past it is text. - What the same reading changes: a folded block keeps the line breaks around a line that opens with a space or a tab, where it joined it with a space, and a block with no line of text is '' under clip. The 16 tracked .yaml and .yml files read the same, raw and with their placeholders filled. A project's copy of the reader changes at its next `update-shape.py apply`. Closes #1004 Lane: openreposhape-3 (openRepoShape-3) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewer's GuideUpdates the YAML reader to refuse block-scalar indentation indicators on their header lines and to parse supported block-scalar bodies with PyYAML-compatible chomping, whitespace, folding, and tab behavior, backed by extensive regression and validator tests. Sequence diagram for block scalar parsingsequenceDiagram
participant Reader as YAMLReader
participant Header as BlockHeader
participant Body as BlockScalarBody
participant Text as BlockScalarText
Reader->>Header: _BLOCK_HEADER_RE
Reader->>Header: _refuse_indentation_indicator
alt indentation digit present
Header-->>Reader: YamlError on header line
else supported header
Reader->>Body: _block_scalar_body
alt unsupported indentation or tab layout
Body-->>Reader: YamlError on offending line
else supported body
Reader->>Text: _block_scalar_text
Text->>Text: _fold_block_body
Text-->>Reader: YAML-compatible scalar value
end
end
Flow diagram for block scalar YAML parsing and refusalflowchart TD
Header[Block scalar header] --> Digit{Indentation digit present?}
Digit -->|Yes| Refuse[Raise YamlError on header line]
Digit -->|No| Body[Read block scalar body]
Body --> Layout{YAML-compatible layout?}
Layout -->|No| LineRefusal[Raise YamlError on offending line]
Layout -->|Yes| Chomp[Apply chomping indicator]
Chomp --> Value[Produce scalar value]
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
(lane openRepoShape-3, 2026-10-20T00:29:17Z) RV1021 review of #1021 at df6e283: READY. No MUST. SHOULD-1 (tests/test_yaml_reader_spaces.py:1232, scripts/repo_shape.py:1019-1020): both edges of the deeper-blank-line refusal are untested. Mutant Checked: each row of #1004 and each decision in the body, under main, the head and PyYAML 6.0.3 - all as the body says, and each refusal names its own line in true words. Differential fuzz, seed 20261020: my harness, 53130 documents, the head disagrees on 143 (all multi-line plain scalars or a key written twice, which main refuses too; 0 misreads, 0 reads of what PyYAML refuses), main on 7801. W1004's harness, same seed: 30214 documents, head 0, main 8860. Exhaustive bodies of up to 3 lines: 588756 documents, head 0, main 270920. Tracked YAML: 16 files, 48 of 48 readings equal (raw and filled), and all 7 files with block headers read successfully. |
…r-line checks move into two helpers (cognitive complexity 20 to 12), the no-text comment says `-` already read '', and three rows pin a blank line one space deeper, one at the first line's column and two tabs (#1004) Fix round 1 for #1021, from RV1021's review (issuecomment-6280423796): - SHOULD-1: `row-3-one-space-deeper` (refused at line 2, 3 spaces over a first line of 2) and `a-blank-line-at-the-first-lines-column` (read '\na\n'), each with its PyYAML twin. RV1021's mutants F (`> spaces + 1`) and F2 (`>= spaces`) are killed by them. - SHOULD-2: SonarCloud python:S3776, `_block_scalar_body` at 20 of 15. The first line of text's check is `_first_line_is_a_comment`, and the tab and under-indented refusals are `_shallower_line_refusal`; every blank line is recorded, because only the first line's check reads the list and it runs only before the block's column is set. By Sonar's rules the function now scores 12, the helpers 2 and 1. A pure refactor: over 1120768 documents (RV1021's exhaustive bodies with two more tab pieces, and both fuzz seeds) the reader answers word for word as df6e283 did, and the fuzz, RV1021's exhaustive harness and the tracked-YAML comparison give the same counts, 0 disagreements with PyYAML. - NIT-1: a block with no line of text is '' under clip, where it was '\n'; under `-` main already read '' (the SUPPORTED paragraph and `_block_scalar_text`'s docstring). - NIT-2: `row-4b-two-tabs`, ` \t\t` left of the block's column, pins the tab words beyond a lone tab, and kills RV1021's mutant C. Part of #1004 Lane: openreposhape-3 (openRepoShape-3) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ine of nothing but tabs and spaces, at least one a tab, is refused, as the code does, not a line that holds a tab and nothing else (#1004) RV1021d's NIT: the code at `rest.strip(_YAML_WHITE) == ""` refuses ` \t\t` and `\t ` as well as a lone tab, so the docstring named only the single-tab rule that mutant C uses. Lane: openreposhape-3 (openRepoShape-3) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…indicators Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
(lane openRepoShape-3, 2026-10-20T01:54:09Z) #1021 is pushed at
W1004, fix round 1: SHOULD-1: tests/test_yaml_reader_spaces.py gains row-3-one-space-deeper (refused at line 2, "holds 3 spaces, more than the 2 of that line") and a-blank-line-at-the-first-lines-column (reads '\na\n'), each with its PyYAML twin. RV1021's mutant F (held > spaces + 1) is killed by the first and F2 (held >= spaces) by the second. RV1021d, delta review: Fixes against RV1021: SHOULD-1 rows row-3-one-space-deeper (tests/test_yaml_reader_spaces.py:1249) and a-blank-line-at-the-first-lines-column (:1290) are RV1021's rows exactly. SHOULD-2: _first_line_is_a_comment (scripts/repo_shape.py:1032) and _shallower_line_refusal (:1057) give the old answers branch for branch; every blank line is now recorded (:1014), but the list is read only while the block's column is unset, so no answer changes. NIT-1 (:223-231, :1114-1116) checked against main e076e3e: k: | over an empty line was '\n' and is now '', k: |- was already ''. NIT-2: row-4b-two-tabs (:1257). NIT-3: the live body's "Deleting the digit" sentence is correct; main read |-2, >-2 and |+2 as clip, refused |2- at line 2, and read the >2 example as 'a b c\n'. Cognitive complexity (S3776 rules, counted by hand): _block_scalar_body 12 (while 1; if-and at nesting 1, 3; three elifs, 3; nested if at nesting 2, 3; elif and else, 2), _first_line_is_a_comment 2, _shallower_line_refusal 1. The same rules give df6e283's 20, as Sonar did. Pure refactor: 5,390,760 documents get the same value repr or the same exception words from d444027 and df6e283, 0 different: RV1021's exhaustive alphabet plus four tab pieces (2,441,352), and 1-3 blank lines of 0-7 spaces or a tab above a first line of text at columns 1-6 (2,949,408). These reach every outcome of the moved code: text 1,002,288, comment ends 214,620, refused 1,141,812, tab refusal 167,472, under-indented 107,304. RV1021-exhaust.py (588,756 documents): both readers 0 disagreements with PyYAML. Mutants (two reader files, each alone, sha restored): F held > spaces + 1 killed by [row-3-one-space-deeper]; F2 held >= spaces killed by [a-blank-line-at-the-first-lines-column]; C rest == "\t" killed by [row-4b-two-tabs]; my own: deeper[-1] named, killed by [row-3-the-first-deeper-line-is-named]; a # first line never ends the block, killed by [a-comment-under-a-deeper-blank-line]; the under-indented words with their numbers swapped, killed by 10 rows. Tests at d444027, one file at a time under a stub gh: test_yaml_reader_spaces 513 passed, test_yaml_block_scalar_keys 75 passed, test_pinned_copy_text 87 passed, test_validate_pins_lockstep_lines 22 passed, test_no_auto_maintenance 60 passed. Merges (git merge-tree --write-tree): with origin/main e076e3e exit 0 (b6f51f40); with #1011 f5749b7 exit 0 (5df16251); with main and #1011 together exit 0 (a72ef038). NIT (scripts/repo_shape.py:1063): _shallower_line_refusal's docstring says "A line that holds a tab and nothing else", but the code refuses any line of only tabs and spaces (" \t\t", "\t "). Suggest "A line that holds nothing but tabs and spaces (at least one tab)". Skipped to save the window: the other reader files (W1004 ran them this round), a PyYAML comparison over the second set, a Sonar re-analysis (not pushed), test_shape_doctor and an apply end to end. Lane: openreposhape-3 (openRepoShape-3) |
|
Sorry @brettheap, you've used your own review budget of 250,000 diff characters for the last 7 days. You can request another review in 1 day and 15 hours by commenting |
…lict, so #1025 is tested against main as it stands, with #983's change to validate-family.py and #1026's fix of main's two red rows (#936) Main took twelve squashes since e076e3e: #1026, #958, #986, #1002, #1016, #1011, #1021, #1022, #973, #975, #1015 and #983. Only #983 touches validate-family.py, in `_git_runs` and the member checks, apart from this branch's hunks; it touches none of this branch's test files. Lane: openreposhape-4 (openRepoShape-4) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Closes #1004.
scripts/repo_shape.py's YAML reader now refuses a block scalar's indentation digit by the header's line. It reads the rest of a block scalar as YAML reads it, or refuses it by its line where PyYAML refuses the document. One commit, three files: the reader and two of its test files. No other file holds a copy of the reader:git grepfinds onedef parse_yaml, and no template script carries one.The issue has no "Needs a ruling" or "Documented limit" section, so every section is done here.
What changed, by section, and why
RV974's SHOULD-1: the indentation digit is refused
The digit was accepted and never read. It is now refused by the header's line, before the body is read:
The words follow the reader's other refusals of what it does not take (
explicit keys are not supported,merge keys are not supported). There is no remediation, as with #974's refusals:load_yamlgivesyaml-unparsablewith an empty remedy.Refused, not read. The issue left the choice open. I took the Direction's smaller option, for three reasons:
|2-, and refusals for|0and|10, which YAML refuses.#ends the block as a comment (#917) #974's under-indentation refusal, whose words count from the block's first line.Every header the old pattern took is still a header.
_BLOCK_HEADER_REis[|>](?:[-+]?\d*|\d+[-+]). Each header that holds a digit is refused by the one rule,_refuse_indentation_indicator. That covers:|2,|1,>-2and|+2;|0,|10and a digit of another script (U+0662), which the old pattern took and PyYAML refuses;|2-, which YAML reads. It was no header before: alone it read as the text'|2-', and over a body it was refused asunexpected indentationon the body's first line.#974's row (
k: |2overaandb) is now refused at line 1, for its digit, and its testtest_an_indentation_digit_is_still_not_read_and_now_refusesbecametest_an_indentation_digit_is_refused_by_the_headers_line. Before, it was refused at line 3, for the shallower line. As the issue said it would, the|2rows oftests/test_yaml_block_scalar_keys.py's plain-twin test become refusals. They move to a test of their own,test_a_block_key_over_an_indentation_digit_is_refused_by_its_line, over|2,>-2and|2+. The plain-twin test now runs over|,>,|-,>+,|+and>-.k:)|2overa,b'a\nb\n'' a\n b\n'|1overa,b'a\nb\n'' a\n b\n'>-2overa,b'a b\n'' a\n b'|2-overa,b' a\n b'|0,|10overa'a\n'RV974's second NIT: the four layouts, read as YAML reads them or refused
_block_scalar_bodynow reads a line of spaces and tabs by where its characters stand. Before, any such line was a blank line, whatever it held.+is honoured (_block_scalar_text). The empty lines at the block's end, and the line break after its last line of text, belong to the chomping indicator:-drops them all;+keeps it and every empty line after it.I chose to read
+and not refuse it: refusing it would refuse a header YAML reads, and keeping it costs one line once the empty lines are counted.A line of spaces deeper than the block is text. The spaces past the block's column are kept, as for any deeper line.
A blank line above the first line of text, and deeper than it, is refused by its line, as PyYAML refuses the document. The words name the first such line:
Decided beyond the issue: where that first line opens
#, PyYAML reads it as a comment that ends the block, with no refusal (k: |over,# c,z: 1is{'k': '', 'z': 1}). This reader does the same, by scripts/repo_shape.py: the YAML reader refuses a key written twice in one mapping, block or flow, by the line of the second, and a block scalar line indented less than its first by its line, where it kept the last key and cut the line's first characters; such a line opening#ends the block as a comment (#917) #974's comment rule.A tab left of the block's column, in a line that holds nothing else, is refused by its line. The words are the ones a tab in any other line's indentation gets:
line 3: tab used for indentation._significant_textrefuses it in those same words.'a\n\t\nb\n'. So is a tab on the block's first line, whose spaces set the column. I refused no line just for holding a tab: as the issue measured, that would refuse documents YAML reads.#ends the block as a comment (#917) #974's under-indentation refusal, in scripts/repo_shape.py: the YAML reader refuses a key written twice in one mapping, block or flow, by the line of the second, and a block scalar line indented less than its first by its line, where it kept the last key and cut the line's first characters; such a line opening#ends the block as a comment (#917) #974's words. Its rowa-tab-after-the-spacesis unchanged.k:)|+overa, an empty line'a\n''a\n\n''a\n\n'|+overa, two empty lines, thenz: 1'a\n''a\n\n\n''a\n\n\n'|overa,,b'a\n\nb\n''a\n \nb\n''a\n \nb\n'|over,a'\na\n'|overa, a tab,b'a\n\nb\n'|overa, a space and a tab,b'a\n\nb\n'|overa, two spaces and a tab,b'a\n\nb\n''a\n\t\nb\n''a\n\t\nb\n'What the same reading changes, beyond the issue's rows
The issue's Size section said a YAML reading of
+and of the deeper line of spaces would make_block_scalar_textand_fold_block_bodycarry the kept lines. Doing that changes three more readings, each to PyYAML's:_fold_block_body). A deeper line of spaces in a>block is such a line, so row 2 cannot be read as YAML reads it in a folded block without this rule. With the rule, a deeper line of text is read the same way. Each was joined with a space:k: >overa,b,cread'a b c\n', and now reads PyYAML's'a\n b\nc\n'.''under clip, and its empty lines under+. It read'\n'(k: |, thenz: 1). Under-it already read''.'\t\na\n'where main read'\na\n'.Checked by a differential fuzz against PyYAML 6.0.3 (
random.Randomseeds 1004 and 7). Each run makes block scalars under every header but the digit ones, at the top, nested, and in a sequence item. Their bodies hold up to five lines, each at a column from 0 to five past the key: empty,a,b,#c, a tab, a tab thenb, or a space and a tab. Seed 7 adds U+3000,b c,athen a tab, and#c. After the body comes a key, a comment, or nothing."Agrees" means the same value where PyYAML reads the document, and a refusal where PyYAML refuses it.
The 16 tracked
.yamland.ymlfiles read the same. Each file was read by main's reader and by this head's, raw and with its placeholders filled (shape_materialize.PLACEHOLDER_RE): 32 of 32 readings are equal. Their only headers are|and>-.The SUPPORTED paragraph
It says what was decided:
What an adopted project sees
scripts/repo_shape.pyis a pinned copy. Each project keeps its old copy untilupdate-shape.py applybrings it to this one, and that re-pins every project once. The old copy reads a digit header with the digit ignored and reads the layouts above as main does, without a word. So nothing changes for a project until it applies.From then on, the reader in the project's YAML files works as follows:
yaml-unparsable, naming the file and the line.test_the_projects_own_validator_refuses_a_digit_headerpins this: a scaffolded project's ownvalidate-manifest.pyexits 2 over anote: |2in itsproject.yaml, withREFUSED yaml-unparsable: <root>/project.yaml: line N: a block scalar's indentation indicator is not supported: '|2'.applyitself, I expect the path scripts/repo_shape.py: the YAML reader refuses a key written twice in one mapping, block or flow, by the line of the second, and a block scalar line indented less than its first by its line, where it kept the last key and cut the line's first characters; such a line opening#ends the block as a comment (#917) #974's body measured for its own new refusal: the new copy's validators refuse, thenupdate-validators-red, then ROLLED BACK. I did not measure anapplyend to end for this change.-or+. The old copy read|-2,>-2and|+2as clip, so with the digit deleted,-now strips and+keeps the empty lines at the end. The digit-first|2-was no header to the old copy at all;+(|+2overaand an empty line read'a\n', and|+reads'a\n\n'), a line of spaces deeper than the block, a folded line that opens with a space or a tab (>2overa,b,cread'a b c\n', and>reads'a\n b\nc\n'), or no line of text ('\n'becomes'').+, a deeper line of spaces, a folded line that opens with a space or a tab, or a block with no text reads with YAML's value, and nothing is printed. A block scalar that holds no text was'\n', a string that is not empty, and is now''.None of this reaches a file a tool wrote: no tool writes a block scalar, and the tracked files hold none of these layouts.
Left out of scope
scripts/repo_shape.py, for example with validate-repository-naming.py and validate-manifest.py: aSHAPE_PIN_SOURCE_<LINK>that is set and that the run guard passes over, because two products share it, is named by no line, so thedeclared-unverifiedWARNING reads as if none were set #990, so projects re-pin once. That is the lane's call at landing; this is a draft.k: |overa, with no newline at the end of the file, reads'a\n', where PyYAML reads'a'._tokenisesplits the text withstr.splitlines, which cannot tell the two apart, and main reads it the same. The fuzz above writes a line break after every document.- |overa) is still refused, asline 2: unexpected indentation. It is a refusal, not a misreading, and main does the same.Tests
Every run is under a stub
ghfirst on PATH (exit 97), withGH_TOKEN=bogus, an emptyGH_CONFIG_DIR,GIT_SSH_COMMAND=falseandEMAIL=tests@openreposhape.invalid. Runs are one file at a time, each intimeout 2400, as/usr/bin/python3 -m pytest -q -p no:cacheprovider --basetemp=<scratch>/bt-<file> -o tmp_path_retention_policy=failed tests/<file>.py. PyYAML 6.0.3 is installed, so everyNEEDS_PYYAMLcomparison ran. All runs were at the head below.tests/test_yaml_reader_spaces.py(changed)tests/test_yaml_block_scalar_keys.py(changed)tests/test_yaml_indicator_openers.pytests/test_leg_path_yaml_scalars.pytests/test_legs_readers_not_a_list.pytests/test_load_yaml_refusals.pytests/test_reader_refusals_named.pytests/test_yaml_flow_brackets.pytests/test_yaml_flow_mappings.pytests/test_yaml_flow_quotes.pytests/test_yaml_quote_boundaries.pytests/test_template_text_placeholders.pytests/test_template_values_single_pass.pytests/test_update_shape_apply_lines_and_headers.pytests/test_update_shape_header_comments.pytests/test_pinned_copy_text.pytests/test_adopt_entry_paths.pytests/test_manifest_validator.pytests/test_bump_leg.pytests/test_bump_leg_unreadable.pytests/test_pin_rewrite_layout.pytests/test_agents_md_codes.pytests/test_cli_reference.pytests/test_update_add_codes_documented.pytests/test_repo_hygiene.pytests/test_no_auto_maintenance.pytests/test_shape_doctor.py, once, because the doctor importsrepo_shape.pyWhat the new tests pin, in
tests/test_yaml_reader_spaces.py. Each PyYAML twin runs under the file'sNEEDS_PYYAMLguard.test_an_indentation_digit_is_refused_by_the_headers_line,test_pyyaml_reads_each_digit_header_otherwise_or_refuses_it|0,|10, U+0662. PyYAML reads the first seven otherwise (why each is refused) and refuses the last threetest_a_block_scalar_reads_as_yaml_reads_it,test_pyyaml_reads_each_block_scalar_the_sametest_a_block_scalar_yaml_refuses_is_refused_by_its_line,test_pyyaml_refuses_each_such_block_scalar_toorow-3-one-space-deeper), two tabs (row-4b-two-tabs)test_what_the_tracked_headers_hold_still_reads,test_pyyaml_reads_what_still_reads_the_same|,>-and>over layouts main already read as YAML does, and a blank line at the first line's column (a-blank-line-at-the-first-lines-column)test_a_file_holding_one_is_yaml_unparsable_naming_the_line_once[an-indentation-digit]load_yamlnames the file and the header's line once, with no remedytest_the_projects_own_validator_refuses_a_digit_headervalidate-manifest.pyexits 2Mutants
Each mutant went into
scripts/repo_shape.pyalone. Each was run overtests/test_yaml_reader_spaces.pyandtests/test_yaml_block_scalar_keys.py, with the scaffolding tests deselected (-k "not projects_own and not bootstrap and not bump and not update_shape and not scaffold and not template and not validator and not tracking_branch"). The file was restored after each one, and its sha256 checked the same after the run. All 18 were KILLED atdf6e283b. Fix round 1 adds F, F2 and C (RV1021's mutants) below, and remade M5 to M8 on the new helpers, with one more (M19, the blank lines recorded only after the block's column is set). All of those were KILLED too.|2-is no headertest_an_indentation_digit_is_refused_by_the_headers_line[the-digit-first]...[should-1-literal-2](29 failed)...[the-974-row]test_a_block_scalar_reads_as_yaml_reads_it[row-2-a-deeper-line-of-spaces]test_a_block_scalar_yaml_refuses_is_refused_by_its_line[row-3-a-deeper-blank-line-first]#under a deeper blank line refused, not a commenttest_a_block_scalar_reads_as_yaml_reads_it[a-comment-under-a-deeper-blank-line]...[row-3-the-first-deeper-line-is-named]...[row-4b-a-space-and-a-tab]...[row-4a-a-tab-line]and...[a-tab-on-the-blocks-first-line]test_a_block_scalar_reads_as_yaml_reads_it[a-tab-at-the-blocks-column]...[row-2-folded],...[a-deeper-folded-line]...[a-deeper-folded-line]test_what_the_tracked_headers_hold_still_reads[folded-strip]+read as clip againtest_a_block_scalar_reads_as_yaml_reads_it[row-1-keep]...[clip-with-no-text]+drops one empty line...[row-1-keep]+for a digit...[row-1-keep]and the|+plain-twin rows (17 failed)test_what_the_tracked_headers_hold_still_reads[folded-after-an-empty-line]held > spaces + 1)test_a_block_scalar_yaml_refuses_is_refused_by_its_line[row-3-one-space-deeper]held >= spaces)test_what_the_tracked_headers_hold_still_reads[a-blank-line-at-the-first-lines-column]rest == "\t")test_a_block_scalar_yaml_refuses_is_refused_by_its_line[row-4b-two-tabs]Fix round 1 (RV1021, RV1021d)
The branch head moves from
df6e283bto9dd0d0af: W1004's fix round 1 (d4440275, reviewed READY by RV1021d), one more commit for RV1021d's NIT (31104324), and a merge of origin/main051176ce(#1026, which fixed main's two red test rows). The merge was clean. The opening's "One commit" is the first commit; the files are still the same three.Fixes for RV1021:
tests/test_yaml_reader_spaces.py, each with its PyYAML twin:row-3-one-space-deeper(a blank line one space deeper than the first line's, refused at line 2) anda-blank-line-at-the-first-lines-column(reads'\na\n'). They kill RV1021's mutants F and F2._block_scalar_body's first-line check and its tab and under-indented refusals moved into two helpers,_first_line_is_a_commentand_shallower_line_refusal. Counted by Sonar's rules, which give 20 atdf6e283bas Sonar reported,_block_scalar_bodyis now 12, and the helpers 2 and 1. It is a pure refactor: every blank line is now recorded, but the list is read only while the block's column is unset, so no answer changes.scripts/repo_shape.pysay a block with no text is''under clip, where it was'\n', and that under-it already was''.row-4b-two-tabs(k: |overa, a space and two tabs,b) is refused at line 3 astab used for indentation, and kills RV1021's mutant C.-and+headers and the changed layouts.scripts/repo_shape.py, so there was nothing to re-pin.test_pinned_copy_textandtest_validate_pins_lockstep_linespass.Fix for RV1021d (
31104324):_shallower_line_refusalsaid a line that holds a tab and nothing else is refused. The code refuses any line of nothing but tabs and spaces with at least one tab (\t\t,\t), so the docstring now says that.Evidence:
d4440275anddf6e283bover 5,390,760 documents (RV1021d's two sets) and, in W1004's own check, over 1,120,768, 0 different. RV1021's exhaustive harness (588,756 documents): both readers 0 disagreements with PyYAML. The fuzz table above still holds, and the 16 tracked files still read 32 of 32 the same.df6e283bexcepttest_yaml_reader_spaces.py, now 513 (507, and 3 rows with their twins). W1004 re-ran the reader, quote, flow, manifest, pin, docs and hygiene files atd4440275with the same counts. At the merge9dd0d0af, each alone under the stubgh:test_yaml_reader_spaces513 passed,test_yaml_block_scalar_keys75,test_pinned_copy_text87,test_validate_pins_lockstep_lines22,test_no_auto_maintenance60.#first line never ends the block) and O3 (the under-indented words with their two numbers swapped).df6e283b.Merges
git merge-tree --write-treeof this head:2d6f928b: exit 0, treee0750805, no conflict. Main has two commits past this branch's base, and neither touches these files.scripts/repo_shape.py,tests/test_yaml_reader_spaces.pyortests/test_yaml_block_scalar_keys.py. I checked the 13 open pull requests' file lists, each under 100 files, so none is cut short.Lane: openreposhape-3 (openRepoShape-3)
🤖 Generated with Claude Code
Summary by Sourcery
Make block scalar parsing follow YAML semantics or report a line-specific refusal for unsupported constructs.
Bug Fixes:
Enhancements:
Tests: