The end+1 → end change in UpperCaseBlock/LowerCaseBlock/SentenceCaseBlock (f3cce7e, fab4b20, e8b2456) was necessary but not sufficient. The duplicate-character symptom it targeted still reproduces: after conversion, GetTextSize() returns 5 and GetNumberofParagraphs() returns 2, where 4 and 1 are expected.
Something in the DeleteBlock() → InsertWordStarString() reinsert path independently reproduces the duplicate-paragraph symptom, separate from the boundary calculation.
Same stale-index pattern as ^KZ: a position is captured, the document is mutated, the original position is reused without recomputation. Per the ^KZ lesson, no further fix attempt until there's a reproducing test that isolates the reinsert path specifically — a second speculative one-liner here risks the same regression cascade.
The
end+1→ end change inUpperCaseBlock/LowerCaseBlock/SentenceCaseBlock(f3cce7e, fab4b20, e8b2456) was necessary but not sufficient. The duplicate-character symptom it targeted still reproduces: after conversion, GetTextSize() returns 5 and GetNumberofParagraphs() returns 2, where 4 and 1 are expected.Something in the DeleteBlock() → InsertWordStarString() reinsert path independently reproduces the duplicate-paragraph symptom, separate from the boundary calculation.
Same stale-index pattern as ^KZ: a position is captured, the document is mutated, the original position is reused without recomputation. Per the ^KZ lesson, no further fix attempt until there's a reproducing test that isolates the reinsert path specifically — a second speculative one-liner here risks the same regression cascade.