Repro
Test doc: https://docs.google.com/document/d/1YKyqqH8wZa3kSnoBEdlwAumI94gRivSsZB1qvc9y4CA (title: sample3)
The doc has a "Columns" section where a single paragraph contains an inline <x-colbreak/> mid-paragraph, followed by a ## Columns heading:
...across to the next.<x-colbreak/>When columns are not created correctly...Obviously, that is not accessible.
The inline columnBreak element splits the paragraph into two columns in the rendered Google Doc.
Edit applied to the pulled markdown: change Obviously to Clearly (same paragraph, after the <x-colbreak/>). No other changes.
Push, then re-pull.
Expected
The inline <x-colbreak/> stays in its original position (mid-paragraph), the paragraph text reflects Clearly instead of Obviously, and the column layout is preserved.
Actual
After re-pull:
- The mid-paragraph
<x-colbreak/> is gone from its original position — the two halves of the paragraph joined into a single paragraph.
- A standalone
<x-colbreak/> appears at the end of the tab, after the final paragraph.
- The document's two-column layout is broken.
Likely area
The reconciler / diffmerge path for paragraphs that contain special inline elements (columnBreak, pageBreak, etc.). A text edit inside a paragraph should be an in-place deleteContentRange+insertText that preserves sibling inline elements; instead, the paragraph appears to be rewritten in a way that loses the inline column break and then a synthetic one gets re-emitted at tab end.
Starting points for investigation:
extradoc/src/extradoc/serde/markdown/_from_markdown.py:131 (_X_COLBREAK_RE) and :1104 — where <x-colbreak/> is parsed into ParagraphElement(column_break=ColumnBreak()).
extradoc/src/extradoc/serde/markdown/_to_markdown.py:477 — serialization of columnBreak to <x-colbreak/>.
extradoc/src/extradoc/diffmerge/content_align.py and extradoc/src/extradoc/diffmerge/diff.py — alignment of paragraph elements across base / ancestor / mine. It is worth checking whether the content alignment treats columnBreak as a matchable element or discards it when the surrounding text changes.
extradoc/src/extradoc/reconcile_v3/lower.py:1875 — lowering of columnBreak / pageBreak / equation inline elements.
It is also worth checking whether the 3-way merge in diffmerge/apply_ops.py drops the columnBreak when the containing paragraph is classified as "changed" and whether a separate codepath re-appends any unmatched columnBreak to the end of the tab.
Environment
- main @ f252136
- Doc id:
1YKyqqH8wZa3kSnoBEdlwAumI94gRivSsZB1qvc9y4CA
Repro
Test doc: https://docs.google.com/document/d/1YKyqqH8wZa3kSnoBEdlwAumI94gRivSsZB1qvc9y4CA (title: sample3)
The doc has a "Columns" section where a single paragraph contains an inline
<x-colbreak/>mid-paragraph, followed by a## Columnsheading:The inline
columnBreakelement splits the paragraph into two columns in the rendered Google Doc.Edit applied to the pulled markdown: change
ObviouslytoClearly(same paragraph, after the<x-colbreak/>). No other changes.Push, then re-pull.
Expected
The inline
<x-colbreak/>stays in its original position (mid-paragraph), the paragraph text reflectsClearlyinstead ofObviously, and the column layout is preserved.Actual
After re-pull:
<x-colbreak/>is gone from its original position — the two halves of the paragraph joined into a single paragraph.<x-colbreak/>appears at the end of the tab, after the final paragraph.Likely area
The reconciler / diffmerge path for paragraphs that contain special inline elements (
columnBreak,pageBreak, etc.). A text edit inside a paragraph should be an in-placedeleteContentRange+insertTextthat preserves sibling inline elements; instead, the paragraph appears to be rewritten in a way that loses the inline column break and then a synthetic one gets re-emitted at tab end.Starting points for investigation:
extradoc/src/extradoc/serde/markdown/_from_markdown.py:131(_X_COLBREAK_RE) and:1104— where<x-colbreak/>is parsed intoParagraphElement(column_break=ColumnBreak()).extradoc/src/extradoc/serde/markdown/_to_markdown.py:477— serialization ofcolumnBreakto<x-colbreak/>.extradoc/src/extradoc/diffmerge/content_align.pyandextradoc/src/extradoc/diffmerge/diff.py— alignment of paragraph elements across base / ancestor / mine. It is worth checking whether the content alignment treatscolumnBreakas a matchable element or discards it when the surrounding text changes.extradoc/src/extradoc/reconcile_v3/lower.py:1875— lowering ofcolumnBreak/pageBreak/equationinline elements.It is also worth checking whether the 3-way merge in
diffmerge/apply_ops.pydrops thecolumnBreakwhen the containing paragraph is classified as "changed" and whether a separate codepath re-appends any unmatchedcolumnBreakto the end of the tab.Environment
1YKyqqH8wZa3kSnoBEdlwAumI94gRivSsZB1qvc9y4CA