Repository navigation
Conversation
Lock the working native PHP Yjs port at 1694b1f1997945f1f362453f79f5da286a9dfd37 so WordPress server-side merge work has a stable dependency. Use a relative local URL in .gitmodules for this server workspace.
Expand the WordPress DE-RTC runtime boundary for server-side sync metadata handling, retry-save merge decisions, presence, history, and capability-sensitive review behavior. Keeps server persistence authoritative while preserving guarded failure paths for unsafe or conflicting edits.
Add and update PHPUnit coverage for sync-meta recovery, post snapshots, history, presence, settings, permission gates, retry-submit, and retry-save behavior including partial-safe review and merge outcomes.
Update the WordPress editor asset package hash after the Gutenberg DE-RTC editor build changes so the default site can serve the matching working copy.
Add guarded review-item storage and REST list/detail/resolution endpoints for unsafe blocks rejected from partial-safe retry-save. Safe edits remain the persisted authority while review-required source is kept in bounded, capability-gated workflow storage with descriptor/detail separation. Also records queued review-item descriptors in retry-save responses and extends retry-save REST coverage for author descriptors, admin-only detail, escaped source display, and idempotent rejection. Verification: npm run test:php -- --filter Tests_DE_RTC_REST_Retry_Save
Extend the DE-RTC presence heartbeat to accept sanitized, content-free selection state and persist it in the presence table without raw text, client IDs, DOM selectors, post content, or save authority. Presence reads now expose selection presence as liveness data only; receivers still decide whether a canvas overlay can be mapped safely. Bump the presence storage schema to v4, cover heartbeat/read contracts for v1/v2 selection payloads, and sync the Gutenberg editor asset version generated from the current build. Verification: npm run test:php -- --filter 'Tests_DE_RTC_(REST_Presence|Presence_Storage)'; docker PHP syntax checks for src/wp-includes/de-rtc.php and the touched DE-RTC presence tests; git diff --check.
Bootstrap the risky-block review UI whenever DE-RTC is enabled and classify lower-privileged retry-save content relative to the current server body. This lets WordPress persist safe edits from an author while holding only KSES-sensitive proposed blocks for review instead of rejecting safe edits because an unchanged admin-authored unsafe block exists in the post. The hypothesis was that Post 810 was not reaching the guarded review path because riskyBlockReview was bootstrapped false, and that safe author edits were being rejected by whole-document KSES comparison rather than change-relative KSES review. After enabling the gate and using the review-item classifier for retry-save and partial-safe candidates, the server persisted the safe italic Cheese edit, withheld the unsafe Custom HTML proposal, and exposed one review item. npm run build was run afterward to copy the Gutenberg bundle into the WordPress tree. Confirmed with: - npm run test:php -- --filter Tests_DE_RTC_Settings - DE_RTC_POST_810_PARTIAL_SAFE_ARTIFACT_DIR=.rtc/public-plan/cycle-20260531-220413-cest/post-810-after-ghost-render-fix npm run test:de-rtc-browser:post-810-partial-safe-cheese-video
Record the generated WordPress block file drift produced while starting the default DE-RTC test environment. The files now guard Gutenberg-specific shared navigation helpers with function_exists checks instead of only checking IS_GUTENBERG_PLUGIN, matching the generated runtime copy used by the localhost:3880 site. This was not a product-code hypothesis for Round 001; it is committed separately to restore git hygiene before the worker evidence cycle continues.
Add conservative server-side same-block merge paths for disjoint rich-text marks and independent table cells while keeping same-cell, structure, and unsupported same-block edits as manual conflicts. Surface content-free merge evidence for table-cell coordinates and rich-text merged blocks. Keep KSES-sensitive review checks focused on newly introduced unsafe material so safe author edits are not rejected only because existing unsafe markup remains in the post. Sync the Gutenberg editor build metadata. Verification: - npm -C wordpress-develop run test:php -- --group de-rtc --filter "table_cell"
Add the native Automerge PHP port as the DE-RTC sync metadata runtime and remove the old Yjs submodule. Rename retry-save evidence, raw post-content preservation hooks, recovery repair helpers, and test expectations from Yjs to Automerge. Keep the guarded save/review paths server-owned, including no-write review-required responses and canonical Automerge repair metadata. Verified with php -l src/wp-includes/de-rtc.php and npm run test:php -- --group de-rtc.
Checkpoint current Automerge migration work before investigating the same-paragraph non-conflicting save failure. Includes retry-save revision handling, sync-meta/recovery test updates, and navigation package metadata updates that were already present in the working tree.
Add block-native RichText content operation evidence for Automerge retry-save and merge two disjoint text splices in one paragraph. The merge remains conservative: overlapping ranges and mark/splice collisions still require manual conflict handling. Hypothesis tested: non-overlapping paragraph word edits need to be expressed and validated as RichText text-splice operations instead of rejecting same-block text changes wholesale. Verified with focused retry-save PHPUnit coverage and the two-tab browser proof.
Treat direct database or plugin-side post_content replacement as authoritative external input when the current body no longer matches the latest valid Automerge sync meta. The snapshot path now applies the guarded recovery candidate, imports the current body as a server-owned Automerge update, and reloads the persisted post instead of returning a synthetic repaired snapshot. Recovery apply now persists the validated candidate exactly, with scoped sync-meta KSES allowance, so the repair is not reinterpreted as a new editor save. Automerge retry-save also preserves an accepted-base revision before every write so later stale editors can still merge against the base they opened. Verified with full DE-RTC PHPUnit coverage and post 963, where the repaired sync meta advanced from version 10 to 11 after an HTML-only direct database replacement.
Derive a public attribution key from the opaque presence session hash, carry the session key through guarded retry-save, and record authorship evidence in Automerge sync metadata without exposing raw session keys. Treat harmless KSES serialization normalization, such as compact separator hr markup, as safe for lesser-privileged author saves while retaining review-required handling for actual unsafe HTML changes. Verified with php -l on modified PHP files, git diff --check, targeted KSES/retry-save phpunit subset (4 tests, 77 assertions), and broader DE-RTC KSES/retry-save filter (17 tests, 382 assertions).
Refresh the WordPress-develop side of the integrated development site after the Gutenberg presence hover fix so localhost:3880 can serve the updated editor package version. The source behavior change lives in Gutenberg commit b8534fc3049. Browser proof: npm run test:de-rtc-browser:presence-hover-panel.
Update the generated WordPress script-loader package version after syncing Gutenberg's DE-RTC status-surface changes into the default runtime. Generated by npm run sync:gutenberg so localhost:3880 serves the dismissible review-required save notice behavior.
Update the generated script-loader package hash after syncing the Gutenberg build that contains the visible presence activity ring fix. This is generated runtime metadata only; the source change is recorded in Gutenberg commit f9258bf194a.
Return the current user's visible pending review count separately from the post-wide pending review count so clients do not show stale review UI when no actionable review item is visible. Normalize review item timestamps before expiry calculation and cover author/admin visibility behavior in retry-save tests. Includes the matching Gutenberg editor asset version update.
Move the native PHP Automerge port from a nested submodule into wp-includes/automerge-php and update the DE-RTC runtime loader to use the vendored Core path. Excludes nested upstream checkout and local VCS metadata so the runtime can be distributed with WordPress source.
|
Hi there! 👋 Thank you for your contribution to WordPress! 💖 It looks like this is your first pull request to No one monitors this repository for new pull requests. Pull requests must be attached to a Trac ticket to be considered for inclusion in WordPress Core. To attach a pull request to a Trac ticket, please include the ticket's full URL in your pull request description. Pull requests are never merged on GitHub. The WordPress codebase continues to be managed through the SVN repository that this GitHub repository mirrors. Please feel free to open pull requests to work on any contribution you are making. More information about how GitHub pull requests can be used to contribute to WordPress can be found in the Core Handbook. Please include automated tests. Including tests in your pull request is one way to help your patch be considered faster. To learn about WordPress' test suites, visit the Automated Testing page in the handbook. If you have not had a chance, please review the Contribute with Code page in the WordPress Core Handbook. The Developer Hub also documents the various coding standards that are followed:
Thank you, |
Updates the generated editor package version after syncing the Gutenberg pending-edit indicator changes into the WordPress development checkout.
Treat base-only KSES-sensitive records as deletions that do not require unfiltered_html review, because removing unsafe content does not persist unsafe markup. Adds regression coverage for top-level deletion, nested deletion, and mixed delete-plus-added-risky-block classification.
Add balanced read-time presence culling for ephemeral DE-RTC rows, deleting expired sessions and more aggressively removing stale sessions without pending work while retaining pending previews for the longer grace window. Surface culling evidence in the presence roster and read contract without touching post content, revisions, post locks, autosaves, or sync metadata. Update REST presence tests for delete-on-read behavior and pending-preview culling. Verified with: php -l src/wp-includes/de-rtc.php; php -l tests/phpunit/tests/de-rtc/rest-presence.php; npm run test:php -- --filter Tests_DE_RTC_REST_Presence.
External edits and malformed/missing sync metadata are repaired by WordPress rather than by a logged-in editor session. Store those repair updates with a synthetic non-human recovery actor so history, REST evidence, and Automerge metadata can distinguish system recovery from human authorship without exposing user/session identifiers. Also align retry-save review approval proof hashing with the production attribution key used by the guarded save candidate path, keeping provenance evidence deterministic across proof and write boundaries. Verified with php -l, diff --check, focused de-rtc recovery/history/retry-save tests, and the full phpunit --group de-rtc suite.
Expose the current DE CRDT version on normal post REST responses and keep bounded content snapshots in sync metadata so base_version updates can resolve against the CRDT state carried in post_content. Teach wp_update_post() to treat base_version as an explicit Distributed Editing merge trigger. The PHP path verifies or adopts submitted Automerge metadata when safe, otherwise fabricates a server-owned edit from the referenced CRDT version, attributes the edit to on_behalf_of, and uses that user's capabilities for review-sensitive checks. Cover REST and wp_update_post() behavior with Tests_DE_RTC_REST_Retry_Save, including no-current-user PHP calls, missing sync-meta repair, trusted client metadata adoption, unsafe author rejection, and wp_error=false rejection semantics. Tests: npm run test:php -- --filter Tests_DE_RTC_REST_Retry_Save
* Vendor automerge-php at includes/lib with lazy loader Imported verbatim from the Gutenberg chriszarate/refreshed-de-rtc branch (lib/compat/wordpress-7.1/distributed-editing/automerge-php, itself a verbatim port of wordpress-develop add/distributed-editing, PR WordPress/wordpress-develop#12334). MIT, PHP 8.2+, namespace WordPress\DistributedEditing\Automerge, no WordPress dependency. The library's conformance suite (php tests/run.php) referenced an upstream/automerge submodule never committed on either source branch; the 11 fixture files it reads (3 storage fixtures + 8 fuzz-crashers) are now vendored under upstream/automerge/, fetched from automerge/automerge@8d7b12f (MIT; recorded in VENDORED_FROM_COMMIT.txt). Suite passes 680/680 locally. includes/lib/automerge-php-loader.php mirrors y-php-loader.php: a lazy PSR-4 shim plus gutenberg_sync_engines_automerge_php_is_supported() (PHP >= 8.2 + mbstring) for callers to gate on. Excluded from phpcs like y-php. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Port the DE-RTC merge core as a frozen engine slice includes/engines/de-rtc/merge-core.php is the exact call-graph closure (113 functions, ~6.4k lines) of the engine-facing entry points in the Gutenberg chriszarate/refreshed-de-rtc branch's de-rtc.php (itself a verbatim port of wordpress-develop add/distributed-editing): update construction/normalization, the serialized-block and block-identity three-way merges, the rich-text merge model, version snapshots, sync-meta format/parse, canonicalization/hashing, and the automerge runtime gate. Extracted token-exactly; the only deltas are the vendored library path and delegating autoloading to automerge-php-loader.php (marked DELTA in place). Excluded from phpcs and frozen like the intent-log cross-language core. The plugin loads it behind a function_exists guard so a Core/Gutenberg build that ships DE-RTC itself wins. tests/phpunit/wpDeRtcMergeCore.php drives the merge seam directly: disjoint block edits merge, non-overlapping rich-text edits within one paragraph merge, overlapping edits escalate (de_rtc_rebase_failed / manual_conflict_required), concurrent differing appends escalate by design, tampered/mismatched updates are rejected, engine-unaware saves get server-generated updates, and version snapshots trim at the limit. Two upstream-faithful behaviors are pinned rather than fixed: the legacy native-automerge-php-v1 lane is dead code (NativePort::merge accepts only document pairs, so operations-array updates are rejected as unverifiable) and same-edge concurrent appends require review. Full PHPUnit: 162 tests / 707 assertions green (baseline 148 + 14 new). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add WP_De_RTC_Engine: the DE-RTC merge core behind the engine SPI The third engine (slug de-rtc): server-governed three-way merges of whole-content proposals. Clients send proposal updates ({proposalId, baseVersion, proposedContent, clientUpdate}); under the per-room ingest lock (three-way merges are order-dependent, so ingest serializes like intent-log, unlike yjs-server's lock-free CRDT path) the engine resolves the named base from its version snapshots, merges with wp_de_rtc_get_automerge_retry_save_result(), and either advances the canonical document (disposition applied + a server-authored content row peers replay) or settles the proposal as escalated (manual-conflict-required, requires-unfiltered-html) or voided (unknown-base-version, invalid-payload, tamper/malformed details). Canonical state ({version, content, sync_meta.version_snapshots}) lives in room meta — not in a post_content sync-meta block, which is what made most of upstream DE-RTC's periphery (revision scan, kses allowance, preservation filters) unnecessary here. Genesis is deterministic from post content and ADOPTS an existing upstream sync-meta block (version lineage continues, content stripped). Server-driven checkpoints reuse the shared retention invariant (trim behind the previous checkpoint, floor-clamp stale cursors). The capability lane escalates whole proposals kses would rewrite (upstream sequesters just the risky blocks for review — documented gap until the review lane exists). Registered in the plugin and on the settings screen. PHPUnit: 174 tests / 763 assertions green (12 new engine tests: SPI identity, genesis+lineage, apply/broadcast, stale-base three-way rebase, conflict escalation, kses escalation, per-row voids, type fencing, persistence across instances, checkpoint trim + floor clamp). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add the de-rtc client engine: proposal wire over a local doc bridge The client half of DE-RTC keeps Distributed Editing's core inversion: the client NEVER merges. A local Y.Doc (shared engines/yjs schema — same undo manager, awareness anchor, and record mapping as the yjs engines) bridges the editor; the session codec speaks the proposal wire: - One coalesced in-flight proposal: local edits mark the doc dirty and a whole-content proposal is built only when none is pending, so a typing burst costs one proposal per poll cycle. The base version is the version last APPLIED to the doc — stale bases are exactly what the server's three-way merge is for. - Canonical rows are deferred while local edits are dirty/in flight (applying them would overwrite edits the server has not seen); the newest deferred row applies when the local state settles. Escalated proposals are abandoned locally once canonical applies — the upstream review/decision UI is a listed follow-up, as is the client-side block-native descriptor builder (proposals send clientUpdate: null and the server derives operations via its engine-unaware writer lane). - Server genesis bootstraps the doc (hydrate is a no-op; pre-bootstrap local changes buffer and replay), mirroring yjs-server. - Collections are inert (the intent-log precedent): awareness flows, rows are ignored, nothing is proposed. The doc bridge serializes/parses through the editor's own block library (wp.blocks at runtime; resolved from the subtree in Jest/tsc, mocked in tests). Registered as the third adapter in src/index.ts. Jest: 347 tests green (8 new: identity, no-seed hydrate + genesis bootstrap, pre-bootstrap buffering, proposal coalescing + settle, remote apply + onRemoteChange + rebased base version, deferred canonical under in-flight, own-row slot clearing, inert collections). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fix de-rtc client rebase races; add the de-rtc collaboration e2e spec Three client fixes found by driving the real editor two-up (each verified with the spec + Playwright traces): 1. Own accepted rows advance the base version. A client's successive typing chunks were proposed against the same old base, so an author's continuation conflicted with their own just-accepted chunk (rich-text overlap at the same position). When our own row round-trips unchanged, advance the version WITHOUT touching the doc (newer keystrokes survive); the next chunk proposes against it. 2. Block-level incorporation of own merged rows. When the server merges peers' work into our proposal, adopt canonical blocks we have not edited since proposing, keep locally-edited blocks (reconciled by the next proposal), handle peer tail-insertions, and bail to deferral on any other structure change. Truly concurrent same-block edits resolve block-level last-writer-wins — the same class of silent register policy yjs-server carries, at coarser grain (documented in the engine comparison). 3. Dispositions only settle the proposal they name. A previous proposal's disposition arrives in the response AFTER the one whose rows already settled it; clearing the in-flight slot unconditionally let a peer's canonical row clobber unproposed local edits, which the next incorporation then wrongly pinned as 'local'. The e2e spec (three scenarios: server-side genesis + bidirectional text sync, concurrent different-block edits surviving the three-way merge, and the save flow persisting both users' settled edits) passes repeatedly in-suite and solo. It opens sessions through a local helper that force-closes the second user's welcome guide when the fixture's preference dispatch loses to late preference hydration (an open modal aria-hides the page and fails discovery even though sync is healthy). Deliberately absent scenarios are the v1 gaps: title sync, and the empty-post concurrent-append case (a BY-DESIGN escalation under DE-RTC policy). Known pre-existing full-suite flake, verified NOT caused by these changes: http-only/collaboration-sync-body-size can fail after any engine-flip suite under load (control: yjs suite + body-size fails identically without de-rtc involved); solo it is green, CI retries absorb it. Jest 347 green; de-rtc e2e 3/3; full e2e 31/32 (the flake above). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Document the de-rtc engine and run automerge-php conformance in CI - AGENTS.md: engines list, repo-layout entries for the frozen merge core and the vendored automerge-php (incl. the PORTING_STATUS.json rewrite side-effect and the fact that the shipping merge path never calls the library), new green baselines (Jest 347, PHPUnit 174/763, e2e 32/32 with the pre-existing body-size-after-engine-flip flake called out), and the de-rtc known-gaps entry. - docs/engine-comparison.md: de-rtc added to the one-sentence list, the parity and host-resource tables, known gaps (no benchmark profile, no review UI/title sync, block-level LWW on same-block concurrency, no client-side proof descriptors), and the bottom line. - README.md: de-rtc in the engines list. - CI: run the vendored automerge-php conformance suite (680 mapped upstream tests, plain php runner, no WordPress) alongside y-php's. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fix conflict syntax error * Actually fix conflict * Pin PHP 8.4 for the conformance suites; surface the automerge report The automerge-php conformance step failed on CI while passing locally: its grapheme-cluster paths split text with PCRE2's \X, and PCRE2 10.42 (bundled by PHP <= 8.3 builds, including the stock runner's 8.3.6 and Ubuntu 24.04 packages) carries a GB11 bug where two ADJACENT emoji-ZWJ sequences count as ONE extended grapheme cluster. PCRE2 10.44 (bundled from PHP 8.4) counts two. Exactly 2 of the 680 mapped upstream tests fail under the old tables — grapheme cursor tracking through an inserted family emoji, and a UTF-16-boundary splice — reproduced in php:8.2/8.3-cli containers (678/680) vs php:8.4-cli (680/680). CI now pins PHP 8.4 via setup-php for the conformance suites (y-php is 7.4+-compatible and unaffected), and the automerge step keeps its JSON report visible — a pass prints the summary line, a failure dumps the failing entries — instead of discarding stdout, which had swallowed the report entirely (the step 'failed silently' in 1.6 s). AGENTS.md documents the PCRE2 >= 10.43 parity requirement. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Testing and early-previews. Entirely generated by Codex.
Pairs with WordPress/gutenberg#79602