compose_score( array() ); } /** * Default doctor probe — returns ok with adapter name. * * Adapters with custom tables MUST override and verify table existence. * * @return array{ok:bool, message:string, details?:array} */ public function doctor_check(): array { return array( 'ok' => true, 'message' => sprintf( '%s: adapter loaded, no custom tables to probe', $this->plugin_slug() ), ); } /** * Default no FSM migrations (adapter is read-only or zero hot fields). * * @return array */ public function migrations(): array { return array(); } // ── Helper: zone-aware field registration shortcuts ───────────────── /** * Register a single hot zone field (varchar/int/decimal column on `wp_wpdo_hot_`). * * @param TMDO_Schema_Registry $registry Provided by `wpdo_register_fields` hook. * @param string $post_type WordPress post type (e.g. 'hp_listing'). * @param string $meta_key wp_postmeta meta_key. * @param string $data_type SQL column type (e.g. "tinyint(1) NOT NULL DEFAULT 0"). * @param array $extra Optional overrides: column, indexed, etc. */ protected function register_hot( TMDO_Schema_Registry $registry, string $post_type, string $meta_key, string $data_type, array $extra = array() ): void { $config = array_merge( array( 'post_type' => $post_type, 'meta_key' => $meta_key, 'zone' => 'hot', 'data_type' => $data_type, 'column' => sanitize_key( $meta_key ), 'indexed' => false, ), $extra ); $this->register_field( $registry, $config ); } /** * Register a single cold zone field (object cache + JSON blob fallback). * * @param TMDO_Schema_Registry $registry Provided by `wpdo_register_fields` hook. * @param string $post_type WordPress post type. * @param string $meta_key wp_postmeta meta_key. * @param int $cache_ttl Cache TTL in seconds (default 1 hour). * @param array $extra Optional overrides. */ protected function register_cold( TMDO_Schema_Registry $registry, string $post_type, string $meta_key, int $cache_ttl = 3600, array $extra = array() ): void { $config = array_merge( array( 'post_type' => $post_type, 'meta_key' => $meta_key, 'zone' => 'cold', 'cache_group' => 'wpdo_cold_' . sanitize_key( $post_type ), 'cache_ttl' => $cache_ttl, ), $extra ); $this->register_field( $registry, $config ); } /** * Register a single warm zone field (TTL counter / temp value). * * @param TMDO_Schema_Registry $registry Provided by `wpdo_register_fields` hook. * @param string $post_type WordPress post type. * @param string $meta_key wp_postmeta meta_key. * @param int|null $ttl TTL in seconds (null = no expiry). * @param array $extra Optional overrides. */ protected function register_warm( TMDO_Schema_Registry $registry, string $post_type, string $meta_key, ?int $ttl = null, array $extra = array() ): void { $config = array_merge( array( 'post_type' => $post_type, 'meta_key' => $meta_key, 'zone' => 'warm', 'ttl' => $ttl, ), $extra ); $this->register_field( $registry, $config ); } /** * Subscribe to writes on another adapter's keys (cross-adapter coordination). * * Wraps `TMDO_Anti_EAV_Aware::on_after_write()` with a description hook * so the cross-adapter linkage is greppable for the suitability scorer's * D5 (Hook Bus Integration) check. * * @param string $key_prefix Meta key prefix (e.g. 'hp_sold_out_'). * @param callable $callback Receives (entity_type, entity_id, key, value, ok, op, before). */ protected function on_after_addon_write( string $key_prefix, callable $callback ): void { $this->on_after_write( $key_prefix, $callback ); } // ── Helper: 8-dimension score composition ─────────────────────────── /** * Compose an 8-dimension score, filling missing keys with 1.0 and * computing the aggregate as `sum / 8 * 1.25` (so 1.0 across all * → 10.0). * * @param array $partial Override values keyed by `d1_meta_calls`...`d8_perf`. * @return array{d1_meta_calls:float, d2_meta_sql:float, d3_table_coverage:float, d4_registry_meta:float, d5_hook_bus:float, d6_options:float, d7_coupling:float, d8_perf:float, aggregate:float} */ protected function compose_score( array $partial ): array { $defaults = array( 'd1_meta_calls' => 1.0, 'd2_meta_sql' => 1.0, 'd3_table_coverage' => 1.0, 'd4_registry_meta' => 1.0, 'd5_hook_bus' => 1.0, 'd6_options' => 1.0, 'd7_coupling' => 1.0, 'd8_perf' => 1.0, ); $score = array_merge( $defaults, $partial ); // Clamp every dimension to [0.0, 1.0]. foreach ( $defaults as $k => $_ ) { $score[ $k ] = max( 0.0, min( 1.0, (float) ( $score[ $k ] ?? 1.0 ) ) ); } $sum = array_sum( array_intersect_key( $score, $defaults ) ); $score['aggregate'] = round( $sum / 8.0 * 10.0, 2 ); return $score; } } } // end if ( ! trait_exists )