feat: consolidate docs, backend/session infra, and settings updates

This commit is contained in:
Dwindi Ramadhana
2026-05-28 00:58:20 +07:00
parent 2424acf726
commit 44e06eed88
102 changed files with 35423 additions and 11181 deletions

View File

@@ -0,0 +1,177 @@
# WP Agentic Writer Fifth Retrace Audit
Status: COMPLETE / RETRACED
Completion marker: 2026-05-25
Follow-up report: `docs/architecture/PLUGIN_AUDIT_RETRACE_SIXTH_PASS_2026-05-25.md`
Audit date: 2026-05-25
Baseline retraced: `docs/architecture/PLUGIN_AUDIT_RETRACE_FOURTH_PASS_2026-05-25.md`
Scope: fifth pass after fourth-retrace implementation, covering REST authorization, conversation context/history, provider metadata, cost attribution, model defaults, and release readiness.
## Executive Summary
The fourth-pass implementation closed meaningful gaps:
- `handle_clear_context()` now checks `edit_post` before clearing post context.
- Legacy chat migration now deletes `_wpaw_chat_history` and writes `_wpaw_chat_history_migrated`.
- `get_context()` now attempts migrate-on-read when no session exists and legacy post meta is present.
- `record_usage()` is now marked deprecated.
- PHP syntax validation still passes.
- `assets/js/sidebar.js` and `assets/js/settings-v2.js` still pass JavaScript syntax validation.
The plugin is closer, but not fully clean. The remaining problem is no longer broad absence of checks; it is **ordering and coverage**. Several handlers added permission checks, but some still read post config/meta before checking access. Other AI utility routes accept `postId` for cost attribution or context but still never verify that the current user can edit that post.
## 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.
- Static trace of fourth-pass findings against current code.
- No live WordPress browser workflow was run in this pass.
## Fourth-Pass Status Trace
| Fourth-pass item | Current status | Evidence |
|---|---:|---|
| Clear-context post auth | Fixed | `handle_clear_context()` checks `check_post_permission()` before clearing at `includes/class-gutenberg-sidebar.php:1240-1263`. |
| Legacy chat migration cleanup | Fixed | `migrate_legacy_chat_history()` deletes legacy meta and writes `_wpaw_chat_history_migrated` at `includes/class-context-service.php:310-312`. |
| Migrate-on-read behavior | Improved | `get_context()` triggers migration when no session exists and legacy history is present at `includes/class-context-service.php:62-78`. |
| Deprecated legacy cost method | Improved | `record_usage()` is marked deprecated at `includes/class-cost-tracker.php:162-188`. |
| Permission sweep | Partially fixed | Several routes now check, but some checks still happen after post reads and some post-id routes still lack checks. |
| Provider metadata response contract | Still open | Chat exposes provider metadata; non-chat generated responses remain inconsistent. |
| Model registry/default unification | Still open | Defaults remain spread across PHP, JS, providers, wrapper, and image manager. |
## Critical Findings
### P0: Some Permission Checks Still Happen After Post-Scoped Reads
The fourth-pass report asked for checks before any post read/write/cost attribution/streaming. Some handlers added checks, but they are still too late:
- `handle_revise_plan()` calls `resolve_post_config_from_request()` and reads `_wpaw_detected_language` before checking `edit_post` at `includes/class-gutenberg-sidebar.php:2023-2057`.
- `handle_block_refine()` calls `resolve_post_config_from_request()` before checking `edit_post` at `includes/class-gutenberg-sidebar.php:4203-4230`.
- `handle_refine_from_chat()` calls `resolve_post_config_from_request()` before checking `edit_post` at `includes/class-gutenberg-sidebar.php:4857-4885`.
- `handle_generate_meta()` reads post content/title with `get_post()` before checking `edit_post` at `includes/class-gutenberg-sidebar.php:6077-6108`.
- `handle_check_clarity()` calls `resolve_post_config_from_request()` before checking `edit_post` at `includes/class-gutenberg-sidebar.php:3809-3839`.
Impact:
- A user can still trigger reads of post config, detected language, post title/content, or other post-scoped metadata for posts they cannot edit.
- These are not merely theoretical because helper calls like `resolve_post_config_from_request()` fall back to stored post config.
Recommended fix:
- Move the post permission check immediately after extracting `postId`, before any helper call that may read post meta/content.
- Use one centralized helper so the ordering is hard to get wrong:
- Extract post id.
- If `postId > 0`, require `edit_post`.
- Only then read config/meta/content or start streaming.
### P0: Some Post-ID Utility Routes Still Have No Target-Post Check
Several routes still accept `postId` and use it for context or cost attribution without validating target-post access:
- `handle_summarize_context()` accepts `postId` and records cost against it without checking `edit_post` at `includes/class-gutenberg-sidebar.php:6258-6330`.
- `handle_detect_intent()` accepts `postId` and records cost against it without checking `edit_post` at `includes/class-gutenberg-sidebar.php:6357-6415`.
- `handle_refine_multi_pass()` accepts `postId` and records cost against it without checking `edit_post` at `includes/class-gutenberg-sidebar.php:6730-6782`.
Impact:
- Cost records can still be attributed to posts the user cannot edit.
- These endpoints can be used to pollute another post's cost ledger even if they do not read that post's content directly.
Recommended fix:
- If an endpoint accepts `postId > 0`, require `edit_post` before using it for cost tracking.
- If the endpoint does not need post authority, ignore client-provided `postId` and track cost against `0` or the active session instead.
## High Priority Findings
### P1: Provider Metadata Is Still Not Uniform Outside Chat
Provider selection metadata exists in many code paths, but only chat responses consistently expose it. Non-chat flows still often return content, blocks, variants, keyword suggestions, or SEO results without a consistent provider envelope.
Examples from the current trace:
- Plan/revise/execute/refine handlers use `WP_Agentic_Writer_Provider_Manager::get_provider_for_task()`, but response envelopes do not consistently return `provider`, `selected_provider`, `fallback_used`, `warnings`, `model`, and `cost`.
- Keyword and image helper classes unwrap provider results but do not expose fallback metadata to the calling UI consistently.
Impact:
- Users and support logs still cannot reliably answer "which provider/model served this request?" outside chat.
- Fallback behavior is harder to debug in plan, refinement, SEO/GEO, keyword, and image paths.
Recommended fix:
- Add a shared helper that builds provider metadata from `WPAW_Provider_Selection_Result` plus model/cost response data.
- Add it to every generated response and streaming completion event.
### P1: Migrate-On-Read May Not Return the Newly Created Session
`get_context()` now calls `migrate_legacy_chat_history( $post_id, $session_id )`, but `migrate_legacy_chat_history()` only accepts `$post_id` in its signature and creates a new session when none exists. After that, `get_context()` tries `$manager->get_session( $session_id )` again.
Evidence:
- `get_context()` calls migration with two arguments at `includes/class-context-service.php:71-73`.
- `migrate_legacy_chat_history()` signature is `migrate_legacy_chat_history( $post_id )` at `includes/class-context-service.php:267`.
- When no session exists, migration creates a new session but does not return that new session id at `includes/class-context-service.php:301-307`.
Impact:
- Legacy history can be migrated and deleted, but the same read may still return an empty context if the caller's original `$session_id` was not the newly created session.
- The data is safer than before, but UX may still appear as "history disappeared" until a separate session lookup/list refresh.
Recommended fix:
- Make `migrate_legacy_chat_history()` return the target/new `session_id`, or accept a requested session id and create/update that session.
- In `get_context()`, fetch the returned session id after migration.
## Medium Priority Findings
### P2: Legacy `/chat-history` Endpoint Still Exposes Deprecated Storage
The route now has permission checks and a deprecated response marker, and legacy writes are disabled. Still, `/chat-history/(?P<post_id>\d+)` remains active and reads `_wpaw_chat_history`.
Impact:
- A deprecated route can keep old UI/client assumptions alive.
- It can confuse the source-of-truth contract if any caller still consumes it.
Recommended fix:
- Return an empty deprecated response after the migration window, or remove the route once the sidebar is fully on conversation sessions.
### P2: Legacy `record_usage()` Still Defaults Provider to OpenRouter
The method is deprecated, but it still records provider as `openrouter` for any caller that uses it.
Recommended fix:
- Change the fallback provider to `unknown`, or require callers to migrate to `record_usage_full()` before accepting records from this compatibility path.
### P2: Model Defaults Remain Fragmented
Model defaults still live across activation, settings PHP, settings JS, providers, image manager, and WP AI wrapper. This is unchanged from the fourth pass.
Recommended fix:
- Add a PHP model registry/default resolver.
- Localize resolved defaults to JS.
- Treat legacy `execution_model` as a migration alias into canonical `writing_model`.
### P2: Sidebar WordPress Compatibility Still Needs Browser Verification
The sidebar still imports `PluginSidebar` from `wp.editPost`. The previous fallback was removed. Syntax is green, but compatibility still needs a browser check on the minimum supported WordPress version.
## Definition of Done Gates for This Pass
Before considering this pass complete:
- Move every post permission check before any post config/meta/content read.
- Add target-post checks or ignore `postId` in summarize-context, detect-intent, and refine-multi-pass.
- Make legacy migrate-on-read return the migrated session in the same request.
- Standardize provider metadata in non-chat generated responses.
- Keep PHP and JS syntax checks green.
## Current Decision
The fourth-pass implementation is a real improvement and the legacy history storage is much closer to sane. Do not shift fully into new chat/context work yet. First finish the permission-order sweep and the few remaining cost-attribution endpoints; then the remaining issues are mostly consistency and observability rather than core safety.