Skip to content

Suggest mode: combined feature branch for Playground testing (draft) - #78994

Draft
adamsilverstein wants to merge 761 commits into
trunkfrom
try/suggest-mode-combined
Draft

adamsilverstein wants to merge 761 commits into
trunkfrom
try/suggest-mode-combined

Conversation

@adamsilverstein

@adamsilverstein adamsilverstein commented Jun 6, 2026 •

Copy link
Copy Markdown
Member

Part of #73411

What

Draft / testing-only branch. Bundles the full Suggest mode feature into one branch so the end-to-end experience can be exercised in WordPress Playground. It is not meant to be merged - the feature lands through the nine reviewable PRs below. This branch just gives reviewers and testers one place to try the whole flow.

  1. #80427 - editor intent (edit/suggest/view) and experiment gate
  2. #80428 - suggestion storage, REST controller, and provider
  3. #80429 - block-level capture (attribute and structural)
  4. #80430 - inline marker primitive
  5. #80431 - inline suggestion operations
  6. #80432 - review UI (Apply/Reject sidebar + summary)
  7. #80433 - inline live wiring
  8. #82047 - architecture documentation
  9. #82048 - end-to-end test suite

One deliberate difference from the stack

Suggest mode is enabled by default here. Everywhere else it sits behind Settings > Experiments > Collaboration > Suggestion Mode, off until you turn it on. That extra step was costing testers their first session: miss it and you get a stock editor, with nothing to tell you that is the wrong one.

So this branch carries one commit of its own on top of the stack tip. It makes the window.__experimentalSuggestionMode bridge unconditional, drops the now-inert Experiments screen entry, and removes the e2e spec that covered the experiment-off state, which cannot happen here. The notice a post shows when it carries suggestion markers and the experiment is off still lives on #80427 and up, along with its coverage.

Nothing else differs. Review the gate on #80427, not here.

Testing

Test in WordPress Playground

https://playground.wordpress.net/gutenberg.html?pr=78994

Open a post with a few paragraphs and look for Options (⋮) > Mode. No setup, no experiment to enable. A multi-paragraph post matters - some of the input handling only shows up once there is more than one block.

Then follow the full walkthrough in the tracking issue: #73411 (comment)

It covers mode switching and shortcuts, inline text suggestions, formatting, attribute and structural suggestions, the notes sidebar, undo, persistence, and the accept/reject cycle. Keeping it in one place means it stays in step with the code.

Notes

  • Review and merge happen on the nine PRs above, not here.
  • The branch is the tip of the stack (suggest/e2e) plus the single default-on commit described above. That is why the diff here is the sum of all nine plus a few lines.
  • Refreshed against trunk on 2026-08-25. The merge cascaded up all nine layers with no conflicts, and the feature delta came through unchanged.
  • e2e coverage lives in test/e2e/specs/editor/various/suggestion-mode*.spec.ts, plus test/e2e/specs/site-editor/suggestion-mode-intent-shortcuts.spec.ts.
  • Architecture write-up: docs/explanations/architecture/suggestions.md.
  • Full map and rationale: Add Suggestion mode with Notes #73411.

AI Use

Built with 🤖 Claude Code over a few rounds of back and forth, and Claude wrote this description too. I will review and test.

@github-actions github-actions Bot added [Package] Editor /packages/editor [Package] Block editor /packages/block-editor [Package] Edit Post /packages/edit-post [Package] Edit Site /packages/edit-site labels Jun 6, 2026
@github-actions

github-actions Bot commented Jun 6, 2026 •

Copy link
Copy Markdown

Size Change: +33.1 kB (+0.42%)

Total Size: 7.95 MB

📦 View Changed
Filename Size Change
build/scripts/block-editor/index.min.js 475 kB +125 B (+0.03%)
build/scripts/core-data/index.min.js 37.4 kB +7 B (+0.02%)
build/scripts/editor/index.min.js 608 kB +29.6 kB (+5.11%) 🔍
build/styles/block-editor/content-rtl.css 6.22 kB +562 B (+9.93%) ⚠️
build/styles/block-editor/content-rtl.min.css 4.67 kB +528 B (+12.75%) ⚠️
build/styles/block-editor/content.css 6.22 kB +562 B (+9.93%) ⚠️
build/styles/block-editor/content.min.css 4.67 kB +532 B (+12.87%) ⚠️
build/styles/block-editor/style-rtl.css 20.4 kB +171 B (+0.85%)
build/styles/block-editor/style-rtl.min.css 17.3 kB +122 B (+0.71%)
build/styles/block-editor/style.css 20.4 kB +168 B (+0.83%)
build/styles/block-editor/style.min.css 17.3 kB +122 B (+0.71%)
build/styles/editor/style-rtl.css 32.1 kB +179 B (+0.56%)
build/styles/editor/style-rtl.min.css 27.4 kB +164 B (+0.6%)
build/styles/editor/style.css 32.2 kB +179 B (+0.56%)
build/styles/editor/style.min.css 27.4 kB +163 B (+0.6%)

compressed-size-action

@github-actions

github-actions Bot commented Jun 6, 2026 •

Copy link
Copy Markdown

Flaky tests detected in 277c3ec.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/32911895936
📝 Reported tests:

Navigates the items list via UP/DOWN arrow keys in /test/e2e/specs/site-editor/dataviews-list-layout-keyboard.spec.js, passed after 1 failed attempt.
Error: expect(locator).toBeFocused() failed

Locator:  getByLabel('Page Two')
Expected: focused
Received: inactive
Timeout:  5000ms

Call log:
  - Expect "toBeFocused" with timeout 5000ms
  - waiting for getByLabel('Page Two')
    14 × locator resolved to <button type="button" tabindex="-1" aria-pressed="false" id="view-list-0-465-item-wrapper" class="dataviews-view-list__item" aria-labelledby="view-list-0-465-label" aria-describedby="view-list-0-465-description"></button>
       - unexpected value "inactive"

    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/site-editor/dataviews-list-layout-keyboard.spec.js:112:49

adamsilverstein added a commit that referenced this pull request Jun 16, 2026
Bring Phase 0-1 of the inline-suggestions work (clean phase branch
try/suggest-mode-inline-markers, stacked on #78218) into the combined
testing branch: the shared inline-markers primitive + the Notes refactor
onto it, and the core/suggestion marker format with its type-aware PHP
strip. This makes the new layer available for the suggest-mode integration
phases (deletions/additions) and for Playground testing on #78994.
adamsilverstein added a commit that referenced this pull request Jun 17, 2026
Bring the Phase 2 inline-deletion work (try/inline-suggestions-phase2)
onto the combined branch for Playground testing: the core/suggestion
format registration + canvas decoration, the accept/reject value
transforms, the provider inline-suggestion apply/reject paths, and the
Suggest deletion toolbar control.

Lets the create -> decorate -> accept/reject deletion flow be exercised in
a running editor on #78994.
@adamsilverstein adamsilverstein added No Core Sync Required Indicates that any changes do not need to be synced to WordPress Core [Type] Feature New feature to highlight in changelogs. Needs Testing Needs further testing to be confirmed. labels Jun 24, 2026
@adamsilverstein adamsilverstein self-assigned this Jun 24, 2026
@adamsilverstein

Copy link
Copy Markdown
Member Author

Fix: empty inserted block no longer becomes a suggestion

Bug: In Suggest mode, clicking the default block appender (the empty space below the last block) inserted an unmodified default paragraph, and the store interceptor's new-block branch immediately tagged it pending-insert and wrote a block-insert-after op — surfacing an "Insert block: paragraph" suggestion for a block the user hadn't put anything into.

Fix: Defer the insertion suggestion while the new block is still an unmodified default block. The interceptor now skips it without recording a snapshot, so the next fire — once the block has content — re-enters the new-block branch and registers the insertion. A suggestion is only created once the user actually types into the block.

Guard added in store-interceptor.js (isUnmodifiedDefaultBlock), plus an e2e test covering the empty-appender case and the type-to-suggest follow-through. All 10 suggestion-mode.spec.js tests pass locally (red→green verified).

Committed here in c63392f, and backported to the insert-mechanism PR #77971 (where this code originates) in c268952.

@adamsilverstein

Copy link
Copy Markdown
Member Author

Fixed the "Format: content" note for whitespace-only suggestions.

Cause: typing only whitespace in Suggest mode produces an inline-suggestion op whose resolved text is all spaces. summarizeOperations required that text to survive a trim() and then ran it through ellipsize() (which collapses/trims whitespace), so a pure-whitespace edit became an empty quote and fell through to the generic Format: content label.

Fix: render the marker text verbatim via a new clampText() helper that caps length without collapsing whitespace, and only fall back to the attribute label when no text resolves (marker edited away). A typed space now reads Add: " ".

Added a unit case (quotes a whitespace-only inline-suggestion add verbatim) and an e2e regression in suggestion-mode.spec.js. Backported to the review PR #79282 (try/inline-suggestions-phase2).

adamsilverstein added a commit that referenced this pull request Jun 24, 2026
…tent

Clicking the default block appender inserts an unmodified default
paragraph via insertDefaultBlock. In Suggest mode that empty block
incorrectly became an Insert block suggestion on its own. Guard the
store interceptor's new-block branch with isUnmodifiedDefaultBlock so
the insertion is only recorded once the block has content, and skip
without recording a snapshot so a later fire re-enters the branch.

Ports the fix already present on the combined branch (#78994) and the
structural stack (#77971) to the inline-suggestions base so #79282
matches. Adds the matching e2e regression test.
adamsilverstein added a commit that referenced this pull request Jun 24, 2026
…ns-base

Brings the inline-suggestions base current with trunk (was 161 commits
behind). Conflicts resolved to mirror the proven combined branch
(#78994) organization, reflecting the graduation of block notes and the
base note REST controller to WordPress 6.9 core:

- lib/compat/wordpress-6.9/block-comments.php and the 6.9 comment
  controller: accept trunk's deletion (graduated to core). The
  suggestion-specific additions they carried are rehoused in the 7.1
  compat layer.
- lib/compat/wordpress-7.1/block-suggestions.php: new file holding the
  suggestion comment-meta registration (_wp_suggestion,
  _wp_suggestion_status, payload-size constant) that previously lived in
  6.9/block-comments.php. Inline-marker strip stays out (phase 2).
- lib/compat/wordpress-7.1/class-gutenberg-rest-comment-controller-7-1.php:
  the suggestion REST permission subclass, moved from the deleted 6.9
  controller and narrowed to suggestion lifecycle updates.
- lib/load.php: require block-bindings (trunk), block-comments,
  block-suggestions, and the 7.1 comment controller.
- collab-sidebar/note.js: take the integrated version (trunk's
  simplified show-more plus the suggestion canResolve guard).
- editor CHANGELOG: keep the suggest-mode Unreleased entries above
  trunk's released 14.49.0 / 14.48.1 headers.
- REST controller test: reference Gutenberg_REST_Comment_Controller_7_1
  and gutenberg_register_suggestion_meta().
adamsilverstein added a commit that referenced this pull request Jun 24, 2026
…s-phase2

Cascades the trunk catch-up and the empty-inserted-block guard up from
the base branch. Conflict resolutions mirror the combined branch
(#78994):

- lib/compat/wordpress-7.1/block-suggestions.php: union of the base's
  suggestion meta registration and this branch's inline-marker
  render-strip (meta + strip).
- lib/load.php: add the 7.1 comment controller require.
- editor CHANGELOG: keep the suggest-mode New Features and Bug Fixes
  entries above trunk's released 14.49.0 / 14.48.1 headers.
- provider.js: point the payload-size doc reference at
  block-suggestions.php (where the meta now lives).

After this merge the suggestion feature footprint is identical to the
combined branch.
@adamsilverstein adamsilverstein changed the title Suggest mode: Combined feature branch (draft, for Playground testing) Suggest mode: Combined feature branch for Playground testing (draft) Jun 30, 2026
@adamsilverstein adamsilverstein changed the title Suggest mode: Combined feature branch for Playground testing (draft) [TEST BRANCH] Suggest mode: Combined feature branch for Playground testing Jun 30, 2026
@adamsilverstein adamsilverstein changed the title [TEST BRANCH] Suggest mode: Combined feature branch for Playground testing Combined feature branch for Playground testing (draft) Jun 30, 2026
@adamsilverstein
adamsilverstein force-pushed the try/suggest-mode-combined branch 3 times, most recently from 61b9e76 to 45a17fd Compare June 30, 2026 20:29
adamsilverstein and others added 30 commits October 7, 2026 10:34
Indenting a list item clones the source list for the new nested list,
so inside a suggested list the clone carried the list's pending-insert
marker and note link. The note then had two anchors: its summary moved
to the nested list, the parent insertion lost its note, and a second
decision appeared that could not resolve (#73411).

A block adopted without a note of its own, inside a pending insertion
or as a list indent's carrier, now drops the inherited suggestion state.
Covers the report on #73411 where a nested list in a suggested list
duplicated the list's note and left a decision that would not resolve.
Trunk's Menu now throws in development builds when a Menu.Group sits
inside a Menu.RadioGroup (#83792), which crashed the editor as soon as
the Options menu opened. Put the Mode label and radio items directly in
the RadioGroup, the same shape trunk gave ModeSwitcher, and cover it
with a jsdom test since production e2e builds never hit the guard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTRGFetxgiXPJC9a91DMTL
# Conflicts:
#	packages/editor/CHANGELOG.md
The test registers the real core-data store, and the reconciler reads
getCurrentUser(), whose resolver calls api-fetch against a jsdom with no
server. On a shuffled CI shard the failed request rejected after the test
ended and Vitest failed the run on the unhandled rejection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTRGFetxgiXPJC9a91DMTL
The test registers the real core-data store, and auto-save reads
getCurrentUser(), whose resolver calls api-fetch against a jsdom with no
server. A failed request can reject after its test ends, which fails a
shuffled CI shard on the unhandled rejection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTRGFetxgiXPJC9a91DMTL

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs Testing Needs further testing to be confirmed. No Core Sync Required Indicates that any changes do not need to be synced to WordPress Core [Package] Block editor /packages/block-editor [Package] Core data /packages/core-data [Package] Editor /packages/editor [Type] Feature New feature to highlight in changelogs.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant