# WP Agentic Writer Twelfth Retrace Audit Audit date: 2026-05-26 Baseline retraced: `docs/architecture/PLUGIN_AUDIT_RETRACE_ELEVENTH_PASS_2026-05-26.md` Scope: twelfth pass after eleventh-retrace implementation, covering chat/context continuity, provider transparency, model registry adoption, cost attribution, UI/UX readiness, and release verification. Status: COMPLETE / RETRACED Completion marker: 2026-05-26 Follow-up retrace: `docs/architecture/PLUGIN_AUDIT_RETRACE_THIRTEENTH_PASS_2026-05-26.md` > This twelfth-pass report has been implemented and retraced. Keep this document as historical evidence only; use the thirteenth-pass report for current remaining work. ## Executive Summary The eleventh-pass implementation closed several meaningful items: - The sidebar now uses the canonical `/conversation/{post_id}` endpoint instead of the deprecated `/chat-history/{post_id}` endpoint. - `applyProviderMetadata()` is now called from many previously missed frontend paths, including meta generation, summarization, intent detection, reformat blocks, and refine-from-chat completion. - Model registry adoption is broader: Settings V2 fallback labels/defaults, OpenRouter constructor defaults, and image manager defaults now draw from `WPAW_Model_Registry`. - PHP and JavaScript syntax checks pass. No new P0 blocker was found. The remaining risk is narrower, but one new regression-class issue appeared during retrace: moving the sidebar to `/conversation` bypasses the legacy chat migration path that still lives under the deprecated chat-history compatibility method. That can make old post-meta chat history disappear from the editor UI for legacy posts that have not yet been migrated into conversation sessions. ## 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 eleventh-pass findings against current code. - Static sweep of provider metadata coverage, model registry usage, chat/context hydration, cost hook contracts, and stale compatibility code. - No live WordPress editor/browser workflow was run in this pass. ## Eleventh-Pass Status Trace | Eleventh-pass item | Current status | Evidence | |---|---:|---| | Sidebar still used deprecated `/chat-history` | Fixed in active sidebar | `assets/js/sidebar.js:673` now fetches `/conversation/${postId}`. | | Provider metadata missing in meta/summarize/intent/reformat/refine paths | Mostly fixed | `applyProviderMetadata()` is now called at `assets/js/sidebar.js:596`, `1603`, `1647`, `2195`, and `2836`. | | Model registry not adopted in Settings V2 fallbacks/OpenRouter/image defaults | Improved | Settings V2 and provider/image defaults now use registry-backed defaults; residual hard-coded presets remain. | | Raw cost hook drift | Still open | Direct `do_action( 'wp_aw_after_api_request', ... )` calls remain, including seven-argument calls that lose provider attribution. | | Browser verification | Still open | Syntax checks passed, but live editor workflows were not verified. | ## Remaining Findings ### P1: Canonical `/conversation` Endpoint Bypasses Legacy Chat Migration The active sidebar moved to the canonical endpoint: - `assets/js/sidebar.js:673` fetches `/conversation/${postId}`. However, the canonical backend handler only reads an existing conversation session: - `includes/class-gutenberg-sidebar.php:1408-1418` calls `get_session_by_post_id()` and returns an empty message list when no session exists. - `includes/class-conversation-manager.php:200-218` returns `null` when no active session is found. The legacy migration behavior still exists, but only in the deprecated compatibility path: - `includes/class-gutenberg-sidebar.php:1479-1492` reads `_wpaw_chat_history`, calls `migrate_legacy_chat_history()`, and returns migrated messages. Impact: - Legacy posts that still have `_wpaw_chat_history` but no conversation session can now hydrate as empty in the sidebar. - This can look like conversation loss after the eleventh-pass fix, even though the data still exists in post meta. - The deprecated endpoint has the safer migrate-on-read behavior, while the canonical endpoint does not. Recommended fix: - Make `handle_get_conversation_by_post()` use the same migrate-on-read behavior when no session exists and `_wpaw_chat_history` is present. - Return the migrated `session_id`, `post_id`, `has_session: true`, and messages after migration. - Add a regression test or fixture for a post with only `_wpaw_chat_history` and no `wpaw_conversations` row. ### P1: Cost Ledger Still Loses Provider Attribution For Some AI Actions The centralized `track_ai_cost()` helper exists, but some AI actions still use the raw hook with the old seven-argument shape. Examples: - `includes/class-keyword-suggester.php:32-34` obtains a provider result, but `includes/class-keyword-suggester.php:121-129` fires `wp_aw_after_api_request` without provider, session, or status arguments. - `includes/class-gutenberg-sidebar.php:6862-6864` obtains the provider for improvement analysis, but `includes/class-gutenberg-sidebar.php:6871-6879` also fires a seven-argument cost hook. - `includes/class-cost-tracker.php:50` registers the listener with nine accepted arguments, so omitted provider fields fall back to `unknown`. Impact: - Cost rows for keyword suggestions and improvement suggestions can under-report provider and fallback status. - Provider/cost dashboards can show `unknown` for actions where provider metadata was actually available. - This weakens the new provider transparency work because the UI response and ledger do not always agree. Recommended fix: - Replace these raw hook calls with `track_ai_cost()` or a shared public cost helper. - Where the helper is not accessible, pass the full nine-argument hook contract, including provider result, session id when available, and status. - Add a static check for seven-argument `wp_aw_after_api_request` calls. ### P2: Provider Metadata UI Coverage Is Much Better, But Not Exhaustive The eleventh-pass implementation fixed the major previously listed misses: - Meta generation calls `applyProviderMetadata(data)` at `assets/js/sidebar.js:596`. - Summarization calls it at `assets/js/sidebar.js:1603`. - Intent detection calls it at `assets/js/sidebar.js:1647`. - Reformat blocks calls it at `assets/js/sidebar.js:2195`. - Refine-from-chat completion calls it at `assets/js/sidebar.js:2836`. Remaining missed or duplicate paths: - One stream completion branch at `assets/js/sidebar.js:3697-3710` emits a completion payload with `totalCost` only, so the frontend has no provider metadata to apply. - Another completion handler at `assets/js/sidebar.js:3930-3945` updates cost/timeline without applying provider metadata. - The clarity check path at `assets/js/sidebar.js:4818-4825` parses `clarityData` but does not apply provider metadata from the response. Impact: - The provider badge is now reliable for many common flows, but can still remain stale after some generation or clarity workflows. - Users may see correct cost movement while the provider/fallback display still reflects a previous request. Recommended fix: - Ensure every backend AI response and stream completion payload includes `provider_metadata` when a provider was involved. - Call `applyProviderMetadata(data)` immediately after every AI JSON response parse and every stream `complete` event that can carry metadata. - For endpoints intentionally without provider metadata, document that in code next to the parse/complete branch. ### P2: Model Registry Still Has Residual Hard-Coded Defaults And Presets Registry adoption is now strong in the active PHP defaults, but not complete: - `assets/js/settings-v2.js:32-58` still defines budget/balanced/premium presets with hard-coded model IDs. - `includes/class-settings.php:72-78`, `98-117`, `138-140`, `197`, and `1029-1049` still contain legacy settings defaults and presets with hard-coded model IDs. - `wp-agentic-writer.php:100-104` can still instantiate the legacy settings class if Settings V2 is unavailable. Some hard-coded model strings are acceptable when they are display labels, compatibility checks, pricing keys, or provider-specific suggestions. The remaining concern is default/preset ownership. Impact: - The registry is not yet the only source of model defaults users can activate. - JS presets and legacy settings can drift from the PHP registry. - Future model migrations still require edits in more than one place. Recommended fix: - Localize presets from `WPAW_Model_Registry::get_frontend_data()` or add explicit registry preset support. - Either retire the legacy `WP_Agentic_Writer_Settings` path or make it read registry defaults. - Keep provider suggestion maps and pricing tables separate, but name them as suggestions/pricing rather than defaults. ### P2: Live Browser Verification Is Still The Final Release Gate Static checks passed, but the plugin still needs a live editor pass before calling the audit chain fully complete. Manual verification should cover: - Sidebar opens in the block editor and survives page reload. - Existing legacy post-meta chat history migrates and appears through `/conversation/{post_id}`. - New chat messages persist, reload, and retain session id continuity. - Provider/fallback badges update after chat, clarity, planning, generation, refinement, summarize, reformat, meta, keyword, and improvement actions. - Cost totals update in the UI and cost ledger with provider/session/status fields populated. - Model setting changes affect generated requests and visible provider metadata. - Unauthorized REST access remains denied. ### P3: Stale Compatibility Comments And Backup Files Can Create Audit Noise The deprecated chat-history docblock is now stale: - `includes/class-gutenberg-sidebar.php:1349-1350` says the endpoint does not use the conversations table, but the implementation delegates through conversation/session migration behavior. Also, backup JavaScript files still reference old endpoint behavior: - `assets/js/sidebar.js.backup` - `assets/js/sidebar.js.bak` Impact: - Future retraces can mistake backup files or stale comments for active behavior. - If backup files are accidentally packaged, old endpoint usage can leak into distribution artifacts. Recommended fix: - Update the deprecated endpoint docblock to describe the actual compatibility behavior. - Exclude backup files from packaging or remove them after confirming they are not needed. ## Priority Queue 1. P1: Add migrate-on-read behavior to `/conversation/{post_id}` for legacy `_wpaw_chat_history`. 2. P1: Fix seven-argument cost hooks for keyword and improvement suggestions so provider attribution is preserved. 3. P2: Finish provider metadata propagation for remaining stream completion and clarity branches. 4. P2: Move active JS presets and legacy settings defaults under the model registry, or explicitly retire/de-scope legacy settings. 5. P2: Run live WordPress editor browser verification. 6. P3: Clean stale chat-history comments and backup endpoint references. ## Completion Criteria For Next Pass The next retrace can mark this pass complete when: - `/conversation/{post_id}` migrates legacy chat history when no session exists. - Keyword and improvement suggestion cost rows include provider, fallback, session/status where available. - Provider metadata is applied or explicitly de-scoped for every AI response path. - Remaining model preset/default ownership is either centralized in the registry or documented as intentional. - A live editor verification note exists with the exact workflows checked.