log( $job, '↪ Cleanup skipped (dry_run)' ); return array( 'status' => 'ok' ); } $mode = TMDO_Mode_Manager::get( $this->entity_type ); if ( TMDO_Mode_Manager::MODE_AEAV_ONLY !== $mode ) { throw new \RuntimeException( "Refusing cleanup — mode is {$mode}, must be aeav_only" ); } if ( ! empty( $job['options']['auto_backup'] ) && empty( $job['backup_path'] ) ) { throw new \RuntimeException( 'Refusing cleanup — auto_backup requested but no backup_path on record' ); } $keys = $this->get_managed_keys(); if ( empty( $keys ) ) { $this->log( $job, '↪ No managed keys to clean' ); return array( 'status' => 'ok' ); } $adapter = TMDO_Entity_Registry::get_adapter( $this->entity_type ); $meta_table = $adapter->get_native_meta_table(); $placeholders = implode( ',', array_fill( 0, count( $keys ), '%s' ) ); $deleted = (int) $wpdb->query( $wpdb->prepare( "DELETE FROM `{$meta_table}` WHERE meta_key IN ({$placeholders})", ...$keys ) ); $preflight = TMDO_Migration_Orchestrator::preflight(); $job['metrics']['eav_rows_now'] = $preflight['eav_rows']; $job['metrics']['ratio_now'] = $preflight['ratio']; $this->log( $job, sprintf( 'Cleanup: deleted %d EAV row(s); ratio now %s', $deleted, (string) $preflight['ratio'] ) ); return array( 'status' => 'ok' ); } }