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

86 lines
3.3 KiB
Markdown

# 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()`:
```php
// 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.
---
## Related
- `includes/interceptors/class-tmdo-sync-bridge.php``is_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