11 KiB
WP Agentic Writer Thirteenth Retrace Audit
Audit date: 2026-05-26
Baseline retraced: docs/architecture/PLUGIN_AUDIT_RETRACE_TWELFTH_PASS_2026-05-26.md
Scope: thirteenth pass after twelfth-retrace implementation, covering legacy chat migration, conversation context continuity, cost attribution, provider metadata coverage, model registry ownership, UI/UX readiness, and release verification.
Status: COMPLETE / RETRACED
Completion marker: 2026-05-26
Follow-up retrace: docs/architecture/PLUGIN_AUDIT_RETRACE_FOURTEENTH_PASS_2026-05-26.md
This thirteenth-pass report has been implemented and retraced. Keep this document as historical evidence only; use the fourteenth-pass report for current remaining work.
Executive Summary
The twelfth-pass implementation closed several items from the previous report:
- The canonical
/conversation/{post_id}handler now attempts legacy_wpaw_chat_historymigration. - The specific keyword and improvement suggestion cost hooks called out in the twelfth report now pass the full hook contract.
- The missed frontend provider metadata calls at the previously listed generation/clarity branches were added.
- The deprecated chat-history docblock now describes migration behavior accurately.
- Backup JavaScript endpoint references were removed from
assets/.
However, a new P0 runtime regression was found in the legacy migration implementation: the new /conversation/{post_id} migration branch directly instantiates WP_Agentic_Writer_Context_Service, but that service has a private constructor. This will fatal when a legacy post has _wpaw_chat_history and no existing conversation session.
Static syntax checks still pass, but PHP linting cannot detect this runtime visibility error.
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 twelfth-pass findings against current code.
- Static sweep of legacy chat migration, provider metadata propagation, raw cost hooks, model default ownership, stale backup files, and browser-verification evidence.
- No live WordPress editor/browser workflow was run in this pass.
Twelfth-Pass Status Trace
| Twelfth-pass item | Current status | Evidence |
|---|---|---|
/conversation/{post_id} should migrate legacy chat history |
Implemented, but broken by P0 | Migration branch exists at includes/class-gutenberg-sidebar.php:1411-1432, but calls a private constructor at line 1415. |
| Keyword suggestion cost attribution | Fixed for called-out path | includes/class-keyword-suggester.php:140-151 now passes provider/session/status fields. |
| Improvement suggestion cost attribution | Fixed for called-out path | includes/class-gutenberg-sidebar.php:6911-6922 now passes provider/session/status fields. |
| Provider metadata calls for listed frontend branches | Mostly fixed | applyProviderMetadata() is now present at the previously missed branches, including assets/js/sidebar.js:3698, 3932, and 4821. |
| Model preset/default ownership | Partially de-scoped | JS and legacy presets now document that they are curated, but duplicated hard-coded presets remain active. |
| Browser verification | Still open | Static checks passed; no live editor workflow evidence was found. |
| Stale chat-history comments and backup files | Fixed | Docblock updated at includes/class-gutenberg-sidebar.php:1346-1350; no *.bak or *.backup files remain under assets/. |
Remaining Findings
P0: Legacy Chat Migration Path Can Fatal Due Private Singleton Constructor
The twelfth implementation added the needed migrate-on-read behavior to the canonical conversation endpoint:
includes/class-gutenberg-sidebar.php:1411-1432checks_wpaw_chat_history, attempts migration, then returns the newly created session.
But the migration branch instantiates the context service directly:
includes/class-gutenberg-sidebar.php:1415usesnew WP_Agentic_Writer_Context_Service().
That class is explicitly a singleton:
includes/class-context-service.php:41-45exposesWP_Agentic_Writer_Context_Service::get_instance().includes/class-context-service.php:51-53declaresprivate function __construct().
Impact:
- A legacy post with
_wpaw_chat_historyand no existing conversation session can trigger a fatal error when the editor loads chat through/conversation/{post_id}. - This is exactly the legacy continuity path the twelfth pass intended to repair.
- PHP syntax checks still pass because this is a runtime visibility error, not a parse error.
Recommended fix:
- Replace
new WP_Agentic_Writer_Context_Service()withWP_Agentic_Writer_Context_Service::get_instance(). - After migration, prefer the returned
$migrated_session_idwhen fetching/returning the session, with a fallback toget_session_by_post_id(). - Add a regression test or manual fixture for: post has
_wpaw_chat_history, has no conversation row, editor loads/conversation/{post_id}.
P1: Raw Cost Hook Drift Still Leaves Provider Attribution Gaps
The two cost examples from the twelfth report were fixed, but a broader scan still found multiple seven-argument wp_aw_after_api_request calls in includes/class-gutenberg-sidebar.php. These calls still omit provider, session id, and status.
Examples:
- Section execution cost at
includes/class-gutenberg-sidebar.php:3034-3042. - Write-from-outline section cost at
includes/class-gutenberg-sidebar.php:3675-3683. - Block refinement cost at
includes/class-gutenberg-sidebar.php:4590-4598. - Streaming block refinement cost at
includes/class-gutenberg-sidebar.php:4718-4726. - Chat refinement planning/streaming costs at
includes/class-gutenberg-sidebar.php:5360-5368and5516-5524. - Meta description cost at
includes/class-gutenberg-sidebar.php:6316-6324. - Intent detection cost at
includes/class-gutenberg-sidebar.php:6708-6716.
Impact:
- The cost ledger can still show
unknownprovider for several real AI workflows. - Provider/fallback transparency can differ between UI responses and persisted cost rows.
- Future fixes remain fragile while some paths use
track_ai_cost()and others manually fire a shorter hook contract.
Recommended fix:
- Convert all internal AI cost tracking in
class-gutenberg-sidebar.phptotrack_ai_cost()where the provider result is in scope. - Where provider result is not currently in scope, pass it through with the generated response, or explicitly document why attribution is unavailable.
- Add a static guard that fails when
do_action( 'wp_aw_after_api_request' )is called without the full provider/session/status contract outside the central helper.
P2: Provider Metadata Coverage Still Has Stream Completion Gaps
The frontend now applies provider metadata in the branches called out by the twelfth pass:
assets/js/sidebar.js:3698assets/js/sidebar.js:3932assets/js/sidebar.js:4821
Remaining gaps:
assets/js/sidebar.js:4222-4224handles another streamcompleteevent and updates cost without callingapplyProviderMetadata(data).- Some backend stream completion payloads still include only completion/cost fields and no provider metadata, including
includes/class-gutenberg-sidebar.php:3730-3732,4824-4827, and5552-5555.
Impact:
- Even when the frontend calls
applyProviderMetadata(), some completion payloads do not contain metadata to apply. - Provider badges can remain stale after specific streaming generation/refinement flows.
Recommended fix:
- Include
provider_metadataon every streamcompletepayload that follows a provider call. - Call
applyProviderMetadata(data)in every frontenddata.type === 'complete'branch that can receive provider-backed output. - For completion events that are intentionally non-provider events, add a short comment so future audits do not treat them as missing.
P2: Live Browser Verification Is Still Required
Static checks passed, but no live WordPress editor workflow evidence was found.
The next browser pass should verify:
- Legacy
_wpaw_chat_historymigrates through/conversation/{post_id}without fatal error. - Sidebar conversation state persists after editor reload.
- Provider badge updates after chat, clarity, planning, generation, block refinement, chat refinement, meta, keyword, intent, and improvement actions.
- Cost log rows include provider/session/status for the same actions.
- Model settings changes affect generated requests.
- Unauthorized REST access remains denied.
P3: Model Presets Are Documented As Curated, But Still Duplicated
The twelfth criteria allowed model presets/default ownership to be centralized or documented as intentional. The implementation chose documentation:
assets/js/settings-v2.js:32-34says presets are curated product decisions, not registry-derived.includes/class-settings.php:1026says the legacy inline presets are curated, not registry-derived.
This is acceptable as a product decision, but it leaves duplicated preset data in active code:
- Active Settings V2 presets are hard-coded at
assets/js/settings-v2.js:35-59. - Legacy settings presets are hard-coded at
includes/class-settings.php:1027-1051. - The legacy settings class can still be instantiated at
wp-agentic-writer.php:100-104.
Impact:
- Presets can drift between Settings V2 and legacy settings.
- Model updates still require edits in more than one place.
Recommended fix:
- If curated presets remain intentional, centralize them in one PHP source and localize them into both UIs.
- If legacy settings is only a fallback, add a deprecation note and a smaller test surface for preset parity.
Priority Queue
- P0: Replace direct
new WP_Agentic_Writer_Context_Service()withWP_Agentic_Writer_Context_Service::get_instance()in the canonical conversation migration path. - P1: Convert remaining seven-argument cost hooks to the full provider/session/status contract or
track_ai_cost(). - P2: Finish provider metadata coverage for every stream
completebranch and payload. - P2: Run the live WordPress editor browser verification pass.
- P3: Centralize curated model presets or document legacy preset parity ownership.
Completion Criteria For Next Pass
The next retrace can mark this pass complete when:
- Legacy chat migration through
/conversation/{post_id}cannot fatal on the context service constructor. - Static scan finds no short-form
wp_aw_after_api_requestcalls in provider-backed workflows. - Provider-backed stream completion payloads include metadata, and frontend completion branches apply it or explicitly de-scope it.
- Browser verification evidence exists for chat persistence, migration, provider badge updates, cost log attribution, model settings, and auth denial.