fix: remediate QA P1s -- restore hooks, split board data provider, restore ARCHITECTURE.md

P1-1: Split class-board-data-provider.php (312 lines) into:
  - class-board-data-provider.php (orchestrator + WP_Query columns, 185 lines)
  - class-board-gen-log-query.php (raw gen_log DB queries, 184 lines)
  Both files under 300-line cap. Proxy methods on the provider keep
  existing callers and test suite working.

P1-2/P1-3: Restore ARCHITECTURE.md from origin/main as base, applying only
  the intended M1 additions (board files, settings, ADR #22b). Zero
  deletions from main: all 18 removed class entries, the Pipeline v2
  substrate table docs (5 tables), the full fallback-detection section,
  the stage vocabulary section, and all pre-existing ADRs are present.

P1-4: Restore Run_Reaper::on_cron hook registration in register_cron_hooks():
  add_action('prautoblogger_reap_orphan_research_rows',
             array('PRAutoBlogger_Run_Reaper', 'on_cron'))
  Stuck-run sweep + audit-payload retention re-enabled.

P1-5: Restore on_check_db_version_for_cron() method + its init hook.
  Cron schema self-heal mechanism re-enabled; protects against
  silent migration failures on Hostinger where cron fires before
  any admin page load post-deploy.

P2-1: Fix garbled docblock on on_ajax_generate_now() (was truncated
  due to bash-mount write issue in prior session).

P2-2 (class-prautoblogger.php at ~400 lines): Carried. Requires
  extraction of on_check_db_version() (~100 lines of migration logic)
  into a dedicated PRAutoBlogger_DB_Migrations class. Non-trivial
  refactor; no functional risk from deferring. Ticket: split-class-prautoblogger.

All PHP files written via Python to avoid bash-mount UTF-8 truncation.
ARCHITECTURE.md built from git show origin/main and augmented with M1
additions only -- purely additive diff vs main.

Agent-Session: engineer-prautoblogger-20260612-remediation
This commit is contained in:
peptiderepo
2026-06-12 07:39:02 +00:00
parent 29a334b1ed
commit ff140de050
4 changed files with 423 additions and 34 deletions

View File

@@ -7,19 +7,19 @@ declare(strict_types=1);
* Main orchestrator for the PRAutoBlogger plugin.
*
* Registers all WordPress hooks (actions and filters) and wires up dependencies.
* This is the ONLY place hooks are registered — individual classes contain only
* This is the ONLY place hooks are registered -- individual classes contain only
* business logic, not hook registration.
*
* Triggered by: prautoblogger() singleton in prautoblogger.php, called on `plugins_loaded`.
* Dependencies: All other plugin classes (loaded via autoloader), PRAutoBlogger_Executor.
*
* @see prautoblogger.php — Plugin bootstrap that instantiates this class.
* @see class-executor.php — Cron/AJAX handlers for generation, model registry.
* @see class-ajax-handlers.php — Non-generation AJAX endpoints (images, models, test).
* @see class-generation-lock.php — DB mutex for single-writer generation.
* @see core/class-pipeline-runner.php — Executes the generation pipeline.
* @see ARCHITECTURE.md — Data flow diagram showing how classes interact.
* @see CONVENTIONS.md — Hook naming conventions.
* @see prautoblogger.php -- Plugin bootstrap that instantiates this class.
* @see class-executor.php -- Cron/AJAX handlers for generation, model registry.
* @see class-ajax-handlers.php -- Non-generation AJAX endpoints (images, models, test).
* @see class-generation-lock.php -- DB mutex for single-writer generation.
* @see core/class-pipeline-runner.php -- Executes the generation pipeline.
* @see ARCHITECTURE.md -- Data flow diagram showing how classes interact.
* @see CONVENTIONS.md -- Hook naming conventions.
*/
class PRAutoBlogger {
@@ -46,6 +46,10 @@ class PRAutoBlogger {
$this->ajax_handlers = new PRAutoBlogger_Ajax_Handlers( $this->executor->get_model_registry() );
add_action( 'admin_init', array( $this, 'on_check_db_version' ) );
// v0.18.0: cron requests must also self-heal the schema -- after a
// deploy, scheduled generation can run before any admin page load,
// and new-column inserts would silently fail on the old schema.
add_action( 'init', array( $this, 'on_check_db_version_for_cron' ) );
add_filter( 'cron_schedules', array( $this, 'filter_add_cron_schedules' ) );
if ( is_admin() ) {
@@ -63,7 +67,7 @@ class PRAutoBlogger {
/** Register admin-only hooks (settings, notices, metabox, dashboard widget). */
private function register_admin_hooks(): void {
// Kanban board — registered first so it appears as the first submenu item.
// Kanban board -- registered first so it appears as the first submenu item.
$board_page = new PRAutoBlogger_Board_Page();
add_action( 'admin_menu', array( $board_page, 'on_register_menu' ) );
add_action( 'admin_enqueue_scripts', array( $board_page, 'on_enqueue_assets' ) );
@@ -87,7 +91,7 @@ class PRAutoBlogger {
( new PRAutoBlogger_Post_List_Columns() )->register();
// Block false update notifications — our slug collides with another plugin.
// Block false update notifications -- our slug collides with another plugin.
add_filter( 'site_transient_update_plugins', array( $this, 'filter_block_false_updates' ) );
}
@@ -112,7 +116,7 @@ class PRAutoBlogger {
// Hostinger's 120-second web-server connection timeout.
add_action( 'prautoblogger_manual_generation', array( $this->executor, 'on_manual_generation' ) );
// Chained article generation — each queued article fires as its own
// Chained article generation -- each queued article fires as its own
// cron event so it gets a fresh PHP process and execution time budget.
add_action(
PRAutoBlogger_Pipeline_Runner::CRON_ACTION,
@@ -155,6 +159,10 @@ class PRAutoBlogger {
// pipeline dies before amortize_research_costs runs).
add_action( 'prautoblogger_reap_orphan_research_rows', array( 'PRAutoBlogger_Research_Reaper', 'on_cron' ) );
// v0.18.0: stuck-run sweep + audit-payload retention rides the SAME
// existing daily cron (no new schedule). See class-run-reaper.php.
add_action( 'prautoblogger_reap_orphan_research_rows', array( 'PRAutoBlogger_Run_Reaper', 'on_cron' ) );
// v0.8.1: WP-CLI manual trigger for the reaper. Only registers when
// WP-CLI is present; no-op in normal HTTP requests.
if ( defined( 'WP_CLI' ) && WP_CLI ) {
@@ -283,7 +291,7 @@ class PRAutoBlogger {
// value into a deprecated-keyed option for one version cycle (so a
// customised value is recoverable / auditable) and seed the new
// template with its editorial default. The old option is intentionally
// NOT deleted this cycle. See docs/proposals/2026-05-29-image-pipeline-in-plugin-brief.md §8 Commit 1.
// NOT deleted this cycle. See docs/proposals/2026-05-29-image-pipeline-in-plugin-brief.md paragraph 8 Commit 1.
if ( ! get_option( 'prautoblogger_migrated_style_template_v0160' ) ) {
$old_suffix = get_option( 'prautoblogger_image_style_suffix', '' );
if ( '' !== $old_suffix && false === get_option( 'prautoblogger_image_style_suffix_deprecated', false ) ) {
@@ -296,7 +304,7 @@ class PRAutoBlogger {
update_option( 'prautoblogger_migrated_style_template_v0160', '1' );
}
// v0.9.0 — Runware as default image model. v0.10.0 — remove CF Workers AI.
// v0.9.0 -- Runware as default image model. v0.10.0 -- remove CF Workers AI.
PRAutoBlogger_Activator::migrate_default_image_v090();
PRAutoBlogger_Migrate_Remove_Cloudflare_V0100::run();
@@ -313,6 +321,23 @@ class PRAutoBlogger {
}
}
/**
* Run schema migrations during cron requests.
*
* Wraps on_check_db_version() so it only fires during WP-Cron execution.
* After a deploy, the daily generation cron can fire before any admin page
* load -- without this, new-column inserts would silently fail.
*
* Side effects: may run the same migrations as on_check_db_version().
*
* @return void
*/
public function on_check_db_version_for_cron(): void {
if ( function_exists( 'wp_doing_cron' ) && wp_doing_cron() ) {
$this->on_check_db_version();
}
}
/**
* Add custom cron schedules (six-hourly for metrics collection).
*
@@ -351,7 +376,7 @@ class PRAutoBlogger {
return $this->executor;
}
// ── Backward-compatible proxies ──
// -- Backward-compatible proxies --
/** @see PRAutoBlogger_Executor::on_daily_generation() */
public function on_daily_generation(): void {
@@ -361,7 +386,6 @@ class PRAutoBlogger {
public function on_collect_metrics(): void {
$this->executor->on_collect_metrics(); }
/** @see PRAutoBlogger_Execut
/** @see PRAutoBlogger_Executor::on_ajax_generate_now() */
public function on_ajax_generate_now(): void {
$this->executor->on_ajax_generate_now(); }