fix(2meet-data-optimizer): serve native meta in shadow_read and compare flat values
- In shadow_read, TMDO_Hook_Bus::intercept_get() returned the flat value. update_metadata() reads the old value through that filter after the Hook Bus has upserted the new one, so WP saw old === new and never wrote native meta: every update in shadow_read was lost on demotion (dev36 2026-09-26). shadow_read now returns $check (native) and compares flat on a sample of reads (filter tmdo_shadow_compare_sample_rate, default 0.1). aeav_only is unchanged; the post query router still routes in shadow_read. - Live suite shadow_write: xfail markers removed, HivePress listing case added (new int key hp_rating_count); fixtures gain post() and a post_type-scoped field()/flat(). - Verify: live shadow_write + serialized 8/8 PASS (old code: 4 FAIL); unit 685 OK, integration 484 OK, phpcs (phpcs.xml) 0, stan OK - PR: PR-056
This commit is contained in:
@@ -388,12 +388,20 @@ final class TMDO_Hook_Bus {
|
||||
// ── Mode-aware dispatch ──────────────────────────────
|
||||
// disabled : 完全不攔截,回傳 $check 讓 WP 走原生 EAV
|
||||
// dual_write : 讀取仍走 EAV(flat 可能還沒有資料),回傳 $check
|
||||
// shadow_read : 讀取走 UAE flat,同時與 EAV 比對記錄 diff
|
||||
// shadow_read : 讀取仍走 EAV,抽樣與 flat 比對記錄 diff
|
||||
// aeav_only : 讀取走 UAE flat,不讀 EAV
|
||||
if ( ! TMDO_Mode_Manager::reads_from_flat( $type ) ) {
|
||||
return $check; // disabled / dual_write
|
||||
}
|
||||
|
||||
// shadow_read serves native: update_metadata() reads the old value
|
||||
// through this filter, and serving the just-upserted flat value made
|
||||
// WP see old === new and skip the native write (dev36, 2026-09-26).
|
||||
if ( TMDO_Mode_Manager::does_shadow_compare( $type ) ) {
|
||||
self::maybe_shadow_compare( $type, (int) $object_id, $meta_key, $field_def );
|
||||
return $check;
|
||||
}
|
||||
|
||||
$group = $field_def['group'];
|
||||
$row = self::get_or_load_row( $type, (int) $object_id, $group );
|
||||
|
||||
@@ -401,22 +409,6 @@ final class TMDO_Hook_Bus {
|
||||
$has_value = is_array( $row ) && array_key_exists( $col, $row );
|
||||
$value = $has_value ? TMDO_Type_Caster::from_db( $row[ $col ], $field_def ) : null;
|
||||
|
||||
// Shadow-read:與 EAV 比對,記錄差異
|
||||
if ( TMDO_Mode_Manager::does_shadow_compare( $type ) ) {
|
||||
try {
|
||||
TMDO_Shadow_Diff_Logger::compare_and_log(
|
||||
$type,
|
||||
(int) $object_id,
|
||||
$meta_key,
|
||||
$value,
|
||||
$field_def
|
||||
);
|
||||
} catch ( \Throwable $e ) {
|
||||
// 比對失敗不該影響讀取
|
||||
TMDO_Logger::error( 'entity_bridge', 'shadow_compare_exception', $e->getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
// 值為空 → 回 WP 原生慣例
|
||||
if ( empty( $row ) || $value === null || $value === '' ) {
|
||||
return $single ? '' : array();
|
||||
@@ -426,6 +418,36 @@ final class TMDO_Hook_Bus {
|
||||
return $single ? array( $value ) : array( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* shadow_read: compare the flat value with native meta for a sample of reads.
|
||||
*
|
||||
* Each compare costs a flat row read and a native SQL read, so only a share
|
||||
* of reads is checked (filter `tmdo_shadow_compare_sample_rate`, 0..1,
|
||||
* default 0.1). The logger rate-limits repeated diffs itself.
|
||||
*
|
||||
* @param string $type Entity type.
|
||||
* @param int $object_id Entity ID.
|
||||
* @param string $meta_key Meta key.
|
||||
* @param array<string, mixed> $field_def Field definition.
|
||||
*/
|
||||
private static function maybe_shadow_compare( string $type, int $object_id, string $meta_key, array $field_def ): void {
|
||||
$rate = (float) apply_filters( 'tmdo_shadow_compare_sample_rate', 0.1, $type, $meta_key );
|
||||
if ( $rate <= 0 || ( $rate < 1 && wp_rand( 1, 1000 ) > $rate * 1000 ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$row = self::get_or_load_row( $type, $object_id, $field_def['group'] );
|
||||
$col = TMDO_Schema_Manager::sanitize_column_name( $meta_key );
|
||||
$value = array_key_exists( $col, $row ) ? TMDO_Type_Caster::from_db( $row[ $col ], $field_def ) : null;
|
||||
|
||||
try {
|
||||
TMDO_Shadow_Diff_Logger::compare_and_log( $type, $object_id, $meta_key, $value, $field_def );
|
||||
} catch ( \Throwable $e ) {
|
||||
// 比對失敗不該影響讀取
|
||||
TMDO_Logger::error( 'entity_bridge', 'shadow_compare_exception', $e->getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得(或載入)完整列資料,並快取
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user