# Live test suite Tests that must run inside a real WordPress site, because the stubbed `tests/integration` bootstrap cannot reproduce: - WP core meta flows (`update_metadata()` reads the old value through `get_metadata_raw()` before writing — the shadow_read write-loss bug lives there) - the SQL that `WP_Query` actually builds, and hook priorities - HivePress / WooCommerce behaviour (`pre_get_posts` sort clauses, empty-key meta reads, direct-SQL stock updates) **Never run against a production site.** Suites create and delete fixtures (`tmdo_live_*` users, `tmdo-live-*` terms). Entity modes are overridden in process through `pre_option_wpdo_bridge_modes`; nothing is written to `wpdo_bridge_modes` or `wpdo_hook_bus_enabled`. The reference site is dev36 (HivePress + Marketplace + WooCommerce), with this plugin symlinked from the `plugins-dev` worktree while developing. ## Run ```bash wp --path=/var/www/Studio/wp-local-dev36 eval-file tests/live/run.php [ ...] ``` Exit code 0 when every test passed, 1 otherwise. Output per test: | Status | Meaning | |---|---| | PASS / FAIL | normal | | XFAIL | known bug, test marked `xfail` with the PR that fixes it; not counted as a failure | | XPASS | an `xfail` test passed — counted as a failure so the fixing PR removes the marker | | SKIP | the site does not register the key / taxonomy the test needs | ## Suites | Suite | Covers | |---|---| | `shadow_write` | writes in shadow_read reach native meta (user, term, HivePress listing) | | `serialized` | array meta values are stored serialized in flat tables, never "Array" | | `resync` | dual_write / shadow_read: flat follows native after every write (4 entities × 2 modes: update, same value, delete, refused writes, stale flat, key rename by meta_id) | | `router` | a routed WP_Query returns the same ids, in order, as native (OR, several post types, untyped numeric compares, named orderby, LIKE, keys of two groups, NOT EXISTS with the status/date copy route, meta orderby: HivePress sort shape, named clause, meta_key + meta_value_num); routed SQL has no GROUP BY | | `rest` | anonymous GET of the public listings endpoints returns no protected or credential-like field (1.1.1) | | `zero_side_effect` | zone tables that were never created are never queried on save / delete | ## Tools (`tools/`) Benchmark and data-flow helpers used for the 2026-09-26 dev36 integration test. Output files go to the current directory (`qbench`) or `$TMDO_LIVE_OUT` (default `/tmp`, `run_batch.sh`), never into the repo. | Tool | Use | |---|---| | `seed.php` | `wp eval-file seed.php [tag]` — seed through real HivePress / WC APIs | | `run_batch.sh` | `run_batch.sh [divisor]` — parallel seeding batch (`TMDO_LIVE_WP_PATH`, `TMDO_LIVE_OUT`) | | `clone.sql` | bench only: clone hp_listing rows to reach large scale (`sed "s/__K__//" clone.sql \| wp db query`) | | `checker.php` | `wp eval-file checker.php [entity]` — native vs flat consistency per registered key (SQL only) | | `qbench.php` / `qdiff.php` | run 16 WP_Query shapes, then diff two runs (native vs routed): result sets, order, latency, SQL errors | | `mut.php` | data-flow mutations through HivePress models, WC CRUD and core APIs; prints native / flat / API values | | `fe.sh` + `zz-s36-probe.php` | front-end search probe (`TMDO_LIVE_URL`). Copy the probe into `wp-content/mu-plugins/` only for the run and remove it afterwards; it only answers requests carrying `X-S36-Probe: 1` |