Index: /branches/7.0/src/js/_enqueues/admin/inline-edit-post.js
===================================================================
--- /branches/7.0/src/js/_enqueues/admin/inline-edit-post.js	(revision 62337)
+++ /branches/7.0/src/js/_enqueues/admin/inline-edit-post.js	(revision 62338)
@@ -615,6 +615,5 @@
 }).on( 'heartbeat-tick.wp-check-locked-posts', function( e, data ) {
 	var locked = data['wp-check-locked-posts'] || {},
-		isRtc = window._wpCollaborationEnabled,
-		lockedClass = isRtc ? 'wp-collaborative-editing' : 'wp-locked';
+		lockedClass = 'wp-locked';
 
 	$('#the-list tr').each( function(i, el) {
@@ -627,5 +626,5 @@
 				row.find('.check-column checkbox').prop('checked', false);
 
-				if ( ! isRtc && lock_data.avatar_src ) {
+				if ( lock_data.avatar_src ) {
 					avatar = $( '<img />', {
 						'class': 'avatar avatar-18 photo',
Index: /branches/7.0/src/wp-admin/css/list-tables.css
===================================================================
--- /branches/7.0/src/wp-admin/css/list-tables.css	(revision 62337)
+++ /branches/7.0/src/wp-admin/css/list-tables.css	(revision 62338)
@@ -636,20 +636,4 @@
 }
 
-.wp-collaborative-editing .locked-info {
-	display: block;
-}
-
-.join-action-text {
-	display: none;
-}
-
-.wp-collaborative-editing .edit-action-text {
-	display: none;
-}
-
-.wp-collaborative-editing .join-action-text {
-	display: inline;
-}
-
 #menu-locations-wrap .widefat {
 	width: 60%;
Index: /branches/7.0/src/wp-admin/includes/class-wp-posts-list-table.php
===================================================================
--- /branches/7.0/src/wp-admin/includes/class-wp-posts-list-table.php	(revision 62337)
+++ /branches/7.0/src/wp-admin/includes/class-wp-posts-list-table.php	(revision 62338)
@@ -1120,14 +1120,8 @@
 
 			if ( $lock_holder ) {
-				if ( get_option( 'wp_collaboration_enabled' ) ) {
-					$locked_avatar = '';
-					/* translators: Collaboration status message for a singular post in the post list. Can be any type of post. */
-					$locked_text   = esc_html_x( 'Currently being edited', 'post list' );
-				} else {
-					$lock_holder   = get_userdata( $lock_holder );
-					$locked_avatar = get_avatar( $lock_holder->ID, 18 );
-					/* translators: %s: User's display name. */
-					$locked_text = esc_html( sprintf( __( '%s is currently editing' ), $lock_holder->display_name ) );
-				}
+				$lock_holder   = get_userdata( $lock_holder );
+				$locked_avatar = get_avatar( $lock_holder->ID, 18 );
+				/* translators: %s: User's display name. */
+				$locked_text = esc_html( sprintf( __( '%s is currently editing' ), $lock_holder->display_name ) );
 			} else {
 				$locked_avatar = '';
@@ -1434,9 +1428,5 @@
 
 		if ( $lock_holder ) {
-			if ( get_option( 'wp_collaboration_enabled' ) ) {
-				$classes .= ' wp-collaborative-editing';
-			} else {
-				$classes .= ' wp-locked';
-			}
+			$classes .= ' wp-locked';
 		}
 
@@ -1492,42 +1482,11 @@
 
 		if ( $can_edit_post && 'trash' !== $post->post_status ) {
-			$is_rtc_enabled = (bool) get_option( 'wp_collaboration_enabled' );
-
-			/*
-			 * When RTC is enabled, both "Edit" and "Join" labels are rendered.
-			 * The visible label is toggled by CSS based on the row's
-			 * `wp-collaborative-editing` class, which is added or removed by
-			 * inline-edit-post.js in response to heartbeat ticks.
-			 */
-			if ( $is_rtc_enabled ) {
-				$actions['edit'] = sprintf(
-					'<a href="%1$s">'
-					. '<span class="edit-action-text">'
-					. '<span aria-hidden="true">%2$s</span>'
-					. '<span class="screen-reader-text">%3$s</span>'
-					. '</span>'
-					. '<span class="join-action-text">'
-					. '<span aria-hidden="true">%4$s</span>'
-					. '<span class="screen-reader-text">%5$s</span>'
-					. '</span>'
-					. '</a>',
-					get_edit_post_link( $post->ID ),
-					__( 'Edit' ),
-					/* translators: %s: Post title. */
-					sprintf( __( 'Edit &#8220;%s&#8221;' ), $title ),
-					/* translators: Action link text for a singular post in the post list. Can be any type of post. */
-					_x( 'Join', 'post list' ),
-					/* translators: %s: Post title. */
-					sprintf( __( 'Join editing &#8220;%s&#8221;', 'post list' ), $title )
-				);
-			} else {
-				$actions['edit'] = sprintf(
-					'<a href="%s" aria-label="%s">%s</a>',
-					get_edit_post_link( $post->ID ),
-					/* translators: %s: Post title. */
-					esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $title ) ),
-					__( 'Edit' )
-				);
-			}
+			$actions['edit'] = sprintf(
+				'<a href="%s" aria-label="%s">%s</a>',
+				get_edit_post_link( $post->ID ),
+				/* translators: %s: Post title. */
+				esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $title ) ),
+				__( 'Edit' )
+			);
 
 			/**
Index: /branches/7.0/src/wp-admin/includes/misc.php
===================================================================
--- /branches/7.0/src/wp-admin/includes/misc.php	(revision 62337)
+++ /branches/7.0/src/wp-admin/includes/misc.php	(revision 62338)
@@ -1137,6 +1137,5 @@
  */
 function wp_check_locked_posts( $response, $data, $screen_id ) {
-	$checked        = array();
-	$is_rtc_enabled = (bool) get_option( 'wp_collaboration_enabled' );
+	$checked = array();
 
 	if ( array_key_exists( 'wp-check-locked-posts', $data ) && is_array( $data['wp-check-locked-posts'] ) ) {
@@ -1154,21 +1153,13 @@
 
 				if ( $user && current_user_can( 'edit_post', $post_id ) ) {
-					if ( $is_rtc_enabled ) {
-						$send = array(
-							/* translators: Collaboration status message for a singular post in the post list. Can be any type of post. */
-							'text'          => _x( 'Currently being edited', 'post list' ),
-							'collaborative' => true,
-						);
-					} else {
-						$send = array(
-							'name' => $user->display_name,
-							/* translators: %s: User's display name. */
-							'text' => sprintf( __( '%s is currently editing' ), $user->display_name ),
-						);
-
-						if ( get_option( 'show_avatars' ) ) {
-							$send['avatar_src']    = get_avatar_url( $user->ID, array( 'size' => 18 ) );
-							$send['avatar_src_2x'] = get_avatar_url( $user->ID, array( 'size' => 36 ) );
-						}
+					$send = array(
+						'name' => $user->display_name,
+						/* translators: %s: User's display name. */
+						'text' => sprintf( __( '%s is currently editing' ), $user->display_name ),
+					);
+
+					if ( get_option( 'show_avatars' ) ) {
+						$send['avatar_src']    = get_avatar_url( $user->ID, array( 'size' => 18 ) );
+						$send['avatar_src_2x'] = get_avatar_url( $user->ID, array( 'size' => 36 ) );
 					}
 
Index: /branches/7.0/src/wp-admin/includes/schema.php
===================================================================
--- /branches/7.0/src/wp-admin/includes/schema.php	(revision 62337)
+++ /branches/7.0/src/wp-admin/includes/schema.php	(revision 62338)
@@ -564,7 +564,4 @@
 		// 6.9.0
 		'wp_notes_notify'                 => 1,
-
-		// 7.0.0
-		'wp_collaboration_enabled'        => 0,
 	);
 
Index: /branches/7.0/src/wp-admin/options-writing.php
===================================================================
--- /branches/7.0/src/wp-admin/options-writing.php	(revision 62337)
+++ /branches/7.0/src/wp-admin/options-writing.php	(revision 62338)
@@ -108,19 +108,4 @@
 <?php endforeach; ?>
 	</select>
-</td>
-</tr>
-<tr>
-<th scope="row"><?php _e( 'Collaboration' ); ?></th>
-<td>
-	<?php if ( wp_is_collaboration_allowed() ) : ?>
-		<label for="wp_collaboration_enabled">
-			<input name="wp_collaboration_enabled" type="checkbox" id="wp_collaboration_enabled" value="1" <?php checked( '1', (bool) get_option( 'wp_collaboration_enabled' ) ); ?> />
-			<?php _e( "Enable early access to real-time collaboration. Real-time collaboration may affect your website's performance." ); ?>
-		</label>
-	<?php else : ?>
-		<div class="notice notice-warning inline">
-			<p><?php _e( '<strong>Note:</strong> Real-time collaboration has been disabled.' ); ?></p>
-		</div>
-	<?php endif; ?>
 </td>
 </tr>
Index: /branches/7.0/src/wp-admin/options.php
===================================================================
--- /branches/7.0/src/wp-admin/options.php	(revision 62337)
+++ /branches/7.0/src/wp-admin/options.php	(revision 62338)
@@ -154,5 +154,4 @@
 		'default_link_category',
 		'default_post_format',
-		'wp_collaboration_enabled',
 	),
 );
Index: anches/7.0/src/wp-includes/collaboration.php
===================================================================
--- /branches/7.0/src/wp-includes/collaboration.php	(revision 62337)
+++ 	(revision )
@@ -1,85 +1,0 @@
-<?php
-/**
- * Bootstraps collaborative editing.
- *
- * @package WordPress
- * @since 7.0.0
- */
-
-/**
- * Determines whether real-time collaboration is enabled.
- *
- * If the WP_ALLOW_COLLABORATION constant is false,
- * collaboration is always disabled regardless of the database option.
- * Otherwise, falls back to the 'wp_collaboration_enabled' option.
- *
- * @since 7.0.0
- *
- * @return bool Whether real-time collaboration is enabled.
- */
-function wp_is_collaboration_enabled() {
-	return (
-		wp_is_collaboration_allowed() &&
-		(bool) get_option( 'wp_collaboration_enabled' )
-	);
-}
-
-/**
- * Determines whether real-time collaboration is allowed.
- *
- * If the WP_ALLOW_COLLABORATION constant is false,
- * collaboration is not allowed and cannot be enabled.
- * The constant defaults to true, unless the WP_ALLOW_COLLABORATION
- * environment variable is set to string "false".
- *
- * @since 7.0.0
- *
- * @return bool Whether real-time collaboration is enabled.
- */
-function wp_is_collaboration_allowed() {
-	if ( ! defined( 'WP_ALLOW_COLLABORATION' ) ) {
-		$env_value = getenv( 'WP_ALLOW_COLLABORATION' );
-		if ( false === $env_value ) {
-			// Environment variable is not defined, default to allowing collaboration.
-			define( 'WP_ALLOW_COLLABORATION', true );
-		} else {
-			/*
-			 * Environment variable is defined, let's confirm it is actually set to
-			 * "true" as it may still have a string value "false" – the preceeding
-			 * `if` branch only tests for the boolean `false`.
-			 */
-			define( 'WP_ALLOW_COLLABORATION', 'true' === $env_value );
-		}
-	}
-
-	return WP_ALLOW_COLLABORATION;
-}
-
-/**
- * Injects the real-time collaboration setting into a global variable.
- *
- * @since 7.0.0
- *
- * @access private
- *
- * @global string $pagenow The filename of the current screen.
- */
-function wp_collaboration_inject_setting() {
-	global $pagenow;
-
-	if ( ! wp_is_collaboration_enabled() ) {
-		return;
-	}
-
-	// Disable real-time collaboration on the site editor.
-	$enabled = true;
-	if ( 'site-editor.php' === $pagenow ) {
-		$enabled = false;
-	}
-
-	wp_add_inline_script(
-		'wp-core-data',
-		'window._wpCollaborationEnabled = ' . wp_json_encode( $enabled ) . ';',
-		'after'
-	);
-}
Index: /branches/7.0/src/wp-includes/default-filters.php
===================================================================
--- /branches/7.0/src/wp-includes/default-filters.php	(revision 62337)
+++ /branches/7.0/src/wp-includes/default-filters.php	(revision 62338)
@@ -791,7 +791,4 @@
 add_action( 'init', '_wp_register_default_font_collections' );
 
-// Collaboration.
-add_action( 'admin_init', 'wp_collaboration_inject_setting' );
-
 // Add ignoredHookedBlocks metadata attribute to the template and template part post types.
 add_filter( 'rest_pre_insert_wp_template', 'inject_ignored_hooked_blocks_metadata_attributes' );
Index: /branches/7.0/src/wp-includes/option.php
===================================================================
--- /branches/7.0/src/wp-includes/option.php	(revision 62337)
+++ /branches/7.0/src/wp-includes/option.php	(revision 62338)
@@ -2887,16 +2887,4 @@
 
 	register_setting(
-		'writing',
-		'wp_collaboration_enabled',
-		array(
-			'type'              => 'boolean',
-			'description'       => __( 'Enable Real-Time Collaboration' ),
-			'sanitize_callback' => 'rest_sanitize_boolean',
-			'default'           => false,
-			'show_in_rest'      => true,
-		)
-	);
-
-	register_setting(
 		'reading',
 		'posts_per_page',
Index: /branches/7.0/src/wp-includes/post.php
===================================================================
--- /branches/7.0/src/wp-includes/post.php	(revision 62337)
+++ /branches/7.0/src/wp-includes/post.php	(revision 62338)
@@ -657,40 +657,4 @@
 		)
 	);
-
-	if ( wp_is_collaboration_enabled() ) {
-		register_post_type(
-			'wp_sync_storage',
-			array(
-				'labels'             => array(
-					'name'          => __( 'Sync Updates' ),
-					'singular_name' => __( 'Sync Update' ),
-				),
-				'public'             => false,
-				'_builtin'           => true, /* internal use only. don't use this when registering your own post type. */
-				'hierarchical'       => false,
-				'capabilities'       => array(
-					'read'                   => 'do_not_allow',
-					'read_private_posts'     => 'do_not_allow',
-					'create_posts'           => 'do_not_allow',
-					'publish_posts'          => 'do_not_allow',
-					'edit_posts'             => 'do_not_allow',
-					'edit_others_posts'      => 'do_not_allow',
-					'edit_published_posts'   => 'do_not_allow',
-					'delete_posts'           => 'do_not_allow',
-					'delete_others_posts'    => 'do_not_allow',
-					'delete_published_posts' => 'do_not_allow',
-				),
-				'map_meta_cap'       => false,
-				'publicly_queryable' => false,
-				'query_var'          => false,
-				'rewrite'            => false,
-				'show_in_menu'       => false,
-				'show_in_rest'       => false,
-				'show_ui'            => false,
-				'can_export'         => false,
-				'supports'           => array( 'custom-fields' ),
-			)
-		);
-	}
 
 	register_post_status(
@@ -8653,5 +8617,4 @@
  *
  * @since 6.3.0 Adds `wp_pattern_sync_status` meta field to the wp_block post type so an unsynced option can be added.
- * @since 7.0.0 Adds `_crdt_document` meta field to post types so that CRDT documents can be persisted.
  *
  * @link https://github.com/WordPress/gutenberg/pull/51144
@@ -8673,29 +8636,3 @@
 		)
 	);
-
-	if ( wp_is_collaboration_enabled() ) {
-		register_meta(
-			'post',
-			'_crdt_document',
-			array(
-				'auth_callback'     => static function ( bool $_allowed, string $_meta_key, int $object_id, int $user_id ): bool {
-					return user_can( $user_id, 'edit_post', $object_id );
-				},
-				/*
-				 * Revisions must be disabled because we always want to preserve
-				 * the latest persisted CRDT document, even when a revision is restored.
-				 * This ensures that we can continue to apply updates to a shared document
-				 * and peers can simply merge the restored revision like any other incoming
-				 * update.
-				 *
-				 * If we want to persist CRDT documents alongside revisions in the
-				 * future, we should do so in a separate meta key.
-				 */
-				'revisions_enabled' => false,
-				'show_in_rest'      => true,
-				'single'            => true,
-				'type'              => 'string',
-			)
-		);
-	}
-}
+}
Index: /branches/7.0/src/wp-includes/rest-api.php
===================================================================
--- /branches/7.0/src/wp-includes/rest-api.php	(revision 62337)
+++ /branches/7.0/src/wp-includes/rest-api.php	(revision 62338)
@@ -429,11 +429,4 @@
 	$icons_controller = new WP_REST_Icons_Controller();
 	$icons_controller->register_routes();
-
-	// Collaboration.
-	if ( wp_is_collaboration_enabled() ) {
-		$sync_storage = new WP_Sync_Post_Meta_Storage();
-		$sync_server  = new WP_HTTP_Polling_Sync_Server( $sync_storage );
-		$sync_server->register_routes();
-	}
 }
 
Index: /branches/7.0/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php
===================================================================
--- /branches/7.0/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php	(revision 62337)
+++ /branches/7.0/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php	(revision 62338)
@@ -230,32 +230,21 @@
 		}
 
-		$post_lock = wp_check_post_lock( $post->ID );
-		$is_draft  = 'draft' === $post->post_status || 'auto-draft' === $post->post_status;
+		$post_lock_is_active = wp_check_post_lock( $post->ID );
+		$is_draft            = 'draft' === $post->post_status || 'auto-draft' === $post->post_status;
 
 		/*
-		 * In the context of real-time collaboration, all peers are effectively
-		 * authors and we don't want to vary behavior based on whether they are the
-		 * original author. Always target an autosave revision.
-		 *
-		 * This avoids the following issue when real-time collaboration is enabled:
-		 *
-		 * - Autosaves from the original author (if they have the post lock) will
-		 *   target the saved post.
-		 *
-		 * - Autosaves from other users are applied to a post revision.
-		 *
-		 * - If any user reloads a post, they load changes from the author's autosave.
-		 *
-		 * - The saved post has now diverged from the persisted CRDT document. The
-		 *   content (and/or title or excerpt) are now "ahead" of the persisted CRDT
-		 *   document.
-		 *
-		 * - When the persisted CRDT document is loaded, a diff is computed against
-		 *   the saved post. This diff is then applied to the in-memory CRDT
-		 *   document, which can lead to duplicate inserts or deletions.
+		 * When a post is still in draft form, updates from the author can directly update the post.
+		 * Other autosaves must be stored as per-user autosave revisions.
 		 */
-		$is_collaboration_enabled = wp_is_collaboration_enabled();
-
-		if ( $is_draft && (int) $post->post_author === $user_id && ! $post_lock && ! $is_collaboration_enabled ) {
+		$can_update_author_draft_post = (
+			$is_draft &&
+			(int) $post->post_author === $user_id
+		);
+
+		$should_update_parent_draft_post = (
+			! $post_lock_is_active && $can_update_author_draft_post
+		);
+
+		if ( $should_update_parent_draft_post ) {
 			/*
 			 * Draft posts for the same author: autosaving updates the post and does not create a revision.
@@ -264,5 +253,4 @@
 			$autosave_id = wp_update_post( wp_slash( (array) $prepared_post ), true );
 		} else {
-			// Non-draft posts: create or update the post autosave. Pass the meta data.
 			$autosave_id = $this->create_post_autosave( (array) $prepared_post, (array) $request->get_param( 'meta' ) );
 		}
Index: /branches/7.0/src/wp-settings.php
===================================================================
--- /branches/7.0/src/wp-settings.php	(revision 62337)
+++ /branches/7.0/src/wp-settings.php	(revision 62338)
@@ -311,8 +311,4 @@
 require ABSPATH . WPINC . '/abilities-api.php';
 require ABSPATH . WPINC . '/abilities.php';
-require ABSPATH . WPINC . '/collaboration/interface-wp-sync-storage.php';
-require ABSPATH . WPINC . '/collaboration/class-wp-sync-post-meta-storage.php';
-require ABSPATH . WPINC . '/collaboration/class-wp-http-polling-sync-server.php';
-require ABSPATH . WPINC . '/collaboration.php';
 require ABSPATH . WPINC . '/rest-api.php';
 require ABSPATH . WPINC . '/rest-api/class-wp-rest-server.php';
Index: /branches/7.0/tests/phpunit/tests/rest-api/rest-autosaves-controller.php
===================================================================
--- /branches/7.0/tests/phpunit/tests/rest-api/rest-autosaves-controller.php	(revision 62337)
+++ /branches/7.0/tests/phpunit/tests/rest-api/rest-autosaves-controller.php	(revision 62338)
@@ -571,6 +571,4 @@
 
 	public function test_rest_autosave_draft_post_same_author() {
-		add_filter( 'pre_option_wp_collaboration_enabled', '__return_zero' ); // Zero as false doesn't work for pre-flight options.
-
 		wp_set_current_user( self::$editor_id );
 
@@ -747,6 +745,4 @@
 
 	public function test_update_item_draft_page_with_parent() {
-		add_filter( 'pre_option_wp_collaboration_enabled', '__return_zero' ); // Zero as false doesn't work for pre-flight options.
-
 		wp_set_current_user( self::$editor_id );
 		$request = new WP_REST_Request( 'POST', '/wp/v2/pages/' . self::$child_draft_page_id . '/autosaves' );
@@ -925,76 +921,3 @@
 		);
 	}
-
-	/**
-	 * When real-time collaboration is enabled, autosaving a draft post by the
-	 * same author should create a revision instead of updating the post directly.
-	 */
-	public function test_rest_autosave_draft_post_same_author_with_rtc() {
-		add_filter( 'pre_option_wp_collaboration_enabled', '__return_true' );
-
-		wp_set_current_user( self::$editor_id );
-
-		$post_data = array(
-			'post_content' => 'Test post content',
-			'post_title'   => 'Test post title',
-			'post_excerpt' => 'Test post excerpt',
-		);
-		$post_id   = wp_insert_post( $post_data );
-
-		$autosave_data = array(
-			'id'      => $post_id,
-			'content' => 'Updated post \ content',
-			'title'   => 'Updated post title',
-		);
-
-		$request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' );
-		$request->add_header( 'Content-Type', 'application/json' );
-		$request->set_body( wp_json_encode( $autosave_data ) );
-
-		$response = rest_get_server()->dispatch( $request );
-		$new_data = $response->get_data();
-		$post     = get_post( $post_id );
-
-		// With RTC enabled, a revision is created instead of updating the post.
-		$this->assertNotSame( $post_id, $new_data['id'] );
-		$this->assertSame( $post_id, $new_data['parent'] );
-
-		// The autosave revision should have the updated content.
-		$this->assertSame( $autosave_data['content'], $new_data['content']['raw'] );
-		$this->assertSame( $autosave_data['title'], $new_data['title']['raw'] );
-
-		// The draft post should not be updated.
-		$this->assertSame( $post_data['post_content'], $post->post_content );
-		$this->assertSame( $post_data['post_title'], $post->post_title );
-		$this->assertSame( $post_data['post_excerpt'], $post->post_excerpt );
-
-		wp_delete_post( $post_id );
-	}
-
-	/**
-	 * When real-time collaboration is enabled, autosaving a draft page with
-	 * a parent should create a revision instead of updating the page directly.
-	 */
-	public function test_update_item_draft_page_with_parent_with_rtc() {
-		add_filter( 'pre_option_wp_collaboration_enabled', '__return_true' );
-
-		wp_set_current_user( self::$editor_id );
-		$request = new WP_REST_Request( 'POST', '/wp/v2/pages/' . self::$child_draft_page_id . '/autosaves' );
-		$request->add_header( 'Content-Type', 'application/x-www-form-urlencoded' );
-
-		$params = $this->set_post_data(
-			array(
-				'id'     => self::$child_draft_page_id,
-				'author' => self::$editor_id,
-			)
-		);
-
-		$request->set_body_params( $params );
-		$response = rest_get_server()->dispatch( $request );
-		$data     = $response->get_data();
-
-		// With RTC enabled, a revision is created instead of updating the page.
-		$this->assertNotSame( self::$child_draft_page_id, $data['id'] );
-		$this->assertSame( self::$child_draft_page_id, $data['parent'] );
-	}
 }
Index: /branches/7.0/tests/phpunit/tests/rest-api/rest-settings-controller.php
===================================================================
--- /branches/7.0/tests/phpunit/tests/rest-api/rest-settings-controller.php	(revision 62337)
+++ /branches/7.0/tests/phpunit/tests/rest-api/rest-settings-controller.php	(revision 62338)
@@ -120,5 +120,4 @@
 			'default_comment_status',
 			'site_icon', // Registered in wp-includes/blocks/site-logo.php
-			'wp_collaboration_enabled',
 		);
 
Index: anches/7.0/tests/phpunit/tests/rest-api/rest-sync-server.php
===================================================================
--- /branches/7.0/tests/phpunit/tests/rest-api/rest-sync-server.php	(revision 62337)
+++ 	(revision )
@@ -1,1175 +1,0 @@
-<?php
-/**
- * Tests for the WP_HTTP_Polling_Sync_Server REST endpoint.
- *
- * @package WordPress
- * @subpackage REST API
- *
- * @group restapi
- */
-class WP_Test_REST_Sync_Server extends WP_Test_REST_Controller_Testcase {
-
-	protected static int $editor_id;
-	protected static int $subscriber_id;
-	protected static int $post_id;
-	protected static int $category_id;
-	protected static int $tag_id;
-	protected static int $comment_id;
-
-	public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
-		self::$editor_id     = $factory->user->create( array( 'role' => 'editor' ) );
-		self::$subscriber_id = $factory->user->create( array( 'role' => 'subscriber' ) );
-		self::$post_id       = $factory->post->create( array( 'post_author' => self::$editor_id ) );
-		self::$category_id   = $factory->category->create();
-		self::$tag_id        = $factory->tag->create();
-		self::$comment_id    = $factory->comment->create( array( 'comment_post_ID' => self::$post_id ) );
-
-		// Enable option in setUpBeforeClass to ensure REST routes are registered.
-		update_option( 'wp_collaboration_enabled', 1 );
-	}
-
-	public static function wpTearDownAfterClass() {
-		self::delete_user( self::$editor_id );
-		self::delete_user( self::$subscriber_id );
-		delete_option( 'wp_collaboration_enabled' );
-		wp_delete_post( self::$post_id, true );
-		wp_delete_term( self::$category_id, 'category' );
-		wp_delete_term( self::$tag_id, 'post_tag' );
-		wp_delete_comment( self::$comment_id, true );
-	}
-
-	public function set_up() {
-		parent::set_up();
-
-		// Enable option for tests.
-		update_option( 'wp_collaboration_enabled', 1 );
-
-		// Reset storage post ID cache to ensure clean state after transaction rollback.
-		$reflection = new ReflectionProperty( 'WP_Sync_Post_Meta_Storage', 'storage_post_ids' );
-		if ( PHP_VERSION_ID < 80100 ) {
-			$reflection->setAccessible( true );
-		}
-		$reflection->setValue( null, array() );
-	}
-
-	/**
-	 * Builds a room request array for the sync endpoint.
-	 *
-	 * @param string $room      Room identifier.
-	 * @param int    $client_id Client ID.
-	 * @param int    $cursor    Cursor value for the 'after' parameter.
-	 * @param array  $awareness Awareness state.
-	 * @param array  $updates   Array of updates.
-	 * @return array Room request data.
-	 */
-	private function build_room( $room, $client_id = 1, $cursor = 0, $awareness = array(), $updates = array() ) {
-		if ( empty( $awareness ) ) {
-			$awareness = array( 'user' => 'test' );
-		}
-
-		return array(
-			'after'     => $cursor,
-			'awareness' => $awareness,
-			'client_id' => $client_id,
-			'room'      => $room,
-			'updates'   => $updates,
-		);
-	}
-
-	/**
-	 * Dispatches a sync request with the given rooms.
-	 *
-	 * @param array $rooms Array of room request data.
-	 * @return WP_REST_Response Response object.
-	 */
-	private function dispatch_sync( $rooms ) {
-		$request = new WP_REST_Request( 'POST', '/wp-sync/v1/updates' );
-		$request->set_body_params( array( 'rooms' => $rooms ) );
-		return rest_get_server()->dispatch( $request );
-	}
-
-	/**
-	 * Returns the default room identifier for the test post.
-	 *
-	 * @return string Room identifier.
-	 */
-	private function get_post_room() {
-		return 'postType/post:' . self::$post_id;
-	}
-
-	/*
-	 * Required abstract method implementations.
-	 *
-	 * The sync endpoint is a single POST endpoint, not a standard CRUD controller.
-	 * Methods that don't apply are stubbed with @doesNotPerformAssertions.
-	 */
-
-	public function test_register_routes() {
-		$routes = rest_get_server()->get_routes();
-		$this->assertArrayHasKey( '/wp-sync/v1/updates', $routes );
-	}
-
-	/**
-	 * Verifies the sync route is registered when relying on the option's default
-	 * value (option not stored in the database).
-	 *
-	 * This covers the upgrade scenario where a site has never explicitly saved
-	 * the collaboration setting.
-	 *
-	 * @ticket 64814
-	 */
-	public function test_register_routes_with_default_option() {
-		global $wp_rest_server;
-
-		// Ensure the option is not in the database.
-		delete_option( 'wp_collaboration_enabled' );
-
-		// Reset the REST server so routes are re-registered from scratch.
-		$wp_rest_server = null;
-
-		$routes = rest_get_server()->get_routes();
-		$this->assertArrayNotHasKey( '/wp-sync/v1/updates', $routes );
-	}
-
-	/**
-	 * @doesNotPerformAssertions
-	 */
-	public function test_context_param() {
-		// Not applicable for sync endpoint.
-	}
-
-	/**
-	 * @doesNotPerformAssertions
-	 */
-	public function test_get_items() {
-		// Not applicable for sync endpoint.
-	}
-
-	/**
-	 * @doesNotPerformAssertions
-	 */
-	public function test_get_item() {
-		// Not applicable for sync endpoint.
-	}
-
-	public function test_create_item() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( $this->get_post_room() ) ) );
-
-		$this->assertSame( 200, $response->get_status() );
-	}
-
-	/**
-	 * @doesNotPerformAssertions
-	 */
-	public function test_update_item() {
-		// Not applicable for sync endpoint.
-	}
-
-	/**
-	 * @doesNotPerformAssertions
-	 */
-	public function test_delete_item() {
-		// Not applicable for sync endpoint.
-	}
-
-	/**
-	 * @doesNotPerformAssertions
-	 */
-	public function test_prepare_item() {
-		// Not applicable for sync endpoint.
-	}
-
-	/**
-	 * @doesNotPerformAssertions
-	 */
-	public function test_get_item_schema() {
-		// Not applicable for sync endpoint.
-	}
-
-	/*
-	 * Permission tests.
-	 */
-
-	public function test_sync_requires_authentication() {
-		wp_set_current_user( 0 );
-
-		$response = $this->dispatch_sync( array( $this->build_room( $this->get_post_room() ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 401 );
-	}
-
-	public function test_sync_post_requires_edit_capability() {
-		wp_set_current_user( self::$subscriber_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( $this->get_post_room() ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	public function test_sync_post_allowed_with_edit_capability() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( $this->get_post_room() ) ) );
-
-		$this->assertSame( 200, $response->get_status() );
-	}
-
-	public function test_sync_post_type_collection_requires_edit_posts_capability() {
-		wp_set_current_user( self::$subscriber_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'postType/post' ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	public function test_sync_post_type_collection_allowed_with_edit_posts_capability() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'postType/post' ) ) );
-
-		$this->assertSame( 200, $response->get_status() );
-	}
-
-	public function test_sync_root_collection_allowed() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'root/site' ) ) );
-
-		$this->assertSame( 200, $response->get_status() );
-	}
-
-	public function test_sync_taxonomy_collection_allowed() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'taxonomy/category' ) ) );
-
-		$this->assertSame( 200, $response->get_status() );
-	}
-
-	public function test_sync_unknown_collection_kind_rejected() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'unknown/entity' ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	public function test_sync_non_posttype_entity_with_object_id_rejected() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'root/site:123' ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	public function test_sync_nonexistent_post_rejected() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'postType/post:999999' ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	public function test_sync_permission_checked_per_room() {
-		wp_set_current_user( self::$editor_id );
-
-		// First room is allowed, second room is forbidden.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $this->get_post_room() ),
-				$this->build_room( 'unknown/entity' ),
-			)
-		);
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	/**
-	 * @ticket 64890
-	 */
-	public function test_sync_malformed_object_id_rejected() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'postType/post:1abc' ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	/**
-	 * @ticket 64890
-	 */
-	public function test_sync_zero_object_id_rejected(): void {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'postType/post:0' ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	/**
-	 * @ticket 64890
-	 */
-	public function test_sync_post_type_mismatch_rejected(): void {
-		wp_set_current_user( self::$editor_id );
-
-		// The test post is of type 'post', not 'page'.
-		$response = $this->dispatch_sync( array( $this->build_room( 'postType/page:' . self::$post_id ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	/**
-	 * @ticket 64890
-	 */
-	public function test_sync_taxonomy_term_allowed(): void {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'taxonomy/category:' . self::$category_id ) ) );
-
-		$this->assertSame( 200, $response->get_status() );
-	}
-
-	/**
-	 * @ticket 64890
-	 */
-	public function test_sync_nonexistent_taxonomy_term_rejected(): void {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'taxonomy/category:999999' ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	/**
-	 * @ticket 64890
-	 */
-	public function test_sync_taxonomy_term_wrong_taxonomy_rejected(): void {
-		wp_set_current_user( self::$editor_id );
-
-		// The tag term exists in 'post_tag', not 'category'.
-		$response = $this->dispatch_sync( array( $this->build_room( 'taxonomy/category:' . self::$tag_id ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	/**
-	 * @ticket 64890
-	 */
-	public function test_sync_comment_allowed(): void {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'root/comment:' . self::$comment_id ) ) );
-
-		$this->assertSame( 200, $response->get_status() );
-	}
-
-	/**
-	 * @ticket 64890
-	 */
-	public function test_sync_nonexistent_comment_rejected(): void {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'root/comment:999999' ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	/**
-	 * @ticket 64890
-	 */
-	public function test_sync_nonexistent_post_type_collection_rejected(): void {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( 'postType/nonexistent_type' ) ) );
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	/*
-	 * Validation tests.
-	 */
-
-	public function test_sync_invalid_room_format_rejected() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( 'invalid-room-format' ),
-			)
-		);
-
-		$this->assertSame( 400, $response->get_status() );
-	}
-
-	/**
-	 * Verifies that schema type validation rejects a non-string value for the
-	 * update 'data' field, confirming that per-arg schema validation still runs
-	 * with a route-level validate_callback registered.
-	 *
-	 * @ticket 64890
-	 */
-	public function test_sync_rejects_non_string_update_data(): void {
-		wp_set_current_user( self::$editor_id );
-
-		$request = new WP_REST_Request( 'POST', '/wp-sync/v1/updates' );
-		$request->set_body_params(
-			array(
-				'rooms' => array(
-					array(
-						'after'     => 0,
-						'awareness' => array( 'user' => 'test' ),
-						'client_id' => 1,
-						'room'      => $this->get_post_room(),
-						'updates'   => array(
-							array(
-								'data' => 12345,
-								'type' => 'update',
-							),
-						),
-					),
-				),
-			)
-		);
-
-		$response = rest_get_server()->dispatch( $request );
-		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
-	}
-
-	/**
-	 * Verifies that schema enum validation rejects an invalid update type,
-	 * confirming that per-arg schema validation still runs with a route-level
-	 * validate_callback registered.
-	 *
-	 * @ticket 64890
-	 */
-	public function test_sync_rejects_invalid_update_type_enum(): void {
-		wp_set_current_user( self::$editor_id );
-
-		$request = new WP_REST_Request( 'POST', '/wp-sync/v1/updates' );
-		$request->set_body_params(
-			array(
-				'rooms' => array(
-					array(
-						'after'     => 0,
-						'awareness' => array( 'user' => 'test' ),
-						'client_id' => 1,
-						'room'      => $this->get_post_room(),
-						'updates'   => array(
-							array(
-								'data' => 'dGVzdA==',
-								'type' => 'invalid_type',
-							),
-						),
-					),
-				),
-			)
-		);
-
-		$response = rest_get_server()->dispatch( $request );
-		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
-	}
-
-	/**
-	 * Verifies that schema required-field validation rejects a room missing
-	 * the 'client_id' field, confirming that per-arg schema validation still
-	 * runs with a route-level validate_callback registered.
-	 *
-	 * @ticket 64890
-	 */
-	public function test_sync_rejects_missing_required_room_field(): void {
-		wp_set_current_user( self::$editor_id );
-
-		$request = new WP_REST_Request( 'POST', '/wp-sync/v1/updates' );
-		$request->set_body_params(
-			array(
-				'rooms' => array(
-					array(
-						'after'     => 0,
-						'awareness' => array( 'user' => 'test' ),
-						// 'client_id' deliberately omitted.
-						'room'      => $this->get_post_room(),
-						'updates'   => array(),
-					),
-				),
-			)
-		);
-
-		$response = rest_get_server()->dispatch( $request );
-		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
-	}
-
-	/**
-	 * Verifies that the maxItems constraint rejects a request with more rooms
-	 * than MAX_ROOMS_PER_REQUEST.
-	 *
-	 * @ticket 64890
-	 */
-	public function test_sync_rejects_rooms_exceeding_max_items(): void {
-		wp_set_current_user( self::$editor_id );
-
-		$rooms = array();
-		for ( $i = 0; $i < WP_HTTP_Polling_Sync_Server::MAX_ROOMS_PER_REQUEST + 1; $i++ ) {
-			$rooms[] = $this->build_room( 'root/site', $i + 1 );
-		}
-
-		$response = $this->dispatch_sync( $rooms );
-		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
-	}
-
-	/**
-	 * Verifies that the maxLength constraint rejects update data exceeding
-	 * MAX_UPDATE_DATA_SIZE.
-	 *
-	 * @ticket 64890
-	 */
-	public function test_sync_rejects_update_data_exceeding_max_length(): void {
-		wp_set_current_user( self::$editor_id );
-
-		$oversized_data = str_repeat( 'a', WP_HTTP_Polling_Sync_Server::MAX_UPDATE_DATA_SIZE + 1 );
-
-		$request = new WP_REST_Request( 'POST', '/wp-sync/v1/updates' );
-		$request->set_body_params(
-			array(
-				'rooms' => array(
-					array(
-						'after'     => 0,
-						'awareness' => array( 'user' => 'test' ),
-						'client_id' => 1,
-						'room'      => $this->get_post_room(),
-						'updates'   => array(
-							array(
-								'data' => $oversized_data,
-								'type' => 'update',
-							),
-						),
-					),
-				),
-			)
-		);
-
-		$response = rest_get_server()->dispatch( $request );
-		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
-	}
-
-	/**
-	 * Verifies that the route-level validate_callback rejects a request body
-	 * exceeding MAX_BODY_SIZE.
-	 *
-	 * @ticket 64890
-	 */
-	public function test_sync_rejects_oversized_request_body(): void {
-		wp_set_current_user( self::$editor_id );
-
-		$request = new WP_REST_Request( 'POST', '/wp-sync/v1/updates' );
-
-		// Set valid parsed params so per-arg schema validation passes first.
-		$request->set_body_params(
-			array(
-				'rooms' => array(
-					$this->build_room( $this->get_post_room() ),
-				),
-			)
-		);
-
-		// Set an oversized raw body to trigger the route-level validate_callback.
-		$request->set_body( str_repeat( 'x', WP_HTTP_Polling_Sync_Server::MAX_BODY_SIZE + 1 ) );
-
-		$response = rest_get_server()->dispatch( $request );
-		$this->assertErrorResponse( 'rest_sync_body_too_large', $response, 413 );
-	}
-
-	/*
-	 * Response format tests.
-	 */
-
-	public function test_sync_response_structure() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( $this->get_post_room() ) ) );
-
-		$this->assertSame( 200, $response->get_status() );
-
-		$data = $response->get_data();
-		$this->assertArrayHasKey( 'rooms', $data );
-		$this->assertCount( 1, $data['rooms'] );
-
-		$room_data = $data['rooms'][0];
-		$this->assertArrayHasKey( 'room', $room_data );
-		$this->assertArrayHasKey( 'awareness', $room_data );
-		$this->assertArrayHasKey( 'updates', $room_data );
-		$this->assertArrayHasKey( 'end_cursor', $room_data );
-		$this->assertArrayHasKey( 'total_updates', $room_data );
-		$this->assertArrayHasKey( 'should_compact', $room_data );
-	}
-
-	public function test_sync_response_room_matches_request() {
-		wp_set_current_user( self::$editor_id );
-
-		$room     = $this->get_post_room();
-		$response = $this->dispatch_sync( array( $this->build_room( $room ) ) );
-
-		$data = $response->get_data();
-		$this->assertSame( $room, $data['rooms'][0]['room'] );
-	}
-
-	public function test_sync_end_cursor_is_positive_integer() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( $this->get_post_room() ) ) );
-
-		$data = $response->get_data();
-		$this->assertIsInt( $data['rooms'][0]['end_cursor'] );
-		$this->assertGreaterThanOrEqual( 0, $data['rooms'][0]['end_cursor'] );
-	}
-
-	public function test_sync_empty_updates_returns_zero_total() {
-		wp_set_current_user( self::$editor_id );
-
-		$response = $this->dispatch_sync( array( $this->build_room( $this->get_post_room() ) ) );
-
-		$data = $response->get_data();
-		$this->assertSame( 0, $data['rooms'][0]['total_updates'] );
-		$this->assertEmpty( $data['rooms'][0]['updates'] );
-	}
-
-	/*
-	 * Update tests.
-	 */
-
-	public function test_sync_update_delivered_to_other_client() {
-		wp_set_current_user( self::$editor_id );
-
-		$room   = $this->get_post_room();
-		$update = array(
-			'type' => 'update',
-			'data' => 'dGVzdCBkYXRh',
-		);
-
-		// Client 1 sends an update.
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'user' => 'client1' ), array( $update ) ),
-			)
-		);
-
-		// Client 2 requests updates from the beginning.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 2, 0 ),
-			)
-		);
-
-		$data    = $response->get_data();
-		$updates = $data['rooms'][0]['updates'];
-
-		$this->assertNotEmpty( $updates );
-
-		$types = wp_list_pluck( $updates, 'type' );
-		$this->assertContains( 'update', $types );
-	}
-
-	public function test_sync_own_updates_not_returned() {
-		wp_set_current_user( self::$editor_id );
-
-		$room   = $this->get_post_room();
-		$update = array(
-			'type' => 'update',
-			'data' => 'b3duIGRhdGE=',
-		);
-
-		// Client 1 sends an update.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'user' => 'client1' ), array( $update ) ),
-			)
-		);
-
-		$data    = $response->get_data();
-		$updates = $data['rooms'][0]['updates'];
-
-		// Client 1 should not see its own non-compaction update.
-		$this->assertEmpty( $updates );
-	}
-
-	public function test_sync_step1_update_stored_and_returned() {
-		wp_set_current_user( self::$editor_id );
-
-		$room   = $this->get_post_room();
-		$update = array(
-			'type' => 'sync_step1',
-			'data' => 'c3RlcDE=',
-		);
-
-		// Client 1 sends sync_step1.
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'user' => 'client1' ), array( $update ) ),
-			)
-		);
-
-		// Client 2 should see the sync_step1 update.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 2, 0 ),
-			)
-		);
-
-		$data  = $response->get_data();
-		$types = wp_list_pluck( $data['rooms'][0]['updates'], 'type' );
-		$this->assertContains( 'sync_step1', $types );
-	}
-
-	public function test_sync_step2_update_stored_and_returned() {
-		wp_set_current_user( self::$editor_id );
-
-		$room   = $this->get_post_room();
-		$update = array(
-			'type' => 'sync_step2',
-			'data' => 'c3RlcDI=',
-		);
-
-		// Client 1 sends sync_step2.
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'user' => 'client1' ), array( $update ) ),
-			)
-		);
-
-		// Client 2 should see the sync_step2 update.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 2, 0 ),
-			)
-		);
-
-		$data  = $response->get_data();
-		$types = wp_list_pluck( $data['rooms'][0]['updates'], 'type' );
-		$this->assertContains( 'sync_step2', $types );
-	}
-
-	public function test_sync_multiple_updates_in_single_request() {
-		wp_set_current_user( self::$editor_id );
-
-		$room    = $this->get_post_room();
-		$updates = array(
-			array(
-				'type' => 'sync_step1',
-				'data' => 'c3RlcDE=',
-			),
-			array(
-				'type' => 'update',
-				'data' => 'dXBkYXRl',
-			),
-		);
-
-		// Client 1 sends multiple updates.
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'user' => 'client1' ), $updates ),
-			)
-		);
-
-		// Client 2 should see both updates.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 2, 0 ),
-			)
-		);
-
-		$data         = $response->get_data();
-		$room_updates = $data['rooms'][0]['updates'];
-
-		$this->assertCount( 2, $room_updates );
-		$this->assertSame( 2, $data['rooms'][0]['total_updates'] );
-	}
-
-	public function test_sync_update_data_preserved() {
-		wp_set_current_user( self::$editor_id );
-
-		$room   = $this->get_post_room();
-		$update = array(
-			'type' => 'update',
-			'data' => 'cHJlc2VydmVkIGRhdGE=',
-		);
-
-		// Client 1 sends an update.
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'user' => 'client1' ), array( $update ) ),
-			)
-		);
-
-		// Client 2 should receive the exact same data.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 2, 0 ),
-			)
-		);
-
-		$data         = $response->get_data();
-		$room_updates = $data['rooms'][0]['updates'];
-
-		$this->assertSame( 'cHJlc2VydmVkIGRhdGE=', $room_updates[0]['data'] );
-		$this->assertSame( 'update', $room_updates[0]['type'] );
-	}
-
-	public function test_sync_total_updates_increments() {
-		wp_set_current_user( self::$editor_id );
-
-		$room   = $this->get_post_room();
-		$update = array(
-			'type' => 'update',
-			'data' => 'dGVzdA==',
-		);
-
-		// Send three updates from different clients.
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'user' => 'c1' ), array( $update ) ),
-			)
-		);
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 2, 0, array( 'user' => 'c2' ), array( $update ) ),
-			)
-		);
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 3, 0, array( 'user' => 'c3' ), array( $update ) ),
-			)
-		);
-
-		// Any client should see total_updates = 3.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 4, 0 ),
-			)
-		);
-
-		$data = $response->get_data();
-		$this->assertSame( 3, $data['rooms'][0]['total_updates'] );
-	}
-
-	/*
-	 * Compaction tests.
-	 */
-
-	public function test_sync_should_compact_is_false_below_threshold() {
-		wp_set_current_user( self::$editor_id );
-
-		$room   = $this->get_post_room();
-		$update = array(
-			'type' => 'update',
-			'data' => 'dGVzdA==',
-		);
-
-		// Client 1 sends a single update.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'user' => 'c1' ), array( $update ) ),
-			)
-		);
-
-		$data = $response->get_data();
-		$this->assertFalse( $data['rooms'][0]['should_compact'] );
-	}
-
-	public function test_sync_should_compact_is_true_above_threshold_for_compactor() {
-		wp_set_current_user( self::$editor_id );
-
-		$room    = $this->get_post_room();
-		$updates = array();
-		for ( $i = 0; $i < 51; $i++ ) {
-			$updates[] = array(
-				'type' => 'update',
-				'data' => base64_encode( "update-$i" ),
-			);
-		}
-
-		// Client 1 sends enough updates to exceed the compaction threshold.
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'user' => 'c1' ), $updates ),
-			)
-		);
-
-		// Client 1 polls again. It is the lowest (only) client, so it is the compactor.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'user' => 'c1' ) ),
-			)
-		);
-
-		$data = $response->get_data();
-		$this->assertTrue( $data['rooms'][0]['should_compact'] );
-	}
-
-	public function test_sync_should_compact_is_false_for_non_compactor() {
-		wp_set_current_user( self::$editor_id );
-
-		$room    = $this->get_post_room();
-		$updates = array();
-		for ( $i = 0; $i < 51; $i++ ) {
-			$updates[] = array(
-				'type' => 'update',
-				'data' => base64_encode( "update-$i" ),
-			);
-		}
-
-		// Client 1 sends enough updates to exceed the compaction threshold.
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'user' => 'c1' ), $updates ),
-			)
-		);
-
-		// Client 2 (higher ID than client 1) should not be the compactor.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 2, 0, array( 'user' => 'c2' ) ),
-			)
-		);
-
-		$data = $response->get_data();
-		$this->assertFalse( $data['rooms'][0]['should_compact'] );
-	}
-
-	public function test_sync_stale_compaction_is_stored_as_update_when_newer_compaction_exists() {
-		wp_set_current_user( self::$editor_id );
-
-		$room   = $this->get_post_room();
-		$update = array(
-			'type' => 'update',
-			'data' => 'dGVzdA==',
-		);
-
-		// Client 1 sends an update to seed the room.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'user' => 'c1' ), array( $update ) ),
-			)
-		);
-
-		$end_cursor = $response->get_data()['rooms'][0]['end_cursor'];
-
-		// Client 2 sends a compaction at the current cursor.
-		$compaction = array(
-			'type' => 'compaction',
-			'data' => 'Y29tcGFjdGVk',
-		);
-
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 2, $end_cursor, array( 'user' => 'c2' ), array( $compaction ) ),
-			)
-		);
-
-		/*
-		 * Client 3 sends a stale compaction at cursor 0 (mirroring two offline
-		 * clients that reconnect from the same baseline cursor). The server
-		 * cannot run remove_updates_before_cursor because client 2 has already
-		 * advanced the frontier, but the bytes must still be stored as a
-		 * regular update so client 3's operations can propagate to other
-		 * clients via Yjs state-as-update merging.
-		 */
-		$stale_compaction = array(
-			'type' => 'compaction',
-			'data' => 'c3RhbGU=',
-		);
-		$response         = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 3, 0, array( 'user' => 'c3' ), array( $stale_compaction ) ),
-			)
-		);
-
-		$this->assertSame( 200, $response->get_status() );
-
-		/*
-		 * Verify the newer compaction is preserved AND the stale compaction's
-		 * bytes were persisted (now as type=update so subsequent compactions
-		 * don't trip the has_newer_compaction check).
-		 */
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 4, 0, array( 'user' => 'c4' ) ),
-			)
-		);
-		$updates  = $response->get_data()['rooms'][0]['updates'];
-
-		$update_data = wp_list_pluck( $updates, 'data' );
-		$this->assertContains( 'Y29tcGFjdGVk', $update_data, 'The newer compaction should be preserved.' );
-		$this->assertContains( 'c3RhbGU=', $update_data, 'The stale compaction bytes should be stored so client 3\'s operations propagate.' );
-
-		$stale_entry = null;
-		foreach ( $updates as $entry ) {
-			if ( 'c3RhbGU=' === $entry['data'] ) {
-				$stale_entry = $entry;
-				break;
-			}
-		}
-		$this->assertNotNull( $stale_entry, 'The stale compaction entry should be present in the room.' );
-		$this->assertSame( 'update', $stale_entry['type'], 'The stale compaction should be stored as type=update, not type=compaction.' );
-	}
-
-	/*
-	 * Awareness tests.
-	 */
-
-	public function test_sync_awareness_returned() {
-		wp_set_current_user( self::$editor_id );
-
-		$awareness = array( 'name' => 'Editor' );
-		$response  = $this->dispatch_sync(
-			array(
-				$this->build_room( $this->get_post_room(), 1, 0, $awareness ),
-			)
-		);
-
-		$data = $response->get_data();
-		$this->assertArrayHasKey( 1, $data['rooms'][0]['awareness'] );
-		$this->assertSame( $awareness, $data['rooms'][0]['awareness'][1] );
-	}
-
-	public function test_sync_awareness_shows_multiple_clients() {
-		wp_set_current_user( self::$editor_id );
-
-		$room = $this->get_post_room();
-
-		// Client 1 connects.
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'name' => 'Client 1' ) ),
-			)
-		);
-
-		// Client 2 connects.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 2, 0, array( 'name' => 'Client 2' ) ),
-			)
-		);
-
-		$data      = $response->get_data();
-		$awareness = $data['rooms'][0]['awareness'];
-
-		$this->assertArrayHasKey( 1, $awareness );
-		$this->assertArrayHasKey( 2, $awareness );
-		$this->assertSame( array( 'name' => 'Client 1' ), $awareness[1] );
-		$this->assertSame( array( 'name' => 'Client 2' ), $awareness[2] );
-	}
-
-	public function test_sync_awareness_updates_existing_client() {
-		wp_set_current_user( self::$editor_id );
-
-		$room = $this->get_post_room();
-
-		// Client 1 connects with initial awareness.
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'cursor' => 'start' ) ),
-			)
-		);
-
-		// Client 1 updates its awareness.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'cursor' => 'updated' ) ),
-			)
-		);
-
-		$data      = $response->get_data();
-		$awareness = $data['rooms'][0]['awareness'];
-
-		// Should have exactly one entry for client 1 with updated state.
-		$this->assertCount( 1, $awareness );
-		$this->assertSame( array( 'cursor' => 'updated' ), $awareness[1] );
-	}
-
-	public function test_sync_awareness_client_id_cannot_be_used_by_another_user() {
-		wp_set_current_user( self::$editor_id );
-
-		$room = $this->get_post_room();
-
-		// Editor establishes awareness with client_id 1.
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'name' => 'Editor' ) ),
-			)
-		);
-
-		// A different user tries to use the same client_id.
-		$editor_id_2 = self::factory()->user->create( array( 'role' => 'editor' ) );
-		wp_set_current_user( $editor_id_2 );
-
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room, 1, 0, array( 'name' => 'Impostor' ) ),
-			)
-		);
-
-		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
-	}
-
-	/*
-	 * Multiple rooms tests.
-	 */
-
-	public function test_sync_multiple_rooms_in_single_request() {
-		wp_set_current_user( self::$editor_id );
-
-		$room1 = $this->get_post_room();
-		$room2 = 'taxonomy/category';
-
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room1 ),
-				$this->build_room( $room2 ),
-			)
-		);
-
-		$this->assertSame( 200, $response->get_status() );
-
-		$data = $response->get_data();
-		$this->assertCount( 2, $data['rooms'] );
-		$this->assertSame( $room1, $data['rooms'][0]['room'] );
-		$this->assertSame( $room2, $data['rooms'][1]['room'] );
-	}
-
-	public function test_sync_rooms_are_isolated() {
-		wp_set_current_user( self::$editor_id );
-
-		$post_id_2 = self::factory()->post->create( array( 'post_author' => self::$editor_id ) );
-		$room1     = $this->get_post_room();
-		$room2     = 'postType/post:' . $post_id_2;
-
-		$update = array(
-			'type' => 'update',
-			'data' => 'cm9vbTEgb25seQ==',
-		);
-
-		// Client 1 sends an update to room 1 only.
-		$this->dispatch_sync(
-			array(
-				$this->build_room( $room1, 1, 0, array( 'user' => 'client1' ), array( $update ) ),
-			)
-		);
-
-		// Client 2 queries both rooms.
-		$response = $this->dispatch_sync(
-			array(
-				$this->build_room( $room1, 2, 0 ),
-				$this->build_room( $room2, 2, 0 ),
-			)
-		);
-
-		$data = $response->get_data();
-
-		// Room 1 should have the update.
-		$this->assertNotEmpty( $data['rooms'][0]['updates'] );
-
-		// Room 2 should have no updates.
-		$this->assertEmpty( $data['rooms'][1]['updates'] );
-	}
-}
Index: /branches/7.0/tests/qunit/fixtures/wp-api-generated.js
===================================================================
--- /branches/7.0/tests/qunit/fixtures/wp-api-generated.js	(revision 62337)
+++ /branches/7.0/tests/qunit/fixtures/wp-api-generated.js	(revision 62338)
@@ -11086,10 +11086,4 @@
                             "required": false
                         },
-                        "wp_collaboration_enabled": {
-                            "title": "",
-                            "description": "Enable Real-Time Collaboration",
-                            "type": "boolean",
-                            "required": false
-                        },
                         "posts_per_page": {
                             "title": "Maximum posts per page",
@@ -14557,5 +14551,4 @@
     "default_category": 1,
     "default_post_format": "0",
-    "wp_collaboration_enabled": false,
     "posts_per_page": 10,
     "show_on_front": "posts",
