fix: track new lines in suggested mode#3600
Conversation
|
I need to be upfront: every call to the ecma-spec MCP tools was blocked at the permission layer (I retried ~9 times across Here's the review based on reading the actual emitted XML in the changed handlers. Status: FAIL The core of this PR is actually a compliance improvement, but there's one genuine schema-order violation introduced by the new export path, plus a pre-existing non-standard attribute that flows through the changed code. 1.
2. Non-standard
What's correct / improved (for the record):
The headline issue is #1 (ordering); #2 is pre-existing cleanup. |
There was a problem hiding this comment.
cubic analysis
3 issues found across 17 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/super-editor/src/editors/v1/core/super-converter/v3/handlers/w/p/helpers/generate-paragraph-properties.js">
<violation number="1" location="packages/super-editor/src/editors/v1/core/super-converter/v3/handlers/w/p/helpers/generate-paragraph-properties.js:24">
P2: Descendant traversal can clear a previously found paragraph-split mark, causing paragraph split tracking to be skipped.</violation>
<violation number="2" location="packages/super-editor/src/editors/v1/core/super-converter/v3/handlers/w/p/helpers/generate-paragraph-properties.js:61">
P2: `w:rPr` is prepended to `w:pPr`, which can break paragraph-property element ordering.</violation>
</file>
<file name="packages/super-editor/src/editors/v1/extensions/track-changes/review-model/decision-engine.js">
<violation number="1" location="packages/super-editor/src/editors/v1/extensions/track-changes/review-model/decision-engine.js:992">
P1: `rejectParagraphSplit` performs `tr.join(...)` in the position-stable mark-op pass, which can invalidate positions for later ops in the same decision transaction.</violation>
</file>
Linked issue analysis
| Status | Acceptance criteria | Notes |
|---|---|---|
| ✅ | Pressing Enter (split run to paragraph) in Suggesting mode records a tracked paragraph-split formatting change that can be accepted or rejected | split-run.js adds addTrackedParagraphSplitMark to create a trackFormat mark for the split; tests in split-run.test.js assert the change is recorded, and that it can be rejected and reverses the split. |
| ✅ | Paragraph-split tracked marks include paragraphSplit snapshots and are exported as a Word-visible paragraph insertion (w:ins) in paragraph properties when exporting a non-final doc (using the Word revision id allocator when present) | helpers detect paragraphSplit snapshots and create w:ins elements for export; generate-paragraph-properties prepends the insertion into w:pPr; tests validate the w:ins element and allocator usage. |
| ✅ | Import restores paragraphSplit snapshots from paragraph mark insertion metadata so imported docs regain the tracked-split representation | markImporter now maps inline paragraph insertion metadata to paragraphSplit snapshots on import; tests verify the snapshot restoration path. |
| ✅ | UI surfaces paragraph splits as a ‘new line’ tracked-change display and Comment dialog shows an 'Added new line' message | tracked-change-display returns a paragraphSplit display type and tests cover it; CommentDialog template and tests were updated to render the 'Added new line' display. |
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
| tr.step(new RemoveMarkStep(op.from, op.to, op.mark)); | ||
| continue; | ||
| } | ||
| if (op.kind === 'rejectParagraphSplit' && op.mark) { |
There was a problem hiding this comment.
P1: rejectParagraphSplit performs tr.join(...) in the position-stable mark-op pass, which can invalidate positions for later ops in the same decision transaction.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/super-editor/src/editors/v1/extensions/track-changes/review-model/decision-engine.js, line 992:
<comment>`rejectParagraphSplit` performs `tr.join(...)` in the position-stable mark-op pass, which can invalidate positions for later ops in the same decision transaction.</comment>
<file context>
@@ -947,6 +989,13 @@ const applyPlan = ({ state, plan }) => {
tr.step(new RemoveMarkStep(op.from, op.to, op.mark));
continue;
}
+ if (op.kind === 'rejectParagraphSplit' && op.mark) {
+ tr.step(new RemoveMarkStep(op.from, op.to, op.mark));
+ if (!rejectParagraphSplitAt(tr, op.from, op.anchor)) {
</file context>
| if (!Array.isArray(runProperties.elements)) runProperties.elements = []; | ||
| const hasParagraphInsertion = runProperties.elements.some((element) => element?.name === 'w:ins'); | ||
| if (!hasParagraphInsertion) runProperties.elements.unshift(insertionElement); | ||
| if (!existingRunProperties) pPr.elements.unshift(runProperties); |
There was a problem hiding this comment.
P2: w:rPr is prepended to w:pPr, which can break paragraph-property element ordering.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/super-editor/src/editors/v1/core/super-converter/v3/handlers/w/p/helpers/generate-paragraph-properties.js, line 61:
<comment>`w:rPr` is prepended to `w:pPr`, which can break paragraph-property element ordering.</comment>
<file context>
@@ -1,5 +1,66 @@
+ if (!Array.isArray(runProperties.elements)) runProperties.elements = [];
+ const hasParagraphInsertion = runProperties.elements.some((element) => element?.name === 'w:ins');
+ if (!hasParagraphInsertion) runProperties.elements.unshift(insertionElement);
+ if (!existingRunProperties) pPr.elements.unshift(runProperties);
+ return pPr;
+}
</file context>
| if (!existingRunProperties) pPr.elements.unshift(runProperties); | |
| if (!existingRunProperties) { | |
| const anchorIdx = pPr.elements.findIndex((element) => element?.name === 'w:sectPr' || element?.name === 'w:pPrChange'); | |
| if (anchorIdx === -1) pPr.elements.push(runProperties); | |
| else pPr.elements.splice(anchorIdx, 0, runProperties); | |
| } |
| found = childMarks.find((mark) => isParagraphSplitTrackFormatMark(mark)) || null; | ||
| return !found; |
There was a problem hiding this comment.
P2: Descendant traversal can clear a previously found paragraph-split mark, causing paragraph split tracking to be skipped.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/super-editor/src/editors/v1/core/super-converter/v3/handlers/w/p/helpers/generate-paragraph-properties.js, line 24:
<comment>Descendant traversal can clear a previously found paragraph-split mark, causing paragraph split tracking to be skipped.</comment>
<file context>
@@ -1,5 +1,66 @@
+ let found = null;
+ node.descendants((child) => {
+ const childMarks = Array.isArray(child?.marks) ? child.marks : [];
+ found = childMarks.find((mark) => isParagraphSplitTrackFormatMark(mark)) || null;
+ return !found;
+ });
</file context>
| found = childMarks.find((mark) => isParagraphSplitTrackFormatMark(mark)) || null; | |
| return !found; | |
| const match = childMarks.find((mark) => isParagraphSplitTrackFormatMark(mark)); | |
| if (match) found = match; | |
| return !found; |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7cb843fabb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
| if (op.kind === 'rejectParagraphSplit' && op.mark) { | ||
| tr.step(new RemoveMarkStep(op.from, op.to, op.mark)); | ||
| if (!rejectParagraphSplitAt(tr, op.from, op.anchor)) { |
There was a problem hiding this comment.
Map paragraph-split positions before joining
When a user rejects two or more paragraphSplit formatting changes in one operation (for example rejectAllTrackedChanges after pressing Enter twice in suggesting mode), the first tr.join changes document positions, but the loop continues using the original op.from/op.to for the later ops. Those stale offsets can make the next RemoveMarkStep/join target the wrong paragraph or fail the whole decision, unlike the previous formatting-only ops which did not change document size.
Useful? React with 👍 / 👎.
No description provided.