feat(2meet-data-optimizer): reconcile post rows written to the wrong group table

- TMDO_Post_Group_Reconciler copies non-NULL values that legacy routing stored in another group's table into the post type's own group (NULL/missing legacy values keep the scoped value), resumable via a cursor, with a catch-up pass for rows updated during the run, then switches on tmdo_post_scoped_routing
- CLI: wp tmdo post-reconcile-groups [--dry-run] [--batch=<n>]; registry exposes get_group_post_types()
- Verify: PostGroupReconcilerPlanTest (4), PostGroupReconcilerTest (6); core unit 635 / integration 449, HP 145/49, WC 10/22 OK; read-only dry-run: dev20 320 values / 0 overwrites, dev21/22 none
- PR: PR-034
This commit is contained in:
2026-09-26 00:04:38 +08:00
parent 3f4fe52e1b
commit e0683a19b1
8 changed files with 506 additions and 0 deletions
@@ -37,6 +37,9 @@ final class TMDO_Entity_Registry {
/** @var array<string, array<string, array<string, array>>> 實體類型 → post_type → meta_key → 欄位定義 */
private static array $scoped_index = array();
/** @var array<string, array<string, string[]>> 實體類型 → 群組名 → 限定的 post_type */
private static array $scopes = array();
/** @var array<string, array> "entity/group" → 同名群組以不同定義重複註冊的紀錄 */
private static array $collisions = array();
@@ -70,6 +73,7 @@ final class TMDO_Entity_Registry {
self::$field_index = array();
self::$unscoped_index = array();
self::$scoped_index = array();
self::$scopes = array();
self::$pending_schemas = array();
self::$collisions = array();
self::$restored = array();
@@ -144,6 +148,9 @@ final class TMDO_Entity_Registry {
// 建立索引以供快速查詢
$post_types = array_values( array_filter( array_map( 'strval', (array) ( $args['post_types'] ?? array() ) ) ) );
if ( $post_types ) {
self::$scopes[ $entity_type ][ $group_name ] = $post_types;
}
foreach ( $normalized as $normalized_field ) {
self::index_field( $entity_type, $normalized_field, $post_types );
}
@@ -365,6 +372,15 @@ final class TMDO_Entity_Registry {
return array_keys( self::$groups[ $entity_type ] ?? array() );
}
/**
* 群組限定的 post_type(未限定時為空陣列)。
*
* @return string[]
*/
public static function get_group_post_types( string $entity_type, string $group_name ): array {
return self::$scopes[ $entity_type ][ $group_name ] ?? array();
}
/**
* 取得特定群組的完整欄位定義
*/