# 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: ```php $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. ## Recommended Next Work 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.