Files
wp-agentic-writer/docs/architecture/PLUGIN_AUDIT_RETRACE_NINTH_PASS_2026-05-26.md

12 KiB

WP Agentic Writer Ninth Retrace Audit

Status: COMPLETE / RETRACED
Completion marker: 2026-05-26
Follow-up report: docs/architecture/PLUGIN_AUDIT_RETRACE_TENTH_PASS_2026-05-26.md

Audit date: 2026-05-26
Baseline retraced: docs/architecture/PLUGIN_AUDIT_RETRACE_EIGHTH_PASS_2026-05-25.md
Scope: ninth pass after eighth-retrace implementation, covering chat/context continuity, failed-attempt tracking, provider transparency, model registry adoption, UI/UX, and release readiness.

Executive Summary

The eighth-pass implementation closed several important items:

  • The /chat-history compatibility path no longer depends on _wpaw_active_session_id; it now uses get_sessions_for_post() and the migrated session id, so the empty-history-after-migration bug appears fixed.
  • A track_ai_cost() helper now exists and failed AI branches were added for several previously invisible error paths.
  • A new includes/class-model-registry.php file exists and activation defaults now use it.
  • Successful backend cost hooks and backend provider metadata coverage remain much better than earlier passes.
  • PHP and JavaScript syntax checks pass.

One serious runtime regression remains: several new failed-attempt paths call $provider_result->get_default_model(), but WPAW_Provider_Selection_Result does not define that method. That will turn provider failures into fatal PHP errors instead of graceful error handling and cost tracking.

The remaining non-fatal gaps are mostly contract adoption: the sidebar still hydrates chat through the deprecated /chat-history route, provider metadata is still not rendered in the editor, and the model registry exists but is not yet the actual single source of truth across settings, JS presets, providers, and image helpers.

Verification Performed

  • PHP syntax check across plugin PHP files: passed.
  • node -c assets/js/sidebar.js: passed.
  • node -c assets/js/settings-v2.js: passed.
  • node -c assets/js/sidebar-utils.js: passed.
  • Static retrace of eighth-pass findings against current code.
  • Static sweep of chat-history migration, failed-attempt tracking, provider metadata UI usage, model registry adoption, and model default duplication.
  • No live WordPress editor/browser workflow was run in this pass.

Eighth-Pass Status Trace

Eighth-pass item Current status Evidence
/chat-history empty after migration Fixed get_post_chat_history() now uses get_sessions_for_post() and the returned $migrated_session_id at includes/class-gutenberg-sidebar.php:1397-1434.
Sidebar dependency on /chat-history Still open as cleanup/API debt assets/js/sidebar.js:644-668 still fetches /chat-history/${postId}.
Failed-attempt cost tracking Regressed in runtime error paths Failed branches call nonexistent $provider_result->get_default_model() at includes/class-gutenberg-sidebar.php:3798, 4165, 7006, and 7104.
Cost helper Added track_ai_cost() exists at includes/class-gutenberg-sidebar.php:966-1005.
Provider metadata backend coverage Improved Backend responses include provider_metadata in more places, and chat now also adds a provider_metadata envelope at includes/class-gutenberg-sidebar.php:1114.
Provider metadata UI rendering Still open assets/js/sidebar.js has no references to provider_metadata, fallback_used, selected_provider, or warnings; only web-search provider checks exist at assets/js/sidebar.js:5983-6000.
Model registry Created, partial adoption includes/class-model-registry.php exists and is required by wp-agentic-writer.php:50-51; activation uses it at wp-agentic-writer.php:140-145.
Model registry as single source of truth Still open Settings, JS presets, provider defaults, and image helper fallbacks still hard-code model ids.
WordPress editor browser pass Still open Syntax checks passed, but no live editor workflow was verified.

Remaining Findings

P0: Failed AI Paths Can Fatal On A Nonexistent Provider-Result Method

The new failed-attempt tracking calls this pattern:

  • includes/class-gutenberg-sidebar.php:3796-3805 for regeneration.
  • includes/class-gutenberg-sidebar.php:4163-4172 for clarity API failure.
  • includes/class-gutenberg-sidebar.php:7004-7012 for multi-pass refinement.
  • includes/class-gutenberg-sidebar.php:7102-7110 for article refinement.

Each uses:

$provider_result->get_default_model() ?? 'unknown'

But WPAW_Provider_Selection_Result only defines public properties and a constructor at includes/class-provider-manager.php:20-33; it has no get_default_model() method. The only get_default_model() found is the static registry method WPAW_Model_Registry::get_default_model( $task ) at includes/class-model-registry.php:131-134.

Impact:

  • A provider error in these routes can produce a fatal PHP error.
  • The intended graceful fallback/error response will not run.
  • The intended failed-attempt cost tracking may not record anything.
  • This is especially risky because it triggers exactly when providers are unavailable, misconfigured, or failing.

Recommended fix:

  • Replace the invalid method call with task-specific registry calls:
    • Regeneration: WPAW_Model_Registry::get_default_model( 'writing' )
    • Clarity: WPAW_Model_Registry::get_default_model( 'clarity' )
    • Multi-pass/article refinement: WPAW_Model_Registry::get_default_model( 'refinement' )
  • Or pass the model explicitly into the failed-attempt helper from the request context/provider.
  • Add a focused regression check that simulates is_wp_error( $response ) for each route and asserts no fatal occurs.

P1: Provider Transparency Still Does Not Reach The Editor UI

Backend metadata improved. build_provider_metadata() returns provider, selected provider, fallback status, warnings, and model at includes/class-gutenberg-sidebar.php:956-963, and chat now also adds provider_metadata at includes/class-gutenberg-sidebar.php:1114.

The editor still does not render that data:

  • assets/js/sidebar.js has no references to provider_metadata, fallback_used, selected_provider, or warnings.
  • The only provider-related sidebar references are web-search availability checks at assets/js/sidebar.js:5983-6000.

Impact:

  • Users still cannot see actual provider/model/fallback behavior in the editor.
  • The Definition of Done requires the UI to show actual provider used.
  • Backend metadata can help logs/API consumers, but it does not yet close the UX transparency gap.

Recommended fix:

  • Add sidebar state for provider metadata from chat, plan, write, refine, meta, and utility AI responses.
  • Render a compact provider/model/fallback line near the cost/status UI.
  • Show warnings when fallback occurs.
  • Verify with a browser/editor pass.

P1: Model Registry Exists But Is Not Yet The Single Source Of Truth

The new registry is a good foundation:

  • includes/class-model-registry.php:24-219 defines task defaults, fallbacks, labels, frontend data, and activation defaults.
  • The plugin requires it at wp-agentic-writer.php:50-51.
  • Activation uses WPAW_Model_Registry::get_activation_defaults() at wp-agentic-writer.php:140-145.

But several runtime surfaces still hard-code defaults independently:

  • Settings V2 localization still falls back to old google/gemini-2.0-flash-exp:free values at includes/class-settings-v2.php:100-111.
  • Settings V2 sanitization still hard-codes defaults at includes/class-settings-v2.php:988-994.
  • JavaScript presets are still hard-coded in assets/js/settings-v2.js:32-58.
  • OpenRouter provider properties are still hard-coded at includes/class-openrouter-provider.php:29-75; comments say registry-sourced, but the constructor uses the hard-coded property values when settings are absent at includes/class-openrouter-provider.php:437-448.
  • Image manager still hard-codes anthropic/claude-3.5-sonnet and openai/gpt-4o fallbacks at includes/class-image-manager.php:183-249.

Impact:

  • The registry can drift from runtime behavior.
  • Settings UI can show or save defaults that do not match activation/provider defaults.
  • The screenshot's "model registry complete" claim is directionally true for creation, but not yet true for full adoption.

Recommended fix:

  • Replace settings fallback literals with WPAW_Model_Registry::get_default_model().
  • Localize WPAW_Model_Registry::get_frontend_data() to settings JS and derive presets from PHP data or explicitly document presets as curated overrides.
  • Initialize provider defaults from the registry instead of matching literals manually.
  • Replace image manager model fallbacks with registry calls.
  • Add a consistency test that fails if hard-coded task default strings appear outside the registry or approved presets.

P2: Sidebar Still Uses Deprecated Chat-History Route

The data-loss-style bug is fixed because get_post_chat_history() now uses sessions and migrated session ids. The remaining issue is contract cleanliness:

  • assets/js/sidebar.js:644-668 still calls /chat-history/${postId}.
  • The endpoint docblock still says it "does not use the conversations table" at includes/class-gutenberg-sidebar.php:1337-1339, but the implementation now does use conversations.

Impact:

  • The frontend still depends on a deprecated compatibility endpoint.
  • Documentation and behavior disagree.
  • Future refactors may remove or alter the route, breaking chat hydration again.

Recommended fix:

  • Move sidebar hydration to the canonical conversation/session context endpoint.
  • If /chat-history remains, update the docblock and response to include the canonical session_id and an explicit source.

P2: Cost Tracking Is Better But Still Allows Raw Hook Drift

track_ai_cost() exists, but many raw do_action( 'wp_aw_after_api_request', ... ) calls still remain in includes/class-gutenberg-sidebar.php.

Impact:

  • New or edited routes can bypass the helper and reintroduce missing provider/session/status data.
  • The failed-attempt fatal bug demonstrates why centralizing error/success tracking matters.

Recommended fix:

  • Convert remaining raw hook calls in class-gutenberg-sidebar.php to track_ai_cost().
  • Add a static check that disallows direct wp_aw_after_api_request calls outside track_ai_cost() and the cost tracker registration.

P2: Editor UI/UX Browser Verification Still Remains

The screenshot correctly identifies browser verification as remaining. Static checks passed, but no live editor workflow was run.

Recommended browser checklist:

  • Sidebar opens and persists in the block editor.
  • Chat session continues after page reload.
  • Provider/fallback warnings render when metadata exists.
  • Cost display updates after chat, plan, refine, and meta actions.
  • Unauthorized post access fails cleanly.
  • Model settings changes reflect in generated requests.
  1. Fix the nonexistent $provider_result->get_default_model() calls immediately.
  2. Render provider/model/fallback/warnings in the sidebar.
  3. Finish model registry adoption across settings, JS, provider defaults, and image manager fallbacks.
  4. Move sidebar chat hydration off /chat-history, or update the compatibility contract and docblock.
  5. Convert raw cost hooks to track_ai_cost() and add a static guard.
  6. Run the live WordPress editor browser workflow pass.

Current Verdict

The eighth-pass implementation is partially proper and closes the prior chat-history migration bug. It also added useful infrastructure with track_ai_cost() and WPAW_Model_Registry.

It is not release-clean yet. The top blocker is the failed-attempt runtime fatal caused by calling get_default_model() on the wrong object. After that, the remaining work is mostly contract completion: provider metadata in UI, full registry adoption, and browser verification.