Files
2meet-data-optimizer/docs/adr-001-post-entity-source-of-truth.md
T
wpdev b63ab46f54
Tests / Integration Tests (push) Successful in 1m11s
Tests / Unit Tests (push) Failing after 11m56s
Anti-EAV Lint + Quality Gate / anti-eav-lint (push) Failing after 12m7s
Tests / PHPStan (push) Failing after 14m37s
Tests / PHPCS (push) Failing after 14m46s
Tests / PHP Lint (push) Failing after 14m57s
docs: 移植 readme.txt / CONTEXT.md / docs(backport A v3.4.6)
- readme.txt(WP 外掛目錄格式,隨 ZIP 發佈):Stable tag 對齊 1.0.0,
  changelog 補 1.0.0 條目
- CONTEXT.md(領域詞彙表):Status 區塊改寫為 v1.0.0 實況;
  HPCT_INTERCEPTORS 與 HivePress Adapter 兩節標註「已搬到 AddOn,核心無此常數」
- docs/:ENTITY_ADAPTER_COOKBOOK、2 篇 ADR、INTEGRATION_PATTERN_DECISION、
  anti-eav-lint.yml.template
  - cookbook 修掉兩個死連結(ANTI_EAV_PLAYBOOK 在來源外掛就不存在)
  - INTEGRATION_PATTERN_DECISION 加 v1.0.0 後記:結論已被 AddOn 拆分取代
  - template 改 wpdev/2meet-data-optimizer + ref v1.0.0 + wp tmdo lint
- README.md 文件索引補上以上 7 個檔案

前綴改寫刻意只動類別/函式/slug(WPDO_→TMDO_、wp-data-optimizer→2meet-...),
wpdo_ option/cron/hook/表名與 wpdo/v1 REST namespace 一律保留 —— 這是資料層
零遷移的前提。
2026-07-31 10:06:03 +08:00

3.3 KiB

ADR-001: Post Entity Source-of-Truth Contract

Status: Accepted
Date: 2026-05-15
Deciders: wpdev


Context

Two code paths can intercept update_post_metadata / add_post_metadata:

  1. TMDO_Sync_Bridge — the original Zone interceptor that dual-writes to Hot (Zone A) and Cold (Zone C) flat tables.
  2. TMDO_Hook_Bus — the Entity Bridge write path added in v2.9.x that writes to wp_wpdo_post_* flat tables via Entity Registry groups.

When both are active without a clear contract, a single update_post_meta() call can fan out to three distinct write paths (wp_postmeta + Zone table + entity flat table), producing divergent row counts and confusing TMDO_API::trace_storage() output.

The defensive patch TMDO_Sync_Bridge::is_owned_by_entity_bridge() (v2.9.2) was added to prevent double-writes but left the authoritative contract undocumented.


Decision

When post entity mode is dual_write, shadow_read, or aeav_only, Entity Bridge (TMDO_Hook_Bus) is the sole source of truth for keys registered in TMDO_Entity_Registry under the post entity type.

Sync_Bridge defers to Entity Bridge for those keys via is_owned_by_entity_bridge():

// TMDO_Sync_Bridge — intercept_update() guard:
if ( self::is_owned_by_entity_bridge( $meta_key ) ) {
    return $check; // pass-through — Entity Bridge owns this key
}

is_owned_by_entity_bridge() returns true when both conditions hold:

  • TMDO_Mode_Manager::writes_to_flat('post') — mode is at least dual_write
  • TMDO_Entity_Registry::get_field('post', $meta_key) — key is registered

Keys not in Entity Registry continue to be owned by Sync_Bridge (Zone path).

Invariants

Condition Owner
post mode = disabled or idle wp_postmeta (no interception)
post mode ≥ dual_write AND key in Entity Registry Entity Bridge
post mode ≥ dual_write AND key not in Entity Registry Sync_Bridge (Zone)
post mode = aeav_only Entity Bridge for registered keys; unregistered keys fallthrough to wp_postmeta

Consequences

Good:

  • Developers adding a new post meta key can determine its owner in O(1): check whether the key is in wpdo_register_fields under post entity. If yes → Entity Bridge owns it; if no → Zone Sync_Bridge handles it.
  • TMDO_API::trace_storage() output reflects this: Entity Bridge keys show the flat entity table; Zone keys show the zone table.

Bad / Watch out for:

  • A key registered in both Schema_Registry (Zone) and Entity_Registry (Entity Bridge groups) will be captured by Entity Bridge and silently dropped by Sync_Bridge. The duplicate registration is a misconfiguration — caught by TMDO_Sync_Bridge guard and validated by wp tmdo conflict-scan.
  • If TMDO_Mode_Manager or TMDO_Entity_Registry are unavailable (e.g. very early bootstrap), is_owned_by_entity_bridge() returns false and all writes fall through to the Zone path — safe degradation.

  • includes/interceptors/class-tmdo-sync-bridge.phpis_owned_by_entity_bridge() (v2.9.2)
  • includes/engine/class-tmdo-hook-bus.php — Entity Bridge write path
  • TMDO_API::trace_storage() — human-readable storage path diagnostics
  • wp tmdo conflict-scan — detects keys registered in both paths