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

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_history migration.
  • 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-1432 checks _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:1415 uses new WP_Agentic_Writer_Context_Service().

That class is explicitly a singleton:

  • includes/class-context-service.php:41-45 exposes WP_Agentic_Writer_Context_Service::get_instance().
  • includes/class-context-service.php:51-53 declares private function __construct().

Impact:

  • A legacy post with _wpaw_chat_history and 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() with WP_Agentic_Writer_Context_Service::get_instance().
  • After migration, prefer the returned $migrated_session_id when fetching/returning the session, with a fallback to get_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-5368 and 5516-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 unknown provider 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.php to track_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:3698
  • assets/js/sidebar.js:3932
  • assets/js/sidebar.js:4821

Remaining gaps:

  • assets/js/sidebar.js:4222-4224 handles another stream complete event and updates cost without calling applyProviderMetadata(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, and 5552-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_metadata on every stream complete payload that follows a provider call.
  • Call applyProviderMetadata(data) in every frontend data.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_history migrates 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-34 says presets are curated product decisions, not registry-derived.
  • includes/class-settings.php:1026 says 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

  1. P0: Replace direct new WP_Agentic_Writer_Context_Service() with WP_Agentic_Writer_Context_Service::get_instance() in the canonical conversation migration path.
  2. P1: Convert remaining seven-argument cost hooks to the full provider/session/status contract or track_ai_cost().
  3. P2: Finish provider metadata coverage for every stream complete branch and payload.
  4. P2: Run the live WordPress editor browser verification pass.
  5. 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_request calls 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.