Skip to content

Suggest mode: keep review decisions out of undo history - #81669

Merged
adamsilverstein merged 5 commits into
WordPress:suggest/inline-wiringfrom
adamsilverstein:fix/73411-f18-accept-undo
Aug 23, 2026
Merged

adamsilverstein merged 5 commits into
WordPress:suggest/inline-wiringfrom
adamsilverstein:fix/73411-f18-accept-undo

Conversation

@adamsilverstein

Copy link
Copy Markdown
Member

What?

Fixes F-18 from the Suggest mode guided testing results (part of #73411): pressing Ctrl+Z right after accepting a suggestion put the <mark> back but restored no note, leaving a marked-up run with no Accept/Reject on it and no way to clear it through the UI.

Based on suggest/inline-wiring (#80433), like the other Table 1 fixes.

Why?

A review decision is half local and half remote. Applying or rejecting writes to the live block - that part the editor owns - and then sets the comment's lifecycle status, which lives on the server and is shared with every other session. Only the first half is something the undo stack can hold: no keystroke here can walk a collaborator's resolved comment back to pending.

Recording the block half as an ordinary undo level therefore let Ctrl+Z pull the two apart. Undo restored the marker; the note stayed resolved, so the sidebar rendered it under Resolved with an "Applied" label and no decision buttons. The marker had nothing left that could act on it.

How?

Every live-block write a decision makes is now marked history: 'ignore' before it dispatches, through one small ignoreNextChangeInUndo() helper in the suggestions provider. The applied content still reaches the entity and still saves - it is just invisible to undo, so the two halves can no longer come apart.

That covers both decisions and their rollbacks: the inline accept/reject rewrite, the structural remove/insert/move paths, the block-move restore inside registry.batch (marked per dispatch, since the flag only covers the next change), and the attribute-set apply and its failure rollback.

This is the treatment already used for the same class of write elsewhere: createSuggestion marks the note-id linkage the same way, and #80710 uses it for the notes delete-cleanup, which is the same bug in the notes feature.

Undo after the fix simply steps past the decision to whatever the reviewer last did themselves. In a real review - reviewer opening a post someone else suggested on - that stack is empty and Ctrl+Z is inert, which is the intent. Verified by hand that undo then redo round-trips cleanly: content back to Hello world, no marker, one note.

Testing Instructions

  1. Enable the gutenberg-suggestion-mode experiment.
  2. In a new post, add a paragraph and switch to Suggesting (Options → Suggesting).
  3. Put the caret at the end and type a few words - a suggestion marker and its note appear.
  4. Switch to Editing, open All notes, and click Accept suggestion.
  5. Press Ctrl/Cmd+Z.

The marker must not come back. Before this change it reappeared with the note already showing "Applied".

Repeat with Reject suggestion for the mirror case.

Automated

  • E2E, test/e2e/specs/editor/various/suggestion-mode-undo.spec.js - two new cases, undo after accepting an addition does not restore its marker and the reject mirror. Red on the unmodified base (toHaveCount expected 0, "locator resolved to 1 element" - the marker was back), green with the fix.
  • Unit, packages/editor/src/components/suggestion-mode/test/provider.js - two new cases asserting the decision's write reports __unstableGetLastBlockChangeHistoryMode() === 'ignore'. Red on base (received "persistent"), green with the fix.
  • Full suites, all green: 26 unit suites / 427 tests; 66 suggestion-mode e2e tests across all five specs, including suggestion-mode.spec.js in full.

Screenshots

Both taken after Ctrl+Z, immediately following an accepted addition.

Before After
The undone marker is back in the canvas while the note sits under Resolved as "Applied" - nothing left to accept or reject. No marker. The decision stands and undo steps past it.

Out of scope

Unrelated to this change but visible in the after screenshot: once an inline marker is gone, its resolved note summarizes as "Format: content" rather than the text it proposed, because the summary resolves its text from the live marker. That is pre-existing for every accepted inline suggestion and belongs with the summary findings (F-10, F-16, F-27).

AI Use

Claude Code did the digging and the typing here; the diagnosis, the fix, the tests and this description are all its work. I will review and test.

Accepting or rejecting a suggestion has two halves: the block change,
which is local, and the comment's resolved status, which lives on the
server and is shared with every session. Only the first can sit on the
undo stack, so recording it there let Ctrl+Z pull the two apart -
restoring the <mark> while the note stayed resolved, leaving a marked-up
run with no Accept/Reject and no way to clear it.

Mark every live-block write a decision makes with history: 'ignore', the
same treatment the note-id linkage and the notes delete-cleanup already
use. The applied content still reaches the entity and saves; it is just
invisible to undo, so the halves can no longer separate.
@github-actions github-actions Bot added the [Package] Editor /packages/editor label Aug 14, 2026
@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: adamsilverstein <adamsilverstein@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

adamsilverstein added a commit to adamsilverstein/gutenberg that referenced this pull request Aug 14, 2026
@adamsilverstein adamsilverstein added the [Type] Bug An existing feature does not function as intended label Aug 15, 2026
…undo

`history: 'ignore'` does not do what this branch needed. It forces
`isPersistentChange` false, which routes the write through `onInput`, and
`onInput` never writes `content` - only `onChange` does. `blocks` and
`selection` are both transient edits, so accepting a suggestion in a post
with no other edits left the post clean: Save disabled, no autosave, and
on reload the marker back from server content with the note already
resolved. That is F-18 reached by reload rather than by Ctrl+Z.

Keep the decision writes persistent so the applied content reaches the
entity, and fix the split from the other side: record the suggestions this
session resolves, and have the note collector reopen one whose marker
comes back. The two halves travel together without the content being at
risk.

Scoped to decisions made in this session. A peer's decision arriving
through sync before local content catches up looks identical from the
outside, and reopening that would undo their review.
…73411-f18-accept-undo

# Conflicts:
#	packages/editor/CHANGELOG.md
…73411-f18-accept-undo

# Conflicts:
#	packages/editor/CHANGELOG.md
#	test/e2e/specs/editor/various/suggestion-mode-undo.spec.js
…73411-f18-accept-undo

# Conflicts:
#	packages/editor/CHANGELOG.md
@adamsilverstein
adamsilverstein merged commit 577edd3 into WordPress:suggest/inline-wiring Aug 23, 2026
22 of 25 checks passed
adamsilverstein added a commit that referenced this pull request Aug 23, 2026
The undo-reopen entry from #81669 now also points at #81963, which makes
the reopen write use a value the registered meta enum accepts.
adamsilverstein added a commit that referenced this pull request Aug 23, 2026
…pts (#81963)

* Reopen an undone suggestion as pending instead of clearing its meta

The reopen pass wrote _wp_suggestion_status: '' to clear the lifecycle
meta, but the registered enum only allows pending, applied and rejected,
so the REST request failed after the comment status had already been
updated. That left the note half reopened: status back to hold, meta
still applied, and the sidebar - which reads the meta - kept the note
resolved with no Accept/Reject on it. Write pending instead, which every
reader already treats the same as absent meta.

Fixes #81962

* Note the reopen-status fix in the editor changelog

The undo-reopen entry from #81669 now also points at #81963, which makes
the reopen write use a value the registered meta enum accepts.
@nickchomey nickchomey mentioned this pull request Sep 22, 2026
5 of 10 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] Editor /packages/editor [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant