Skip to content

Suggest mode 8/9: architecture documentation - #82047

Open
adamsilverstein wants to merge 103 commits into
suggest/inline-wiringfrom
suggest/docs
Open

adamsilverstein wants to merge 103 commits into
suggest/inline-wiringfrom
suggest/docs

Conversation

@adamsilverstein

@adamsilverstein adamsilverstein commented Aug 25, 2026 •

Copy link
Copy Markdown
Member

Part of #73411

Claude drafted this description from the docs it helped write:

What's in this PR

Splits the Suggestion mode architecture docs out of the wiring PR (#80433), so they can be read as prose instead of scrolled past inside a diff of a hundred files. There are two documents, meant to be read in this order:

  1. Architecture overview for reviewers (suggestions-overview.md, new). The map: the three kinds of suggestion (inline text, structural, block attribute) and how each is captured, stored and rendered, a diagram of every layer in this stack and what it owns, sequence diagrams for each data flow and for accept / reject, how the front end keeps pending suggestions off the published page, the redesigns in flight from the 2026-10-04 architecture review, and open questions for reviewers. Start here.
  2. Suggestions architecture (suggestions.md). The detailed reference: every module, the payload schema, the marker rules and the known limitations.

suggestions.md is registered in docs/toc.json and linked from the architecture index, so it shows up in the developer docs handbook. The overview is linked from the same index entry but is not in the handbook TOC. docs/manifest.json is the regenerated output of npm run docs:gen, and the only change in it is the one new entry.

The reference was also brought in line with the code: TypeScript file names, the PHP living in lib/compat/wordpress-7.1/, core permissions (there is no Gutenberg permission override), one replace note for a type-over, the inline-suggestion op, and a dozen modules it was missing. Both docs now use the Google Docs names throughout: Suggestion mode, with Editing, Suggesting and Viewing modes.

Testing

Nothing to run. Read both docs against the layers below and see whether they describe what the code actually does. Feedback on the overview's "Questions for reviewers" section is especially welcome.

Check that the Mermaid diagrams render in the GitHub preview.

To check the handbook wiring: npm run docs:gen should leave the tree clean.


Suggestion mode stack

This rebuilds the manually-stacked Suggestion mode work (#73411) as a GitHub Stack of 9 small, independently reviewable PRs, each building on the one below it:

  1. #80427 - editor intent (edit/suggest/view) + experiment gate
  2. #80428 - suggestion storage, REST controller, provider
  3. #80429 - block-level capture (attribute + 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

Each follow up fix now sits in the layer that owns the code it changes, rather than piling onto the top of the stack. The whole feature can be exercised end-to-end via the combined testing branch #78994 (Playground). Behind the "Suggestion Mode" experiment (Gutenberg > Experiments).


AI Use

Both documents and this description came out of a conversation with 🤖 Claude Code. Docs only, no code in this PR. I will review them for accuracy.

🤖 Generated with Claude Code

https://claude.ai/code/session_016nxoTjV6e8hn6YUb7AEioP

Describe how a suggestion is captured, stored, marked inline and
reviewed, so the subsystem has a written explanation alongside the code
rather than only in the pull requests that built it.
@github-actions

Copy link
Copy Markdown

Warning: Type of PR label mismatch

To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.

  • Required label: Any label starting with [Type].
  • Labels found: .

Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task.

@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.

The document was added to docs/explanations/architecture but never listed
in docs/toc.json, so it did not reach the generated manifest or the
developer docs handbook. Add the toc entry, regenerate the manifest, and
link it from the architecture index alongside the other editor docs.
Cascade the trunk refresh up the Suggest mode stack.
@github-actions

Copy link
Copy Markdown

Flaky tests detected in 17466ed.
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/33117847764
📝 Reported tests:

refuses the drop and uploads nothing in /test/e2e/specs/editor/various/single-file-placeholder-drop.spec.js, passed after 1 failed attempt.
Error: expect(received).toHaveLength(expected)

Expected length: 0
Received length: 2
Received array:  [{"_links": {"about": [{"href": "http://localhost:8889/wp-json/wp/v2/types/attachment"}], "author": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/users/1"}], "collection": [{"href": "http://localhost:8889/wp-json/wp/v2/media"}], "curies": [{"href": "https://api.w.org/{rel}", "name": "wp", "templated": true}], "replies": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/comments?post=106"}], "self": [{"href": "http://localhost:8889/wp-json/wp/v2/media/106", "targetHints": {"allow": ["GET", "POST", "PUT", "PATCH", "DELETE"]}}], "wp:attached-to": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/posts/104", "id": 104, "post_type": "post"}]}, "alt_text": "", "author": 1, "caption": {"rendered": ""}, "class_list": ["post-106", "attachment", "type-attachment", "status-inherit", "hentry", "entry"], "comment_status": "open", "date": "2026-08-27T21:37:30", "date_gmt": "2026-08-27T21:37:30", "description": {"rendered": "<p class=\"attachment\"><a href='http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK-1.png'><img loading=\"lazy\" decoding=\"async\" width=\"10\" height=\"10\" src=\"http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK-1.png\" class=\"attachment-medium size-medium\" alt=\"\" style=\"width:100%;height:100%;max-width:10px;\" /></a></p>
"}, "featured_media": 0, "filename": "10x10_e2e_test_image_z9T8jK-1.png", "filesize": 80, "guid": {"rendered": "http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK-1.png"}, "id": 106, "link": "http://localhost:8889/?attachment_id=106", "media_details": {"file": "2026/08/10x10_e2e_test_image_z9T8jK-1.png", "filesize": 80, "height": 10, "image_meta": {"alt": "", "aperture": "0", "camera": "", "caption": "", "copyright": "", "created_timestamp": "0", "credit": "", "focal_length": "0", "iso": "0", "keywords": [], "orientation": "0", "shutter_speed": "0", "title": ""}, "sizes": {}, "width": 10}, "media_type": "image", "meta": [], "mime_type": "image/png", "modified": "2026-08-27T21:37:30", "modified_gmt": "2026-08-27T21:37:30", "ping_status": "closed", "post": 104, "slug": "10x10_e2e_test_image_z9t8jk-2", "source_url": "http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK-1.png", "status": "inherit", "template": "", "title": {"rendered": "10x10_e2e_test_image_z9T8jK"}, "type": "attachment"}, {"_links": {"about": [{"href": "http://localhost:8889/wp-json/wp/v2/types/attachment"}], "author": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/users/1"}], "collection": [{"href": "http://localhost:8889/wp-json/wp/v2/media"}], "curies": [{"href": "https://api.w.org/{rel}", "name": "wp", "templated": true}], "replies": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/comments?post=105"}], "self": [{"href": "http://localhost:8889/wp-json/wp/v2/media/105", "targetHints": {"allow": ["GET", "POST", "PUT", "PATCH", "DELETE"]}}], "wp:attached-to": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/posts/104", "id": 104, "post_type": "post"}]}, "alt_text": "", "author": 1, "caption": {"rendered": ""}, "class_list": ["post-105", "attachment", "type-attachment", "status-inherit", "hentry", "entry"], "comment_status": "open", "date": "2026-08-27T21:37:30", "date_gmt": "2026-08-27T21:37:30", "description": {"rendered": "<p class=\"attachment\"><a href='http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK.png'><img loading=\"lazy\" decoding=\"async\" width=\"10\" height=\"10\" src=\"http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK.png\" class=\"attachment-medium size-medium\" alt=\"\" style=\"width:100%;height:100%;max-width:10px;\" /></a></p>
"}, "featured_media": 0, "filename": "10x10_e2e_test_image_z9T8jK.png", "filesize": 80, "guid": {"rendered": "http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK.png"}, "id": 105, "link": "http://localhost:8889/?attachment_id=105", "media_details": {"file": "2026/08/10x10_e2e_test_image_z9T8jK.png", "filesize": 80, "height": 10, "image_meta": {"alt": "", "aperture": "0", "camera": "", "caption": "", "copyright": "", "created_timestamp": "0", "credit": "", "focal_length": "0", "iso": "0", "keywords": [], "orientation": "0", "shutter_speed": "0", "title": ""}, "sizes": {}, "width": 10}, "media_type": "image", "meta": [], "mime_type": "image/png", "modified": "2026-08-27T21:37:30", "modified_gmt": "2026-08-27T21:37:30", "ping_status": "closed", "post": 104, "slug": "10x10_e2e_test_image_z9t8jk", "source_url": "http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK.png", "status": "inherit", "template": "", "title": {"rendered": "10x10_e2e_test_image_z9T8jK"}, "type": "attachment"}]
    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/single-file-placeholder-drop.spec.js:71:45

@adamsilverstein
adamsilverstein requested review from Mamaduka, retrofox and t-hamano and removed request for ajitbohra and fabiankaegy September 4, 2026 00:22
@adamsilverstein adamsilverstein added the [Type] Developer Documentation Documentation for developers label Sep 4, 2026
adamsilverstein and others added 30 commits October 6, 2026 13:18
…the overview

Attribute suggestions now live on the block's metadata.suggestion marker
instead of an in-memory overlay, and the provider sits behind a
SuggestionStore with submission and decision hooks. Both landed in
#80433, so the overview's tables, diagrams and open findings described a
model the code no longer has.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01USLfaxhwoVRBZ7QFP5XoeU
The overview claimed the Note collector restores a Note on redo for
every marker. End to end, a redone attribute proposal is saved as a new
Note instead: auto-save finds the linked Note trashed and opens another.
Describe that so a reviewer is not sent looking for a restore that does
not happen.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017NSEHmsqyXW8Yf62bJ3ckf
The architecture doc said only that the note collector restores a
note when redo brings an inline marker back. It now covers the redo of
a decision, the structural restore, and that deleting a block with a
pending move proposes the removal from the move's origin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GLh3wdWJSgU3NLobNDk6x
Replace the title-only section with how every post-level field is
either proposed (held in the editor store, shown in place, one note
each) or locked (read-only, refused at `editPost`, at the entity guard
and at save), plus the server-side validation and the new limitations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GLh3wdWJSgU3NLobNDk6x
getEditedPostAttribute is public, and while suggesting it returns a
field's pending suggested value rather than the post's. That is what lets
every panel and plugin show the proposal, so it stays, but its docblock
now says so and where to read the post's own value. The architecture doc
and the changelog cover it along with new term suggestions, restoring
proposals after a reload, and the trash and site settings locks.

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

The render strip resolved a format marker's note against the block's
postId context, which inside a Query Loop names each queried post
rather than the post whose content holds the marker. Track the post
whose content the_content is expanding instead, so blocks of a loop
resolve against the content that holds the loop while a nested
post-content block resolves against its own post.

The lookup now also requires that the post's stored content (or the
current user's autosave in a preview) holds the marker, that the post
is not password protected, that the note is not trashed or spam, and
that the suggestion is neither applied nor rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GLh3wdWJSgU3NLobNDk6x
Records the decision lifecycle: the status table and state diagram, the
save pass that finalizes and outdates, the refusal of client writes of a
final status, how the sidebar presents each state, and that the note
collector now only trashes the current user's own notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GLh3wdWJSgU3NLobNDk6x
The architecture doc now describes the marker contract as it is: one
format and class per kind, the class authoritative, the canonical
nesting order, and no migration of the retired single class. A new
Overlapping suggestions section covers the overlap matrix, the
resolution rule with a diagram, the sidebar's context and consequence
lines, the RTC guard and how the render strip resolves nesting. Known
limitations add same-kind refusal and outdated notes waiting for the
save pass. The reviewer overview follows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GLh3wdWJSgU3NLobNDk6x
Describe how the save pass keeps proposals out of the stored post: the
anchor each proposal leaves, where the originals are stored, when the
editor gets them back, the fail-closed rules and the residuals, plus the
legacy marker strip and post-field finalizing on wp_after_insert_post.

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

Say which post a format marker resolves against when blocks come from a
synced pattern, a template part, a menu or Latest Posts, that spam notes
are not inflated, and that the sidebar flags a suggestion too large to
move out of the post.

Layer: docs.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GLh3wdWJSgU3NLobNDk6x
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GLh3wdWJSgU3NLobNDk6x
Carries the changelog section fix up from suggest/inline-wiring.

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

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

[Type] Developer Documentation Documentation for developers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant